@dropp.cc/payment-sdk 1.0.6 โ 1.0.7
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/README.md
CHANGED
|
@@ -92,7 +92,7 @@ Dropp.pay({
|
|
|
92
92
|
|
|
93
93
|
The Web SDK can also open Dropp-hosted pages inside the same modal container.
|
|
94
94
|
|
|
95
|
-
### `Dropp.
|
|
95
|
+
### `Dropp.dashboard(options)`
|
|
96
96
|
|
|
97
97
|
Loads `/#/firsttimeflow` for the dashboard/home page.
|
|
98
98
|
|
|
@@ -100,11 +100,11 @@ Loads `/#/firsttimeflow` for the dashboard/home page.
|
|
|
100
100
|
|
|
101
101
|
Loads `/#/unlink` for the account unlink page.
|
|
102
102
|
|
|
103
|
-
### `Dropp.
|
|
103
|
+
### `Dropp.transactions(options)`
|
|
104
104
|
|
|
105
105
|
Loads `/#/transactions` for the transactions page.
|
|
106
106
|
|
|
107
|
-
### `Dropp.
|
|
107
|
+
### `Dropp.offers(options)`
|
|
108
108
|
|
|
109
109
|
Loads `/#/offers` for the offers page.
|
|
110
110
|
|
|
@@ -116,15 +116,15 @@ Loads `/#/offers` for the offers page.
|
|
|
116
116
|
### Hosted Page Example:
|
|
117
117
|
|
|
118
118
|
```javascript
|
|
119
|
-
await Dropp.
|
|
119
|
+
await Dropp.dashboard({
|
|
120
120
|
onClose: () => {
|
|
121
121
|
console.log('Dashboard modal closed');
|
|
122
122
|
}
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
await Dropp.unlinkAccount();
|
|
126
|
-
await Dropp.
|
|
127
|
-
await Dropp.
|
|
126
|
+
await Dropp.transactions();
|
|
127
|
+
await Dropp.offers();
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
### SDK Instance Example:
|
|
@@ -137,10 +137,10 @@ const { sdk } = await Dropp.init({
|
|
|
137
137
|
environment: 'production'
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
-
await sdk.
|
|
140
|
+
await sdk.dashboard();
|
|
141
141
|
await sdk.unlinkAccount();
|
|
142
|
-
await sdk.
|
|
143
|
-
await sdk.
|
|
142
|
+
await sdk.transactions();
|
|
143
|
+
await sdk.offers();
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
## Environments
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e={READY:"DROPP_SDK_READY",PAYMENT_SUCCESS:"PAYMENT_SUCCESS",PAYMENT_FAILED:"PAYMENT_FAILED",PAYMENT_CANCELLED:"PAYMENT_CANCELLED",CLOSE_WEBVIEW:"CLOSE_WEBVIEW",AUTO_CLOSE_WEBVIEW:"AUTO_CLOSE_WEBVIEW",PAYMENT_PAGE_LOADED:"PAYMENT_PAGE_LOADED"},t="DROPP_SDK_INIT",n="DROPP_SDK_CLOSE",i={PRODUCTION:"production",QA:"qa",SANDBOX:"sandbox"},s={[i.PRODUCTION]:"https://wv.dropp.cc",[i.QA]:"https://wv.qa.dropp.cc",[i.SANDBOX]:"https://wv.sandbox.dropp.cc"},r={[i.PRODUCTION]:["https://wv.dropp.cc"],[i.QA]:["https://wv.qa.dropp.cc"],[i.SANDBOX]:["https://wv.sandbox.dropp.cc"]},o=3e4,a=6e5,l={STANDARD:"standard",PREAUTH:"preauth",RECURRING:"recurring"},c="INIT_TIMEOUT",d="PAYMENT_TIMEOUT",p="INVALID_CONFIG",h="ALREADY_OPEN",u="UNKNOWN_ERROR",m="1.0.2";const g=new class{constructor(e,t={}){this.environment=e,this.forceEnabled=!!t.enabled,this.enabled=this._shouldEnableLogging()}_shouldEnableLogging(){return this.forceEnabled}setEnvironment(e,t={}){this.environment=e,"boolean"==typeof t.enabled&&(this.forceEnabled=t.enabled),this.enabled=this._shouldEnableLogging()}setEnabled(e){this.forceEnabled=!!e,this.enabled=this._shouldEnableLogging()}log(...e){this.enabled&&console.log(...e)}warn(...e){this.enabled&&console.warn(...e)}error(...e){this.enabled&&console.error(...e)}debug(...e){this.enabled&&console.debug(...e)}info(...e){this.enabled&&console.info(...e)}}("qa",{enabled:!1}),y=["USD","HBAR","USDC"],f=["NONE","HALF_HOURLY","HOURLY","DAILY","WEEKLY","MONTHLY","YEARLY"],D=[l.STANDARD,l.PREAUTH,l.RECURRING];function S(e,t={}){const{isProduction:n=!1,allowLocalCallbacksInNonProd:i=!1}=t;if("string"!=typeof e||!e.trim())return!1;try{const t=new URL(e.trim()),s="https:"===t.protocol;if(!("http:"===t.protocol)&&!s)return!1;return function(e){if(!e)return!1;const t=e.trim().toLowerCase();if("localhost"===t||"127.0.0.1"===t||"::1"===t||t.endsWith(".local"))return!0;if(!/^(\d{1,3}\.){3}\d{1,3}$/.test(t))return!1;const n=t.split(".").map(e=>Number(e));if(n.some(e=>Number.isNaN(e)||e<0||e>255))return!1;const[i,s]=n;return 10===i||127===i||172===i&&s>=16&&s<=31||192===i&&168===s||169===i&&254===s}(t.hostname)?!n&&i:!n||s}catch{return!1}}function v(e={},t={}){const n=[],i=e.paymentType||l.STANDARD,s="production"===(t.environment||"").toLowerCase(),r=!!t.allowLocalCallbacksInNonProd,o="string"==typeof e.currency?e.currency.trim().toUpperCase():"";if(D.includes(i)||n.push(`paymentType must be one of: ${D.join(", ")}`),void 0===e.amount||null===e.amount||""===e.amount?n.push("amount is required"):function(e){const t="number"==typeof e?e:parseFloat(e);return"number"==typeof t&&!Number.isNaN(t)&&t>0}(e.amount)||n.push("amount must be a positive number"),e.currency&&"string"==typeof e.currency&&e.currency.trim()?y.includes(o)||n.push(`currency must be one of: ${y.join(", ")}`):n.push("currency is required"),e.itemName&&"string"==typeof e.itemName&&e.itemName.trim()||n.push("itemName is required"),i===l.PREAUTH&&(o&&"USD"!==o&&n.push("currency must be USD for preauth payments"),e.callbackUrl&&String(e.callbackUrl).trim()?S(e.callbackUrl,{isProduction:s,allowLocalCallbacksInNonProd:r})||n.push(s?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for preauth payments"),void 0===e.authHoldTimeInSeconds||null===e.authHoldTimeInSeconds||""===e.authHoldTimeInSeconds?n.push("authHoldTimeInSeconds is required for preauth payments"):function(e){const t="number"==typeof e?e:parseInt(e,10);return Number.isInteger(t)&&t>0}(e.authHoldTimeInSeconds)||n.push("authHoldTimeInSeconds must be a positive integer (seconds)")),i===l.RECURRING){e.callbackUrl&&String(e.callbackUrl).trim()?S(e.callbackUrl,{isProduction:s,allowLocalCallbacksInNonProd:r})||n.push(s?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for recurring payments");const t=(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase();t?f.includes(t)||n.push(`frequency must be one of: ${f.join(", ")}`):n.push("frequency is required for recurring payments"),e.recurringEndDate&&String(e.recurringEndDate).trim()?!function(e){if("string"!=typeof e||!e.trim())return!1;const t=new Date(e.trim());return!Number.isNaN(t.getTime())}(e.recurringEndDate)?n.push("recurringEndDate must be a valid ISO date-time string"):new Date(e.recurringEndDate.trim())<=new Date&&n.push("recurringEndDate must be in the future"):n.push("recurringEndDate (expiry) is required for recurring payments")}return{valid:0===n.length,errors:n}}function b(e,t,n={}){return{code:e,message:t,details:n,timestamp:(new Date).toISOString(),toString(){return this.message||"Dropp SDK error"}}}class w{constructor(e,t,n=null){this.environment=e,this.onMessage=t,this.sessionId=`dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2,15)}`,g.log("[MessageHandler] Session initialized"),this.iframe=null,this.allowedOrigins=n?.length>0?n:r[e]||[],this.messageListener=null,this.pendingMessages=new Map}init(e){this.iframe=e,this.messageListener=this._handleMessage.bind(this),window.addEventListener("message",this.messageListener)}destroy(){this.messageListener&&(window.removeEventListener("message",this.messageListener),this.messageListener=null),this.iframe=null,this.pendingMessages.clear()}_handleMessage(e){if(g.log("[MessageHandler] Received postMessage event"),e.source===window)return void g.log("[MessageHandler] Ignoring message from self");if(!this._validateOrigin(e.origin))return void g.warn("[Dropp SDK] Rejected message from untrusted origin:",e.origin);if(!this.iframe||e.source!==this.iframe.contentWindow)return void g.warn("[Dropp SDK] Rejected message from unexpected source",{eventOrigin:e.origin});const t=e.data;this._validateMessageStructure(t)?t.sessionId&&t.sessionId!==this.sessionId?g.warn("[Dropp SDK] Rejected message with invalid session ID"):(g.log("[MessageHandler] Message passed validation"),this._processMessage(t)):g.warn("[Dropp SDK] Rejected message with invalid structure")}_validateOrigin(e){return!(!e.startsWith("http://localhost:")&&!e.startsWith("http://127.0.0.1:"))||this.allowedOrigins.includes(e)}_validateMessageStructure(t){if(!t||"object"!=typeof t)return!1;if(!t.type||"string"!=typeof t.type)return!1;return!!Object.values(e).includes(t.type)&&!!t.timestamp}_processMessage(e){g.log("[Dropp SDK] Received message:",e.type),this.onMessage&&this.onMessage(e)}sendToPaymentApp(e,t={}){if(!this.iframe||!this.iframe.contentWindow)return g.error("[Dropp SDK] Cannot send message: iframe not ready"),!1;const n={type:e,data:t,sessionId:this.sessionId,timestamp:(new Date).toISOString(),sdkVersion:"1.0.0"},i=this.allowedOrigins[0]||"*";try{return this.iframe.contentWindow.postMessage(n,i),g.log("[Dropp SDK] Sent message:",e),!0}catch(e){return g.error("[Dropp SDK] Error sending message:",e),!1}}sendInit(e){return this.sendToPaymentApp(t,{mode:"sdk",config:e})}sendClose(){return this.sendToPaymentApp(n,{})}getSessionId(){return this.sessionId}}class E{constructor(e){this.onClose=e,this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,this.isOpen=!1,this.escapeListener=null}open(){return this.isOpen?(g.warn("[Dropp SDK] Modal is already open"),null):(this._createModal(),this._attachEventListeners(),this._show(),this.isOpen=!0,this.iframe)}close(){g.log("[ModalManager] ๐ฆ close() called, isOpen:",this.isOpen),this.isOpen?(g.log("[ModalManager] ๐ฆ Hiding modal..."),this._hide(),g.log("[ModalManager] ๐ฆ Removing event listeners..."),this._removeEventListeners(),g.log("[ModalManager] ๐ฆ Destroying modal..."),this._destroyModal(),this.isOpen=!1,g.log("[ModalManager] โ
Modal close sequence initiated")):g.log("[ModalManager] โ ๏ธ Modal is not open, skipping close")}_createModal(){this.overlay=document.createElement("div"),this.overlay.id="dropp-payment-overlay",this._applyOverlayStyles(this.overlay),this.container=document.createElement("div"),this.container.id="dropp-payment-container",this._applyContainerStyles(this.container),this.iframe=document.createElement("iframe"),this.iframe.id="dropp-payment-iframe",this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups"),this.iframe.setAttribute("referrerpolicy","no-referrer"),this.iframe.setAttribute("title","Dropp Payment"),this._applyIframeStyles(this.iframe),this.container.appendChild(this.iframe),this.overlay.appendChild(this.container),document.body.appendChild(this.overlay)}_applyOverlayStyles(e){Object.assign(e.style,{position:"fixed",inset:"0",width:"100vw",height:"100vh",margin:"0",padding:"20px",boxSizing:"border-box",backgroundColor:"rgba(0, 0, 0, 0.6)",zIndex:999999..toString(),display:"flex",alignItems:"center",justifyContent:"center",opacity:"0",transition:"opacity 0.3s ease",backdropFilter:"blur(4px)",overflow:"auto"})}_applyContainerStyles(e){const t=window.innerWidth<768;this._isMobile=t,Object.assign(e.style,{position:"relative",flex:"0 0 auto",alignSelf:"center",margin:"auto",width:"100%",maxWidth:t?"100%":"400px",height:t?"100%":"auto",minHeight:t?"100%":"800px",maxHeight:t?"100%":"min(1000px, calc(100vh - 40px))",backgroundColor:"#ffffff",borderRadius:t?"0":"16px",boxShadow:"0 20px 60px rgba(0, 0, 0, 0.3)",overflow:"hidden",transform:"scale(0.95)",transition:"transform 0.3s ease, opacity 0.3s ease",display:"flex",flexDirection:"column"})}_getContainerTransform(e){return`scale(${e})`}_applyCloseButtonStyles(e){Object.assign(e.style,{position:"absolute",top:"16px",right:"16px",zIndex:"10",width:"40px",height:"40px",border:"none",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.9)",color:"#333",fontSize:"28px",lineHeight:"1",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.15)",transition:"all 0.2s ease",fontFamily:"Arial, sans-serif",padding:"0"}),e.addEventListener("mouseenter",()=>{Object.assign(e.style,{backgroundColor:"#f5f5f5",transform:"scale(1.1)"})}),e.addEventListener("mouseleave",()=>{Object.assign(e.style,{backgroundColor:"rgba(255, 255, 255, 0.9)",transform:"scale(1)"})})}_applyIframeStyles(e){const t=this._isMobile;Object.assign(e.style,{width:"100%",flex:"1 1 auto",minHeight:t?"100%":"min(520px, calc(90vh - 40px))",height:t?"100%":"min(520px, calc(90vh - 40px))",border:"none",display:"block"})}_show(){document.body.style.overflow="hidden",requestAnimationFrame(()=>{this.overlay&&(this.overlay.style.opacity="1"),this.container&&(this.container.style.transform=this._getContainerTransform(1))})}_hide(){g.log("[ModalManager] ๐ญ _hide() called"),this.overlay&&(this.overlay.style.opacity="0",g.log("[ModalManager] ๐ญ Overlay opacity set to 0")),this.container&&(this.container.style.transform=this._getContainerTransform(.95),g.log("[ModalManager] ๐ญ Container transform set to scale(0.95)")),document.body.style.overflow="",g.log("[ModalManager] ๐ญ Body scroll restored")}_destroyModal(){g.log("[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation"),setTimeout(()=>{g.log("[ModalManager] ๐๏ธ Animation complete, removing from DOM"),this.overlay&&this.overlay.parentNode&&(this.overlay.parentNode.removeChild(this.overlay),g.log("[ModalManager] ๐๏ธ Overlay removed from DOM")),this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,g.log("[ModalManager] โ
Modal destroyed")},300)}_attachEventListeners(){}_removeEventListeners(){this.escapeListener&&(document.removeEventListener("keydown",this.escapeListener),this.escapeListener=null)}_handleCloseClick(e){e.stopPropagation(),this.onClose&&this.onClose("user_closed")}_handleOverlayClick(e){e.target===this.overlay&&this.onClose&&this.onClose("user_closed")}_handleEscapeKey(e){"Escape"===e.key&&this.isOpen&&this.onClose&&this.onClose("user_closed")}getIframe(){return this.iframe}getIsOpen(){return this.isOpen}}class T{constructor(e={}){if("undefined"==typeof window||"undefined"==typeof document)throw new Error("Dropp Payment SDK can only be used in a browser environment");if(!e.merchantId||!e.apiKey||!e.packageName)throw new Error("merchantId, apiKey, and packageName are required to initialize SDK");if(this.merchantId=e.merchantId,this.apiKey=e.apiKey,this.packageName=e.packageName,this.environment=e.environment||i.QA,this.baseUrl=e.paymentAppUrl||e.baseUrl||s[this.environment],this.isInitialized=!1,this.initializationPromise=null,this.getServerAuthToken="function"==typeof e.getServerAuthToken?e.getServerAuthToken:null,this.requireServerAuthToken="boolean"==typeof e.requireServerAuthToken?e.requireServerAuthToken:this.environment===i.PRODUCTION,this.allowLocalCallbacksInNonProd=!!e.allowLocalCallbacksInNonProd,e.allowedOrigins?.length)this.allowedOrigins=e.allowedOrigins;else try{this.allowedOrigins=[new URL(this.baseUrl).origin]}catch{this.allowedOrigins=r[this.environment]||[]}this.isOpen=!1,this.currentSession=null,this.currentFlowType=null,this.initTimeout=null,this.paymentTimeout=null,this.messageHandler=null,this.modalManager=null,g.setEnvironment(this.environment,{enabled:!!e.debugLogging}),g.log(`[Dropp SDK] Initialized v${m} - Environment: ${this.environment}`)}pay(e={}){return new Promise((t,n)=>{if(this.isOpen){const e=b(h,"A payment session is already in progress",{currentSession:this.currentSession});return void n(e)}(async()=>{try{await this.initialize();const i=v(e,{environment:this.environment,allowLocalCallbacksInNonProd:this.allowLocalCallbacksInNonProd});if(!i.valid){const e=b(p,"Invalid payment configuration",{errors:i.errors});return void n(e)}this.onSuccess=e.onSuccess||null,this.onFailure=e.onFailure||null,this.onCancel=e.onCancel||null,this.onClose=e.onClose||null,this.currentSession={resolve:t,reject:n,options:e,startTime:Date.now()},await this._initializePayment(e)}catch(e){const t=e&&e.code===p?e:b(u,"Failed to initialize payment",{originalError:e?.message||String(e)});n(t),this._cleanup()}})()})}async initialize(){return this.initializationPromise||(this.initializationPromise=(async()=>(await this._validateInitializationCredentials(),this.isInitialized=!0,{status:"success",code:"INITIALIZED",message:"Dropp SDK initialized successfully"}))().catch(e=>{throw this.isInitialized=!1,this.initializationPromise=null,e})),this.initializationPromise}_getValidationUrl(){const e={[i.QA]:"https://main.qa.dropp.cc/payer/webview/validate",[i.SANDBOX]:"https://sandbox.api.dropp.cc/payer/webview/validate",[i.PRODUCTION]:"https://api.dropp.cc/payer/webview/validate"};return e[this.environment]||e[i.QA]}async _validateInitializationCredentials(){const e=this._getValidationUrl();let t,n=null;try{t=await fetch(e,{method:"POST",headers:{accept:"application/json, text/plain, */*","content-type":"application/json","x-api-key":this.apiKey,"x-app-package":this.packageName},body:JSON.stringify({id:this.merchantId})})}catch(t){throw b(p,"Unable to validate merchant credentials",{endpoint:e,originalError:t?.message||String(t)})}try{n=await t.json()}catch{n=null}if(!t.ok)throw b(p,"Merchant validation failed for merchantId/apiKey/packageName",{endpoint:e,status:t.status,response:n});const i=Number(n?.responseCode),s=n?.errors,r=!Array.isArray(s)||0===s.length;if(!(n&&0===i&&r))throw b(p,"Merchant validation returned an unsuccessful response",{endpoint:e,status:t.status,response:n});g.log("[Dropp SDK] Merchant credentials validated successfully")}closePayment(){if(this.isOpen){if("page"===this.currentFlowType)return void this._cleanup();this._handleCancel("sdk_close")}}dashboard(e={}){return this._openHostedPage("/firsttimeflow",e)}unlinkAccount(e={}){return this._openHostedPage("/unlink",e)}transactions(e={}){return this._openHostedPage("/transactions",e)}offers(e={}){return this._openHostedPage("/offers",e)}async _initializePayment(e){g.log("[Dropp SDK] Initializing payment session"),this.currentFlowType="payment",this.messageHandler=new w(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new E(this._handleModalClose.bind(this));const t=this.modalManager.open();if(!t)throw new Error("Failed to create modal iframe");this.messageHandler.init(t);const n=e.paymentType||l.STANDARD;let i="/payViaUrl";n===l.PREAUTH?i="/preAuthPayment":n===l.RECURRING&&(i="/recurringPayment");const s=n===l.RECURRING?(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase():"",r=n===l.RECURRING&&"NONE"===s,c=e.appUrl||("undefined"!=typeof window&&window.location?window.location.href:void 0),d={merchantAccount:this.merchantId,amount:n===l.PREAUTH?void 0:e.amount,maxAmount:n===l.PREAUTH||r?e.amount:void 0,fixAmount:n!==l.RECURRING||r?void 0:e.amount,acceptPaymentDelay:n===l.STANDARD&&!0===e.acceptPaymentDelay||void 0,currency:e.currency,itemName:e.itemName,description:e.description,invoiceId:e.invoiceId||`INV-${Date.now()}`,invoiceType:n===l.PREAUTH?"PREAUTH":void 0,apiKey:this.apiKey,packageName:this.packageName,sdkVersion:m,platform:"web",appUrl:c,sessionId:this.messageHandler.getSessionId()};if(g.log("[Dropp SDK] Including SDK session context in payment params"),e.successURL&&(d.successURL=e.successURL),e.failureURL&&(d.failureURL=e.failureURL),n===l.RECURRING){const t=e.frequency||e.recurringInterval;t&&(d.frequency=t),e.recurringEndDate&&(d.expiry=e.recurringEndDate)}n===l.PREAUTH&&e.authHoldTimeInSeconds&&(d.authHoldTimeInSeconds=e.authHoldTimeInSeconds),e.callbackUrl&&(d.url=e.callbackUrl,d.submitToCallBack="post");const h={sessionId:d.sessionId,merchantAccount:this.merchantId,amount:e.amount,paymentType:n,invoiceId:d.invoiceId,expiry:e.recurringEndDate||null,issuedAt:Date.now()};let u="string"==typeof e.serverAuthToken?e.serverAuthToken.trim():"";if(!u&&this.getServerAuthToken)try{const e=await this.getServerAuthToken(h);u="string"==typeof e?e.trim():""}catch(e){throw b(p,"Failed to obtain server auth token",{originalError:e?.message||String(e)})}if(this.requireServerAuthToken&&!u)throw b(p,"serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.",{environment:this.environment,paymentType:n,invoiceId:d.invoiceId});const y=await async function(e,t,n,i,s={}){try{const{serverAuthToken:r=""}=s,o={};Object.keys(n).forEach(e=>{const t=n[e];null!=t&&(o[e]=t)}),g.log("[buildPaymentUrl] Building payment URL payload");const a=JSON.stringify(o),l=btoa(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""),c=Date.now().toString(),d=new URLSearchParams({pay:l,sdkTs:c,sdkVersion:i,platform:"web"});return r&&d.set("authToken",r),`${e}/#${t}?${d.toString()}`}catch(e){throw g.error("Error building payment URL:",e),e}}(this.baseUrl,i,d,m,{serverAuthToken:u});g.log("[Dropp SDK] Loading payment flow iframe"),t.src=y,this.isOpen=!0,this.initTimeout=setTimeout(()=>{this._handleTimeout("init")},o),this.paymentTimeout=setTimeout(()=>{this._handleTimeout("payment")},a)}async _openHostedPage(e,t={}){if(this.isOpen)throw b(h,"A Dropp session is already in progress",{currentSession:this.currentSession,route:e});await this.initialize(),this.currentFlowType="page",this.currentSession=null,this.onSuccess=null,this.onFailure=null,this.onCancel=null,this.onClose="function"==typeof t.onClose?t.onClose:null,this.modalManager=new E(this._handleModalClose.bind(this));const n=this.modalManager.open();if(!n)throw new Error("Failed to create modal iframe");const i=this.baseUrl.replace(/\/+$/,"");return n.src=`${i}/#${e}`,this.isOpen=!0,g.log("[Dropp SDK] Hosted page opened",{route:e}),{status:"opened",route:e}}_handleMessage(t){const{type:n,data:i}=t;switch(n){case e.READY:this._handleReady(i);break;case e.PAYMENT_PAGE_LOADED:this._handlePageLoaded(i);break;case e.PAYMENT_SUCCESS:this._handleSuccess(i);break;case e.PAYMENT_FAILED:this._handleFailure(i);break;case e.PAYMENT_CANCELLED:this._handleCancel("user_cancelled");break;case e.AUTO_CLOSE_WEBVIEW:g.log("[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal"),this._cleanup(),g.log("[Dropp SDK] Cleanup completed");break;case e.CLOSE_WEBVIEW:g.log("[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal"),this._handleCancel("app_close");break;default:g.warn("[Dropp SDK] Unknown message type:",n)}}_handleReady(e){if(g.log("[Dropp SDK] Payment app ready"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.messageHandler&&this.currentSession){const e={};Object.keys(this.currentSession.options).forEach(t=>{const n=this.currentSession.options[t];"function"!=typeof n&&(e[t]=n)}),g.log("[Dropp SDK] Sending init config to payment app"),this.messageHandler.sendInit(e)}}_handlePageLoaded(e){g.log("[Dropp SDK] Payment page loaded")}_handleSuccess(e){g.log("[Dropp SDK] Payment successful");const t={status:"success",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onSuccess&&this.onSuccess(t)}_handleFailure(e){g.log("[Dropp SDK] Payment failed");const t={status:"failed",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onFailure&&this.onFailure(t)}_handleCancel(e){g.log("[Dropp SDK] Payment cancelled");const t={status:"cancelled",reason:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0};this.currentSession&&this.currentSession.resolve(t),this.onCancel&&this.onCancel(t),this._cleanup()}_handleModalClose(e){g.log("[Dropp SDK] Modal closed by user"),"page"!==this.currentFlowType?this._handleCancel(e):this._cleanup()}_handleTimeout(e){g.error("[Dropp SDK] Timeout:",e);const t=b("init"===e?c:d,"init"===e?"Payment app failed to load within timeout period":"Payment session timed out",{type:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0});this.currentSession&&this.currentSession.reject(t),this.onFailure&&this.onFailure({status:"failed",error:t}),this._cleanup()}_cleanup(){g.log("[Dropp SDK] ๐งน Cleaning up session - starting cleanup"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.paymentTimeout&&(clearTimeout(this.paymentTimeout),this.paymentTimeout=null),this.messageHandler&&(g.log("[Dropp SDK] ๐งน Destroying message handler"),this.messageHandler.destroy(),this.messageHandler=null),this.modalManager&&(g.log("[Dropp SDK] ๐งน Closing modal manager"),this.modalManager.close(),g.log("[Dropp SDK] ๐งน Modal manager closed"),this.modalManager=null),this.currentSession=null,this.currentFlowType=null,this.isOpen=!1,this.onClose&&this.onClose()}static getVersion(){return m}static getEnvironments(){return{...i}}static getPaymentTypes(){return{...l}}}let _=null;async function I(e){_=new T(e);return{...await _.initialize(),sdk:_}}function A(){return _}const C={init:e=>I(e),pay(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.pay(e)},dashboard(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.dashboard(e)},unlinkAccount(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.unlinkAccount(e)},transactions(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.transactions(e)},offers(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.offers(e)},getInstance:()=>_};var N={DroppPaymentSDK:T,createPaymentSDK:I,Dropp:C,ENVIRONMENTS:i,PAYMENT_TYPES:l};export{C as Dropp,T as DroppPaymentSDK,i as ENVIRONMENTS,l as PAYMENT_TYPES,I as createPaymentSDK,N as default,A as getDroppInstance};
|
|
1
|
+
const e={READY:"DROPP_SDK_READY",PAYMENT_SUCCESS:"PAYMENT_SUCCESS",PAYMENT_FAILED:"PAYMENT_FAILED",PAYMENT_CANCELLED:"PAYMENT_CANCELLED",CLOSE_WEBVIEW:"CLOSE_WEBVIEW",AUTO_CLOSE_WEBVIEW:"AUTO_CLOSE_WEBVIEW",PAYMENT_PAGE_LOADED:"PAYMENT_PAGE_LOADED"},t="DROPP_SDK_INIT",n="DROPP_SDK_CLOSE",i={PRODUCTION:"production",QA:"qa",SANDBOX:"sandbox"},s={[i.PRODUCTION]:"https://wv.dropp.cc",[i.QA]:"https://wv.qa.dropp.cc",[i.SANDBOX]:"https://wv.sandbox.dropp.cc"},r={[i.PRODUCTION]:["https://wv.dropp.cc"],[i.QA]:["https://wv.qa.dropp.cc"],[i.SANDBOX]:["https://wv.sandbox.dropp.cc"]},o=3e4,a=6e5,l={STANDARD:"standard",PREAUTH:"preauth",RECURRING:"recurring"},c="INIT_TIMEOUT",d="PAYMENT_TIMEOUT",p="INVALID_CONFIG",h="ALREADY_OPEN",u="UNKNOWN_ERROR",m="1.0.2";const g=new class{constructor(e,t={}){this.environment=e,this.forceEnabled=!!t.enabled,this.enabled=this._shouldEnableLogging()}_shouldEnableLogging(){return this.forceEnabled}setEnvironment(e,t={}){this.environment=e,"boolean"==typeof t.enabled&&(this.forceEnabled=t.enabled),this.enabled=this._shouldEnableLogging()}setEnabled(e){this.forceEnabled=!!e,this.enabled=this._shouldEnableLogging()}log(...e){this.enabled&&console.log(...e)}warn(...e){this.enabled&&console.warn(...e)}error(...e){this.enabled&&console.error(...e)}debug(...e){this.enabled&&console.debug(...e)}info(...e){this.enabled&&console.info(...e)}}("qa",{enabled:!1}),y=["USD","HBAR","USDC"],f=["NONE","HALF_HOURLY","HOURLY","DAILY","WEEKLY","MONTHLY","YEARLY"],D=[l.STANDARD,l.PREAUTH,l.RECURRING];function S(e,t={}){const{isProduction:n=!1,allowLocalCallbacksInNonProd:i=!1}=t;if("string"!=typeof e||!e.trim())return!1;try{const t=new URL(e.trim()),s="https:"===t.protocol;if(!("http:"===t.protocol)&&!s)return!1;return function(e){if(!e)return!1;const t=e.trim().toLowerCase();if("localhost"===t||"127.0.0.1"===t||"::1"===t||t.endsWith(".local"))return!0;if(!/^(\d{1,3}\.){3}\d{1,3}$/.test(t))return!1;const n=t.split(".").map(e=>Number(e));if(n.some(e=>Number.isNaN(e)||e<0||e>255))return!1;const[i,s]=n;return 10===i||127===i||172===i&&s>=16&&s<=31||192===i&&168===s||169===i&&254===s}(t.hostname)?!n&&i:!n||s}catch{return!1}}function v(e={},t={}){const n=[],i=e.paymentType||l.STANDARD,s="production"===(t.environment||"").toLowerCase(),r=!!t.allowLocalCallbacksInNonProd,o="string"==typeof e.currency?e.currency.trim().toUpperCase():"";if(D.includes(i)||n.push(`paymentType must be one of: ${D.join(", ")}`),void 0===e.amount||null===e.amount||""===e.amount?n.push("amount is required"):function(e){const t="number"==typeof e?e:parseFloat(e);return"number"==typeof t&&!Number.isNaN(t)&&t>0}(e.amount)||n.push("amount must be a positive number"),e.currency&&"string"==typeof e.currency&&e.currency.trim()?y.includes(o)||n.push(`currency must be one of: ${y.join(", ")}`):n.push("currency is required"),e.itemName&&"string"==typeof e.itemName&&e.itemName.trim()||n.push("itemName is required"),i===l.PREAUTH&&(o&&"USD"!==o&&n.push("currency must be USD for preauth payments"),e.callbackUrl&&String(e.callbackUrl).trim()?S(e.callbackUrl,{isProduction:s,allowLocalCallbacksInNonProd:r})||n.push(s?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for preauth payments"),void 0===e.authHoldTimeInSeconds||null===e.authHoldTimeInSeconds||""===e.authHoldTimeInSeconds?n.push("authHoldTimeInSeconds is required for preauth payments"):function(e){const t="number"==typeof e?e:parseInt(e,10);return Number.isInteger(t)&&t>0}(e.authHoldTimeInSeconds)||n.push("authHoldTimeInSeconds must be a positive integer (seconds)")),i===l.RECURRING){e.callbackUrl&&String(e.callbackUrl).trim()?S(e.callbackUrl,{isProduction:s,allowLocalCallbacksInNonProd:r})||n.push(s?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for recurring payments");const t=(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase();t?f.includes(t)||n.push(`frequency must be one of: ${f.join(", ")}`):n.push("frequency is required for recurring payments"),e.recurringEndDate&&String(e.recurringEndDate).trim()?!function(e){if("string"!=typeof e||!e.trim())return!1;const t=new Date(e.trim());return!Number.isNaN(t.getTime())}(e.recurringEndDate)?n.push("recurringEndDate must be a valid ISO date-time string"):new Date(e.recurringEndDate.trim())<=new Date&&n.push("recurringEndDate must be in the future"):n.push("recurringEndDate (expiry) is required for recurring payments")}return{valid:0===n.length,errors:n}}function b(e,t,n={}){return{code:e,message:t,details:n,timestamp:(new Date).toISOString(),toString(){return this.message||"Dropp SDK error"}}}class w{constructor(e,t,n=null){this.environment=e,this.onMessage=t,this.sessionId=`dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2,15)}`,g.log("[MessageHandler] Session initialized"),this.iframe=null,this.allowedOrigins=n?.length>0?n:r[e]||[],this.messageListener=null,this.pendingMessages=new Map}init(e){this.iframe=e,this.messageListener=this._handleMessage.bind(this),window.addEventListener("message",this.messageListener)}destroy(){this.messageListener&&(window.removeEventListener("message",this.messageListener),this.messageListener=null),this.iframe=null,this.pendingMessages.clear()}_handleMessage(e){if(g.log("[MessageHandler] Received postMessage event"),e.source===window)return void g.log("[MessageHandler] Ignoring message from self");if(!this._validateOrigin(e.origin))return void g.warn("[Dropp SDK] Rejected message from untrusted origin:",e.origin);if(!this.iframe||e.source!==this.iframe.contentWindow)return void g.warn("[Dropp SDK] Rejected message from unexpected source",{eventOrigin:e.origin});const t=e.data;this._validateMessageStructure(t)?t.sessionId&&t.sessionId!==this.sessionId?g.warn("[Dropp SDK] Rejected message with invalid session ID"):(g.log("[MessageHandler] Message passed validation"),this._processMessage(t)):g.warn("[Dropp SDK] Rejected message with invalid structure")}_validateOrigin(e){return!(!e.startsWith("http://localhost:")&&!e.startsWith("http://127.0.0.1:"))||this.allowedOrigins.includes(e)}_validateMessageStructure(t){if(!t||"object"!=typeof t)return!1;if(!t.type||"string"!=typeof t.type)return!1;return!!Object.values(e).includes(t.type)&&!!t.timestamp}_processMessage(e){g.log("[Dropp SDK] Received message:",e.type),this.onMessage&&this.onMessage(e)}sendToPaymentApp(e,t={}){if(!this.iframe||!this.iframe.contentWindow)return g.error("[Dropp SDK] Cannot send message: iframe not ready"),!1;const n={type:e,data:t,sessionId:this.sessionId,timestamp:(new Date).toISOString(),sdkVersion:"1.0.0"},i=this.allowedOrigins[0]||"*";try{return this.iframe.contentWindow.postMessage(n,i),g.log("[Dropp SDK] Sent message:",e),!0}catch(e){return g.error("[Dropp SDK] Error sending message:",e),!1}}sendInit(e){return this.sendToPaymentApp(t,{mode:"sdk",config:e})}sendClose(){return this.sendToPaymentApp(n,{})}getSessionId(){return this.sessionId}}class E{constructor(e){this.onClose=e,this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,this.isOpen=!1,this.escapeListener=null}open(){return this.isOpen?(g.warn("[Dropp SDK] Modal is already open"),null):(this._createModal(),this._attachEventListeners(),this._show(),this.isOpen=!0,this.iframe)}close(){g.log("[ModalManager] ๐ฆ close() called, isOpen:",this.isOpen),this.isOpen?(g.log("[ModalManager] ๐ฆ Hiding modal..."),this._hide(),g.log("[ModalManager] ๐ฆ Removing event listeners..."),this._removeEventListeners(),g.log("[ModalManager] ๐ฆ Destroying modal..."),this._destroyModal(),this.isOpen=!1,g.log("[ModalManager] โ
Modal close sequence initiated")):g.log("[ModalManager] โ ๏ธ Modal is not open, skipping close")}_createModal(){this.overlay=document.createElement("div"),this.overlay.id="dropp-payment-overlay",this._applyOverlayStyles(this.overlay),this.container=document.createElement("div"),this.container.id="dropp-payment-container",this._applyContainerStyles(this.container),this.iframe=document.createElement("iframe"),this.iframe.id="dropp-payment-iframe",this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups"),this.iframe.setAttribute("referrerpolicy","no-referrer"),this.iframe.setAttribute("title","Dropp Payment"),this._applyIframeStyles(this.iframe),this.container.appendChild(this.iframe),this.overlay.appendChild(this.container),document.body.appendChild(this.overlay)}_applyOverlayStyles(e){Object.assign(e.style,{position:"fixed",inset:"0",width:"100vw",height:"100vh",margin:"0",padding:"20px",boxSizing:"border-box",backgroundColor:"rgba(0, 0, 0, 0.6)",zIndex:999999..toString(),display:"flex",alignItems:"center",justifyContent:"center",opacity:"0",transition:"opacity 0.3s ease",backdropFilter:"blur(4px)",overflow:"auto"})}_applyContainerStyles(e){const t=window.innerWidth<768;this._isMobile=t,Object.assign(e.style,{position:"relative",flex:"0 0 auto",alignSelf:"center",margin:"auto",width:"100%",maxWidth:t?"100%":"400px",height:t?"100%":"auto",minHeight:t?"100%":"800px",maxHeight:t?"100%":"min(1000px, calc(100vh - 40px))",backgroundColor:"#ffffff",borderRadius:t?"0":"16px",boxShadow:"0 20px 60px rgba(0, 0, 0, 0.3)",overflow:"hidden",transform:"scale(0.95)",transition:"transform 0.3s ease, opacity 0.3s ease",display:"flex",flexDirection:"column"})}_getContainerTransform(e){return`scale(${e})`}_applyCloseButtonStyles(e){Object.assign(e.style,{position:"absolute",top:"16px",right:"16px",zIndex:"10",width:"40px",height:"40px",border:"none",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.9)",color:"#333",fontSize:"28px",lineHeight:"1",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.15)",transition:"all 0.2s ease",fontFamily:"Arial, sans-serif",padding:"0"}),e.addEventListener("mouseenter",()=>{Object.assign(e.style,{backgroundColor:"#f5f5f5",transform:"scale(1.1)"})}),e.addEventListener("mouseleave",()=>{Object.assign(e.style,{backgroundColor:"rgba(255, 255, 255, 0.9)",transform:"scale(1)"})})}_applyIframeStyles(e){const t=this._isMobile;Object.assign(e.style,{width:"100%",flex:"1 1 auto",minHeight:t?"100%":"min(520px, calc(90vh - 40px))",height:t?"100%":"min(520px, calc(90vh - 40px))",border:"none",display:"block"})}_show(){document.body.style.overflow="hidden",requestAnimationFrame(()=>{this.overlay&&(this.overlay.style.opacity="1"),this.container&&(this.container.style.transform=this._getContainerTransform(1))})}_hide(){g.log("[ModalManager] ๐ญ _hide() called"),this.overlay&&(this.overlay.style.opacity="0",g.log("[ModalManager] ๐ญ Overlay opacity set to 0")),this.container&&(this.container.style.transform=this._getContainerTransform(.95),g.log("[ModalManager] ๐ญ Container transform set to scale(0.95)")),document.body.style.overflow="",g.log("[ModalManager] ๐ญ Body scroll restored")}_destroyModal(){g.log("[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation"),setTimeout(()=>{g.log("[ModalManager] ๐๏ธ Animation complete, removing from DOM"),this.overlay&&this.overlay.parentNode&&(this.overlay.parentNode.removeChild(this.overlay),g.log("[ModalManager] ๐๏ธ Overlay removed from DOM")),this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,g.log("[ModalManager] โ
Modal destroyed")},300)}_attachEventListeners(){}_removeEventListeners(){this.escapeListener&&(document.removeEventListener("keydown",this.escapeListener),this.escapeListener=null)}_handleCloseClick(e){e.stopPropagation(),this.onClose&&this.onClose("user_closed")}_handleOverlayClick(e){e.target===this.overlay&&this.onClose&&this.onClose("user_closed")}_handleEscapeKey(e){"Escape"===e.key&&this.isOpen&&this.onClose&&this.onClose("user_closed")}getIframe(){return this.iframe}getIsOpen(){return this.isOpen}}class T{constructor(e={}){if("undefined"==typeof window||"undefined"==typeof document)throw new Error("Dropp Payment SDK can only be used in a browser environment");if(!e.merchantId||!e.apiKey||!e.packageName)throw new Error("merchantId, apiKey, and packageName are required to initialize SDK");if(this.merchantId=e.merchantId,this.apiKey=e.apiKey,this.packageName=e.packageName,this.environment=e.environment||i.QA,this.baseUrl=e.paymentAppUrl||e.baseUrl||s[this.environment],this.isInitialized=!1,this.initializationPromise=null,this.getServerAuthToken="function"==typeof e.getServerAuthToken?e.getServerAuthToken:null,this.requireServerAuthToken="boolean"==typeof e.requireServerAuthToken?e.requireServerAuthToken:this.environment===i.PRODUCTION,this.allowLocalCallbacksInNonProd=!!e.allowLocalCallbacksInNonProd,e.allowedOrigins?.length)this.allowedOrigins=e.allowedOrigins;else try{this.allowedOrigins=[new URL(this.baseUrl).origin]}catch{this.allowedOrigins=r[this.environment]||[]}this.isOpen=!1,this.currentSession=null,this.currentFlowType=null,this.initTimeout=null,this.paymentTimeout=null,this.messageHandler=null,this.modalManager=null,g.setEnvironment(this.environment,{enabled:!!e.debugLogging}),g.log(`[Dropp SDK] Initialized v${m} - Environment: ${this.environment}`)}pay(e={}){return new Promise((t,n)=>{if(this.isOpen){const e=b(h,"A payment session is already in progress",{currentSession:this.currentSession});return void n(e)}(async()=>{try{await this.initialize();const i=v(e,{environment:this.environment,allowLocalCallbacksInNonProd:this.allowLocalCallbacksInNonProd});if(!i.valid){const e=b(p,"Invalid payment configuration",{errors:i.errors});return void n(e)}this.onSuccess=e.onSuccess||null,this.onFailure=e.onFailure||null,this.onCancel=e.onCancel||null,this.onClose=e.onClose||null,this.currentSession={resolve:t,reject:n,options:e,startTime:Date.now()},await this._initializePayment(e)}catch(e){const t=e&&e.code===p?e:b(u,"Failed to initialize payment",{originalError:e?.message||String(e)});n(t),this._cleanup()}})()})}async initialize(){return this.initializationPromise||(this.initializationPromise=(async()=>(await this._validateInitializationCredentials(),this.isInitialized=!0,{status:"success",code:"INITIALIZED",message:"Dropp SDK initialized successfully"}))().catch(e=>{throw this.isInitialized=!1,this.initializationPromise=null,e})),this.initializationPromise}_getValidationUrl(){const e={[i.QA]:"https://main.qa.dropp.cc/payer/webview/validate",[i.SANDBOX]:"https://sandbox.api.dropp.cc/payer/webview/validate",[i.PRODUCTION]:"https://api.dropp.cc/payer/webview/validate"};return e[this.environment]||e[i.QA]}async _validateInitializationCredentials(){const e=this._getValidationUrl();let t,n=null;try{t=await fetch(e,{method:"POST",headers:{accept:"application/json, text/plain, */*","content-type":"application/json","x-api-key":this.apiKey,"x-app-package":this.packageName},body:JSON.stringify({id:this.merchantId})})}catch(t){throw b(p,"Unable to validate merchant credentials",{endpoint:e,originalError:t?.message||String(t)})}try{n=await t.json()}catch{n=null}if(!t.ok)throw b(p,"Merchant validation failed for merchantId/apiKey/packageName",{endpoint:e,status:t.status,response:n});const i=Number(n?.responseCode),s=n?.errors,r=!Array.isArray(s)||0===s.length;if(!(n&&0===i&&r))throw b(p,"Merchant validation returned an unsuccessful response",{endpoint:e,status:t.status,response:n});g.log("[Dropp SDK] Merchant credentials validated successfully")}closePayment(){if(this.isOpen){if("page"===this.currentFlowType)return void this._cleanup();this._handleCancel("sdk_close")}}dashboard(e={}){return this._openHostedPage("/firsttimeflow",e)}unlinkAccount(e={}){return this._openHostedPage("/unlink",e)}transactions(e={}){return this._openHostedPage("/transactions",e)}offers(e={}){return this._openHostedPage("/offers",e)}async _initializePayment(e){g.log("[Dropp SDK] Initializing payment session"),this.currentFlowType="payment",this.messageHandler=new w(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new E(this._handleModalClose.bind(this));const t=this.modalManager.open();if(!t)throw new Error("Failed to create modal iframe");this.messageHandler.init(t);const n=e.paymentType||l.STANDARD;let i="/payViaUrl";n===l.PREAUTH?i="/preAuthPayment":n===l.RECURRING&&(i="/recurringPayment");const s=n===l.RECURRING?(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase():"",r=n===l.RECURRING&&"NONE"===s,c=e.appUrl||("undefined"!=typeof window&&window.location?window.location.href:void 0),d={merchantAccount:this.merchantId,amount:n===l.PREAUTH?void 0:e.amount,maxAmount:n===l.PREAUTH||r?e.amount:void 0,fixAmount:n!==l.RECURRING||r?void 0:e.amount,acceptPaymentDelay:n===l.STANDARD&&!0===e.acceptPaymentDelay||void 0,currency:e.currency,itemName:e.itemName,description:e.description,invoiceId:e.invoiceId||`INV-${Date.now()}`,invoiceType:n===l.PREAUTH?"PREAUTH":void 0,apiKey:this.apiKey,packageName:this.packageName,sdkVersion:m,platform:"web",appUrl:c,sessionId:this.messageHandler.getSessionId()};if(g.log("[Dropp SDK] Including SDK session context in payment params"),e.successURL&&(d.successURL=e.successURL),e.failureURL&&(d.failureURL=e.failureURL),n===l.RECURRING){const t=e.frequency||e.recurringInterval;t&&(d.frequency=t),e.recurringEndDate&&(d.expiry=e.recurringEndDate)}n===l.PREAUTH&&e.authHoldTimeInSeconds&&(d.authHoldTimeInSeconds=e.authHoldTimeInSeconds),e.callbackUrl&&(d.url=e.callbackUrl,d.submitToCallBack="post");const h={sessionId:d.sessionId,merchantAccount:this.merchantId,amount:e.amount,paymentType:n,invoiceId:d.invoiceId,expiry:e.recurringEndDate||null,issuedAt:Date.now()};let u="string"==typeof e.serverAuthToken?e.serverAuthToken.trim():"";if(!u&&this.getServerAuthToken)try{const e=await this.getServerAuthToken(h);u="string"==typeof e?e.trim():""}catch(e){throw b(p,"Failed to obtain server auth token",{originalError:e?.message||String(e)})}if(this.requireServerAuthToken&&!u)throw b(p,"serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.",{environment:this.environment,paymentType:n,invoiceId:d.invoiceId});const y=await async function(e,t,n,i,s={}){try{const{serverAuthToken:r=""}=s,o={};Object.keys(n).forEach(e=>{const t=n[e];null!=t&&(o[e]=t)}),g.log("[buildPaymentUrl] Building payment URL payload");const a=JSON.stringify(o),l=btoa(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""),c=Date.now().toString(),d=new URLSearchParams({pay:l,sdkTs:c,sdkVersion:i,platform:"web"});return r&&d.set("authToken",r),`${e}/#${t}?${d.toString()}`}catch(e){throw g.error("Error building payment URL:",e),e}}(this.baseUrl,i,d,m,{serverAuthToken:u});g.log("[Dropp SDK] Loading payment flow iframe"),t.src=y,this.isOpen=!0,this.initTimeout=setTimeout(()=>{this._handleTimeout("init")},o),this.paymentTimeout=setTimeout(()=>{this._handleTimeout("payment")},a)}async _openHostedPage(e,t={}){if(this.isOpen)throw b(h,"A Dropp session is already in progress",{currentSession:this.currentSession,route:e});await this.initialize(),this.currentFlowType="page",this.currentSession=null,this.onSuccess=null,this.onFailure=null,this.onCancel=null,this.onClose="function"==typeof t.onClose?t.onClose:null,this.messageHandler=new w(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new E(this._handleModalClose.bind(this));const n=this.modalManager.open();if(!n)throw new Error("Failed to create modal iframe");this.messageHandler.init(n);const i=this.baseUrl.replace(/\/+$/,"");return n.src=`${i}/#${e}`,this.isOpen=!0,g.log("[Dropp SDK] Hosted page opened",{route:e}),{status:"opened",route:e}}_handleMessage(t){const{type:n,data:i}=t;switch(n){case e.READY:this._handleReady(i);break;case e.PAYMENT_PAGE_LOADED:this._handlePageLoaded(i);break;case e.PAYMENT_SUCCESS:this._handleSuccess(i);break;case e.PAYMENT_FAILED:this._handleFailure(i);break;case e.PAYMENT_CANCELLED:this._handleCancel("user_cancelled");break;case e.AUTO_CLOSE_WEBVIEW:g.log("[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal"),this._cleanup(),g.log("[Dropp SDK] Cleanup completed");break;case e.CLOSE_WEBVIEW:g.log("[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal"),this._handleCancel("app_close");break;default:g.warn("[Dropp SDK] Unknown message type:",n)}}_handleReady(e){if(g.log("[Dropp SDK] Payment app ready"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.messageHandler&&this.currentSession){const e={};Object.keys(this.currentSession.options).forEach(t=>{const n=this.currentSession.options[t];"function"!=typeof n&&(e[t]=n)}),g.log("[Dropp SDK] Sending init config to payment app"),this.messageHandler.sendInit(e)}}_handlePageLoaded(e){g.log("[Dropp SDK] Payment page loaded")}_handleSuccess(e){g.log("[Dropp SDK] Payment successful");const t={status:"success",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onSuccess&&this.onSuccess(t)}_handleFailure(e){g.log("[Dropp SDK] Payment failed");const t={status:"failed",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onFailure&&this.onFailure(t)}_handleCancel(e){g.log("[Dropp SDK] Payment cancelled");const t={status:"cancelled",reason:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0};this.currentSession&&this.currentSession.resolve(t),this.onCancel&&this.onCancel(t),this._cleanup()}_handleModalClose(e){g.log("[Dropp SDK] Modal closed by user"),"page"!==this.currentFlowType?this._handleCancel(e):this._cleanup()}_handleTimeout(e){g.error("[Dropp SDK] Timeout:",e);const t=b("init"===e?c:d,"init"===e?"Payment app failed to load within timeout period":"Payment session timed out",{type:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0});this.currentSession&&this.currentSession.reject(t),this.onFailure&&this.onFailure({status:"failed",error:t}),this._cleanup()}_cleanup(){g.log("[Dropp SDK] ๐งน Cleaning up session - starting cleanup"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.paymentTimeout&&(clearTimeout(this.paymentTimeout),this.paymentTimeout=null),this.messageHandler&&(g.log("[Dropp SDK] ๐งน Destroying message handler"),this.messageHandler.destroy(),this.messageHandler=null),this.modalManager&&(g.log("[Dropp SDK] ๐งน Closing modal manager"),this.modalManager.close(),g.log("[Dropp SDK] ๐งน Modal manager closed"),this.modalManager=null),this.currentSession=null,this.currentFlowType=null,this.isOpen=!1,this.onClose&&this.onClose()}static getVersion(){return m}static getEnvironments(){return{...i}}static getPaymentTypes(){return{...l}}}let _=null;async function I(e){_=new T(e);return{...await _.initialize(),sdk:_}}function A(){return _}const C={init:e=>I(e),pay(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.pay(e)},dashboard(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.dashboard(e)},unlinkAccount(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.unlinkAccount(e)},transactions(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.transactions(e)},offers(e){if(!_){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).");throw e.code="SDK_NOT_INITIALIZED",e}return _.offers(e)},getInstance:()=>_};var N={DroppPaymentSDK:T,createPaymentSDK:I,Dropp:C,ENVIRONMENTS:i,PAYMENT_TYPES:l};export{C as Dropp,T as DroppPaymentSDK,i as ENVIRONMENTS,l as PAYMENT_TYPES,I as createPaymentSDK,N as default,A as getDroppInstance};
|
|
2
2
|
//# sourceMappingURL=dropp-payment-sdk.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropp-payment-sdk.esm.js","sources":["../src/constants.js","../src/logger.js","../src/utils.js","../src/messageHandler.js","../src/modalManager.js","../src/DroppPaymentSDK.js","../src/index.js"],"sourcesContent":["/**\n * Constants for Dropp Payment SDK\n */\n\n// Message types from payment app to SDK\nexport const MESSAGE_TYPES = {\n READY: 'DROPP_SDK_READY',\n PAYMENT_SUCCESS: 'PAYMENT_SUCCESS',\n PAYMENT_FAILED: 'PAYMENT_FAILED',\n PAYMENT_CANCELLED: 'PAYMENT_CANCELLED',\n CLOSE_WEBVIEW: 'CLOSE_WEBVIEW',\n AUTO_CLOSE_WEBVIEW: 'AUTO_CLOSE_WEBVIEW',\n PAYMENT_PAGE_LOADED: 'PAYMENT_PAGE_LOADED'\n};\n\n// Message types from SDK to payment app\nexport const SDK_MESSAGE_TYPES = {\n INIT: 'DROPP_SDK_INIT',\n CLOSE: 'DROPP_SDK_CLOSE'\n};\n\n// Environment configurations\nexport const ENVIRONMENTS = {\n PRODUCTION: 'production',\n QA: 'qa',\n SANDBOX: 'sandbox'\n};\n\n// Payment app URLs by environment\nexport const PAYMENT_APP_URLS = {\n [ENVIRONMENTS.PRODUCTION]: 'https://wv.dropp.cc',\n [ENVIRONMENTS.QA]: 'https://wv.qa.dropp.cc', // Assuming local QA server\n [ENVIRONMENTS.SANDBOX]: 'https://wv.sandbox.dropp.cc'\n};\n\n// Allowed origins for message validation (by environment)\nexport const ALLOWED_ORIGINS = {\n [ENVIRONMENTS.PRODUCTION]: ['https://wv.dropp.cc'],\n [ENVIRONMENTS.QA]: ['https://wv.qa.dropp.cc'], // Match QA server origin\n [ENVIRONMENTS.SANDBOX]: ['https://wv.sandbox.dropp.cc']\n};\n\n// Timeouts\nexport const TIMEOUTS = {\n INIT: 30000, // 30 seconds for app to load and send READY\n PAYMENT: 600000, // 10 minutes max for payment completion\n CLOSE_DELAY: 10000 // 10 seconds delay before closing modal after success/failure\n};\n\n// Payment types\nexport const PAYMENT_TYPES = {\n STANDARD: 'standard',\n PREAUTH: 'preauth',\n RECURRING: 'recurring'\n};\n\n// Error codes\nexport const ERROR_CODES = {\n INIT_TIMEOUT: 'INIT_TIMEOUT',\n PAYMENT_TIMEOUT: 'PAYMENT_TIMEOUT',\n INVALID_CONFIG: 'INVALID_CONFIG',\n ALREADY_OPEN: 'ALREADY_OPEN',\n ORIGIN_MISMATCH: 'ORIGIN_MISMATCH',\n MESSAGE_VALIDATION_FAILED: 'MESSAGE_VALIDATION_FAILED',\n IFRAME_BLOCKED: 'IFRAME_BLOCKED',\n UNKNOWN_ERROR: 'UNKNOWN_ERROR'\n};\n\n// SDK version\nexport const SDK_VERSION = '1.0.2';\n\n// CSS z-index for modal\nexport const MODAL_Z_INDEX = 999999;\n","/**\n * Logger utility for Dropp Payment SDK\n * Logging is disabled by default and can be enabled explicitly.\n */\n\nclass Logger {\n constructor(environment, options = {}) {\n this.environment = environment;\n this.forceEnabled = !!options.enabled;\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Determine if logging should be enabled\n * @private\n */\n _shouldEnableLogging() {\n return this.forceEnabled;\n }\n\n /**\n * Update environment and recalculate logging state\n */\n setEnvironment(environment, options = {}) {\n this.environment = environment;\n if (typeof options.enabled === 'boolean') {\n this.forceEnabled = options.enabled;\n }\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Explicitly enable or disable logging.\n */\n setEnabled(enabled) {\n this.forceEnabled = !!enabled;\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Log info messages\n */\n log(...args) {\n if (this.enabled) {\n console.log(...args);\n }\n }\n\n /**\n * Log warning messages\n */\n warn(...args) {\n if (this.enabled) {\n console.warn(...args);\n }\n }\n\n /**\n * Log error messages\n */\n error(...args) {\n if (this.enabled) {\n console.error(...args);\n }\n }\n\n /**\n * Log debug messages\n */\n debug(...args) {\n if (this.enabled) {\n console.debug(...args);\n }\n }\n\n /**\n * Log info messages\n */\n info(...args) {\n if (this.enabled) {\n console.info(...args);\n }\n }\n}\n\n// Create singleton instance with default environment\nconst logger = new Logger('qa', { enabled: false });\n\nexport default logger;\n","/**\n * Utility functions for Dropp Payment SDK\n */\n\nimport logger from './logger.js';\nimport { PAYMENT_TYPES } from './constants.js';\n\nconst SUPPORTED_CURRENCIES = ['USD', 'HBAR', 'USDC'];\n\nconst RECURRING_FREQUENCY_VALUES = [\n 'NONE',\n 'HALF_HOURLY',\n 'HOURLY',\n 'DAILY',\n 'WEEKLY',\n 'MONTHLY',\n 'YEARLY'\n];\n\nconst PAYMENT_TYPE_VALUES = [\n PAYMENT_TYPES.STANDARD,\n PAYMENT_TYPES.PREAUTH,\n PAYMENT_TYPES.RECURRING\n];\n\nfunction isPositiveNumber(value) {\n const num = typeof value === 'number' ? value : parseFloat(value);\n return typeof num === 'number' && !Number.isNaN(num) && num > 0;\n}\n\nfunction isPositiveInteger(value) {\n const num = typeof value === 'number' ? value : parseInt(value, 10);\n return Number.isInteger(num) && num > 0;\n}\n\nfunction isIpV4(value) {\n return /^(\\d{1,3}\\.){3}\\d{1,3}$/.test(value);\n}\n\nfunction isPrivateOrLoopbackHost(hostname) {\n if (!hostname) {\n return false;\n }\n\n const normalized = hostname.trim().toLowerCase();\n if (\n normalized === 'localhost' ||\n normalized === '127.0.0.1' ||\n normalized === '::1' ||\n normalized.endsWith('.local')\n ) {\n return true;\n }\n\n if (!isIpV4(normalized)) {\n return false;\n }\n\n const octets = normalized.split('.').map(part => Number(part));\n if (octets.some(octet => Number.isNaN(octet) || octet < 0 || octet > 255)) {\n return false;\n }\n\n const [a, b] = octets;\n // RFC1918 private ranges + loopback + link-local\n if (a === 10 || a === 127) {\n return true;\n }\n if (a === 172 && b >= 16 && b <= 31) {\n return true;\n }\n if (a === 192 && b === 168) {\n return true;\n }\n if (a === 169 && b === 254) {\n return true;\n }\n\n return false;\n}\n\nfunction isValidCallbackUrl(url, options = {}) {\n const {\n isProduction = false,\n allowLocalCallbacksInNonProd = false\n } = options;\n\n if (typeof url !== 'string' || !url.trim()) {\n return false;\n }\n\n try {\n const parsed = new URL(url.trim());\n const isHttps = parsed.protocol === 'https:';\n const isHttp = parsed.protocol === 'http:';\n\n if (!isHttp && !isHttps) {\n return false;\n }\n\n const isPrivateOrLoopback = isPrivateOrLoopbackHost(parsed.hostname);\n if (isPrivateOrLoopback) {\n return !isProduction && allowLocalCallbacksInNonProd;\n }\n\n if (isProduction) {\n return isHttps;\n }\n\n // Non-production can allow HTTP for public hosts by default.\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidIsoDateTime(value) {\n if (typeof value !== 'string' || !value.trim()) {\n return false;\n }\n const date = new Date(value.trim());\n return !Number.isNaN(date.getTime());\n}\n\n/**\n * Generate a unique session ID\n */\nexport function generateSessionId() {\n return `dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n\n/**\n * Build payment URL with base64 payload (matching Android SDK pattern)\n */\nexport async function buildPaymentUrl(baseUrl, route, params, sdkVersion, authOptions = {}) {\n try {\n const { serverAuthToken = '' } = authOptions;\n\n // Create JSON payload\n const payload = {};\n Object.keys(params).forEach(key => {\n const value = params[key];\n if (value !== null && value !== undefined) {\n payload[key] = value;\n }\n });\n \n logger.log('[buildPaymentUrl] Building payment URL payload');\n \n // Base64 encode payload (URL-safe, no padding)\n const jsonString = JSON.stringify(payload);\n const base64Payload = btoa(jsonString)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n \n const timestamp = Date.now().toString();\n const queryParams = new URLSearchParams({\n pay: base64Payload,\n sdkTs: timestamp,\n sdkVersion,\n platform: 'web'\n });\n\n if (serverAuthToken) {\n queryParams.set('authToken', serverAuthToken);\n }\n\n const url = `${baseUrl}/#${route}?${queryParams.toString()}`;\n \n return url;\n } catch (error) {\n logger.error('Error building payment URL:', error);\n throw error;\n }\n}\n\n/**\n * Validate payment configuration for standard, preauth, and recurring payments\n */\nexport function validateConfig(config = {}, options = {}) {\n const errors = [];\n const paymentType = config.paymentType || PAYMENT_TYPES.STANDARD;\n const isProduction = (options.environment || '').toLowerCase() === 'production';\n const allowLocalCallbacksInNonProd = !!options.allowLocalCallbacksInNonProd;\n const normalizedCurrency =\n typeof config.currency === 'string' ? config.currency.trim().toUpperCase() : '';\n\n if (!PAYMENT_TYPE_VALUES.includes(paymentType)) {\n errors.push(\n `paymentType must be one of: ${PAYMENT_TYPE_VALUES.join(', ')}`\n );\n }\n\n if (config.amount === undefined || config.amount === null || config.amount === '') {\n errors.push('amount is required');\n } else if (!isPositiveNumber(config.amount)) {\n errors.push('amount must be a positive number');\n }\n\n if (!config.currency || typeof config.currency !== 'string' || !config.currency.trim()) {\n errors.push('currency is required');\n } else if (!SUPPORTED_CURRENCIES.includes(normalizedCurrency)) {\n errors.push(`currency must be one of: ${SUPPORTED_CURRENCIES.join(', ')}`);\n }\n\n if (!config.itemName || typeof config.itemName !== 'string' || !config.itemName.trim()) {\n errors.push('itemName is required');\n }\n\n if (paymentType === PAYMENT_TYPES.PREAUTH) {\n if (normalizedCurrency && normalizedCurrency !== 'USD') {\n errors.push('currency must be USD for preauth payments');\n }\n\n if (!config.callbackUrl || !String(config.callbackUrl).trim()) {\n errors.push('callbackUrl (signing URL) is required for preauth payments');\n } else if (!isValidCallbackUrl(config.callbackUrl, {\n isProduction,\n allowLocalCallbacksInNonProd\n })) {\n errors.push(\n isProduction\n ? 'callbackUrl must be HTTPS in production and cannot target loopback/private hosts'\n : 'callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled'\n );\n }\n\n if (\n config.authHoldTimeInSeconds === undefined ||\n config.authHoldTimeInSeconds === null ||\n config.authHoldTimeInSeconds === ''\n ) {\n errors.push('authHoldTimeInSeconds is required for preauth payments');\n } else if (!isPositiveInteger(config.authHoldTimeInSeconds)) {\n errors.push('authHoldTimeInSeconds must be a positive integer (seconds)');\n }\n }\n\n if (paymentType === PAYMENT_TYPES.RECURRING) {\n if (!config.callbackUrl || !String(config.callbackUrl).trim()) {\n errors.push('callbackUrl (signing URL) is required for recurring payments');\n } else if (!isValidCallbackUrl(config.callbackUrl, {\n isProduction,\n allowLocalCallbacksInNonProd\n })) {\n errors.push(\n isProduction\n ? 'callbackUrl must be HTTPS in production and cannot target loopback/private hosts'\n : 'callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled'\n );\n }\n\n const frequency = (config.frequency || config.recurringInterval || '')\n .toString()\n .trim()\n .toUpperCase();\n\n if (!frequency) {\n errors.push('frequency is required for recurring payments');\n } else if (!RECURRING_FREQUENCY_VALUES.includes(frequency)) {\n errors.push(\n `frequency must be one of: ${RECURRING_FREQUENCY_VALUES.join(', ')}`\n );\n }\n\n if (!config.recurringEndDate || !String(config.recurringEndDate).trim()) {\n errors.push('recurringEndDate (expiry) is required for recurring payments');\n } else if (!isValidIsoDateTime(config.recurringEndDate)) {\n errors.push('recurringEndDate must be a valid ISO date-time string');\n } else if (new Date(config.recurringEndDate.trim()) <= new Date()) {\n errors.push('recurringEndDate must be in the future');\n }\n }\n\n return {\n valid: errors.length === 0,\n errors\n };\n}\n\n/**\n * Create error object\n */\nexport function createError(code, message, details = {}) {\n return {\n code,\n message,\n details,\n timestamp: new Date().toISOString(),\n toString() {\n return this.message || 'Dropp SDK error';\n }\n };\n}\n\n/**\n * Deep clone object\n */\nexport function deepClone(obj) {\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * Check if running in browser environment\n */\nexport function isBrowser() {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Sanitize HTML to prevent XSS\n */\nexport function sanitizeHTML(str) {\n if (!str) return '';\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n}\n\n/**\n * Format amount for display\n */\nexport function formatAmount(amount, currency) {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: currency || 'USD'\n }).format(amount);\n } catch (error) {\n return `${amount} ${currency}`;\n }\n}\n","/**\n * Secure Message Handler for SDK โ Payment App Communication\n * \n * Implements:\n * - Origin validation\n * - Message schema validation\n * - Session correlation\n * - Anti-spoofing protection\n */\n\nimport { MESSAGE_TYPES, SDK_MESSAGE_TYPES, ALLOWED_ORIGINS } from './constants.js';\nimport { generateSessionId } from './utils.js';\nimport logger from './logger.js';\n\nexport class MessageHandler {\n constructor(environment, onMessage, allowedOrigins = null) {\n this.environment = environment;\n this.onMessage = onMessage;\n this.sessionId = generateSessionId();\n logger.log('[MessageHandler] Session initialized');\n this.iframe = null;\n this.allowedOrigins =\n allowedOrigins?.length > 0\n ? allowedOrigins\n : ALLOWED_ORIGINS[environment] || [];\n this.messageListener = null;\n this.pendingMessages = new Map(); // Track correlation IDs for request/response\n }\n\n /**\n * Initialize message listener\n */\n init(iframe) {\n this.iframe = iframe;\n this.messageListener = this._handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n }\n\n /**\n * Clean up message listener\n */\n destroy() {\n if (this.messageListener) {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n this.iframe = null;\n this.pendingMessages.clear();\n }\n\n /**\n * Handle incoming postMessage events\n * @private\n */\n _handleMessage(event) {\n logger.log('[MessageHandler] Received postMessage event');\n\n // Ignore messages from self (parent window)\n if (event.source === window) {\n logger.log('[MessageHandler] Ignoring message from self');\n return;\n }\n\n // 1. Validate origin\n if (!this._validateOrigin(event.origin)) {\n logger.warn('[Dropp SDK] Rejected message from untrusted origin:', event.origin);\n return;\n }\n\n // 2. Validate event source\n if (!this.iframe || event.source !== this.iframe.contentWindow) {\n logger.warn('[Dropp SDK] Rejected message from unexpected source', {\n eventOrigin: event.origin\n });\n return;\n }\n\n // 3. Validate message structure\n const message = event.data;\n if (!this._validateMessageStructure(message)) {\n logger.warn('[Dropp SDK] Rejected message with invalid structure');\n return;\n }\n\n // 4. Validate session ID (if present)\n if (message.sessionId && message.sessionId !== this.sessionId) {\n logger.warn('[Dropp SDK] Rejected message with invalid session ID');\n return;\n }\n\n // 5. Process valid message\n logger.log('[MessageHandler] Message passed validation');\n this._processMessage(message);\n }\n\n /**\n * Validate message origin against allowed list\n * @private\n */\n _validateOrigin(origin) {\n // In development/testing, allow localhost\n if (origin.startsWith('http://localhost:') || origin.startsWith('http://127.0.0.1:')) {\n return true;\n }\n\n // Enforce exact scheme + host + port origin match.\n return this.allowedOrigins.includes(origin);\n }\n\n /**\n * Validate message structure and type\n * @private\n */\n _validateMessageStructure(message) {\n if (!message || typeof message !== 'object') {\n return false;\n }\n\n // Must have a type field\n if (!message.type || typeof message.type !== 'string') {\n return false;\n }\n\n // Must be a known message type from payment app\n const validTypes = Object.values(MESSAGE_TYPES);\n if (!validTypes.includes(message.type)) {\n return false;\n }\n\n // Must have timestamp\n if (!message.timestamp) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Process validated message\n * @private\n */\n _processMessage(message) {\n logger.log('[Dropp SDK] Received message:', message.type);\n\n // Invoke callback\n if (this.onMessage) {\n this.onMessage(message);\n }\n }\n\n /**\n * Send message to payment app\n */\n sendToPaymentApp(type, data = {}) {\n if (!this.iframe || !this.iframe.contentWindow) {\n logger.error('[Dropp SDK] Cannot send message: iframe not ready');\n return false;\n }\n\n const message = {\n type,\n data,\n sessionId: this.sessionId,\n timestamp: new Date().toISOString(),\n sdkVersion: '1.0.0'\n };\n\n // Get target origin from allowed origins\n const targetOrigin = this.allowedOrigins[0] || '*';\n\n try {\n this.iframe.contentWindow.postMessage(message, targetOrigin);\n logger.log('[Dropp SDK] Sent message:', type);\n return true;\n } catch (error) {\n logger.error('[Dropp SDK] Error sending message:', error);\n return false;\n }\n }\n\n /**\n * Send init message to payment app\n */\n sendInit(config) {\n return this.sendToPaymentApp(SDK_MESSAGE_TYPES.INIT, {\n mode: 'sdk',\n config\n });\n }\n\n /**\n * Send close request to payment app\n */\n sendClose() {\n return this.sendToPaymentApp(SDK_MESSAGE_TYPES.CLOSE, {});\n }\n\n /**\n * Get session ID\n */\n getSessionId() {\n return this.sessionId;\n }\n}\n","/**\n * Modal Manager - Creates and manages the payment modal UI\n * \n * Responsibilities:\n * - Create modal overlay and container\n * - Manage modal lifecycle (open/close/destroy)\n * - Handle focus trapping\n * - Clean up DOM and event listeners\n * - Responsive design\n */\n\nimport { MODAL_Z_INDEX } from './constants.js';\nimport logger from './logger.js';\n\nexport class ModalManager {\n constructor(onClose) {\n this.onClose = onClose;\n this.overlay = null;\n this.container = null;\n this.iframe = null;\n this.closeButton = null;\n this.isOpen = false;\n this.escapeListener = null;\n }\n\n /**\n * Create and show modal\n */\n open() {\n if (this.isOpen) {\n logger.warn('[Dropp SDK] Modal is already open');\n return null;\n }\n\n this._createModal();\n this._attachEventListeners();\n this._show();\n\n this.isOpen = true;\n return this.iframe;\n }\n\n /**\n * Close and cleanup modal\n */\n close() {\n logger.log('[ModalManager] ๐ฆ close() called, isOpen:', this.isOpen);\n \n if (!this.isOpen) {\n logger.log('[ModalManager] โ ๏ธ Modal is not open, skipping close');\n return;\n }\n\n logger.log('[ModalManager] ๐ฆ Hiding modal...');\n this._hide();\n logger.log('[ModalManager] ๐ฆ Removing event listeners...');\n this._removeEventListeners();\n logger.log('[ModalManager] ๐ฆ Destroying modal...');\n this._destroyModal();\n\n this.isOpen = false;\n logger.log('[ModalManager] โ
Modal close sequence initiated');\n }\n\n /**\n * Create modal DOM elements\n * @private\n */\n _createModal() {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.id = 'dropp-payment-overlay';\n this._applyOverlayStyles(this.overlay);\n\n // Create container\n this.container = document.createElement('div');\n this.container.id = 'dropp-payment-container';\n this._applyContainerStyles(this.container);\n\n // Close button removed - will be rendered by chrome app instead\n\n // Create iframe\n this.iframe = document.createElement('iframe');\n this.iframe.id = 'dropp-payment-iframe';\n this.iframe.setAttribute('allow', 'payment');\n this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');\n this.iframe.setAttribute('referrerpolicy', 'no-referrer');\n this.iframe.setAttribute('title', 'Dropp Payment');\n this._applyIframeStyles(this.iframe);\n\n // Assemble modal\n this.container.appendChild(this.iframe);\n this.overlay.appendChild(this.container);\n\n // Add to DOM\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Apply styles to overlay\n * @private\n */\n _applyOverlayStyles(element) {\n Object.assign(element.style, {\n position: 'fixed',\n inset: '0',\n width: '100vw',\n height: '100vh',\n margin: '0',\n padding: '20px',\n boxSizing: 'border-box',\n backgroundColor: 'rgba(0, 0, 0, 0.6)',\n zIndex: MODAL_Z_INDEX.toString(),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n opacity: '0',\n transition: 'opacity 0.3s ease',\n backdropFilter: 'blur(4px)',\n overflow: 'auto'\n });\n }\n\n /**\n * Apply styles to container\n * @private\n */\n _applyContainerStyles(element) {\n const isMobile = window.innerWidth < 768;\n this._isMobile = isMobile;\n\n Object.assign(element.style, {\n position: 'relative',\n flex: '0 0 auto',\n alignSelf: 'center',\n margin: 'auto',\n width: '100%',\n maxWidth: isMobile ? '100%' : '400px',\n height: isMobile ? '100%' : 'auto',\n minHeight: isMobile ? '100%' : '800px',\n maxHeight: isMobile ? '100%' : 'min(1000px, calc(100vh - 40px))',\n backgroundColor: '#ffffff',\n borderRadius: isMobile ? '0' : '16px',\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.3)',\n overflow: 'hidden',\n transform: 'scale(0.95)',\n transition: 'transform 0.3s ease, opacity 0.3s ease',\n display: 'flex',\n flexDirection: 'column'\n });\n }\n\n _getContainerTransform(scale) {\n return `scale(${scale})`;\n }\n\n /**\n * Apply styles to close button\n * @private\n */\n _applyCloseButtonStyles(element) {\n Object.assign(element.style, {\n position: 'absolute',\n top: '16px',\n right: '16px',\n zIndex: '10',\n width: '40px',\n height: '40px',\n border: 'none',\n borderRadius: '50%',\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n color: '#333',\n fontSize: '28px',\n lineHeight: '1',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',\n transition: 'all 0.2s ease',\n fontFamily: 'Arial, sans-serif',\n padding: '0'\n });\n\n // Hover effect\n element.addEventListener('mouseenter', () => {\n Object.assign(element.style, {\n backgroundColor: '#f5f5f5',\n transform: 'scale(1.1)'\n });\n });\n\n element.addEventListener('mouseleave', () => {\n Object.assign(element.style, {\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n transform: 'scale(1)'\n });\n });\n }\n\n /**\n * Apply styles to iframe\n * @private\n */\n _applyIframeStyles(element) {\n const isMobile = this._isMobile;\n Object.assign(element.style, {\n width: '100%',\n flex: '1 1 auto',\n minHeight: isMobile ? '100%' : 'min(520px, calc(90vh - 40px))',\n height: isMobile ? '100%' : 'min(520px, calc(90vh - 40px))',\n border: 'none',\n display: 'block'\n });\n }\n\n /**\n * Show modal with animation\n * @private\n */\n _show() {\n // Prevent body scroll\n document.body.style.overflow = 'hidden';\n\n // Trigger animation\n requestAnimationFrame(() => {\n if (this.overlay) {\n this.overlay.style.opacity = '1';\n }\n if (this.container) {\n this.container.style.transform = this._getContainerTransform(1);\n }\n });\n }\n\n /**\n * Hide modal with animation\n * @private\n */\n _hide() {\n logger.log('[ModalManager] ๐ญ _hide() called');\n if (this.overlay) {\n this.overlay.style.opacity = '0';\n logger.log('[ModalManager] ๐ญ Overlay opacity set to 0');\n }\n if (this.container) {\n this.container.style.transform = this._getContainerTransform(0.95);\n logger.log('[ModalManager] ๐ญ Container transform set to scale(0.95)');\n }\n\n // Restore body scroll\n document.body.style.overflow = '';\n logger.log('[ModalManager] ๐ญ Body scroll restored');\n }\n\n /**\n * Destroy modal DOM elements\n * @private\n */\n _destroyModal() {\n logger.log('[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation');\n // Wait for animation to complete\n setTimeout(() => {\n logger.log('[ModalManager] ๐๏ธ Animation complete, removing from DOM');\n if (this.overlay && this.overlay.parentNode) {\n this.overlay.parentNode.removeChild(this.overlay);\n logger.log('[ModalManager] ๐๏ธ Overlay removed from DOM');\n }\n this.overlay = null;\n this.container = null;\n this.iframe = null;\n this.closeButton = null;\n logger.log('[ModalManager] โ
Modal destroyed');\n }, 300);\n }\n\n /**\n * Attach event listeners\n * @private\n */\n _attachEventListeners() {\n // Close button removed - will be handled by chrome app\n // Close button click\n // if (this.closeButton) {\n // this.closeButton.addEventListener('click', this._handleCloseClick.bind(this));\n // }\n\n // Backdrop click disabled for payment security\n // Users must use close button or complete/cancel payment\n // if (this.overlay) {\n // this.overlay.addEventListener('click', this._handleOverlayClick.bind(this));\n // }\n\n // Escape key disabled for payment security\n // Users must use close button or complete/cancel payment\n // this.escapeListener = this._handleEscapeKey.bind(this);\n // document.addEventListener('keydown', this.escapeListener);\n }\n\n /**\n * Remove event listeners\n * @private\n */\n _removeEventListeners() {\n if (this.escapeListener) {\n document.removeEventListener('keydown', this.escapeListener);\n this.escapeListener = null;\n }\n }\n\n /**\n * Handle close button click\n * @private\n */\n _handleCloseClick(event) {\n event.stopPropagation();\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n\n /**\n * Handle overlay click (backdrop)\n * @private\n */\n _handleOverlayClick(event) {\n // Only close if clicking directly on overlay (not container)\n if (event.target === this.overlay) {\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n }\n\n /**\n * Handle escape key press\n * @private\n */\n _handleEscapeKey(event) {\n if (event.key === 'Escape' && this.isOpen) {\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n }\n\n /**\n * Get iframe element\n */\n getIframe() {\n return this.iframe;\n }\n\n /**\n * Check if modal is open\n */\n getIsOpen() {\n return this.isOpen;\n }\n}\n","/**\n * Dropp Payment SDK - Main SDK Class\n * \n * Public API for integrating Dropp payments into web applications\n */\n\nimport { \n ENVIRONMENTS, \n PAYMENT_APP_URLS,\n ALLOWED_ORIGINS,\n MESSAGE_TYPES, \n ERROR_CODES, \n TIMEOUTS, \n PAYMENT_TYPES,\n SDK_VERSION\n} from './constants.js';\nimport { MessageHandler } from './messageHandler.js';\nimport { ModalManager } from './modalManager.js';\nimport { \n buildPaymentUrl, \n validateConfig, \n createError, \n isBrowser \n} from './utils.js';\nimport logger from './logger.js';\n\nexport class DroppPaymentSDK {\n /**\n * Create SDK instance\n * @param {Object} config - SDK configuration\n * @param {string} config.merchantId - Merchant Hedera account ID (required, e.g., '0.0.123456')\n * @param {string} config.apiKey - API Key (required)\n * @param {string} config.packageName - Package name (required)\n * @param {string} config.environment - Environment: 'production', 'qa', or 'sandbox'\n * @param {Function} [config.getServerAuthToken] - Optional async callback that returns a server-issued auth token\n * @param {boolean} [config.requireServerAuthToken] - Require server auth token (defaults to true in production)\n * @param {boolean} [config.allowLocalCallbacksInNonProd] - Allow loopback/private callback URLs in non-production\n */\n constructor(config = {}) {\n if (!isBrowser()) {\n throw new Error('Dropp Payment SDK can only be used in a browser environment');\n }\n\n // Validate required credentials\n if (!config.merchantId || !config.apiKey || !config.packageName) {\n throw new Error('merchantId, apiKey, and packageName are required to initialize SDK');\n }\n\n // Store credentials\n this.merchantId = config.merchantId;\n this.apiKey = config.apiKey;\n this.packageName = config.packageName;\n\n this.environment = config.environment || ENVIRONMENTS.QA;\n this.baseUrl =\n config.paymentAppUrl ||\n config.baseUrl ||\n PAYMENT_APP_URLS[this.environment];\n\n // Initialization state\n this.isInitialized = false;\n this.initializationPromise = null;\n\n this.getServerAuthToken =\n typeof config.getServerAuthToken === 'function'\n ? config.getServerAuthToken\n : null;\n this.requireServerAuthToken =\n typeof config.requireServerAuthToken === 'boolean'\n ? config.requireServerAuthToken\n : this.environment === ENVIRONMENTS.PRODUCTION;\n this.allowLocalCallbacksInNonProd = !!config.allowLocalCallbacksInNonProd;\n\n if (config.allowedOrigins?.length) {\n this.allowedOrigins = config.allowedOrigins;\n } else {\n try {\n // Derive allowed origin from the effective payment URL to keep a\n // single source of truth for iframe loading and postMessage validation.\n this.allowedOrigins = [new URL(this.baseUrl).origin];\n } catch {\n this.allowedOrigins = ALLOWED_ORIGINS[this.environment] || [];\n }\n }\n\n // State\n this.isOpen = false;\n this.currentSession = null;\n this.currentFlowType = null;\n this.initTimeout = null;\n this.paymentTimeout = null;\n\n // Managers\n this.messageHandler = null;\n this.modalManager = null;\n\n // Set logger environment\n logger.setEnvironment(this.environment, { enabled: !!config.debugLogging });\n logger.log(`[Dropp SDK] Initialized v${SDK_VERSION} - Environment: ${this.environment}`);\n }\n\n /**\n * Open payment modal\n * @param {Object} options - Payment options\n * @param {number} options.amount - Payment amount (required)\n * @param {string} options.currency - Currency code (required)\n * @param {string} options.itemName - Item/service name (required)\n * @param {string} options.description - Payment description\n * @param {string} options.invoiceId - Invoice ID\n * @param {string} options.paymentType - Payment type: 'standard', 'preauth', or 'recurring'\n * @param {string} options.thumbnail - Product image URL\n * @param {number} options.authHoldTimeInSeconds - For preauth: hold time in seconds\n * @param {string} options.callbackUrl - Server callback URL\n * @param {boolean} [options.acceptPaymentDelay=false] - Allow delayed payment acceptance for standard payments (sent only when true)\n * @param {string} [options.serverAuthToken] - Server-issued short-lived token bound to payment context\n * @param {Function} options.onSuccess - Callback for successful payment\n * @param {Function} options.onFailure - Callback for failed payment\n * @param {Function} options.onCancel - Callback for cancelled payment\n * @param {Function} options.onClose - Callback for modal close\n * @returns {Promise<PaymentResult>}\n */\n pay(options = {}) {\n return new Promise((resolve, reject) => {\n // Check if already open\n if (this.isOpen) {\n const error = createError(\n ERROR_CODES.ALREADY_OPEN,\n 'A payment session is already in progress',\n { currentSession: this.currentSession }\n );\n reject(error);\n return;\n }\n\n (async () => {\n try {\n await this.initialize();\n\n // Validate payment configuration\n const validation = validateConfig(options, {\n environment: this.environment,\n allowLocalCallbacksInNonProd: this.allowLocalCallbacksInNonProd\n });\n if (!validation.valid) {\n const error = createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Invalid payment configuration',\n { errors: validation.errors }\n );\n reject(error);\n return;\n }\n\n // Store callbacks from options\n this.onSuccess = options.onSuccess || null;\n this.onFailure = options.onFailure || null;\n this.onCancel = options.onCancel || null;\n this.onClose = options.onClose || null;\n\n // Store resolve/reject for later\n this.currentSession = {\n resolve,\n reject,\n options,\n startTime: Date.now()\n };\n\n await this._initializePayment(options);\n } catch (error) {\n const isInitValidationError =\n error && error.code === ERROR_CODES.INVALID_CONFIG;\n const sdkError = isInitValidationError\n ? error\n : createError(\n ERROR_CODES.UNKNOWN_ERROR,\n 'Failed to initialize payment',\n { originalError: error?.message || String(error) }\n );\n\n reject(sdkError);\n this._cleanup();\n }\n })();\n });\n }\n\n /**\n * Initialize and validate merchant credentials with Dropp backend.\n * @returns {Promise<{status: string, code: string, message: string}>}\n */\n async initialize() {\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n\n this.initializationPromise = (async () => {\n await this._validateInitializationCredentials();\n this.isInitialized = true;\n return {\n status: 'success',\n code: 'INITIALIZED',\n message: 'Dropp SDK initialized successfully'\n };\n })().catch(error => {\n this.isInitialized = false;\n this.initializationPromise = null;\n throw error;\n });\n\n return this.initializationPromise;\n }\n\n /**\n * Resolve validation endpoint from configured base URL.\n * @private\n */\n _getValidationUrl() {\n const validationUrls = {\n [ENVIRONMENTS.QA]: 'https://main.qa.dropp.cc/payer/webview/validate',\n [ENVIRONMENTS.SANDBOX]: 'https://sandbox.api.dropp.cc/payer/webview/validate',\n [ENVIRONMENTS.PRODUCTION]: 'https://api.dropp.cc/payer/webview/validate'\n };\n\n return (\n validationUrls[this.environment] ||\n validationUrls[ENVIRONMENTS.QA]\n );\n }\n\n /**\n * Validate merchant credentials and app package before any payment flow.\n * @private\n */\n async _validateInitializationCredentials() {\n const validationUrl = this._getValidationUrl();\n\n let response;\n let responseBody = null;\n try {\n response = await fetch(validationUrl, {\n method: 'POST',\n headers: {\n accept: 'application/json, text/plain, */*',\n 'content-type': 'application/json',\n 'x-api-key': this.apiKey,\n 'x-app-package': this.packageName\n },\n body: JSON.stringify({ id: this.merchantId })\n });\n } catch (error) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Unable to validate merchant credentials',\n {\n endpoint: validationUrl,\n originalError: error?.message || String(error)\n }\n );\n }\n\n try {\n responseBody = await response.json();\n } catch {\n responseBody = null;\n }\n\n if (!response.ok) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Merchant validation failed for merchantId/apiKey/packageName',\n {\n endpoint: validationUrl,\n status: response.status,\n response: responseBody\n }\n );\n }\n\n const responseCode = Number(responseBody?.responseCode);\n const errors = responseBody?.errors;\n const hasNoErrors = !Array.isArray(errors) || errors.length === 0;\n const isValidationSuccess = responseBody && responseCode === 0 && hasNoErrors;\n\n if (!isValidationSuccess) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Merchant validation returned an unsuccessful response',\n {\n endpoint: validationUrl,\n status: response.status,\n response: responseBody\n }\n );\n }\n\n logger.log('[Dropp SDK] Merchant credentials validated successfully');\n }\n\n /**\n * Close payment modal programmatically\n */\n closePayment() {\n if (this.isOpen) {\n if (this.currentFlowType === 'page') {\n this._cleanup();\n return;\n }\n this._handleCancel('sdk_close');\n }\n }\n\n /**\n * Open the dashboard/home page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n dashboard(options = {}) {\n return this._openHostedPage('/firsttimeflow', options);\n }\n\n /**\n * Open the unlink account page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n unlinkAccount(options = {}) {\n return this._openHostedPage('/unlink', options);\n }\n\n /**\n * Open the transactions page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n transactions(options = {}) {\n return this._openHostedPage('/transactions', options);\n }\n\n /**\n * Open the offers page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n offers(options = {}) {\n return this._openHostedPage('/offers', options);\n }\n\n /**\n * Initialize payment session\n * @private\n */\n async _initializePayment(options) {\n logger.log('[Dropp SDK] Initializing payment session');\n this.currentFlowType = 'payment';\n\n // Create message handler\n this.messageHandler = new MessageHandler(\n this.environment,\n this._handleMessage.bind(this),\n this.allowedOrigins\n );\n\n // Create modal manager\n this.modalManager = new ModalManager(\n this._handleModalClose.bind(this)\n );\n\n // Open modal and get iframe\n const iframe = this.modalManager.open();\n if (!iframe) {\n throw new Error('Failed to create modal iframe');\n }\n\n // Initialize message handler with iframe\n this.messageHandler.init(iframe);\n\n // Determine payment route based on type\n const paymentType = options.paymentType || PAYMENT_TYPES.STANDARD;\n let route = '/payViaUrl';\n if (paymentType === PAYMENT_TYPES.PREAUTH) {\n route = '/preAuthPayment';\n } else if (paymentType === PAYMENT_TYPES.RECURRING) {\n route = '/recurringPayment';\n }\n\n // Build payment parameters (matching Android SDK)\n // For recurring payments with frequency NONE, use maxAmount instead of fixAmount\n const recurringFrequency = paymentType === PAYMENT_TYPES.RECURRING \n ? (options.frequency || options.recurringInterval || '').toString().trim().toUpperCase()\n : '';\n const isRecurringNone = paymentType === PAYMENT_TYPES.RECURRING && recurringFrequency === 'NONE';\n const detectedAppUrl =\n options.appUrl ||\n (typeof window !== 'undefined' && window.location ? window.location.href : undefined);\n \n const params = {\n merchantAccount: this.merchantId,\n amount: paymentType === PAYMENT_TYPES.PREAUTH ? undefined : options.amount,\n maxAmount: (paymentType === PAYMENT_TYPES.PREAUTH || isRecurringNone) ? options.amount : undefined,\n fixAmount: (paymentType === PAYMENT_TYPES.RECURRING && !isRecurringNone) ? options.amount : undefined,\n acceptPaymentDelay:\n paymentType === PAYMENT_TYPES.STANDARD && options.acceptPaymentDelay === true\n ? true\n : undefined,\n currency: options.currency,\n itemName: options.itemName,\n description: options.description,\n invoiceId: options.invoiceId || `INV-${Date.now()}`,\n invoiceType: paymentType === PAYMENT_TYPES.PREAUTH ? 'PREAUTH' : undefined,\n apiKey: this.apiKey,\n packageName: this.packageName,\n sdkVersion: SDK_VERSION,\n platform: 'web',\n appUrl: detectedAppUrl,\n sessionId: this.messageHandler.getSessionId() // Include SDK session ID for message validation\n };\n \n logger.log('[Dropp SDK] Including SDK session context in payment params');\n\n // Add optional parameters\n if (options.successURL) params.successURL = options.successURL;\n if (options.failureURL) params.failureURL = options.failureURL;\n \n // Recurring payment specific fields\n if (paymentType === PAYMENT_TYPES.RECURRING) {\n const frequency = options.frequency || options.recurringInterval;\n if (frequency) params.frequency = frequency;\n if (options.recurringEndDate) params.expiry = options.recurringEndDate;\n }\n \n // Pre-auth specific fields\n if (paymentType === PAYMENT_TYPES.PREAUTH && options.authHoldTimeInSeconds) {\n params.authHoldTimeInSeconds = options.authHoldTimeInSeconds;\n }\n \n // Callback URL for server-side submission\n if (options.callbackUrl) {\n params.url = options.callbackUrl;\n params.submitToCallBack = 'post';\n }\n\n const authContext = {\n sessionId: params.sessionId,\n merchantAccount: this.merchantId,\n amount: options.amount,\n paymentType,\n invoiceId: params.invoiceId,\n expiry: options.recurringEndDate || null,\n issuedAt: Date.now()\n };\n\n let serverAuthToken =\n typeof options.serverAuthToken === 'string'\n ? options.serverAuthToken.trim()\n : '';\n\n if (!serverAuthToken && this.getServerAuthToken) {\n try {\n const tokenFromCallback = await this.getServerAuthToken(authContext);\n serverAuthToken = typeof tokenFromCallback === 'string'\n ? tokenFromCallback.trim()\n : '';\n } catch (error) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Failed to obtain server auth token',\n {\n originalError: error?.message || String(error)\n }\n );\n }\n }\n\n if (this.requireServerAuthToken && !serverAuthToken) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.',\n {\n environment: this.environment,\n paymentType,\n invoiceId: params.invoiceId\n }\n );\n }\n\n // Build payment URL with base64 payload and optional server-issued auth token.\n const paymentUrl = await buildPaymentUrl(\n this.baseUrl,\n route,\n params,\n SDK_VERSION,\n { serverAuthToken }\n );\n\n logger.log('[Dropp SDK] Loading payment flow iframe');\n\n // Load payment app in iframe\n iframe.src = paymentUrl;\n\n this.isOpen = true;\n\n // Set initialization timeout\n this.initTimeout = setTimeout(() => {\n this._handleTimeout('init');\n }, TIMEOUTS.INIT);\n\n // Set payment timeout\n this.paymentTimeout = setTimeout(() => {\n this._handleTimeout('payment');\n }, TIMEOUTS.PAYMENT);\n }\n\n /**\n * Open a hosted Dropp page in the modal.\n * @private\n */\n async _openHostedPage(route, options = {}) {\n if (this.isOpen) {\n throw createError(\n ERROR_CODES.ALREADY_OPEN,\n 'A Dropp session is already in progress',\n { currentSession: this.currentSession, route }\n );\n }\n\n await this.initialize();\n\n this.currentFlowType = 'page';\n this.currentSession = null;\n this.onSuccess = null;\n this.onFailure = null;\n this.onCancel = null;\n this.onClose = typeof options.onClose === 'function' ? options.onClose : null;\n\n this.modalManager = new ModalManager(\n this._handleModalClose.bind(this)\n );\n\n const iframe = this.modalManager.open();\n if (!iframe) {\n throw new Error('Failed to create modal iframe');\n }\n\n const normalizedBaseUrl = this.baseUrl.replace(/\\/+$/, '');\n iframe.src = `${normalizedBaseUrl}/#${route}`;\n this.isOpen = true;\n\n logger.log('[Dropp SDK] Hosted page opened', { route });\n\n return {\n status: 'opened',\n route\n };\n }\n\n /**\n * Handle messages from payment app\n * @private\n */\n _handleMessage(message) {\n const { type, data } = message;\n\n switch (type) {\n case MESSAGE_TYPES.READY:\n this._handleReady(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_PAGE_LOADED:\n this._handlePageLoaded(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_SUCCESS:\n this._handleSuccess(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_FAILED:\n this._handleFailure(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_CANCELLED:\n this._handleCancel('user_cancelled');\n break;\n\n case MESSAGE_TYPES.AUTO_CLOSE_WEBVIEW:\n // Auto-close from payment app after success/failure countdown\n // Just close the modal without triggering callbacks (already called)\n logger.log('[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal');\n this._cleanup();\n logger.log('[Dropp SDK] Cleanup completed');\n break;\n\n case MESSAGE_TYPES.CLOSE_WEBVIEW:\n // Manual close request from chrome app\n logger.log('[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal');\n this._handleCancel('app_close');\n break;\n\n default:\n logger.warn('[Dropp SDK] Unknown message type:', type);\n }\n }\n\n /**\n * Handle ready message from payment app\n * @private\n */\n _handleReady(data) {\n logger.log('[Dropp SDK] Payment app ready');\n \n // Clear init timeout\n if (this.initTimeout) {\n clearTimeout(this.initTimeout);\n this.initTimeout = null;\n }\n\n // Send init message to payment app\n // Filter out non-serializable data (functions) from options\n if (this.messageHandler && this.currentSession) {\n const serializableOptions = {};\n Object.keys(this.currentSession.options).forEach(key => {\n const value = this.currentSession.options[key];\n // Only include serializable values (exclude functions)\n if (typeof value !== 'function') {\n serializableOptions[key] = value;\n }\n });\n \n logger.log('[Dropp SDK] Sending init config to payment app');\n this.messageHandler.sendInit(serializableOptions);\n }\n }\n\n /**\n * Handle page loaded message\n * @private\n */\n _handlePageLoaded(data) {\n logger.log('[Dropp SDK] Payment page loaded');\n }\n\n /**\n * Handle successful payment\n * @private\n */\n _handleSuccess(data) {\n logger.log('[Dropp SDK] Payment successful');\n\n const result = {\n status: 'success',\n ...data,\n sessionDuration: Date.now() - this.currentSession.startTime\n };\n\n // Resolve promise\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onSuccess) {\n this.onSuccess(result);\n }\n\n // Note: Modal will be closed by AUTO_CLOSE_WEBVIEW message from payment app\n // after the countdown completes (no need for timeout here)\n }\n\n /**\n * Handle failed payment\n * @private\n */\n _handleFailure(data) {\n logger.log('[Dropp SDK] Payment failed');\n\n const result = {\n status: 'failed',\n ...data,\n sessionDuration: Date.now() - this.currentSession.startTime\n };\n\n // Resolve promise (not reject - failed payment is still a valid result)\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onFailure) {\n this.onFailure(result);\n }\n\n // Note: Modal will be closed by AUTO_CLOSE_WEBVIEW message from payment app\n // after the countdown completes (no need for timeout here)\n }\n\n /**\n * Handle cancelled payment\n * @private\n */\n _handleCancel(reason) {\n logger.log('[Dropp SDK] Payment cancelled');\n\n const result = {\n status: 'cancelled',\n reason,\n sessionDuration: this.currentSession ? Date.now() - this.currentSession.startTime : 0\n };\n\n // Resolve promise (not reject - cancellation is a valid result)\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onCancel) {\n this.onCancel(result);\n }\n\n // Close immediately\n this._cleanup();\n }\n\n /**\n * Handle modal close by user\n * @private\n */\n _handleModalClose(reason) {\n logger.log('[Dropp SDK] Modal closed by user');\n if (this.currentFlowType === 'page') {\n this._cleanup();\n return;\n }\n this._handleCancel(reason);\n }\n\n /**\n * Handle timeout\n * @private\n */\n _handleTimeout(type) {\n logger.error('[Dropp SDK] Timeout:', type);\n\n const errorCode = type === 'init' ? ERROR_CODES.INIT_TIMEOUT : ERROR_CODES.PAYMENT_TIMEOUT;\n const errorMessage = type === 'init' \n ? 'Payment app failed to load within timeout period'\n : 'Payment session timed out';\n\n const error = createError(errorCode, errorMessage, {\n type,\n sessionDuration: this.currentSession ? Date.now() - this.currentSession.startTime : 0\n });\n\n // Reject promise\n if (this.currentSession) {\n this.currentSession.reject(error);\n }\n\n // Invoke failure callback\n if (this.onFailure) {\n this.onFailure({ status: 'failed', error });\n }\n\n this._cleanup();\n }\n\n /**\n * Cleanup resources\n * @private\n */\n _cleanup() {\n logger.log('[Dropp SDK] ๐งน Cleaning up session - starting cleanup');\n\n // Clear timeouts\n if (this.initTimeout) {\n clearTimeout(this.initTimeout);\n this.initTimeout = null;\n }\n\n if (this.paymentTimeout) {\n clearTimeout(this.paymentTimeout);\n this.paymentTimeout = null;\n }\n\n // Destroy managers\n if (this.messageHandler) {\n logger.log('[Dropp SDK] ๐งน Destroying message handler');\n this.messageHandler.destroy();\n this.messageHandler = null;\n }\n\n if (this.modalManager) {\n logger.log('[Dropp SDK] ๐งน Closing modal manager');\n this.modalManager.close();\n logger.log('[Dropp SDK] ๐งน Modal manager closed');\n this.modalManager = null;\n }\n\n // Clear state\n this.currentSession = null;\n this.currentFlowType = null;\n this.isOpen = false;\n\n // Invoke onClose callback\n if (this.onClose) {\n this.onClose();\n }\n }\n\n /**\n * Get SDK version\n */\n static getVersion() {\n return SDK_VERSION;\n }\n\n /**\n * Get available environments\n */\n static getEnvironments() {\n return { ...ENVIRONMENTS };\n }\n\n /**\n * Get payment types\n */\n static getPaymentTypes() {\n return { ...PAYMENT_TYPES };\n }\n}\n\nexport default DroppPaymentSDK;\n","/**\n * Dropp Payment SDK for Web\n * \n * Main entry point - exports SDK class and factory functions\n */\n\nimport { DroppPaymentSDK } from './DroppPaymentSDK.js';\nimport { ENVIRONMENTS, PAYMENT_TYPES } from './constants.js';\n\n// Export main SDK class\nexport { DroppPaymentSDK };\n\n// Export constants\nexport { ENVIRONMENTS, PAYMENT_TYPES };\n\n// Global Dropp instance\nlet globalDroppInstance = null;\n\n/**\n * Factory function to create and initialize SDK instance\n * @param {Object} config - SDK configuration\n * @param {string} config.merchantId - Merchant Hedera account ID (required, e.g., '0.0.123456')\n * @param {string} config.apiKey - API Key (required)\n * @param {string} config.packageName - Package name (required)\n * @param {string} config.environment - Environment: 'production', 'qa', or 'sandbox'\n * @returns {Promise<{status: string, code: string, message: string, sdk: DroppPaymentSDK}>}\n */\nexport async function createPaymentSDK(config) {\n globalDroppInstance = new DroppPaymentSDK(config);\n const initResult = await globalDroppInstance.initialize();\n return {\n ...initResult,\n sdk: globalDroppInstance\n };\n}\n\n/**\n * Get the global Dropp instance\n * @returns {DroppPaymentSDK|null}\n */\nexport function getDroppInstance() {\n return globalDroppInstance;\n}\n\n/**\n * Global Dropp object with pay method\n */\nexport const Dropp = {\n /**\n * Initialize SDK (sets global instance)\n * @param {Object} config - SDK configuration\n * @returns {Promise<{status: string, code: string, message: string, sdk: DroppPaymentSDK}>}\n */\n init(config) {\n return createPaymentSDK(config);\n },\n \n /**\n * Make a payment using the initialized SDK\n * @param {Object} options - Payment options\n * @returns {Promise<PaymentResult>}\n */\n pay(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.pay(options);\n },\n\n /**\n * Open the dashboard/home page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n dashboard(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.dashboard(options);\n },\n\n /**\n * Open the unlink account page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n unlinkAccount(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.unlinkAccount(options);\n },\n\n /**\n * Open the transactions page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n transactions(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.transactions(options);\n },\n\n /**\n * Open the offers page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n offers(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.offers(options);\n },\n \n /**\n * Get the current SDK instance\n * @returns {DroppPaymentSDK|null}\n */\n getInstance() {\n return globalDroppInstance;\n }\n};\n\n// Default export\nexport default {\n DroppPaymentSDK,\n createPaymentSDK,\n Dropp,\n ENVIRONMENTS,\n PAYMENT_TYPES\n};\n"],"names":["MESSAGE_TYPES","READY","PAYMENT_SUCCESS","PAYMENT_FAILED","PAYMENT_CANCELLED","CLOSE_WEBVIEW","AUTO_CLOSE_WEBVIEW","PAYMENT_PAGE_LOADED","SDK_MESSAGE_TYPES","ENVIRONMENTS","PRODUCTION","QA","SANDBOX","PAYMENT_APP_URLS","ALLOWED_ORIGINS","TIMEOUTS","PAYMENT_TYPES","STANDARD","PREAUTH","RECURRING","ERROR_CODES","SDK_VERSION","logger","constructor","environment","options","this","forceEnabled","enabled","_shouldEnableLogging","setEnvironment","setEnabled","log","args","console","warn","error","debug","info","SUPPORTED_CURRENCIES","RECURRING_FREQUENCY_VALUES","PAYMENT_TYPE_VALUES","isValidCallbackUrl","url","isProduction","allowLocalCallbacksInNonProd","trim","parsed","URL","isHttps","protocol","hostname","normalized","toLowerCase","endsWith","test","octets","split","map","part","Number","some","octet","isNaN","a","b","isPrivateOrLoopbackHost","validateConfig","config","errors","paymentType","normalizedCurrency","currency","toUpperCase","includes","push","join","undefined","amount","value","num","parseFloat","isPositiveNumber","itemName","callbackUrl","String","authHoldTimeInSeconds","parseInt","isInteger","isPositiveInteger","frequency","recurringInterval","toString","recurringEndDate","date","Date","getTime","isValidIsoDateTime","valid","length","createError","code","message","details","timestamp","toISOString","MessageHandler","onMessage","allowedOrigins","sessionId","now","Math","random","substring","iframe","messageListener","pendingMessages","Map","init","_handleMessage","bind","window","addEventListener","destroy","removeEventListener","clear","event","source","_validateOrigin","origin","contentWindow","eventOrigin","data","_validateMessageStructure","_processMessage","startsWith","type","Object","values","sendToPaymentApp","sdkVersion","targetOrigin","postMessage","sendInit","mode","sendClose","getSessionId","ModalManager","onClose","overlay","container","closeButton","isOpen","escapeListener","open","_createModal","_attachEventListeners","_show","close","_hide","_removeEventListeners","_destroyModal","document","createElement","id","_applyOverlayStyles","_applyContainerStyles","setAttribute","_applyIframeStyles","appendChild","body","element","assign","style","position","inset","width","height","margin","padding","boxSizing","backgroundColor","zIndex","display","alignItems","justifyContent","opacity","transition","backdropFilter","overflow","isMobile","innerWidth","_isMobile","flex","alignSelf","maxWidth","minHeight","maxHeight","borderRadius","boxShadow","transform","flexDirection","_getContainerTransform","scale","_applyCloseButtonStyles","top","right","border","color","fontSize","lineHeight","cursor","fontFamily","requestAnimationFrame","setTimeout","parentNode","removeChild","_handleCloseClick","stopPropagation","_handleOverlayClick","target","_handleEscapeKey","key","getIframe","getIsOpen","DroppPaymentSDK","Error","merchantId","apiKey","packageName","baseUrl","paymentAppUrl","isInitialized","initializationPromise","getServerAuthToken","requireServerAuthToken","currentSession","currentFlowType","initTimeout","paymentTimeout","messageHandler","modalManager","debugLogging","pay","Promise","resolve","reject","initialize","validation","onSuccess","onFailure","onCancel","startTime","_initializePayment","sdkError","originalError","_cleanup","_validateInitializationCredentials","status","catch","_getValidationUrl","validationUrls","validationUrl","response","responseBody","fetch","method","headers","accept","JSON","stringify","endpoint","json","ok","responseCode","hasNoErrors","Array","isArray","closePayment","_handleCancel","dashboard","_openHostedPage","unlinkAccount","transactions","offers","_handleModalClose","route","recurringFrequency","isRecurringNone","detectedAppUrl","appUrl","location","href","params","merchantAccount","maxAmount","fixAmount","acceptPaymentDelay","description","invoiceId","invoiceType","platform","successURL","failureURL","expiry","submitToCallBack","authContext","issuedAt","serverAuthToken","tokenFromCallback","paymentUrl","async","authOptions","payload","keys","forEach","jsonString","base64Payload","btoa","replace","queryParams","URLSearchParams","sdkTs","set","buildPaymentUrl","src","_handleTimeout","normalizedBaseUrl","_handleReady","_handlePageLoaded","_handleSuccess","_handleFailure","clearTimeout","serializableOptions","result","sessionDuration","reason","getVersion","getEnvironments","getPaymentTypes","globalDroppInstance","createPaymentSDK","sdk","getDroppInstance","Dropp","getInstance","index"],"mappings":"AAKO,MAAMA,EAAgB,CAC3BC,MAAO,kBACPC,gBAAiB,kBACjBC,eAAgB,iBAChBC,kBAAmB,oBACnBC,cAAe,gBACfC,mBAAoB,qBACpBC,oBAAqB,uBAIVC,EACL,iBADKA,EAEJ,kBAIIC,EAAe,CAC1BC,WAAY,aACZC,GAAI,KACJC,QAAS,WAIEC,EAAmB,CAC9B,CAACJ,EAAaC,YAAa,sBAC3B,CAACD,EAAaE,IAAK,yBACnB,CAACF,EAAaG,SAAU,+BAIbE,EAAkB,CAC7B,CAACL,EAAaC,YAAa,CAAC,uBAC5B,CAACD,EAAaE,IAAK,CAAC,0BACpB,CAACF,EAAaG,SAAU,CAAC,gCAIdG,EACL,IADKA,EAEF,IAKEC,EAAgB,CAC3BC,SAAU,WACVC,QAAS,UACTC,UAAW,aAIAC,EACG,eADHA,EAEM,kBAFNA,EAGK,iBAHLA,EAIG,eAJHA,EAQI,gBAIJC,EAAc,QCiB3B,MAAMC,EAAS,IAjFf,MACE,WAAAC,CAAYC,EAAaC,EAAU,IACjCC,KAAKF,YAAcA,EACnBE,KAAKC,eAAiBF,EAAQG,QAC9BF,KAAKE,QAAUF,KAAKG,sBACrB,CAMD,oBAAAA,GACE,OAAOH,KAAKC,YACb,CAKD,cAAAG,CAAeN,EAAaC,EAAU,IACpCC,KAAKF,YAAcA,EACY,kBAApBC,EAAQG,UACjBF,KAAKC,aAAeF,EAAQG,SAE9BF,KAAKE,QAAUF,KAAKG,sBACrB,CAKD,UAAAE,CAAWH,GACTF,KAAKC,eAAiBC,EACtBF,KAAKE,QAAUF,KAAKG,sBACrB,CAKD,GAAAG,IAAOC,GACDP,KAAKE,SACPM,QAAQF,OAAOC,EAElB,CAKD,IAAAE,IAAQF,GACFP,KAAKE,SACPM,QAAQC,QAAQF,EAEnB,CAKD,KAAAG,IAASH,GACHP,KAAKE,SACPM,QAAQE,SAASH,EAEpB,CAKD,KAAAI,IAASJ,GACHP,KAAKE,SACPM,QAAQG,SAASJ,EAEpB,CAKD,IAAAK,IAAQL,GACFP,KAAKE,SACPM,QAAQI,QAAQL,EAEnB,GAIuB,KAAM,CAAEL,SAAS,IC/ErCW,EAAuB,CAAC,MAAO,OAAQ,QAEvCC,EAA6B,CACjC,OACA,cACA,SACA,QACA,SACA,UACA,UAGIC,EAAsB,CAC1BzB,EAAcC,SACdD,EAAcE,QACdF,EAAcG,WA2DhB,SAASuB,EAAmBC,EAAKlB,EAAU,IACzC,MAAMmB,aACJA,GAAe,EAAKC,6BACpBA,GAA+B,GAC7BpB,EAEJ,GAAmB,iBAARkB,IAAqBA,EAAIG,OAClC,OAAO,EAGT,IACE,MAAMC,EAAS,IAAIC,IAAIL,EAAIG,QACrBG,EAA8B,WAApBF,EAAOG,SAGvB,KAFmC,UAApBH,EAAOG,YAEND,EACd,OAAO,EAIT,OA9DJ,SAAiCE,GAC/B,IAAKA,EACH,OAAO,EAGT,MAAMC,EAAaD,EAASL,OAAOO,cACnC,GACiB,cAAfD,GACe,cAAfA,GACe,QAAfA,GACAA,EAAWE,SAAS,UAEpB,OAAO,EAGT,IAlBO,0BAA0BC,KAkBrBH,GACV,OAAO,EAGT,MAAMI,EAASJ,EAAWK,MAAM,KAAKC,IAAIC,GAAQC,OAAOD,IACxD,GAAIH,EAAOK,KAAKC,GAASF,OAAOG,MAAMD,IAAUA,EAAQ,GAAKA,EAAQ,KACnE,OAAO,EAGT,MAAOE,EAAGC,GAAKT,EAEf,OAAU,KAANQ,GAAkB,MAANA,GAGN,MAANA,GAAaC,GAAK,IAAMA,GAAK,IAGvB,MAAND,GAAmB,MAANC,GAGP,MAAND,GAAmB,MAANC,CAKnB,CAqBgCC,CAAwBnB,EAAOI,WAEjDP,GAAgBC,GAGtBD,GACKK,CAKb,CAAI,MACA,OAAO,CACR,CACH,CAkEO,SAASkB,EAAeC,EAAS,GAAI3C,EAAU,CAAA,GACpD,MAAM4C,EAAS,GACTC,EAAcF,EAAOE,aAAetD,EAAcC,SAClD2B,EAA6D,gBAA7CnB,EAAQD,aAAe,IAAI6B,cAC3CR,IAAiCpB,EAAQoB,6BACzC0B,EACuB,iBAApBH,EAAOI,SAAwBJ,EAAOI,SAAS1B,OAAO2B,cAAgB,GAqD/E,GAnDKhC,EAAoBiC,SAASJ,IAChCD,EAAOM,KACL,+BAA+BlC,EAAoBmC,KAAK,cAItCC,IAAlBT,EAAOU,QAA0C,OAAlBV,EAAOU,QAAqC,KAAlBV,EAAOU,OAClET,EAAOM,KAAK,sBA1KhB,SAA0BI,GACxB,MAAMC,EAAuB,iBAAVD,EAAqBA,EAAQE,WAAWF,GAC3D,MAAsB,iBAARC,IAAqBpB,OAAOG,MAAMiB,IAAQA,EAAM,CAChE,CAwKcE,CAAiBd,EAAOU,SAClCT,EAAOM,KAAK,oCAGTP,EAAOI,UAAuC,iBAApBJ,EAAOI,UAA0BJ,EAAOI,SAAS1B,OAEpEP,EAAqBmC,SAASH,IACxCF,EAAOM,KAAK,4BAA4BpC,EAAqBqC,KAAK,SAFlEP,EAAOM,KAAK,wBAKTP,EAAOe,UAAuC,iBAApBf,EAAOe,UAA0Bf,EAAOe,SAASrC,QAC9EuB,EAAOM,KAAK,wBAGVL,IAAgBtD,EAAcE,UAC5BqD,GAA6C,QAAvBA,GACxBF,EAAOM,KAAK,6CAGTP,EAAOgB,aAAgBC,OAAOjB,EAAOgB,aAAatC,OAE3CJ,EAAmB0B,EAAOgB,YAAa,CACjDxC,eACAC,kCAEAwB,EAAOM,KACL/B,EACI,mFACA,iHARNyB,EAAOM,KAAK,mEAaqBE,IAAjCT,EAAOkB,uBAC0B,OAAjClB,EAAOkB,uBAC0B,KAAjClB,EAAOkB,sBAEPjB,EAAOM,KAAK,0DA3MlB,SAA2BI,GACzB,MAAMC,EAAuB,iBAAVD,EAAqBA,EAAQQ,SAASR,EAAO,IAChE,OAAOnB,OAAO4B,UAAUR,IAAQA,EAAM,CACxC,CAyMgBS,CAAkBrB,EAAOkB,wBACnCjB,EAAOM,KAAK,+DAIZL,IAAgBtD,EAAcG,UAAW,CACtCiD,EAAOgB,aAAgBC,OAAOjB,EAAOgB,aAAatC,OAE3CJ,EAAmB0B,EAAOgB,YAAa,CACjDxC,eACAC,kCAEAwB,EAAOM,KACL/B,EACI,mFACA,iHARNyB,EAAOM,KAAK,gEAYd,MAAMe,GAAatB,EAAOsB,WAAatB,EAAOuB,mBAAqB,IAChEC,WACA9C,OACA2B,cAEEiB,EAEOlD,EAA2BkC,SAASgB,IAC9CrB,EAAOM,KACL,6BAA6BnC,EAA2BoC,KAAK,SAH/DP,EAAOM,KAAK,gDAOTP,EAAOyB,kBAAqBR,OAAOjB,EAAOyB,kBAAkB/C,QAtJrE,SAA4BiC,GAC1B,GAAqB,iBAAVA,IAAuBA,EAAMjC,OACtC,OAAO,EAET,MAAMgD,EAAO,IAAIC,KAAKhB,EAAMjC,QAC5B,OAAQc,OAAOG,MAAM+B,EAAKE,UAC5B,CAkJgBC,CAAmB7B,EAAOyB,kBACpCxB,EAAOM,KAAK,yDACH,IAAIoB,KAAK3B,EAAOyB,iBAAiB/C,SAAW,IAAIiD,MACzD1B,EAAOM,KAAK,0CAJZN,EAAOM,KAAK,+DAMf,CAED,MAAO,CACLuB,MAAyB,IAAlB7B,EAAO8B,OACd9B,SAEJ,CAKO,SAAS+B,EAAYC,EAAMC,EAASC,EAAU,CAAA,GACnD,MAAO,CACLF,OACAC,UACAC,UACAC,WAAW,IAAIT,MAAOU,cACtB,QAAAb,GACE,OAAOlE,KAAK4E,SAAW,iBACxB,EAEL,CCxRO,MAAMI,EACX,WAAAnF,CAAYC,EAAamF,EAAWC,EAAiB,MACnDlF,KAAKF,YAAcA,EACnBE,KAAKiF,UAAYA,EACjBjF,KAAKmF,UD8GA,aAAad,KAAKe,SAASC,KAAKC,SAASpB,SAAS,IAAIqB,UAAU,EAAG,MC7GxE3F,EAAOU,IAAI,wCACXN,KAAKwF,OAAS,KACdxF,KAAKkF,eACHA,GAAgBT,OAAS,EACrBS,EACA9F,EAAgBU,IAAgB,GACtCE,KAAKyF,gBAAkB,KACvBzF,KAAK0F,gBAAkB,IAAIC,GAC5B,CAKD,IAAAC,CAAKJ,GACHxF,KAAKwF,OAASA,EACdxF,KAAKyF,gBAAkBzF,KAAK6F,eAAeC,KAAK9F,MAChD+F,OAAOC,iBAAiB,UAAWhG,KAAKyF,gBACzC,CAKD,OAAAQ,GACMjG,KAAKyF,kBACPM,OAAOG,oBAAoB,UAAWlG,KAAKyF,iBAC3CzF,KAAKyF,gBAAkB,MAEzBzF,KAAKwF,OAAS,KACdxF,KAAK0F,gBAAgBS,OACtB,CAMD,cAAAN,CAAeO,GAIb,GAHAxG,EAAOU,IAAI,+CAGP8F,EAAMC,SAAWN,OAEnB,YADAnG,EAAOU,IAAI,+CAKb,IAAKN,KAAKsG,gBAAgBF,EAAMG,QAE9B,YADA3G,EAAOa,KAAK,sDAAuD2F,EAAMG,QAK3E,IAAKvG,KAAKwF,QAAUY,EAAMC,SAAWrG,KAAKwF,OAAOgB,cAI/C,YAHA5G,EAAOa,KAAK,sDAAuD,CACjEgG,YAAaL,EAAMG,SAMvB,MAAM3B,EAAUwB,EAAMM,KACjB1G,KAAK2G,0BAA0B/B,GAMhCA,EAAQO,WAAaP,EAAQO,YAAcnF,KAAKmF,UAClDvF,EAAOa,KAAK,yDAKdb,EAAOU,IAAI,8CACXN,KAAK4G,gBAAgBhC,IAZnBhF,EAAOa,KAAK,sDAaf,CAMD,eAAA6F,CAAgBC,GAEd,SAAIA,EAAOM,WAAW,uBAAwBN,EAAOM,WAAW,uBAKzD7G,KAAKkF,eAAelC,SAASuD,EACrC,CAMD,yBAAAI,CAA0B/B,GACxB,IAAKA,GAA8B,iBAAZA,EACrB,OAAO,EAIT,IAAKA,EAAQkC,MAAgC,iBAAjBlC,EAAQkC,KAClC,OAAO,EAKT,QADmBC,OAAOC,OAAO1I,GACjB0E,SAAS4B,EAAQkC,SAK5BlC,EAAQE,SAKd,CAMD,eAAA8B,CAAgBhC,GACdhF,EAAOU,IAAI,gCAAiCsE,EAAQkC,MAGhD9G,KAAKiF,WACPjF,KAAKiF,UAAUL,EAElB,CAKD,gBAAAqC,CAAiBH,EAAMJ,EAAO,IAC5B,IAAK1G,KAAKwF,SAAWxF,KAAKwF,OAAOgB,cAE/B,OADA5G,EAAOc,MAAM,sDACN,EAGT,MAAMkE,EAAU,CACdkC,OACAJ,OACAvB,UAAWnF,KAAKmF,UAChBL,WAAW,IAAIT,MAAOU,cACtBmC,WAAY,SAIRC,EAAenH,KAAKkF,eAAe,IAAM,IAE/C,IAGE,OAFAlF,KAAKwF,OAAOgB,cAAcY,YAAYxC,EAASuC,GAC/CvH,EAAOU,IAAI,4BAA6BwG,IACjC,CACR,CAAC,MAAOpG,GAEP,OADAd,EAAOc,MAAM,qCAAsCA,IAC5C,CACR,CACF,CAKD,QAAA2G,CAAS3E,GACP,OAAO1C,KAAKiH,iBAAiBnI,EAAwB,CACnDwI,KAAM,MACN5E,UAEH,CAKD,SAAA6E,GACE,OAAOvH,KAAKiH,iBAAiBnI,EAAyB,CAAE,EACzD,CAKD,YAAA0I,GACE,OAAOxH,KAAKmF,SACb,EC5LI,MAAMsC,EACX,WAAA5H,CAAY6H,GACV1H,KAAK0H,QAAUA,EACf1H,KAAK2H,QAAU,KACf3H,KAAK4H,UAAY,KACjB5H,KAAKwF,OAAS,KACdxF,KAAK6H,YAAc,KACnB7H,KAAK8H,QAAS,EACd9H,KAAK+H,eAAiB,IACvB,CAKD,IAAAC,GACE,OAAIhI,KAAK8H,QACPlI,EAAOa,KAAK,qCACL,OAGTT,KAAKiI,eACLjI,KAAKkI,wBACLlI,KAAKmI,QAELnI,KAAK8H,QAAS,EACP9H,KAAKwF,OACb,CAKD,KAAA4C,GACExI,EAAOU,IAAI,4CAA6CN,KAAK8H,QAExD9H,KAAK8H,QAKVlI,EAAOU,IAAI,qCACXN,KAAKqI,QACLzI,EAAOU,IAAI,iDACXN,KAAKsI,wBACL1I,EAAOU,IAAI,yCACXN,KAAKuI,gBAELvI,KAAK8H,QAAS,EACdlI,EAAOU,IAAI,oDAZTV,EAAOU,IAAI,sDAad,CAMD,YAAA2H,GAEEjI,KAAK2H,QAAUa,SAASC,cAAc,OACtCzI,KAAK2H,QAAQe,GAAK,wBAClB1I,KAAK2I,oBAAoB3I,KAAK2H,SAG9B3H,KAAK4H,UAAYY,SAASC,cAAc,OACxCzI,KAAK4H,UAAUc,GAAK,0BACpB1I,KAAK4I,sBAAsB5I,KAAK4H,WAKhC5H,KAAKwF,OAASgD,SAASC,cAAc,UACrCzI,KAAKwF,OAAOkD,GAAK,uBACjB1I,KAAKwF,OAAOqD,aAAa,QAAS,WAClC7I,KAAKwF,OAAOqD,aAAa,UAAW,4DACpC7I,KAAKwF,OAAOqD,aAAa,iBAAkB,eAC3C7I,KAAKwF,OAAOqD,aAAa,QAAS,iBAClC7I,KAAK8I,mBAAmB9I,KAAKwF,QAG7BxF,KAAK4H,UAAUmB,YAAY/I,KAAKwF,QAChCxF,KAAK2H,QAAQoB,YAAY/I,KAAK4H,WAG9BY,SAASQ,KAAKD,YAAY/I,KAAK2H,QAChC,CAMD,mBAAAgB,CAAoBM,GAClBlC,OAAOmC,OAAOD,EAAQE,MAAO,CAC3BC,SAAU,QACVC,MAAO,IACPC,MAAO,QACPC,OAAQ,QACRC,OAAQ,IACRC,QAAS,OACTC,UAAW,aACXC,gBAAiB,qBACjBC,OJxCuB,QIwCD1F,WACtB2F,QAAS,OACTC,WAAY,SACZC,eAAgB,SAChBC,QAAS,IACTC,WAAY,oBACZC,eAAgB,YAChBC,SAAU,QAEb,CAMD,qBAAAvB,CAAsBK,GACpB,MAAMmB,EAAWrE,OAAOsE,WAAa,IACrCrK,KAAKsK,UAAYF,EAEjBrD,OAAOmC,OAAOD,EAAQE,MAAO,CAC3BC,SAAU,WACVmB,KAAM,WACNC,UAAW,SACXhB,OAAQ,OACRF,MAAO,OACPmB,SAAUL,EAAW,OAAS,QAC9Bb,OAAQa,EAAW,OAAS,OAC5BM,UAAWN,EAAW,OAAS,QAC/BO,UAAWP,EAAW,OAAS,kCAC/BT,gBAAiB,UACjBiB,aAAcR,EAAW,IAAM,OAC/BS,UAAW,iCACXV,SAAU,SACVW,UAAW,cACXb,WAAY,yCACZJ,QAAS,OACTkB,cAAe,UAElB,CAED,sBAAAC,CAAuBC,GACrB,MAAO,SAASA,IACjB,CAMD,uBAAAC,CAAwBjC,GACtBlC,OAAOmC,OAAOD,EAAQE,MAAO,CAC3BC,SAAU,WACV+B,IAAK,OACLC,MAAO,OACPxB,OAAQ,KACRN,MAAO,OACPC,OAAQ,OACR8B,OAAQ,OACRT,aAAc,MACdjB,gBAAiB,2BACjB2B,MAAO,OACPC,SAAU,OACVC,WAAY,IACZC,OAAQ,UACR5B,QAAS,OACTC,WAAY,SACZC,eAAgB,SAChBc,UAAW,gCACXZ,WAAY,gBACZyB,WAAY,oBACZjC,QAAS,MAIXR,EAAQjD,iBAAiB,aAAc,KACrCe,OAAOmC,OAAOD,EAAQE,MAAO,CAC3BQ,gBAAiB,UACjBmB,UAAW,iBAIf7B,EAAQjD,iBAAiB,aAAc,KACrCe,OAAOmC,OAAOD,EAAQE,MAAO,CAC3BQ,gBAAiB,2BACjBmB,UAAW,cAGhB,CAMD,kBAAAhC,CAAmBG,GACjB,MAAMmB,EAAWpK,KAAKsK,UACtBvD,OAAOmC,OAAOD,EAAQE,MAAO,CAC3BG,MAAO,OACPiB,KAAM,WACNG,UAAWN,EAAW,OAAS,gCAC/Bb,OAAQa,EAAW,OAAS,gCAC5BiB,OAAQ,OACRxB,QAAS,SAEZ,CAMD,KAAA1B,GAEEK,SAASQ,KAAKG,MAAMgB,SAAW,SAG/BwB,sBAAsB,KAChB3L,KAAK2H,UACP3H,KAAK2H,QAAQwB,MAAMa,QAAU,KAE3BhK,KAAK4H,YACP5H,KAAK4H,UAAUuB,MAAM2B,UAAY9K,KAAKgL,uBAAuB,KAGlE,CAMD,KAAA3C,GACEzI,EAAOU,IAAI,oCACPN,KAAK2H,UACP3H,KAAK2H,QAAQwB,MAAMa,QAAU,IAC7BpK,EAAOU,IAAI,+CAETN,KAAK4H,YACP5H,KAAK4H,UAAUuB,MAAM2B,UAAY9K,KAAKgL,uBAAuB,KAC7DpL,EAAOU,IAAI,6DAIbkI,SAASQ,KAAKG,MAAMgB,SAAW,GAC/BvK,EAAOU,IAAI,yCACZ,CAMD,aAAAiI,GACE3I,EAAOU,IAAI,0EAEXsL,WAAW,KACThM,EAAOU,IAAI,4DACPN,KAAK2H,SAAW3H,KAAK2H,QAAQkE,aAC/B7L,KAAK2H,QAAQkE,WAAWC,YAAY9L,KAAK2H,SACzC/H,EAAOU,IAAI,gDAEbN,KAAK2H,QAAU,KACf3H,KAAK4H,UAAY,KACjB5H,KAAKwF,OAAS,KACdxF,KAAK6H,YAAc,KACnBjI,EAAOU,IAAI,qCACV,IACJ,CAMD,qBAAA4H,GAiBC,CAMD,qBAAAI,GACMtI,KAAK+H,iBACPS,SAAStC,oBAAoB,UAAWlG,KAAK+H,gBAC7C/H,KAAK+H,eAAiB,KAEzB,CAMD,iBAAAgE,CAAkB3F,GAChBA,EAAM4F,kBACFhM,KAAK0H,SACP1H,KAAK0H,QAAQ,cAEhB,CAMD,mBAAAuE,CAAoB7F,GAEdA,EAAM8F,SAAWlM,KAAK2H,SACpB3H,KAAK0H,SACP1H,KAAK0H,QAAQ,cAGlB,CAMD,gBAAAyE,CAAiB/F,GACG,WAAdA,EAAMgG,KAAoBpM,KAAK8H,QAC7B9H,KAAK0H,SACP1H,KAAK0H,QAAQ,cAGlB,CAKD,SAAA2E,GACE,OAAOrM,KAAKwF,MACb,CAKD,SAAA8G,GACE,OAAOtM,KAAK8H,MACb,EC5UI,MAAMyE,EAYX,WAAA1M,CAAY6C,EAAS,IACnB,GH4QuB,oBAAXqD,QAA8C,oBAAbyC,SG3Q3C,MAAM,IAAIgE,MAAM,+DAIlB,IAAK9J,EAAO+J,aAAe/J,EAAOgK,SAAWhK,EAAOiK,YAClD,MAAM,IAAIH,MAAM,sEA4BlB,GAxBAxM,KAAKyM,WAAa/J,EAAO+J,WACzBzM,KAAK0M,OAAShK,EAAOgK,OACrB1M,KAAK2M,YAAcjK,EAAOiK,YAE1B3M,KAAKF,YAAc4C,EAAO5C,aAAef,EAAaE,GACtDe,KAAK4M,QACHlK,EAAOmK,eACPnK,EAAOkK,SACPzN,EAAiBa,KAAKF,aAGxBE,KAAK8M,eAAgB,EACrB9M,KAAK+M,sBAAwB,KAE7B/M,KAAKgN,mBACkC,mBAA9BtK,EAAOsK,mBACVtK,EAAOsK,mBACP,KACNhN,KAAKiN,uBACsC,kBAAlCvK,EAAOuK,uBACVvK,EAAOuK,uBACPjN,KAAKF,cAAgBf,EAAaC,WACxCgB,KAAKmB,+BAAiCuB,EAAOvB,6BAEzCuB,EAAOwC,gBAAgBT,OACzBzE,KAAKkF,eAAiBxC,EAAOwC,oBAE7B,IAGElF,KAAKkF,eAAiB,CAAC,IAAI5D,IAAItB,KAAK4M,SAASrG,OACrD,CAAQ,MACAvG,KAAKkF,eAAiB9F,EAAgBY,KAAKF,cAAgB,EAC5D,CAIHE,KAAK8H,QAAS,EACd9H,KAAKkN,eAAiB,KACtBlN,KAAKmN,gBAAkB,KACvBnN,KAAKoN,YAAc,KACnBpN,KAAKqN,eAAiB,KAGtBrN,KAAKsN,eAAiB,KACtBtN,KAAKuN,aAAe,KAGpB3N,EAAOQ,eAAeJ,KAAKF,YAAa,CAAEI,UAAWwC,EAAO8K,eAC5D5N,EAAOU,IAAI,4BAA4BX,oBAA8BK,KAAKF,cAC3E,CAsBD,GAAA2N,CAAI1N,EAAU,IACZ,OAAO,IAAI2N,QAAQ,CAACC,EAASC,KAE3B,GAAI5N,KAAK8H,OAAQ,CACf,MAAMpH,EAAQgE,EACZhF,EACA,2CACA,CAAEwN,eAAgBlN,KAAKkN,iBAGzB,YADAU,EAAOlN,EAER,CAED,WACE,UACQV,KAAK6N,aAGX,MAAMC,EAAarL,EAAe1C,EAAS,CACzCD,YAAaE,KAAKF,YAClBqB,6BAA8BnB,KAAKmB,+BAErC,IAAK2M,EAAWtJ,MAAO,CACrB,MAAM9D,EAAQgE,EACZhF,EACA,gCACA,CAAEiD,OAAQmL,EAAWnL,SAGvB,YADAiL,EAAOlN,EAER,CAGDV,KAAK+N,UAAYhO,EAAQgO,WAAa,KACtC/N,KAAKgO,UAAYjO,EAAQiO,WAAa,KACtChO,KAAKiO,SAAWlO,EAAQkO,UAAY,KACpCjO,KAAK0H,QAAU3H,EAAQ2H,SAAW,KAGlC1H,KAAKkN,eAAiB,CACpBS,UACAC,SACA7N,UACAmO,UAAW7J,KAAKe,aAGZpF,KAAKmO,mBAAmBpO,EAC/B,CAAC,MAAOW,GACP,MAEM0N,EADJ1N,GAASA,EAAMiE,OAASjF,EAEtBgB,EACAgE,EACEhF,EACA,+BACA,CAAE2O,cAAe3N,GAAOkE,SAAWjB,OAAOjD,KAGhDkN,EAAOQ,GACPpO,KAAKsO,UACN,CACF,EAhDD,IAkDH,CAMD,gBAAMT,GACJ,OAAI7N,KAAK+M,wBAIT/M,KAAK+M,sBAAwB,iBACrB/M,KAAKuO,qCACXvO,KAAK8M,eAAgB,EACd,CACL0B,OAAQ,UACR7J,KAAM,cACNC,QAAS,uCANgB,GAQxB6J,MAAM/N,IAGT,MAFAV,KAAK8M,eAAgB,EACrB9M,KAAK+M,sBAAwB,KACvBrM,KAdCV,KAAK+M,qBAkBf,CAMD,iBAAA2B,GACE,MAAMC,EAAiB,CACrB,CAAC5P,EAAaE,IAAK,kDACnB,CAACF,EAAaG,SAAU,sDACxB,CAACH,EAAaC,YAAa,+CAG7B,OACE2P,EAAe3O,KAAKF,cACpB6O,EAAe5P,EAAaE,GAE/B,CAMD,wCAAMsP,GACJ,MAAMK,EAAgB5O,KAAK0O,oBAE3B,IAAIG,EACAC,EAAe,KACnB,IACED,QAAiBE,MAAMH,EAAe,CACpCI,OAAQ,OACRC,QAAS,CACPC,OAAQ,oCACR,eAAgB,mBAChB,YAAalP,KAAK0M,OAClB,gBAAiB1M,KAAK2M,aAExB3D,KAAMmG,KAAKC,UAAU,CAAE1G,GAAI1I,KAAKyM,cAEnC,CAAC,MAAO/L,GACP,MAAMgE,EACJhF,EACA,0CACA,CACE2P,SAAUT,EACVP,cAAe3N,GAAOkE,SAAWjB,OAAOjD,IAG7C,CAED,IACEoO,QAAqBD,EAASS,MACpC,CAAM,MACAR,EAAe,IAChB,CAED,IAAKD,EAASU,GACZ,MAAM7K,EACJhF,EACA,+DACA,CACE2P,SAAUT,EACVJ,OAAQK,EAASL,OACjBK,SAAUC,IAKhB,MAAMU,EAAetN,OAAO4M,GAAcU,cACpC7M,EAASmM,GAAcnM,OACvB8M,GAAeC,MAAMC,QAAQhN,IAA6B,IAAlBA,EAAO8B,OAGrD,KAF4BqK,GAAiC,IAAjBU,GAAsBC,GAGhE,MAAM/K,EACJhF,EACA,wDACA,CACE2P,SAAUT,EACVJ,OAAQK,EAASL,OACjBK,SAAUC,IAKhBlP,EAAOU,IAAI,0DACZ,CAKD,YAAAsP,GACE,GAAI5P,KAAK8H,OAAQ,CACf,GAA6B,SAAzB9H,KAAKmN,gBAEP,YADAnN,KAAKsO,WAGPtO,KAAK6P,cAAc,YACpB,CACF,CAQD,SAAAC,CAAU/P,EAAU,IAClB,OAAOC,KAAK+P,gBAAgB,iBAAkBhQ,EAC/C,CAQD,aAAAiQ,CAAcjQ,EAAU,IACtB,OAAOC,KAAK+P,gBAAgB,UAAWhQ,EACxC,CAQD,YAAAkQ,CAAalQ,EAAU,IACrB,OAAOC,KAAK+P,gBAAgB,gBAAiBhQ,EAC9C,CAQD,MAAAmQ,CAAOnQ,EAAU,IACf,OAAOC,KAAK+P,gBAAgB,UAAWhQ,EACxC,CAMD,wBAAMoO,CAAmBpO,GACvBH,EAAOU,IAAI,4CACXN,KAAKmN,gBAAkB,UAGvBnN,KAAKsN,eAAiB,IAAItI,EACxBhF,KAAKF,YACLE,KAAK6F,eAAeC,KAAK9F,MACzBA,KAAKkF,gBAIPlF,KAAKuN,aAAe,IAAI9F,EACtBzH,KAAKmQ,kBAAkBrK,KAAK9F,OAI9B,MAAMwF,EAASxF,KAAKuN,aAAavF,OACjC,IAAKxC,EACH,MAAM,IAAIgH,MAAM,iCAIlBxM,KAAKsN,eAAe1H,KAAKJ,GAGzB,MAAM5C,EAAc7C,EAAQ6C,aAAetD,EAAcC,SACzD,IAAI6Q,EAAQ,aACRxN,IAAgBtD,EAAcE,QAChC4Q,EAAQ,kBACCxN,IAAgBtD,EAAcG,YACvC2Q,EAAQ,qBAKV,MAAMC,EAAqBzN,IAAgBtD,EAAcG,WACpDM,EAAQiE,WAAajE,EAAQkE,mBAAqB,IAAIC,WAAW9C,OAAO2B,cACzE,GACEuN,EAAkB1N,IAAgBtD,EAAcG,WAAoC,SAAvB4Q,EAC7DE,EACJxQ,EAAQyQ,SACW,oBAAXzK,QAA0BA,OAAO0K,SAAW1K,OAAO0K,SAASC,UAAOvN,GAEvEwN,EAAS,CACbC,gBAAiB5Q,KAAKyM,WACtBrJ,OAAQR,IAAgBtD,EAAcE,aAAU2D,EAAYpD,EAAQqD,OACpEyN,UAAYjO,IAAgBtD,EAAcE,SAAW8Q,EAAmBvQ,EAAQqD,YAASD,EACzF2N,UAAYlO,IAAgBtD,EAAcG,WAAc6Q,OAAoCnN,EAAjBpD,EAAQqD,OACnF2N,mBACEnO,IAAgBtD,EAAcC,WAA2C,IAA/BQ,EAAQgR,yBAE9C5N,EACNL,SAAU/C,EAAQ+C,SAClBW,SAAU1D,EAAQ0D,SAClBuN,YAAajR,EAAQiR,YACrBC,UAAWlR,EAAQkR,WAAa,OAAO5M,KAAKe,QAC5C8L,YAAatO,IAAgBtD,EAAcE,QAAU,eAAY2D,EACjEuJ,OAAQ1M,KAAK0M,OACbC,YAAa3M,KAAK2M,YAClBzF,WAAYvH,EACZwR,SAAU,MACVX,OAAQD,EACRpL,UAAWnF,KAAKsN,eAAe9F,gBAUjC,GAPA5H,EAAOU,IAAI,+DAGPP,EAAQqR,aAAYT,EAAOS,WAAarR,EAAQqR,YAChDrR,EAAQsR,aAAYV,EAAOU,WAAatR,EAAQsR,YAGhDzO,IAAgBtD,EAAcG,UAAW,CAC3C,MAAMuE,EAAYjE,EAAQiE,WAAajE,EAAQkE,kBAC3CD,IAAW2M,EAAO3M,UAAYA,GAC9BjE,EAAQoE,mBAAkBwM,EAAOW,OAASvR,EAAQoE,iBACvD,CAGGvB,IAAgBtD,EAAcE,SAAWO,EAAQ6D,wBACnD+M,EAAO/M,sBAAwB7D,EAAQ6D,uBAIrC7D,EAAQ2D,cACViN,EAAO1P,IAAMlB,EAAQ2D,YACrBiN,EAAOY,iBAAmB,QAG5B,MAAMC,EAAc,CAClBrM,UAAWwL,EAAOxL,UAClByL,gBAAiB5Q,KAAKyM,WACtBrJ,OAAQrD,EAAQqD,OAChBR,cACAqO,UAAWN,EAAOM,UAClBK,OAAQvR,EAAQoE,kBAAoB,KACpCsN,SAAUpN,KAAKe,OAGjB,IAAIsM,EACiC,iBAA5B3R,EAAQ2R,gBACX3R,EAAQ2R,gBAAgBtQ,OACxB,GAEN,IAAKsQ,GAAmB1R,KAAKgN,mBAC3B,IACE,MAAM2E,QAA0B3R,KAAKgN,mBAAmBwE,GACxDE,EAA+C,iBAAtBC,EACrBA,EAAkBvQ,OAClB,EACL,CAAC,MAAOV,GACP,MAAMgE,EACJhF,EACA,qCACA,CACE2O,cAAe3N,GAAOkE,SAAWjB,OAAOjD,IAG7C,CAGH,GAAIV,KAAKiN,yBAA2ByE,EAClC,MAAMhN,EACJhF,EACA,6FACA,CACEI,YAAaE,KAAKF,YAClB8C,cACAqO,UAAWN,EAAOM,YAMxB,MAAMW,QHpWHC,eAA+BjF,EAASwD,EAAOO,EAAQzJ,EAAY4K,EAAc,IACtF,IACE,MAAMJ,gBAAEA,EAAkB,IAAOI,EAG3BC,EAAU,CAAA,EAChBhL,OAAOiL,KAAKrB,GAAQsB,QAAQ7F,IAC1B,MAAM/I,EAAQsN,EAAOvE,GACjB/I,UACF0O,EAAQ3F,GAAO/I,KAInBzD,EAAOU,IAAI,kDAGX,MAAM4R,EAAa/C,KAAKC,UAAU2C,GAC5BI,EAAgBC,KAAKF,GACxBG,QAAQ,MAAO,KACfA,QAAQ,MAAO,KACfA,QAAQ,MAAO,IAEZvN,EAAYT,KAAKe,MAAMlB,WACvBoO,EAAc,IAAIC,gBAAgB,CACtC9E,IAAK0E,EACLK,MAAO1N,EACPoC,aACAiK,SAAU,QASZ,OANIO,GACFY,EAAYG,IAAI,YAAaf,GAGnB,GAAG9E,MAAYwD,KAASkC,EAAYpO,YAGjD,CAAC,MAAOxD,GAEP,MADAd,EAAOc,MAAM,8BAA+BA,GACtCA,CACP,CACH,CG2T6BgS,CACvB1S,KAAK4M,QACLwD,EACAO,EACAhR,EACA,CAAE+R,oBAGJ9R,EAAOU,IAAI,2CAGXkF,EAAOmN,IAAMf,EAEb5R,KAAK8H,QAAS,EAGd9H,KAAKoN,YAAcxB,WAAW,KAC5B5L,KAAK4S,eAAe,SACnBvT,GAGHW,KAAKqN,eAAiBzB,WAAW,KAC/B5L,KAAK4S,eAAe,YACnBvT,EACJ,CAMD,qBAAM0Q,CAAgBK,EAAOrQ,EAAU,IACrC,GAAIC,KAAK8H,OACP,MAAMpD,EACJhF,EACA,yCACA,CAAEwN,eAAgBlN,KAAKkN,eAAgBkD,gBAIrCpQ,KAAK6N,aAEX7N,KAAKmN,gBAAkB,OACvBnN,KAAKkN,eAAiB,KACtBlN,KAAK+N,UAAY,KACjB/N,KAAKgO,UAAY,KACjBhO,KAAKiO,SAAW,KAChBjO,KAAK0H,QAAqC,mBAApB3H,EAAQ2H,QAAyB3H,EAAQ2H,QAAU,KAEzE1H,KAAKuN,aAAe,IAAI9F,EACtBzH,KAAKmQ,kBAAkBrK,KAAK9F,OAG9B,MAAMwF,EAASxF,KAAKuN,aAAavF,OACjC,IAAKxC,EACH,MAAM,IAAIgH,MAAM,iCAGlB,MAAMqG,EAAoB7S,KAAK4M,QAAQyF,QAAQ,OAAQ,IAMvD,OALA7M,EAAOmN,IAAM,GAAGE,MAAsBzC,IACtCpQ,KAAK8H,QAAS,EAEdlI,EAAOU,IAAI,iCAAkC,CAAE8P,UAExC,CACL5B,OAAQ,SACR4B,QAEH,CAMD,cAAAvK,CAAejB,GACb,MAAMkC,KAAEA,EAAIJ,KAAEA,GAAS9B,EAEvB,OAAQkC,GACN,KAAKxI,EAAcC,MACjByB,KAAK8S,aAAapM,GAClB,MAEF,KAAKpI,EAAcO,oBACjBmB,KAAK+S,kBAAkBrM,GACvB,MAEF,KAAKpI,EAAcE,gBACjBwB,KAAKgT,eAAetM,GACpB,MAEF,KAAKpI,EAAcG,eACjBuB,KAAKiT,eAAevM,GACpB,MAEF,KAAKpI,EAAcI,kBACjBsB,KAAK6P,cAAc,kBACnB,MAEF,KAAKvR,EAAcM,mBAGjBgB,EAAOU,IAAI,2DACXN,KAAKsO,WACL1O,EAAOU,IAAI,iCACX,MAEF,KAAKhC,EAAcK,cAEjBiB,EAAOU,IAAI,+DACXN,KAAK6P,cAAc,aACnB,MAEF,QACEjQ,EAAOa,KAAK,oCAAqCqG,GAEtD,CAMD,YAAAgM,CAAapM,GAWX,GAVA9G,EAAOU,IAAI,iCAGPN,KAAKoN,cACP8F,aAAalT,KAAKoN,aAClBpN,KAAKoN,YAAc,MAKjBpN,KAAKsN,gBAAkBtN,KAAKkN,eAAgB,CAC9C,MAAMiG,EAAsB,CAAA,EAC5BpM,OAAOiL,KAAKhS,KAAKkN,eAAenN,SAASkS,QAAQ7F,IAC/C,MAAM/I,EAAQrD,KAAKkN,eAAenN,QAAQqM,GAErB,mBAAV/I,IACT8P,EAAoB/G,GAAO/I,KAI/BzD,EAAOU,IAAI,kDACXN,KAAKsN,eAAejG,SAAS8L,EAC9B,CACF,CAMD,iBAAAJ,CAAkBrM,GAChB9G,EAAOU,IAAI,kCACZ,CAMD,cAAA0S,CAAetM,GACb9G,EAAOU,IAAI,kCAEX,MAAM8S,EAAS,CACb5E,OAAQ,aACL9H,EACH2M,gBAAiBhP,KAAKe,MAAQpF,KAAKkN,eAAegB,WAIhDlO,KAAKkN,gBACPlN,KAAKkN,eAAeS,QAAQyF,GAI1BpT,KAAK+N,WACP/N,KAAK+N,UAAUqF,EAKlB,CAMD,cAAAH,CAAevM,GACb9G,EAAOU,IAAI,8BAEX,MAAM8S,EAAS,CACb5E,OAAQ,YACL9H,EACH2M,gBAAiBhP,KAAKe,MAAQpF,KAAKkN,eAAegB,WAIhDlO,KAAKkN,gBACPlN,KAAKkN,eAAeS,QAAQyF,GAI1BpT,KAAKgO,WACPhO,KAAKgO,UAAUoF,EAKlB,CAMD,aAAAvD,CAAcyD,GACZ1T,EAAOU,IAAI,iCAEX,MAAM8S,EAAS,CACb5E,OAAQ,YACR8E,SACAD,gBAAiBrT,KAAKkN,eAAiB7I,KAAKe,MAAQpF,KAAKkN,eAAegB,UAAY,GAIlFlO,KAAKkN,gBACPlN,KAAKkN,eAAeS,QAAQyF,GAI1BpT,KAAKiO,UACPjO,KAAKiO,SAASmF,GAIhBpT,KAAKsO,UACN,CAMD,iBAAA6B,CAAkBmD,GAChB1T,EAAOU,IAAI,oCACkB,SAAzBN,KAAKmN,gBAITnN,KAAK6P,cAAcyD,GAHjBtT,KAAKsO,UAIR,CAMD,cAAAsE,CAAe9L,GACblH,EAAOc,MAAM,uBAAwBoG,GAErC,MAKMpG,EAAQgE,EALa,SAAToC,EAAkBpH,EAA2BA,EACjC,SAAToH,EACjB,mDACA,4BAE+C,CACjDA,OACAuM,gBAAiBrT,KAAKkN,eAAiB7I,KAAKe,MAAQpF,KAAKkN,eAAegB,UAAY,IAIlFlO,KAAKkN,gBACPlN,KAAKkN,eAAeU,OAAOlN,GAIzBV,KAAKgO,WACPhO,KAAKgO,UAAU,CAAEQ,OAAQ,SAAU9N,UAGrCV,KAAKsO,UACN,CAMD,QAAAA,GACE1O,EAAOU,IAAI,yDAGPN,KAAKoN,cACP8F,aAAalT,KAAKoN,aAClBpN,KAAKoN,YAAc,MAGjBpN,KAAKqN,iBACP6F,aAAalT,KAAKqN,gBAClBrN,KAAKqN,eAAiB,MAIpBrN,KAAKsN,iBACP1N,EAAOU,IAAI,6CACXN,KAAKsN,eAAerH,UACpBjG,KAAKsN,eAAiB,MAGpBtN,KAAKuN,eACP3N,EAAOU,IAAI,wCACXN,KAAKuN,aAAanF,QAClBxI,EAAOU,IAAI,uCACXN,KAAKuN,aAAe,MAItBvN,KAAKkN,eAAiB,KACtBlN,KAAKmN,gBAAkB,KACvBnN,KAAK8H,QAAS,EAGV9H,KAAK0H,SACP1H,KAAK0H,SAER,CAKD,iBAAO6L,GACL,OAAO5T,CACR,CAKD,sBAAO6T,GACL,MAAO,IAAKzU,EACb,CAKD,sBAAO0U,GACL,MAAO,IAAKnU,EACb,EC9yBH,IAAIoU,EAAsB,KAWnB7B,eAAe8B,EAAiBjR,GACrCgR,EAAsB,IAAInH,EAAgB7J,GAE1C,MAAO,UADkBgR,EAAoB7F,aAG3C+F,IAAKF,EAET,CAMO,SAASG,IACd,OAAOH,CACT,CAKY,MAACI,EAAQ,CAMnBlO,KAAKlD,GACIiR,EAAiBjR,GAQ1B,GAAA+K,CAAI1N,GACF,IAAK2T,EAAqB,CACxB,MAAMhT,EAAQ,IAAI8L,MAAM,oFAExB,MADA9L,EAAMiE,KAAO,sBACPjE,CACP,CACD,OAAOgT,EAAoBjG,IAAI1N,EAChC,EAOD,SAAA+P,CAAU/P,GACR,IAAK2T,EAAqB,CACxB,MAAMhT,EAAQ,IAAI8L,MAAM,0FAExB,MADA9L,EAAMiE,KAAO,sBACPjE,CACP,CACD,OAAOgT,EAAoB5D,UAAU/P,EACtC,EAOD,aAAAiQ,CAAcjQ,GACZ,IAAK2T,EAAqB,CACxB,MAAMhT,EAAQ,IAAI8L,MAAM,8FAExB,MADA9L,EAAMiE,KAAO,sBACPjE,CACP,CACD,OAAOgT,EAAoB1D,cAAcjQ,EAC1C,EAOD,YAAAkQ,CAAalQ,GACX,IAAK2T,EAAqB,CACxB,MAAMhT,EAAQ,IAAI8L,MAAM,6FAExB,MADA9L,EAAMiE,KAAO,sBACPjE,CACP,CACD,OAAOgT,EAAoBzD,aAAalQ,EACzC,EAOD,MAAAmQ,CAAOnQ,GACL,IAAK2T,EAAqB,CACxB,MAAMhT,EAAQ,IAAI8L,MAAM,uFAExB,MADA9L,EAAMiE,KAAO,sBACPjE,CACP,CACD,OAAOgT,EAAoBxD,OAAOnQ,EACnC,EAMDgU,YAAW,IACFL,GAKX,IAAeM,EAAA,CACbzH,kBACAoH,mBACAG,QACA/U,eACAO"}
|
|
1
|
+
{"version":3,"file":"dropp-payment-sdk.esm.js","sources":["../src/constants.js","../src/logger.js","../src/utils.js","../src/messageHandler.js","../src/modalManager.js","../src/DroppPaymentSDK.js","../src/index.js"],"sourcesContent":["/**\n * Constants for Dropp Payment SDK\n */\n\n// Message types from payment app to SDK\nexport const MESSAGE_TYPES = {\n READY: 'DROPP_SDK_READY',\n PAYMENT_SUCCESS: 'PAYMENT_SUCCESS',\n PAYMENT_FAILED: 'PAYMENT_FAILED',\n PAYMENT_CANCELLED: 'PAYMENT_CANCELLED',\n CLOSE_WEBVIEW: 'CLOSE_WEBVIEW',\n AUTO_CLOSE_WEBVIEW: 'AUTO_CLOSE_WEBVIEW',\n PAYMENT_PAGE_LOADED: 'PAYMENT_PAGE_LOADED'\n};\n\n// Message types from SDK to payment app\nexport const SDK_MESSAGE_TYPES = {\n INIT: 'DROPP_SDK_INIT',\n CLOSE: 'DROPP_SDK_CLOSE'\n};\n\n// Environment configurations\nexport const ENVIRONMENTS = {\n PRODUCTION: 'production',\n QA: 'qa',\n SANDBOX: 'sandbox'\n};\n\n// Payment app URLs by environment\nexport const PAYMENT_APP_URLS = {\n [ENVIRONMENTS.PRODUCTION]: 'https://wv.dropp.cc',\n [ENVIRONMENTS.QA]: 'https://wv.qa.dropp.cc', // Assuming local QA server\n [ENVIRONMENTS.SANDBOX]: 'https://wv.sandbox.dropp.cc'\n};\n\n// Allowed origins for message validation (by environment)\nexport const ALLOWED_ORIGINS = {\n [ENVIRONMENTS.PRODUCTION]: ['https://wv.dropp.cc'],\n [ENVIRONMENTS.QA]: ['https://wv.qa.dropp.cc'], // Match QA server origin\n [ENVIRONMENTS.SANDBOX]: ['https://wv.sandbox.dropp.cc']\n};\n\n// Timeouts\nexport const TIMEOUTS = {\n INIT: 30000, // 30 seconds for app to load and send READY\n PAYMENT: 600000, // 10 minutes max for payment completion\n CLOSE_DELAY: 10000 // 10 seconds delay before closing modal after success/failure\n};\n\n// Payment types\nexport const PAYMENT_TYPES = {\n STANDARD: 'standard',\n PREAUTH: 'preauth',\n RECURRING: 'recurring'\n};\n\n// Error codes\nexport const ERROR_CODES = {\n INIT_TIMEOUT: 'INIT_TIMEOUT',\n PAYMENT_TIMEOUT: 'PAYMENT_TIMEOUT',\n INVALID_CONFIG: 'INVALID_CONFIG',\n ALREADY_OPEN: 'ALREADY_OPEN',\n ORIGIN_MISMATCH: 'ORIGIN_MISMATCH',\n MESSAGE_VALIDATION_FAILED: 'MESSAGE_VALIDATION_FAILED',\n IFRAME_BLOCKED: 'IFRAME_BLOCKED',\n UNKNOWN_ERROR: 'UNKNOWN_ERROR'\n};\n\n// SDK version\nexport const SDK_VERSION = '1.0.2';\n\n// CSS z-index for modal\nexport const MODAL_Z_INDEX = 999999;\n","/**\n * Logger utility for Dropp Payment SDK\n * Logging is disabled by default and can be enabled explicitly.\n */\n\nclass Logger {\n constructor(environment, options = {}) {\n this.environment = environment;\n this.forceEnabled = !!options.enabled;\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Determine if logging should be enabled\n * @private\n */\n _shouldEnableLogging() {\n return this.forceEnabled;\n }\n\n /**\n * Update environment and recalculate logging state\n */\n setEnvironment(environment, options = {}) {\n this.environment = environment;\n if (typeof options.enabled === 'boolean') {\n this.forceEnabled = options.enabled;\n }\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Explicitly enable or disable logging.\n */\n setEnabled(enabled) {\n this.forceEnabled = !!enabled;\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Log info messages\n */\n log(...args) {\n if (this.enabled) {\n console.log(...args);\n }\n }\n\n /**\n * Log warning messages\n */\n warn(...args) {\n if (this.enabled) {\n console.warn(...args);\n }\n }\n\n /**\n * Log error messages\n */\n error(...args) {\n if (this.enabled) {\n console.error(...args);\n }\n }\n\n /**\n * Log debug messages\n */\n debug(...args) {\n if (this.enabled) {\n console.debug(...args);\n }\n }\n\n /**\n * Log info messages\n */\n info(...args) {\n if (this.enabled) {\n console.info(...args);\n }\n }\n}\n\n// Create singleton instance with default environment\nconst logger = new Logger('qa', { enabled: false });\n\nexport default logger;\n","/**\n * Utility functions for Dropp Payment SDK\n */\n\nimport logger from './logger.js';\nimport { PAYMENT_TYPES } from './constants.js';\n\nconst SUPPORTED_CURRENCIES = ['USD', 'HBAR', 'USDC'];\n\nconst RECURRING_FREQUENCY_VALUES = [\n 'NONE',\n 'HALF_HOURLY',\n 'HOURLY',\n 'DAILY',\n 'WEEKLY',\n 'MONTHLY',\n 'YEARLY'\n];\n\nconst PAYMENT_TYPE_VALUES = [\n PAYMENT_TYPES.STANDARD,\n PAYMENT_TYPES.PREAUTH,\n PAYMENT_TYPES.RECURRING\n];\n\nfunction isPositiveNumber(value) {\n const num = typeof value === 'number' ? value : parseFloat(value);\n return typeof num === 'number' && !Number.isNaN(num) && num > 0;\n}\n\nfunction isPositiveInteger(value) {\n const num = typeof value === 'number' ? value : parseInt(value, 10);\n return Number.isInteger(num) && num > 0;\n}\n\nfunction isIpV4(value) {\n return /^(\\d{1,3}\\.){3}\\d{1,3}$/.test(value);\n}\n\nfunction isPrivateOrLoopbackHost(hostname) {\n if (!hostname) {\n return false;\n }\n\n const normalized = hostname.trim().toLowerCase();\n if (\n normalized === 'localhost' ||\n normalized === '127.0.0.1' ||\n normalized === '::1' ||\n normalized.endsWith('.local')\n ) {\n return true;\n }\n\n if (!isIpV4(normalized)) {\n return false;\n }\n\n const octets = normalized.split('.').map(part => Number(part));\n if (octets.some(octet => Number.isNaN(octet) || octet < 0 || octet > 255)) {\n return false;\n }\n\n const [a, b] = octets;\n // RFC1918 private ranges + loopback + link-local\n if (a === 10 || a === 127) {\n return true;\n }\n if (a === 172 && b >= 16 && b <= 31) {\n return true;\n }\n if (a === 192 && b === 168) {\n return true;\n }\n if (a === 169 && b === 254) {\n return true;\n }\n\n return false;\n}\n\nfunction isValidCallbackUrl(url, options = {}) {\n const {\n isProduction = false,\n allowLocalCallbacksInNonProd = false\n } = options;\n\n if (typeof url !== 'string' || !url.trim()) {\n return false;\n }\n\n try {\n const parsed = new URL(url.trim());\n const isHttps = parsed.protocol === 'https:';\n const isHttp = parsed.protocol === 'http:';\n\n if (!isHttp && !isHttps) {\n return false;\n }\n\n const isPrivateOrLoopback = isPrivateOrLoopbackHost(parsed.hostname);\n if (isPrivateOrLoopback) {\n return !isProduction && allowLocalCallbacksInNonProd;\n }\n\n if (isProduction) {\n return isHttps;\n }\n\n // Non-production can allow HTTP for public hosts by default.\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidIsoDateTime(value) {\n if (typeof value !== 'string' || !value.trim()) {\n return false;\n }\n const date = new Date(value.trim());\n return !Number.isNaN(date.getTime());\n}\n\n/**\n * Generate a unique session ID\n */\nexport function generateSessionId() {\n return `dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n\n/**\n * Build payment URL with base64 payload (matching Android SDK pattern)\n */\nexport async function buildPaymentUrl(baseUrl, route, params, sdkVersion, authOptions = {}) {\n try {\n const { serverAuthToken = '' } = authOptions;\n\n // Create JSON payload\n const payload = {};\n Object.keys(params).forEach(key => {\n const value = params[key];\n if (value !== null && value !== undefined) {\n payload[key] = value;\n }\n });\n \n logger.log('[buildPaymentUrl] Building payment URL payload');\n \n // Base64 encode payload (URL-safe, no padding)\n const jsonString = JSON.stringify(payload);\n const base64Payload = btoa(jsonString)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n \n const timestamp = Date.now().toString();\n const queryParams = new URLSearchParams({\n pay: base64Payload,\n sdkTs: timestamp,\n sdkVersion,\n platform: 'web'\n });\n\n if (serverAuthToken) {\n queryParams.set('authToken', serverAuthToken);\n }\n\n const url = `${baseUrl}/#${route}?${queryParams.toString()}`;\n \n return url;\n } catch (error) {\n logger.error('Error building payment URL:', error);\n throw error;\n }\n}\n\n/**\n * Validate payment configuration for standard, preauth, and recurring payments\n */\nexport function validateConfig(config = {}, options = {}) {\n const errors = [];\n const paymentType = config.paymentType || PAYMENT_TYPES.STANDARD;\n const isProduction = (options.environment || '').toLowerCase() === 'production';\n const allowLocalCallbacksInNonProd = !!options.allowLocalCallbacksInNonProd;\n const normalizedCurrency =\n typeof config.currency === 'string' ? config.currency.trim().toUpperCase() : '';\n\n if (!PAYMENT_TYPE_VALUES.includes(paymentType)) {\n errors.push(\n `paymentType must be one of: ${PAYMENT_TYPE_VALUES.join(', ')}`\n );\n }\n\n if (config.amount === undefined || config.amount === null || config.amount === '') {\n errors.push('amount is required');\n } else if (!isPositiveNumber(config.amount)) {\n errors.push('amount must be a positive number');\n }\n\n if (!config.currency || typeof config.currency !== 'string' || !config.currency.trim()) {\n errors.push('currency is required');\n } else if (!SUPPORTED_CURRENCIES.includes(normalizedCurrency)) {\n errors.push(`currency must be one of: ${SUPPORTED_CURRENCIES.join(', ')}`);\n }\n\n if (!config.itemName || typeof config.itemName !== 'string' || !config.itemName.trim()) {\n errors.push('itemName is required');\n }\n\n if (paymentType === PAYMENT_TYPES.PREAUTH) {\n if (normalizedCurrency && normalizedCurrency !== 'USD') {\n errors.push('currency must be USD for preauth payments');\n }\n\n if (!config.callbackUrl || !String(config.callbackUrl).trim()) {\n errors.push('callbackUrl (signing URL) is required for preauth payments');\n } else if (!isValidCallbackUrl(config.callbackUrl, {\n isProduction,\n allowLocalCallbacksInNonProd\n })) {\n errors.push(\n isProduction\n ? 'callbackUrl must be HTTPS in production and cannot target loopback/private hosts'\n : 'callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled'\n );\n }\n\n if (\n config.authHoldTimeInSeconds === undefined ||\n config.authHoldTimeInSeconds === null ||\n config.authHoldTimeInSeconds === ''\n ) {\n errors.push('authHoldTimeInSeconds is required for preauth payments');\n } else if (!isPositiveInteger(config.authHoldTimeInSeconds)) {\n errors.push('authHoldTimeInSeconds must be a positive integer (seconds)');\n }\n }\n\n if (paymentType === PAYMENT_TYPES.RECURRING) {\n if (!config.callbackUrl || !String(config.callbackUrl).trim()) {\n errors.push('callbackUrl (signing URL) is required for recurring payments');\n } else if (!isValidCallbackUrl(config.callbackUrl, {\n isProduction,\n allowLocalCallbacksInNonProd\n })) {\n errors.push(\n isProduction\n ? 'callbackUrl must be HTTPS in production and cannot target loopback/private hosts'\n : 'callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled'\n );\n }\n\n const frequency = (config.frequency || config.recurringInterval || '')\n .toString()\n .trim()\n .toUpperCase();\n\n if (!frequency) {\n errors.push('frequency is required for recurring payments');\n } else if (!RECURRING_FREQUENCY_VALUES.includes(frequency)) {\n errors.push(\n `frequency must be one of: ${RECURRING_FREQUENCY_VALUES.join(', ')}`\n );\n }\n\n if (!config.recurringEndDate || !String(config.recurringEndDate).trim()) {\n errors.push('recurringEndDate (expiry) is required for recurring payments');\n } else if (!isValidIsoDateTime(config.recurringEndDate)) {\n errors.push('recurringEndDate must be a valid ISO date-time string');\n } else if (new Date(config.recurringEndDate.trim()) <= new Date()) {\n errors.push('recurringEndDate must be in the future');\n }\n }\n\n return {\n valid: errors.length === 0,\n errors\n };\n}\n\n/**\n * Create error object\n */\nexport function createError(code, message, details = {}) {\n return {\n code,\n message,\n details,\n timestamp: new Date().toISOString(),\n toString() {\n return this.message || 'Dropp SDK error';\n }\n };\n}\n\n/**\n * Deep clone object\n */\nexport function deepClone(obj) {\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * Check if running in browser environment\n */\nexport function isBrowser() {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Sanitize HTML to prevent XSS\n */\nexport function sanitizeHTML(str) {\n if (!str) return '';\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n}\n\n/**\n * Format amount for display\n */\nexport function formatAmount(amount, currency) {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: currency || 'USD'\n }).format(amount);\n } catch (error) {\n return `${amount} ${currency}`;\n }\n}\n","/**\n * Secure Message Handler for SDK โ Payment App Communication\n * \n * Implements:\n * - Origin validation\n * - Message schema validation\n * - Session correlation\n * - Anti-spoofing protection\n */\n\nimport { MESSAGE_TYPES, SDK_MESSAGE_TYPES, ALLOWED_ORIGINS } from './constants.js';\nimport { generateSessionId } from './utils.js';\nimport logger from './logger.js';\n\nexport class MessageHandler {\n constructor(environment, onMessage, allowedOrigins = null) {\n this.environment = environment;\n this.onMessage = onMessage;\n this.sessionId = generateSessionId();\n logger.log('[MessageHandler] Session initialized');\n this.iframe = null;\n this.allowedOrigins =\n allowedOrigins?.length > 0\n ? allowedOrigins\n : ALLOWED_ORIGINS[environment] || [];\n this.messageListener = null;\n this.pendingMessages = new Map(); // Track correlation IDs for request/response\n }\n\n /**\n * Initialize message listener\n */\n init(iframe) {\n this.iframe = iframe;\n this.messageListener = this._handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n }\n\n /**\n * Clean up message listener\n */\n destroy() {\n if (this.messageListener) {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n this.iframe = null;\n this.pendingMessages.clear();\n }\n\n /**\n * Handle incoming postMessage events\n * @private\n */\n _handleMessage(event) {\n logger.log('[MessageHandler] Received postMessage event');\n\n // Ignore messages from self (parent window)\n if (event.source === window) {\n logger.log('[MessageHandler] Ignoring message from self');\n return;\n }\n\n // 1. Validate origin\n if (!this._validateOrigin(event.origin)) {\n logger.warn('[Dropp SDK] Rejected message from untrusted origin:', event.origin);\n return;\n }\n\n // 2. Validate event source\n if (!this.iframe || event.source !== this.iframe.contentWindow) {\n logger.warn('[Dropp SDK] Rejected message from unexpected source', {\n eventOrigin: event.origin\n });\n return;\n }\n\n // 3. Validate message structure\n const message = event.data;\n if (!this._validateMessageStructure(message)) {\n logger.warn('[Dropp SDK] Rejected message with invalid structure');\n return;\n }\n\n // 4. Validate session ID (if present)\n if (message.sessionId && message.sessionId !== this.sessionId) {\n logger.warn('[Dropp SDK] Rejected message with invalid session ID');\n return;\n }\n\n // 5. Process valid message\n logger.log('[MessageHandler] Message passed validation');\n this._processMessage(message);\n }\n\n /**\n * Validate message origin against allowed list\n * @private\n */\n _validateOrigin(origin) {\n // In development/testing, allow localhost\n if (origin.startsWith('http://localhost:') || origin.startsWith('http://127.0.0.1:')) {\n return true;\n }\n\n // Enforce exact scheme + host + port origin match.\n return this.allowedOrigins.includes(origin);\n }\n\n /**\n * Validate message structure and type\n * @private\n */\n _validateMessageStructure(message) {\n if (!message || typeof message !== 'object') {\n return false;\n }\n\n // Must have a type field\n if (!message.type || typeof message.type !== 'string') {\n return false;\n }\n\n // Must be a known message type from payment app\n const validTypes = Object.values(MESSAGE_TYPES);\n if (!validTypes.includes(message.type)) {\n return false;\n }\n\n // Must have timestamp\n if (!message.timestamp) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Process validated message\n * @private\n */\n _processMessage(message) {\n logger.log('[Dropp SDK] Received message:', message.type);\n\n // Invoke callback\n if (this.onMessage) {\n this.onMessage(message);\n }\n }\n\n /**\n * Send message to payment app\n */\n sendToPaymentApp(type, data = {}) {\n if (!this.iframe || !this.iframe.contentWindow) {\n logger.error('[Dropp SDK] Cannot send message: iframe not ready');\n return false;\n }\n\n const message = {\n type,\n data,\n sessionId: this.sessionId,\n timestamp: new Date().toISOString(),\n sdkVersion: '1.0.0'\n };\n\n // Get target origin from allowed origins\n const targetOrigin = this.allowedOrigins[0] || '*';\n\n try {\n this.iframe.contentWindow.postMessage(message, targetOrigin);\n logger.log('[Dropp SDK] Sent message:', type);\n return true;\n } catch (error) {\n logger.error('[Dropp SDK] Error sending message:', error);\n return false;\n }\n }\n\n /**\n * Send init message to payment app\n */\n sendInit(config) {\n return this.sendToPaymentApp(SDK_MESSAGE_TYPES.INIT, {\n mode: 'sdk',\n config\n });\n }\n\n /**\n * Send close request to payment app\n */\n sendClose() {\n return this.sendToPaymentApp(SDK_MESSAGE_TYPES.CLOSE, {});\n }\n\n /**\n * Get session ID\n */\n getSessionId() {\n return this.sessionId;\n }\n}\n","/**\n * Modal Manager - Creates and manages the payment modal UI\n * \n * Responsibilities:\n * - Create modal overlay and container\n * - Manage modal lifecycle (open/close/destroy)\n * - Handle focus trapping\n * - Clean up DOM and event listeners\n * - Responsive design\n */\n\nimport { MODAL_Z_INDEX } from './constants.js';\nimport logger from './logger.js';\n\nexport class ModalManager {\n constructor(onClose) {\n this.onClose = onClose;\n this.overlay = null;\n this.container = null;\n this.iframe = null;\n this.closeButton = null;\n this.isOpen = false;\n this.escapeListener = null;\n }\n\n /**\n * Create and show modal\n */\n open() {\n if (this.isOpen) {\n logger.warn('[Dropp SDK] Modal is already open');\n return null;\n }\n\n this._createModal();\n this._attachEventListeners();\n this._show();\n\n this.isOpen = true;\n return this.iframe;\n }\n\n /**\n * Close and cleanup modal\n */\n close() {\n logger.log('[ModalManager] ๐ฆ close() called, isOpen:', this.isOpen);\n \n if (!this.isOpen) {\n logger.log('[ModalManager] โ ๏ธ Modal is not open, skipping close');\n return;\n }\n\n logger.log('[ModalManager] ๐ฆ Hiding modal...');\n this._hide();\n logger.log('[ModalManager] ๐ฆ Removing event listeners...');\n this._removeEventListeners();\n logger.log('[ModalManager] ๐ฆ Destroying modal...');\n this._destroyModal();\n\n this.isOpen = false;\n logger.log('[ModalManager] โ
Modal close sequence initiated');\n }\n\n /**\n * Create modal DOM elements\n * @private\n */\n _createModal() {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.id = 'dropp-payment-overlay';\n this._applyOverlayStyles(this.overlay);\n\n // Create container\n this.container = document.createElement('div');\n this.container.id = 'dropp-payment-container';\n this._applyContainerStyles(this.container);\n\n // Close button removed - will be rendered by chrome app instead\n\n // Create iframe\n this.iframe = document.createElement('iframe');\n this.iframe.id = 'dropp-payment-iframe';\n this.iframe.setAttribute('allow', 'payment');\n this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');\n this.iframe.setAttribute('referrerpolicy', 'no-referrer');\n this.iframe.setAttribute('title', 'Dropp Payment');\n this._applyIframeStyles(this.iframe);\n\n // Assemble modal\n this.container.appendChild(this.iframe);\n this.overlay.appendChild(this.container);\n\n // Add to DOM\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Apply styles to overlay\n * @private\n */\n _applyOverlayStyles(element) {\n Object.assign(element.style, {\n position: 'fixed',\n inset: '0',\n width: '100vw',\n height: '100vh',\n margin: '0',\n padding: '20px',\n boxSizing: 'border-box',\n backgroundColor: 'rgba(0, 0, 0, 0.6)',\n zIndex: MODAL_Z_INDEX.toString(),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n opacity: '0',\n transition: 'opacity 0.3s ease',\n backdropFilter: 'blur(4px)',\n overflow: 'auto'\n });\n }\n\n /**\n * Apply styles to container\n * @private\n */\n _applyContainerStyles(element) {\n const isMobile = window.innerWidth < 768;\n this._isMobile = isMobile;\n\n Object.assign(element.style, {\n position: 'relative',\n flex: '0 0 auto',\n alignSelf: 'center',\n margin: 'auto',\n width: '100%',\n maxWidth: isMobile ? '100%' : '400px',\n height: isMobile ? '100%' : 'auto',\n minHeight: isMobile ? '100%' : '800px',\n maxHeight: isMobile ? '100%' : 'min(1000px, calc(100vh - 40px))',\n backgroundColor: '#ffffff',\n borderRadius: isMobile ? '0' : '16px',\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.3)',\n overflow: 'hidden',\n transform: 'scale(0.95)',\n transition: 'transform 0.3s ease, opacity 0.3s ease',\n display: 'flex',\n flexDirection: 'column'\n });\n }\n\n _getContainerTransform(scale) {\n return `scale(${scale})`;\n }\n\n /**\n * Apply styles to close button\n * @private\n */\n _applyCloseButtonStyles(element) {\n Object.assign(element.style, {\n position: 'absolute',\n top: '16px',\n right: '16px',\n zIndex: '10',\n width: '40px',\n height: '40px',\n border: 'none',\n borderRadius: '50%',\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n color: '#333',\n fontSize: '28px',\n lineHeight: '1',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',\n transition: 'all 0.2s ease',\n fontFamily: 'Arial, sans-serif',\n padding: '0'\n });\n\n // Hover effect\n element.addEventListener('mouseenter', () => {\n Object.assign(element.style, {\n backgroundColor: '#f5f5f5',\n transform: 'scale(1.1)'\n });\n });\n\n element.addEventListener('mouseleave', () => {\n Object.assign(element.style, {\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n transform: 'scale(1)'\n });\n });\n }\n\n /**\n * Apply styles to iframe\n * @private\n */\n _applyIframeStyles(element) {\n const isMobile = this._isMobile;\n Object.assign(element.style, {\n width: '100%',\n flex: '1 1 auto',\n minHeight: isMobile ? '100%' : 'min(520px, calc(90vh - 40px))',\n height: isMobile ? '100%' : 'min(520px, calc(90vh - 40px))',\n border: 'none',\n display: 'block'\n });\n }\n\n /**\n * Show modal with animation\n * @private\n */\n _show() {\n // Prevent body scroll\n document.body.style.overflow = 'hidden';\n\n // Trigger animation\n requestAnimationFrame(() => {\n if (this.overlay) {\n this.overlay.style.opacity = '1';\n }\n if (this.container) {\n this.container.style.transform = this._getContainerTransform(1);\n }\n });\n }\n\n /**\n * Hide modal with animation\n * @private\n */\n _hide() {\n logger.log('[ModalManager] ๐ญ _hide() called');\n if (this.overlay) {\n this.overlay.style.opacity = '0';\n logger.log('[ModalManager] ๐ญ Overlay opacity set to 0');\n }\n if (this.container) {\n this.container.style.transform = this._getContainerTransform(0.95);\n logger.log('[ModalManager] ๐ญ Container transform set to scale(0.95)');\n }\n\n // Restore body scroll\n document.body.style.overflow = '';\n logger.log('[ModalManager] ๐ญ Body scroll restored');\n }\n\n /**\n * Destroy modal DOM elements\n * @private\n */\n _destroyModal() {\n logger.log('[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation');\n // Wait for animation to complete\n setTimeout(() => {\n logger.log('[ModalManager] ๐๏ธ Animation complete, removing from DOM');\n if (this.overlay && this.overlay.parentNode) {\n this.overlay.parentNode.removeChild(this.overlay);\n logger.log('[ModalManager] ๐๏ธ Overlay removed from DOM');\n }\n this.overlay = null;\n this.container = null;\n this.iframe = null;\n this.closeButton = null;\n logger.log('[ModalManager] โ
Modal destroyed');\n }, 300);\n }\n\n /**\n * Attach event listeners\n * @private\n */\n _attachEventListeners() {\n // Close button removed - will be handled by chrome app\n // Close button click\n // if (this.closeButton) {\n // this.closeButton.addEventListener('click', this._handleCloseClick.bind(this));\n // }\n\n // Backdrop click disabled for payment security\n // Users must use close button or complete/cancel payment\n // if (this.overlay) {\n // this.overlay.addEventListener('click', this._handleOverlayClick.bind(this));\n // }\n\n // Escape key disabled for payment security\n // Users must use close button or complete/cancel payment\n // this.escapeListener = this._handleEscapeKey.bind(this);\n // document.addEventListener('keydown', this.escapeListener);\n }\n\n /**\n * Remove event listeners\n * @private\n */\n _removeEventListeners() {\n if (this.escapeListener) {\n document.removeEventListener('keydown', this.escapeListener);\n this.escapeListener = null;\n }\n }\n\n /**\n * Handle close button click\n * @private\n */\n _handleCloseClick(event) {\n event.stopPropagation();\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n\n /**\n * Handle overlay click (backdrop)\n * @private\n */\n _handleOverlayClick(event) {\n // Only close if clicking directly on overlay (not container)\n if (event.target === this.overlay) {\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n }\n\n /**\n * Handle escape key press\n * @private\n */\n _handleEscapeKey(event) {\n if (event.key === 'Escape' && this.isOpen) {\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n }\n\n /**\n * Get iframe element\n */\n getIframe() {\n return this.iframe;\n }\n\n /**\n * Check if modal is open\n */\n getIsOpen() {\n return this.isOpen;\n }\n}\n","/**\n * Dropp Payment SDK - Main SDK Class\n * \n * Public API for integrating Dropp payments into web applications\n */\n\nimport { \n ENVIRONMENTS, \n PAYMENT_APP_URLS,\n ALLOWED_ORIGINS,\n MESSAGE_TYPES, \n ERROR_CODES, \n TIMEOUTS, \n PAYMENT_TYPES,\n SDK_VERSION\n} from './constants.js';\nimport { MessageHandler } from './messageHandler.js';\nimport { ModalManager } from './modalManager.js';\nimport { \n buildPaymentUrl, \n validateConfig, \n createError, \n isBrowser \n} from './utils.js';\nimport logger from './logger.js';\n\nexport class DroppPaymentSDK {\n /**\n * Create SDK instance\n * @param {Object} config - SDK configuration\n * @param {string} config.merchantId - Merchant Hedera account ID (required, e.g., '0.0.123456')\n * @param {string} config.apiKey - API Key (required)\n * @param {string} config.packageName - Package name (required)\n * @param {string} config.environment - Environment: 'production', 'qa', or 'sandbox'\n * @param {Function} [config.getServerAuthToken] - Optional async callback that returns a server-issued auth token\n * @param {boolean} [config.requireServerAuthToken] - Require server auth token (defaults to true in production)\n * @param {boolean} [config.allowLocalCallbacksInNonProd] - Allow loopback/private callback URLs in non-production\n */\n constructor(config = {}) {\n if (!isBrowser()) {\n throw new Error('Dropp Payment SDK can only be used in a browser environment');\n }\n\n // Validate required credentials\n if (!config.merchantId || !config.apiKey || !config.packageName) {\n throw new Error('merchantId, apiKey, and packageName are required to initialize SDK');\n }\n\n // Store credentials\n this.merchantId = config.merchantId;\n this.apiKey = config.apiKey;\n this.packageName = config.packageName;\n\n this.environment = config.environment || ENVIRONMENTS.QA;\n this.baseUrl =\n config.paymentAppUrl ||\n config.baseUrl ||\n PAYMENT_APP_URLS[this.environment];\n\n // Initialization state\n this.isInitialized = false;\n this.initializationPromise = null;\n\n this.getServerAuthToken =\n typeof config.getServerAuthToken === 'function'\n ? config.getServerAuthToken\n : null;\n this.requireServerAuthToken =\n typeof config.requireServerAuthToken === 'boolean'\n ? config.requireServerAuthToken\n : this.environment === ENVIRONMENTS.PRODUCTION;\n this.allowLocalCallbacksInNonProd = !!config.allowLocalCallbacksInNonProd;\n\n if (config.allowedOrigins?.length) {\n this.allowedOrigins = config.allowedOrigins;\n } else {\n try {\n // Derive allowed origin from the effective payment URL to keep a\n // single source of truth for iframe loading and postMessage validation.\n this.allowedOrigins = [new URL(this.baseUrl).origin];\n } catch {\n this.allowedOrigins = ALLOWED_ORIGINS[this.environment] || [];\n }\n }\n\n // State\n this.isOpen = false;\n this.currentSession = null;\n this.currentFlowType = null;\n this.initTimeout = null;\n this.paymentTimeout = null;\n\n // Managers\n this.messageHandler = null;\n this.modalManager = null;\n\n // Set logger environment\n logger.setEnvironment(this.environment, { enabled: !!config.debugLogging });\n logger.log(`[Dropp SDK] Initialized v${SDK_VERSION} - Environment: ${this.environment}`);\n }\n\n /**\n * Open payment modal\n * @param {Object} options - Payment options\n * @param {number} options.amount - Payment amount (required)\n * @param {string} options.currency - Currency code (required)\n * @param {string} options.itemName - Item/service name (required)\n * @param {string} options.description - Payment description\n * @param {string} options.invoiceId - Invoice ID\n * @param {string} options.paymentType - Payment type: 'standard', 'preauth', or 'recurring'\n * @param {string} options.thumbnail - Product image URL\n * @param {number} options.authHoldTimeInSeconds - For preauth: hold time in seconds\n * @param {string} options.callbackUrl - Server callback URL\n * @param {boolean} [options.acceptPaymentDelay=false] - Allow delayed payment acceptance for standard payments (sent only when true)\n * @param {string} [options.serverAuthToken] - Server-issued short-lived token bound to payment context\n * @param {Function} options.onSuccess - Callback for successful payment\n * @param {Function} options.onFailure - Callback for failed payment\n * @param {Function} options.onCancel - Callback for cancelled payment\n * @param {Function} options.onClose - Callback for modal close\n * @returns {Promise<PaymentResult>}\n */\n pay(options = {}) {\n return new Promise((resolve, reject) => {\n // Check if already open\n if (this.isOpen) {\n const error = createError(\n ERROR_CODES.ALREADY_OPEN,\n 'A payment session is already in progress',\n { currentSession: this.currentSession }\n );\n reject(error);\n return;\n }\n\n (async () => {\n try {\n await this.initialize();\n\n // Validate payment configuration\n const validation = validateConfig(options, {\n environment: this.environment,\n allowLocalCallbacksInNonProd: this.allowLocalCallbacksInNonProd\n });\n if (!validation.valid) {\n const error = createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Invalid payment configuration',\n { errors: validation.errors }\n );\n reject(error);\n return;\n }\n\n // Store callbacks from options\n this.onSuccess = options.onSuccess || null;\n this.onFailure = options.onFailure || null;\n this.onCancel = options.onCancel || null;\n this.onClose = options.onClose || null;\n\n // Store resolve/reject for later\n this.currentSession = {\n resolve,\n reject,\n options,\n startTime: Date.now()\n };\n\n await this._initializePayment(options);\n } catch (error) {\n const isInitValidationError =\n error && error.code === ERROR_CODES.INVALID_CONFIG;\n const sdkError = isInitValidationError\n ? error\n : createError(\n ERROR_CODES.UNKNOWN_ERROR,\n 'Failed to initialize payment',\n { originalError: error?.message || String(error) }\n );\n\n reject(sdkError);\n this._cleanup();\n }\n })();\n });\n }\n\n /**\n * Initialize and validate merchant credentials with Dropp backend.\n * @returns {Promise<{status: string, code: string, message: string}>}\n */\n async initialize() {\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n\n this.initializationPromise = (async () => {\n await this._validateInitializationCredentials();\n this.isInitialized = true;\n return {\n status: 'success',\n code: 'INITIALIZED',\n message: 'Dropp SDK initialized successfully'\n };\n })().catch(error => {\n this.isInitialized = false;\n this.initializationPromise = null;\n throw error;\n });\n\n return this.initializationPromise;\n }\n\n /**\n * Resolve validation endpoint from configured base URL.\n * @private\n */\n _getValidationUrl() {\n const validationUrls = {\n [ENVIRONMENTS.QA]: 'https://main.qa.dropp.cc/payer/webview/validate',\n [ENVIRONMENTS.SANDBOX]: 'https://sandbox.api.dropp.cc/payer/webview/validate',\n [ENVIRONMENTS.PRODUCTION]: 'https://api.dropp.cc/payer/webview/validate'\n };\n\n return (\n validationUrls[this.environment] ||\n validationUrls[ENVIRONMENTS.QA]\n );\n }\n\n /**\n * Validate merchant credentials and app package before any payment flow.\n * @private\n */\n async _validateInitializationCredentials() {\n const validationUrl = this._getValidationUrl();\n\n let response;\n let responseBody = null;\n try {\n response = await fetch(validationUrl, {\n method: 'POST',\n headers: {\n accept: 'application/json, text/plain, */*',\n 'content-type': 'application/json',\n 'x-api-key': this.apiKey,\n 'x-app-package': this.packageName\n },\n body: JSON.stringify({ id: this.merchantId })\n });\n } catch (error) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Unable to validate merchant credentials',\n {\n endpoint: validationUrl,\n originalError: error?.message || String(error)\n }\n );\n }\n\n try {\n responseBody = await response.json();\n } catch {\n responseBody = null;\n }\n\n if (!response.ok) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Merchant validation failed for merchantId/apiKey/packageName',\n {\n endpoint: validationUrl,\n status: response.status,\n response: responseBody\n }\n );\n }\n\n const responseCode = Number(responseBody?.responseCode);\n const errors = responseBody?.errors;\n const hasNoErrors = !Array.isArray(errors) || errors.length === 0;\n const isValidationSuccess = responseBody && responseCode === 0 && hasNoErrors;\n\n if (!isValidationSuccess) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Merchant validation returned an unsuccessful response',\n {\n endpoint: validationUrl,\n status: response.status,\n response: responseBody\n }\n );\n }\n\n logger.log('[Dropp SDK] Merchant credentials validated successfully');\n }\n\n /**\n * Close payment modal programmatically\n */\n closePayment() {\n if (this.isOpen) {\n if (this.currentFlowType === 'page') {\n this._cleanup();\n return;\n }\n this._handleCancel('sdk_close');\n }\n }\n\n /**\n * Open the dashboard/home page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n dashboard(options = {}) {\n return this._openHostedPage('/firsttimeflow', options);\n }\n\n /**\n * Open the unlink account page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n unlinkAccount(options = {}) {\n return this._openHostedPage('/unlink', options);\n }\n\n /**\n * Open the transactions page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n transactions(options = {}) {\n return this._openHostedPage('/transactions', options);\n }\n\n /**\n * Open the offers page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n offers(options = {}) {\n return this._openHostedPage('/offers', options);\n }\n\n /**\n * Initialize payment session\n * @private\n */\n async _initializePayment(options) {\n logger.log('[Dropp SDK] Initializing payment session');\n this.currentFlowType = 'payment';\n\n // Create message handler\n this.messageHandler = new MessageHandler(\n this.environment,\n this._handleMessage.bind(this),\n this.allowedOrigins\n );\n\n // Create modal manager\n this.modalManager = new ModalManager(\n this._handleModalClose.bind(this)\n );\n\n // Open modal and get iframe\n const iframe = this.modalManager.open();\n if (!iframe) {\n throw new Error('Failed to create modal iframe');\n }\n\n // Initialize message handler with iframe\n this.messageHandler.init(iframe);\n\n // Determine payment route based on type\n const paymentType = options.paymentType || PAYMENT_TYPES.STANDARD;\n let route = '/payViaUrl';\n if (paymentType === PAYMENT_TYPES.PREAUTH) {\n route = '/preAuthPayment';\n } else if (paymentType === PAYMENT_TYPES.RECURRING) {\n route = '/recurringPayment';\n }\n\n // Build payment parameters (matching Android SDK)\n // For recurring payments with frequency NONE, use maxAmount instead of fixAmount\n const recurringFrequency = paymentType === PAYMENT_TYPES.RECURRING \n ? (options.frequency || options.recurringInterval || '').toString().trim().toUpperCase()\n : '';\n const isRecurringNone = paymentType === PAYMENT_TYPES.RECURRING && recurringFrequency === 'NONE';\n const detectedAppUrl =\n options.appUrl ||\n (typeof window !== 'undefined' && window.location ? window.location.href : undefined);\n \n const params = {\n merchantAccount: this.merchantId,\n amount: paymentType === PAYMENT_TYPES.PREAUTH ? undefined : options.amount,\n maxAmount: (paymentType === PAYMENT_TYPES.PREAUTH || isRecurringNone) ? options.amount : undefined,\n fixAmount: (paymentType === PAYMENT_TYPES.RECURRING && !isRecurringNone) ? options.amount : undefined,\n acceptPaymentDelay:\n paymentType === PAYMENT_TYPES.STANDARD && options.acceptPaymentDelay === true\n ? true\n : undefined,\n currency: options.currency,\n itemName: options.itemName,\n description: options.description,\n invoiceId: options.invoiceId || `INV-${Date.now()}`,\n invoiceType: paymentType === PAYMENT_TYPES.PREAUTH ? 'PREAUTH' : undefined,\n apiKey: this.apiKey,\n packageName: this.packageName,\n sdkVersion: SDK_VERSION,\n platform: 'web',\n appUrl: detectedAppUrl,\n sessionId: this.messageHandler.getSessionId() // Include SDK session ID for message validation\n };\n \n logger.log('[Dropp SDK] Including SDK session context in payment params');\n\n // Add optional parameters\n if (options.successURL) params.successURL = options.successURL;\n if (options.failureURL) params.failureURL = options.failureURL;\n \n // Recurring payment specific fields\n if (paymentType === PAYMENT_TYPES.RECURRING) {\n const frequency = options.frequency || options.recurringInterval;\n if (frequency) params.frequency = frequency;\n if (options.recurringEndDate) params.expiry = options.recurringEndDate;\n }\n \n // Pre-auth specific fields\n if (paymentType === PAYMENT_TYPES.PREAUTH && options.authHoldTimeInSeconds) {\n params.authHoldTimeInSeconds = options.authHoldTimeInSeconds;\n }\n \n // Callback URL for server-side submission\n if (options.callbackUrl) {\n params.url = options.callbackUrl;\n params.submitToCallBack = 'post';\n }\n\n const authContext = {\n sessionId: params.sessionId,\n merchantAccount: this.merchantId,\n amount: options.amount,\n paymentType,\n invoiceId: params.invoiceId,\n expiry: options.recurringEndDate || null,\n issuedAt: Date.now()\n };\n\n let serverAuthToken =\n typeof options.serverAuthToken === 'string'\n ? options.serverAuthToken.trim()\n : '';\n\n if (!serverAuthToken && this.getServerAuthToken) {\n try {\n const tokenFromCallback = await this.getServerAuthToken(authContext);\n serverAuthToken = typeof tokenFromCallback === 'string'\n ? tokenFromCallback.trim()\n : '';\n } catch (error) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Failed to obtain server auth token',\n {\n originalError: error?.message || String(error)\n }\n );\n }\n }\n\n if (this.requireServerAuthToken && !serverAuthToken) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.',\n {\n environment: this.environment,\n paymentType,\n invoiceId: params.invoiceId\n }\n );\n }\n\n // Build payment URL with base64 payload and optional server-issued auth token.\n const paymentUrl = await buildPaymentUrl(\n this.baseUrl,\n route,\n params,\n SDK_VERSION,\n { serverAuthToken }\n );\n\n logger.log('[Dropp SDK] Loading payment flow iframe');\n\n // Load payment app in iframe\n iframe.src = paymentUrl;\n\n this.isOpen = true;\n\n // Set initialization timeout\n this.initTimeout = setTimeout(() => {\n this._handleTimeout('init');\n }, TIMEOUTS.INIT);\n\n // Set payment timeout\n this.paymentTimeout = setTimeout(() => {\n this._handleTimeout('payment');\n }, TIMEOUTS.PAYMENT);\n }\n\n /**\n * Open a hosted Dropp page in the modal.\n * @private\n */\n async _openHostedPage(route, options = {}) {\n if (this.isOpen) {\n throw createError(\n ERROR_CODES.ALREADY_OPEN,\n 'A Dropp session is already in progress',\n { currentSession: this.currentSession, route }\n );\n }\n\n await this.initialize();\n\n this.currentFlowType = 'page';\n this.currentSession = null;\n this.onSuccess = null;\n this.onFailure = null;\n this.onCancel = null;\n this.onClose = typeof options.onClose === 'function' ? options.onClose : null;\n\n this.messageHandler = new MessageHandler(\n this.environment,\n this._handleMessage.bind(this),\n this.allowedOrigins\n );\n\n this.modalManager = new ModalManager(\n this._handleModalClose.bind(this)\n );\n\n const iframe = this.modalManager.open();\n if (!iframe) {\n throw new Error('Failed to create modal iframe');\n }\n\n this.messageHandler.init(iframe);\n\n const normalizedBaseUrl = this.baseUrl.replace(/\\/+$/, '');\n iframe.src = `${normalizedBaseUrl}/#${route}`;\n this.isOpen = true;\n\n logger.log('[Dropp SDK] Hosted page opened', { route });\n\n return {\n status: 'opened',\n route\n };\n }\n\n /**\n * Handle messages from payment app\n * @private\n */\n _handleMessage(message) {\n const { type, data } = message;\n\n switch (type) {\n case MESSAGE_TYPES.READY:\n this._handleReady(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_PAGE_LOADED:\n this._handlePageLoaded(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_SUCCESS:\n this._handleSuccess(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_FAILED:\n this._handleFailure(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_CANCELLED:\n this._handleCancel('user_cancelled');\n break;\n\n case MESSAGE_TYPES.AUTO_CLOSE_WEBVIEW:\n // Auto-close from payment app after success/failure countdown\n // Just close the modal without triggering callbacks (already called)\n logger.log('[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal');\n this._cleanup();\n logger.log('[Dropp SDK] Cleanup completed');\n break;\n\n case MESSAGE_TYPES.CLOSE_WEBVIEW:\n // Manual close request from chrome app\n logger.log('[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal');\n this._handleCancel('app_close');\n break;\n\n default:\n logger.warn('[Dropp SDK] Unknown message type:', type);\n }\n }\n\n /**\n * Handle ready message from payment app\n * @private\n */\n _handleReady(data) {\n logger.log('[Dropp SDK] Payment app ready');\n \n // Clear init timeout\n if (this.initTimeout) {\n clearTimeout(this.initTimeout);\n this.initTimeout = null;\n }\n\n // Send init message to payment app\n // Filter out non-serializable data (functions) from options\n if (this.messageHandler && this.currentSession) {\n const serializableOptions = {};\n Object.keys(this.currentSession.options).forEach(key => {\n const value = this.currentSession.options[key];\n // Only include serializable values (exclude functions)\n if (typeof value !== 'function') {\n serializableOptions[key] = value;\n }\n });\n \n logger.log('[Dropp SDK] Sending init config to payment app');\n this.messageHandler.sendInit(serializableOptions);\n }\n }\n\n /**\n * Handle page loaded message\n * @private\n */\n _handlePageLoaded(data) {\n logger.log('[Dropp SDK] Payment page loaded');\n }\n\n /**\n * Handle successful payment\n * @private\n */\n _handleSuccess(data) {\n logger.log('[Dropp SDK] Payment successful');\n\n const result = {\n status: 'success',\n ...data,\n sessionDuration: Date.now() - this.currentSession.startTime\n };\n\n // Resolve promise\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onSuccess) {\n this.onSuccess(result);\n }\n\n // Note: Modal will be closed by AUTO_CLOSE_WEBVIEW message from payment app\n // after the countdown completes (no need for timeout here)\n }\n\n /**\n * Handle failed payment\n * @private\n */\n _handleFailure(data) {\n logger.log('[Dropp SDK] Payment failed');\n\n const result = {\n status: 'failed',\n ...data,\n sessionDuration: Date.now() - this.currentSession.startTime\n };\n\n // Resolve promise (not reject - failed payment is still a valid result)\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onFailure) {\n this.onFailure(result);\n }\n\n // Note: Modal will be closed by AUTO_CLOSE_WEBVIEW message from payment app\n // after the countdown completes (no need for timeout here)\n }\n\n /**\n * Handle cancelled payment\n * @private\n */\n _handleCancel(reason) {\n logger.log('[Dropp SDK] Payment cancelled');\n\n const result = {\n status: 'cancelled',\n reason,\n sessionDuration: this.currentSession ? Date.now() - this.currentSession.startTime : 0\n };\n\n // Resolve promise (not reject - cancellation is a valid result)\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onCancel) {\n this.onCancel(result);\n }\n\n // Close immediately\n this._cleanup();\n }\n\n /**\n * Handle modal close by user\n * @private\n */\n _handleModalClose(reason) {\n logger.log('[Dropp SDK] Modal closed by user');\n if (this.currentFlowType === 'page') {\n this._cleanup();\n return;\n }\n this._handleCancel(reason);\n }\n\n /**\n * Handle timeout\n * @private\n */\n _handleTimeout(type) {\n logger.error('[Dropp SDK] Timeout:', type);\n\n const errorCode = type === 'init' ? ERROR_CODES.INIT_TIMEOUT : ERROR_CODES.PAYMENT_TIMEOUT;\n const errorMessage = type === 'init' \n ? 'Payment app failed to load within timeout period'\n : 'Payment session timed out';\n\n const error = createError(errorCode, errorMessage, {\n type,\n sessionDuration: this.currentSession ? Date.now() - this.currentSession.startTime : 0\n });\n\n // Reject promise\n if (this.currentSession) {\n this.currentSession.reject(error);\n }\n\n // Invoke failure callback\n if (this.onFailure) {\n this.onFailure({ status: 'failed', error });\n }\n\n this._cleanup();\n }\n\n /**\n * Cleanup resources\n * @private\n */\n _cleanup() {\n logger.log('[Dropp SDK] ๐งน Cleaning up session - starting cleanup');\n\n // Clear timeouts\n if (this.initTimeout) {\n clearTimeout(this.initTimeout);\n this.initTimeout = null;\n }\n\n if (this.paymentTimeout) {\n clearTimeout(this.paymentTimeout);\n this.paymentTimeout = null;\n }\n\n // Destroy managers\n if (this.messageHandler) {\n logger.log('[Dropp SDK] ๐งน Destroying message handler');\n this.messageHandler.destroy();\n this.messageHandler = null;\n }\n\n if (this.modalManager) {\n logger.log('[Dropp SDK] ๐งน Closing modal manager');\n this.modalManager.close();\n logger.log('[Dropp SDK] ๐งน Modal manager closed');\n this.modalManager = null;\n }\n\n // Clear state\n this.currentSession = null;\n this.currentFlowType = null;\n this.isOpen = false;\n\n // Invoke onClose callback\n if (this.onClose) {\n this.onClose();\n }\n }\n\n /**\n * Get SDK version\n */\n static getVersion() {\n return SDK_VERSION;\n }\n\n /**\n * Get available environments\n */\n static getEnvironments() {\n return { ...ENVIRONMENTS };\n }\n\n /**\n * Get payment types\n */\n static getPaymentTypes() {\n return { ...PAYMENT_TYPES };\n }\n}\n\nexport default DroppPaymentSDK;\n","/**\n * Dropp Payment SDK for Web\n * \n * Main entry point - exports SDK class and factory functions\n */\n\nimport { DroppPaymentSDK } from './DroppPaymentSDK.js';\nimport { ENVIRONMENTS, PAYMENT_TYPES } from './constants.js';\n\n// Export main SDK class\nexport { DroppPaymentSDK };\n\n// Export constants\nexport { ENVIRONMENTS, PAYMENT_TYPES };\n\n// Global Dropp instance\nlet globalDroppInstance = null;\n\n/**\n * Factory function to create and initialize SDK instance\n * @param {Object} config - SDK configuration\n * @param {string} config.merchantId - Merchant Hedera account ID (required, e.g., '0.0.123456')\n * @param {string} config.apiKey - API Key (required)\n * @param {string} config.packageName - Package name (required)\n * @param {string} config.environment - Environment: 'production', 'qa', or 'sandbox'\n * @returns {Promise<{status: string, code: string, message: string, sdk: DroppPaymentSDK}>}\n */\nexport async function createPaymentSDK(config) {\n globalDroppInstance = new DroppPaymentSDK(config);\n const initResult = await globalDroppInstance.initialize();\n return {\n ...initResult,\n sdk: globalDroppInstance\n };\n}\n\n/**\n * Get the global Dropp instance\n * @returns {DroppPaymentSDK|null}\n */\nexport function getDroppInstance() {\n return globalDroppInstance;\n}\n\n/**\n * Global Dropp object with pay method\n */\nexport const Dropp = {\n /**\n * Initialize SDK (sets global instance)\n * @param {Object} config - SDK configuration\n * @returns {Promise<{status: string, code: string, message: string, sdk: DroppPaymentSDK}>}\n */\n init(config) {\n return createPaymentSDK(config);\n },\n \n /**\n * Make a payment using the initialized SDK\n * @param {Object} options - Payment options\n * @returns {Promise<PaymentResult>}\n */\n pay(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.pay(options);\n },\n\n /**\n * Open the dashboard/home page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n dashboard(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.dashboard(options);\n },\n\n /**\n * Open the unlink account page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n unlinkAccount(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.unlinkAccount(options);\n },\n\n /**\n * Open the transactions page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n transactions(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.transactions(options);\n },\n\n /**\n * Open the offers page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n offers(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.offers(options);\n },\n \n /**\n * Get the current SDK instance\n * @returns {DroppPaymentSDK|null}\n */\n getInstance() {\n return globalDroppInstance;\n }\n};\n\n// Default export\nexport default {\n DroppPaymentSDK,\n createPaymentSDK,\n Dropp,\n ENVIRONMENTS,\n PAYMENT_TYPES\n};\n"],"names":["MESSAGE_TYPES","READY","PAYMENT_SUCCESS","PAYMENT_FAILED","PAYMENT_CANCELLED","CLOSE_WEBVIEW","AUTO_CLOSE_WEBVIEW","PAYMENT_PAGE_LOADED","SDK_MESSAGE_TYPES","ENVIRONMENTS","PRODUCTION","QA","SANDBOX","PAYMENT_APP_URLS","ALLOWED_ORIGINS","TIMEOUTS","PAYMENT_TYPES","STANDARD","PREAUTH","RECURRING","ERROR_CODES","SDK_VERSION","logger","constructor","environment","options","this","forceEnabled","enabled","_shouldEnableLogging","setEnvironment","setEnabled","log","args","console","warn","error","debug","info","SUPPORTED_CURRENCIES","RECURRING_FREQUENCY_VALUES","PAYMENT_TYPE_VALUES","isValidCallbackUrl","url","isProduction","allowLocalCallbacksInNonProd","trim","parsed","URL","isHttps","protocol","hostname","normalized","toLowerCase","endsWith","test","octets","split","map","part","Number","some","octet","isNaN","a","b","isPrivateOrLoopbackHost","validateConfig","config","errors","paymentType","normalizedCurrency","currency","toUpperCase","includes","push","join","undefined","amount","value","num","parseFloat","isPositiveNumber","itemName","callbackUrl","String","authHoldTimeInSeconds","parseInt","isInteger","isPositiveInteger","frequency","recurringInterval","toString","recurringEndDate","date","Date","getTime","isValidIsoDateTime","valid","length","createError","code","message","details","timestamp","toISOString","MessageHandler","onMessage","allowedOrigins","sessionId","now","Math","random","substring","iframe","messageListener","pendingMessages","Map","init","_handleMessage","bind","window","addEventListener","destroy","removeEventListener","clear","event","source","_validateOrigin","origin","contentWindow","eventOrigin","data","_validateMessageStructure","_processMessage","startsWith","type","Object","values","sendToPaymentApp","sdkVersion","targetOrigin","postMessage","sendInit","mode","sendClose","getSessionId","ModalManager","onClose","overlay","container","closeButton","isOpen","escapeListener","open","_createModal","_attachEventListeners","_show","close","_hide","_removeEventListeners","_destroyModal","document","createElement","id","_applyOverlayStyles","_applyContainerStyles","setAttribute","_applyIframeStyles","appendChild","body","element","assign","style","position","inset","width","height","margin","padding","boxSizing","backgroundColor","zIndex","display","alignItems","justifyContent","opacity","transition","backdropFilter","overflow","isMobile","innerWidth","_isMobile","flex","alignSelf","maxWidth","minHeight","maxHeight","borderRadius","boxShadow","transform","flexDirection","_getContainerTransform","scale","_applyCloseButtonStyles","top","right","border","color","fontSize","lineHeight","cursor","fontFamily","requestAnimationFrame","setTimeout","parentNode","removeChild","_handleCloseClick","stopPropagation","_handleOverlayClick","target","_handleEscapeKey","key","getIframe","getIsOpen","DroppPaymentSDK","Error","merchantId","apiKey","packageName","baseUrl","paymentAppUrl","isInitialized","initializationPromise","getServerAuthToken","requireServerAuthToken","currentSession","currentFlowType","initTimeout","paymentTimeout","messageHandler","modalManager","debugLogging","pay","Promise","resolve","reject","initialize","validation","onSuccess","onFailure","onCancel","startTime","_initializePayment","sdkError","originalError","_cleanup","_validateInitializationCredentials","status","catch","_getValidationUrl","validationUrls","validationUrl","response","responseBody","fetch","method","headers","accept","JSON","stringify","endpoint","json","ok","responseCode","hasNoErrors","Array","isArray","closePayment","_handleCancel","dashboard","_openHostedPage","unlinkAccount","transactions","offers","_handleModalClose","route","recurringFrequency","isRecurringNone","detectedAppUrl","appUrl","location","href","params","merchantAccount","maxAmount","fixAmount","acceptPaymentDelay","description","invoiceId","invoiceType","platform","successURL","failureURL","expiry","submitToCallBack","authContext","issuedAt","serverAuthToken","tokenFromCallback","paymentUrl","async","authOptions","payload","keys","forEach","jsonString","base64Payload","btoa","replace","queryParams","URLSearchParams","sdkTs","set","buildPaymentUrl","src","_handleTimeout","normalizedBaseUrl","_handleReady","_handlePageLoaded","_handleSuccess","_handleFailure","clearTimeout","serializableOptions","result","sessionDuration","reason","getVersion","getEnvironments","getPaymentTypes","globalDroppInstance","createPaymentSDK","sdk","getDroppInstance","Dropp","getInstance","index"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).DroppPaymentSDK={})}(this,function(e){"use strict";const t={READY:"DROPP_SDK_READY",PAYMENT_SUCCESS:"PAYMENT_SUCCESS",PAYMENT_FAILED:"PAYMENT_FAILED",PAYMENT_CANCELLED:"PAYMENT_CANCELLED",CLOSE_WEBVIEW:"CLOSE_WEBVIEW",AUTO_CLOSE_WEBVIEW:"AUTO_CLOSE_WEBVIEW",PAYMENT_PAGE_LOADED:"PAYMENT_PAGE_LOADED"},n="DROPP_SDK_INIT",i="DROPP_SDK_CLOSE",s={PRODUCTION:"production",QA:"qa",SANDBOX:"sandbox"},o={[s.PRODUCTION]:"https://wv.dropp.cc",[s.QA]:"https://wv.qa.dropp.cc",[s.SANDBOX]:"https://wv.sandbox.dropp.cc"},r={[s.PRODUCTION]:["https://wv.dropp.cc"],[s.QA]:["https://wv.qa.dropp.cc"],[s.SANDBOX]:["https://wv.sandbox.dropp.cc"]},a=3e4,l=6e5,c={STANDARD:"standard",PREAUTH:"preauth",RECURRING:"recurring"},d="INIT_TIMEOUT",p="PAYMENT_TIMEOUT",h="INVALID_CONFIG",u="ALREADY_OPEN",m="UNKNOWN_ERROR",g="1.0.2";const y=new class{constructor(e,t={}){this.environment=e,this.forceEnabled=!!t.enabled,this.enabled=this._shouldEnableLogging()}_shouldEnableLogging(){return this.forceEnabled}setEnvironment(e,t={}){this.environment=e,"boolean"==typeof t.enabled&&(this.forceEnabled=t.enabled),this.enabled=this._shouldEnableLogging()}setEnabled(e){this.forceEnabled=!!e,this.enabled=this._shouldEnableLogging()}log(...e){this.enabled&&console.log(...e)}warn(...e){this.enabled&&console.warn(...e)}error(...e){this.enabled&&console.error(...e)}debug(...e){this.enabled&&console.debug(...e)}info(...e){this.enabled&&console.info(...e)}}("qa",{enabled:!1}),f=["USD","HBAR","USDC"],D=["NONE","HALF_HOURLY","HOURLY","DAILY","WEEKLY","MONTHLY","YEARLY"],S=[c.STANDARD,c.PREAUTH,c.RECURRING];function b(e,t={}){const{isProduction:n=!1,allowLocalCallbacksInNonProd:i=!1}=t;if("string"!=typeof e||!e.trim())return!1;try{const t=new URL(e.trim()),s="https:"===t.protocol;if(!("http:"===t.protocol)&&!s)return!1;return function(e){if(!e)return!1;const t=e.trim().toLowerCase();if("localhost"===t||"127.0.0.1"===t||"::1"===t||t.endsWith(".local"))return!0;if(!/^(\d{1,3}\.){3}\d{1,3}$/.test(t))return!1;const n=t.split(".").map(e=>Number(e));if(n.some(e=>Number.isNaN(e)||e<0||e>255))return!1;const[i,s]=n;return 10===i||127===i||172===i&&s>=16&&s<=31||192===i&&168===s||169===i&&254===s}(t.hostname)?!n&&i:!n||s}catch{return!1}}function v(e={},t={}){const n=[],i=e.paymentType||c.STANDARD,s="production"===(t.environment||"").toLowerCase(),o=!!t.allowLocalCallbacksInNonProd,r="string"==typeof e.currency?e.currency.trim().toUpperCase():"";if(S.includes(i)||n.push(`paymentType must be one of: ${S.join(", ")}`),void 0===e.amount||null===e.amount||""===e.amount?n.push("amount is required"):function(e){const t="number"==typeof e?e:parseFloat(e);return"number"==typeof t&&!Number.isNaN(t)&&t>0}(e.amount)||n.push("amount must be a positive number"),e.currency&&"string"==typeof e.currency&&e.currency.trim()?f.includes(r)||n.push(`currency must be one of: ${f.join(", ")}`):n.push("currency is required"),e.itemName&&"string"==typeof e.itemName&&e.itemName.trim()||n.push("itemName is required"),i===c.PREAUTH&&(r&&"USD"!==r&&n.push("currency must be USD for preauth payments"),e.callbackUrl&&String(e.callbackUrl).trim()?b(e.callbackUrl,{isProduction:s,allowLocalCallbacksInNonProd:o})||n.push(s?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for preauth payments"),void 0===e.authHoldTimeInSeconds||null===e.authHoldTimeInSeconds||""===e.authHoldTimeInSeconds?n.push("authHoldTimeInSeconds is required for preauth payments"):function(e){const t="number"==typeof e?e:parseInt(e,10);return Number.isInteger(t)&&t>0}(e.authHoldTimeInSeconds)||n.push("authHoldTimeInSeconds must be a positive integer (seconds)")),i===c.RECURRING){e.callbackUrl&&String(e.callbackUrl).trim()?b(e.callbackUrl,{isProduction:s,allowLocalCallbacksInNonProd:o})||n.push(s?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for recurring payments");const t=(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase();t?D.includes(t)||n.push(`frequency must be one of: ${D.join(", ")}`):n.push("frequency is required for recurring payments"),e.recurringEndDate&&String(e.recurringEndDate).trim()?!function(e){if("string"!=typeof e||!e.trim())return!1;const t=new Date(e.trim());return!Number.isNaN(t.getTime())}(e.recurringEndDate)?n.push("recurringEndDate must be a valid ISO date-time string"):new Date(e.recurringEndDate.trim())<=new Date&&n.push("recurringEndDate must be in the future"):n.push("recurringEndDate (expiry) is required for recurring payments")}return{valid:0===n.length,errors:n}}function w(e,t,n={}){return{code:e,message:t,details:n,timestamp:(new Date).toISOString(),toString(){return this.message||"Dropp SDK error"}}}class E{constructor(e,t,n=null){this.environment=e,this.onMessage=t,this.sessionId=`dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2,15)}`,y.log("[MessageHandler] Session initialized"),this.iframe=null,this.allowedOrigins=n?.length>0?n:r[e]||[],this.messageListener=null,this.pendingMessages=new Map}init(e){this.iframe=e,this.messageListener=this._handleMessage.bind(this),window.addEventListener("message",this.messageListener)}destroy(){this.messageListener&&(window.removeEventListener("message",this.messageListener),this.messageListener=null),this.iframe=null,this.pendingMessages.clear()}_handleMessage(e){if(y.log("[MessageHandler] Received postMessage event"),e.source===window)return void y.log("[MessageHandler] Ignoring message from self");if(!this._validateOrigin(e.origin))return void y.warn("[Dropp SDK] Rejected message from untrusted origin:",e.origin);if(!this.iframe||e.source!==this.iframe.contentWindow)return void y.warn("[Dropp SDK] Rejected message from unexpected source",{eventOrigin:e.origin});const t=e.data;this._validateMessageStructure(t)?t.sessionId&&t.sessionId!==this.sessionId?y.warn("[Dropp SDK] Rejected message with invalid session ID"):(y.log("[MessageHandler] Message passed validation"),this._processMessage(t)):y.warn("[Dropp SDK] Rejected message with invalid structure")}_validateOrigin(e){return!(!e.startsWith("http://localhost:")&&!e.startsWith("http://127.0.0.1:"))||this.allowedOrigins.includes(e)}_validateMessageStructure(e){if(!e||"object"!=typeof e)return!1;if(!e.type||"string"!=typeof e.type)return!1;return!!Object.values(t).includes(e.type)&&!!e.timestamp}_processMessage(e){y.log("[Dropp SDK] Received message:",e.type),this.onMessage&&this.onMessage(e)}sendToPaymentApp(e,t={}){if(!this.iframe||!this.iframe.contentWindow)return y.error("[Dropp SDK] Cannot send message: iframe not ready"),!1;const n={type:e,data:t,sessionId:this.sessionId,timestamp:(new Date).toISOString(),sdkVersion:"1.0.0"},i=this.allowedOrigins[0]||"*";try{return this.iframe.contentWindow.postMessage(n,i),y.log("[Dropp SDK] Sent message:",e),!0}catch(e){return y.error("[Dropp SDK] Error sending message:",e),!1}}sendInit(e){return this.sendToPaymentApp(n,{mode:"sdk",config:e})}sendClose(){return this.sendToPaymentApp(i,{})}getSessionId(){return this.sessionId}}class T{constructor(e){this.onClose=e,this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,this.isOpen=!1,this.escapeListener=null}open(){return this.isOpen?(y.warn("[Dropp SDK] Modal is already open"),null):(this._createModal(),this._attachEventListeners(),this._show(),this.isOpen=!0,this.iframe)}close(){y.log("[ModalManager] ๐ฆ close() called, isOpen:",this.isOpen),this.isOpen?(y.log("[ModalManager] ๐ฆ Hiding modal..."),this._hide(),y.log("[ModalManager] ๐ฆ Removing event listeners..."),this._removeEventListeners(),y.log("[ModalManager] ๐ฆ Destroying modal..."),this._destroyModal(),this.isOpen=!1,y.log("[ModalManager] โ
Modal close sequence initiated")):y.log("[ModalManager] โ ๏ธ Modal is not open, skipping close")}_createModal(){this.overlay=document.createElement("div"),this.overlay.id="dropp-payment-overlay",this._applyOverlayStyles(this.overlay),this.container=document.createElement("div"),this.container.id="dropp-payment-container",this._applyContainerStyles(this.container),this.iframe=document.createElement("iframe"),this.iframe.id="dropp-payment-iframe",this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups"),this.iframe.setAttribute("referrerpolicy","no-referrer"),this.iframe.setAttribute("title","Dropp Payment"),this._applyIframeStyles(this.iframe),this.container.appendChild(this.iframe),this.overlay.appendChild(this.container),document.body.appendChild(this.overlay)}_applyOverlayStyles(e){Object.assign(e.style,{position:"fixed",inset:"0",width:"100vw",height:"100vh",margin:"0",padding:"20px",boxSizing:"border-box",backgroundColor:"rgba(0, 0, 0, 0.6)",zIndex:999999..toString(),display:"flex",alignItems:"center",justifyContent:"center",opacity:"0",transition:"opacity 0.3s ease",backdropFilter:"blur(4px)",overflow:"auto"})}_applyContainerStyles(e){const t=window.innerWidth<768;this._isMobile=t,Object.assign(e.style,{position:"relative",flex:"0 0 auto",alignSelf:"center",margin:"auto",width:"100%",maxWidth:t?"100%":"400px",height:t?"100%":"auto",minHeight:t?"100%":"800px",maxHeight:t?"100%":"min(1000px, calc(100vh - 40px))",backgroundColor:"#ffffff",borderRadius:t?"0":"16px",boxShadow:"0 20px 60px rgba(0, 0, 0, 0.3)",overflow:"hidden",transform:"scale(0.95)",transition:"transform 0.3s ease, opacity 0.3s ease",display:"flex",flexDirection:"column"})}_getContainerTransform(e){return`scale(${e})`}_applyCloseButtonStyles(e){Object.assign(e.style,{position:"absolute",top:"16px",right:"16px",zIndex:"10",width:"40px",height:"40px",border:"none",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.9)",color:"#333",fontSize:"28px",lineHeight:"1",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.15)",transition:"all 0.2s ease",fontFamily:"Arial, sans-serif",padding:"0"}),e.addEventListener("mouseenter",()=>{Object.assign(e.style,{backgroundColor:"#f5f5f5",transform:"scale(1.1)"})}),e.addEventListener("mouseleave",()=>{Object.assign(e.style,{backgroundColor:"rgba(255, 255, 255, 0.9)",transform:"scale(1)"})})}_applyIframeStyles(e){const t=this._isMobile;Object.assign(e.style,{width:"100%",flex:"1 1 auto",minHeight:t?"100%":"min(520px, calc(90vh - 40px))",height:t?"100%":"min(520px, calc(90vh - 40px))",border:"none",display:"block"})}_show(){document.body.style.overflow="hidden",requestAnimationFrame(()=>{this.overlay&&(this.overlay.style.opacity="1"),this.container&&(this.container.style.transform=this._getContainerTransform(1))})}_hide(){y.log("[ModalManager] ๐ญ _hide() called"),this.overlay&&(this.overlay.style.opacity="0",y.log("[ModalManager] ๐ญ Overlay opacity set to 0")),this.container&&(this.container.style.transform=this._getContainerTransform(.95),y.log("[ModalManager] ๐ญ Container transform set to scale(0.95)")),document.body.style.overflow="",y.log("[ModalManager] ๐ญ Body scroll restored")}_destroyModal(){y.log("[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation"),setTimeout(()=>{y.log("[ModalManager] ๐๏ธ Animation complete, removing from DOM"),this.overlay&&this.overlay.parentNode&&(this.overlay.parentNode.removeChild(this.overlay),y.log("[ModalManager] ๐๏ธ Overlay removed from DOM")),this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,y.log("[ModalManager] โ
Modal destroyed")},300)}_attachEventListeners(){}_removeEventListeners(){this.escapeListener&&(document.removeEventListener("keydown",this.escapeListener),this.escapeListener=null)}_handleCloseClick(e){e.stopPropagation(),this.onClose&&this.onClose("user_closed")}_handleOverlayClick(e){e.target===this.overlay&&this.onClose&&this.onClose("user_closed")}_handleEscapeKey(e){"Escape"===e.key&&this.isOpen&&this.onClose&&this.onClose("user_closed")}getIframe(){return this.iframe}getIsOpen(){return this.isOpen}}class _{constructor(e={}){if("undefined"==typeof window||"undefined"==typeof document)throw new Error("Dropp Payment SDK can only be used in a browser environment");if(!e.merchantId||!e.apiKey||!e.packageName)throw new Error("merchantId, apiKey, and packageName are required to initialize SDK");if(this.merchantId=e.merchantId,this.apiKey=e.apiKey,this.packageName=e.packageName,this.environment=e.environment||s.QA,this.baseUrl=e.paymentAppUrl||e.baseUrl||o[this.environment],this.isInitialized=!1,this.initializationPromise=null,this.getServerAuthToken="function"==typeof e.getServerAuthToken?e.getServerAuthToken:null,this.requireServerAuthToken="boolean"==typeof e.requireServerAuthToken?e.requireServerAuthToken:this.environment===s.PRODUCTION,this.allowLocalCallbacksInNonProd=!!e.allowLocalCallbacksInNonProd,e.allowedOrigins?.length)this.allowedOrigins=e.allowedOrigins;else try{this.allowedOrigins=[new URL(this.baseUrl).origin]}catch{this.allowedOrigins=r[this.environment]||[]}this.isOpen=!1,this.currentSession=null,this.currentFlowType=null,this.initTimeout=null,this.paymentTimeout=null,this.messageHandler=null,this.modalManager=null,y.setEnvironment(this.environment,{enabled:!!e.debugLogging}),y.log(`[Dropp SDK] Initialized v${g} - Environment: ${this.environment}`)}pay(e={}){return new Promise((t,n)=>{if(this.isOpen){const e=w(u,"A payment session is already in progress",{currentSession:this.currentSession});return void n(e)}(async()=>{try{await this.initialize();const i=v(e,{environment:this.environment,allowLocalCallbacksInNonProd:this.allowLocalCallbacksInNonProd});if(!i.valid){const e=w(h,"Invalid payment configuration",{errors:i.errors});return void n(e)}this.onSuccess=e.onSuccess||null,this.onFailure=e.onFailure||null,this.onCancel=e.onCancel||null,this.onClose=e.onClose||null,this.currentSession={resolve:t,reject:n,options:e,startTime:Date.now()},await this._initializePayment(e)}catch(e){const t=e&&e.code===h?e:w(m,"Failed to initialize payment",{originalError:e?.message||String(e)});n(t),this._cleanup()}})()})}async initialize(){return this.initializationPromise||(this.initializationPromise=(async()=>(await this._validateInitializationCredentials(),this.isInitialized=!0,{status:"success",code:"INITIALIZED",message:"Dropp SDK initialized successfully"}))().catch(e=>{throw this.isInitialized=!1,this.initializationPromise=null,e})),this.initializationPromise}_getValidationUrl(){const e={[s.QA]:"https://main.qa.dropp.cc/payer/webview/validate",[s.SANDBOX]:"https://sandbox.api.dropp.cc/payer/webview/validate",[s.PRODUCTION]:"https://api.dropp.cc/payer/webview/validate"};return e[this.environment]||e[s.QA]}async _validateInitializationCredentials(){const e=this._getValidationUrl();let t,n=null;try{t=await fetch(e,{method:"POST",headers:{accept:"application/json, text/plain, */*","content-type":"application/json","x-api-key":this.apiKey,"x-app-package":this.packageName},body:JSON.stringify({id:this.merchantId})})}catch(t){throw w(h,"Unable to validate merchant credentials",{endpoint:e,originalError:t?.message||String(t)})}try{n=await t.json()}catch{n=null}if(!t.ok)throw w(h,"Merchant validation failed for merchantId/apiKey/packageName",{endpoint:e,status:t.status,response:n});const i=Number(n?.responseCode),s=n?.errors,o=!Array.isArray(s)||0===s.length;if(!(n&&0===i&&o))throw w(h,"Merchant validation returned an unsuccessful response",{endpoint:e,status:t.status,response:n});y.log("[Dropp SDK] Merchant credentials validated successfully")}closePayment(){if(this.isOpen){if("page"===this.currentFlowType)return void this._cleanup();this._handleCancel("sdk_close")}}dashboard(e={}){return this._openHostedPage("/firsttimeflow",e)}unlinkAccount(e={}){return this._openHostedPage("/unlink",e)}transactions(e={}){return this._openHostedPage("/transactions",e)}offers(e={}){return this._openHostedPage("/offers",e)}async _initializePayment(e){y.log("[Dropp SDK] Initializing payment session"),this.currentFlowType="payment",this.messageHandler=new E(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new T(this._handleModalClose.bind(this));const t=this.modalManager.open();if(!t)throw new Error("Failed to create modal iframe");this.messageHandler.init(t);const n=e.paymentType||c.STANDARD;let i="/payViaUrl";n===c.PREAUTH?i="/preAuthPayment":n===c.RECURRING&&(i="/recurringPayment");const s=n===c.RECURRING?(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase():"",o=n===c.RECURRING&&"NONE"===s,r=e.appUrl||("undefined"!=typeof window&&window.location?window.location.href:void 0),d={merchantAccount:this.merchantId,amount:n===c.PREAUTH?void 0:e.amount,maxAmount:n===c.PREAUTH||o?e.amount:void 0,fixAmount:n!==c.RECURRING||o?void 0:e.amount,acceptPaymentDelay:n===c.STANDARD&&!0===e.acceptPaymentDelay||void 0,currency:e.currency,itemName:e.itemName,description:e.description,invoiceId:e.invoiceId||`INV-${Date.now()}`,invoiceType:n===c.PREAUTH?"PREAUTH":void 0,apiKey:this.apiKey,packageName:this.packageName,sdkVersion:g,platform:"web",appUrl:r,sessionId:this.messageHandler.getSessionId()};if(y.log("[Dropp SDK] Including SDK session context in payment params"),e.successURL&&(d.successURL=e.successURL),e.failureURL&&(d.failureURL=e.failureURL),n===c.RECURRING){const t=e.frequency||e.recurringInterval;t&&(d.frequency=t),e.recurringEndDate&&(d.expiry=e.recurringEndDate)}n===c.PREAUTH&&e.authHoldTimeInSeconds&&(d.authHoldTimeInSeconds=e.authHoldTimeInSeconds),e.callbackUrl&&(d.url=e.callbackUrl,d.submitToCallBack="post");const p={sessionId:d.sessionId,merchantAccount:this.merchantId,amount:e.amount,paymentType:n,invoiceId:d.invoiceId,expiry:e.recurringEndDate||null,issuedAt:Date.now()};let u="string"==typeof e.serverAuthToken?e.serverAuthToken.trim():"";if(!u&&this.getServerAuthToken)try{const e=await this.getServerAuthToken(p);u="string"==typeof e?e.trim():""}catch(e){throw w(h,"Failed to obtain server auth token",{originalError:e?.message||String(e)})}if(this.requireServerAuthToken&&!u)throw w(h,"serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.",{environment:this.environment,paymentType:n,invoiceId:d.invoiceId});const m=await async function(e,t,n,i,s={}){try{const{serverAuthToken:o=""}=s,r={};Object.keys(n).forEach(e=>{const t=n[e];null!=t&&(r[e]=t)}),y.log("[buildPaymentUrl] Building payment URL payload");const a=JSON.stringify(r),l=btoa(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""),c=Date.now().toString(),d=new URLSearchParams({pay:l,sdkTs:c,sdkVersion:i,platform:"web"});return o&&d.set("authToken",o),`${e}/#${t}?${d.toString()}`}catch(e){throw y.error("Error building payment URL:",e),e}}(this.baseUrl,i,d,g,{serverAuthToken:u});y.log("[Dropp SDK] Loading payment flow iframe"),t.src=m,this.isOpen=!0,this.initTimeout=setTimeout(()=>{this._handleTimeout("init")},a),this.paymentTimeout=setTimeout(()=>{this._handleTimeout("payment")},l)}async _openHostedPage(e,t={}){if(this.isOpen)throw w(u,"A Dropp session is already in progress",{currentSession:this.currentSession,route:e});await this.initialize(),this.currentFlowType="page",this.currentSession=null,this.onSuccess=null,this.onFailure=null,this.onCancel=null,this.onClose="function"==typeof t.onClose?t.onClose:null,this.modalManager=new T(this._handleModalClose.bind(this));const n=this.modalManager.open();if(!n)throw new Error("Failed to create modal iframe");const i=this.baseUrl.replace(/\/+$/,"");return n.src=`${i}/#${e}`,this.isOpen=!0,y.log("[Dropp SDK] Hosted page opened",{route:e}),{status:"opened",route:e}}_handleMessage(e){const{type:n,data:i}=e;switch(n){case t.READY:this._handleReady(i);break;case t.PAYMENT_PAGE_LOADED:this._handlePageLoaded(i);break;case t.PAYMENT_SUCCESS:this._handleSuccess(i);break;case t.PAYMENT_FAILED:this._handleFailure(i);break;case t.PAYMENT_CANCELLED:this._handleCancel("user_cancelled");break;case t.AUTO_CLOSE_WEBVIEW:y.log("[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal"),this._cleanup(),y.log("[Dropp SDK] Cleanup completed");break;case t.CLOSE_WEBVIEW:y.log("[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal"),this._handleCancel("app_close");break;default:y.warn("[Dropp SDK] Unknown message type:",n)}}_handleReady(e){if(y.log("[Dropp SDK] Payment app ready"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.messageHandler&&this.currentSession){const e={};Object.keys(this.currentSession.options).forEach(t=>{const n=this.currentSession.options[t];"function"!=typeof n&&(e[t]=n)}),y.log("[Dropp SDK] Sending init config to payment app"),this.messageHandler.sendInit(e)}}_handlePageLoaded(e){y.log("[Dropp SDK] Payment page loaded")}_handleSuccess(e){y.log("[Dropp SDK] Payment successful");const t={status:"success",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onSuccess&&this.onSuccess(t)}_handleFailure(e){y.log("[Dropp SDK] Payment failed");const t={status:"failed",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onFailure&&this.onFailure(t)}_handleCancel(e){y.log("[Dropp SDK] Payment cancelled");const t={status:"cancelled",reason:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0};this.currentSession&&this.currentSession.resolve(t),this.onCancel&&this.onCancel(t),this._cleanup()}_handleModalClose(e){y.log("[Dropp SDK] Modal closed by user"),"page"!==this.currentFlowType?this._handleCancel(e):this._cleanup()}_handleTimeout(e){y.error("[Dropp SDK] Timeout:",e);const t=w("init"===e?d:p,"init"===e?"Payment app failed to load within timeout period":"Payment session timed out",{type:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0});this.currentSession&&this.currentSession.reject(t),this.onFailure&&this.onFailure({status:"failed",error:t}),this._cleanup()}_cleanup(){y.log("[Dropp SDK] ๐งน Cleaning up session - starting cleanup"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.paymentTimeout&&(clearTimeout(this.paymentTimeout),this.paymentTimeout=null),this.messageHandler&&(y.log("[Dropp SDK] ๐งน Destroying message handler"),this.messageHandler.destroy(),this.messageHandler=null),this.modalManager&&(y.log("[Dropp SDK] ๐งน Closing modal manager"),this.modalManager.close(),y.log("[Dropp SDK] ๐งน Modal manager closed"),this.modalManager=null),this.currentSession=null,this.currentFlowType=null,this.isOpen=!1,this.onClose&&this.onClose()}static getVersion(){return g}static getEnvironments(){return{...s}}static getPaymentTypes(){return{...c}}}let I=null;async function A(e){I=new _(e);return{...await I.initialize(),sdk:I}}const C={init:e=>A(e),pay(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.pay(e)},dashboard(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.dashboard(e)},unlinkAccount(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.unlinkAccount(e)},transactions(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.transactions(e)},offers(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.offers(e)},getInstance:()=>I};var N={DroppPaymentSDK:_,createPaymentSDK:A,Dropp:C,ENVIRONMENTS:s,PAYMENT_TYPES:c};e.Dropp=C,e.DroppPaymentSDK=_,e.ENVIRONMENTS=s,e.PAYMENT_TYPES=c,e.createPaymentSDK=A,e.default=N,e.getDroppInstance=function(){return I},Object.defineProperty(e,"__esModule",{value:!0})});
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).DroppPaymentSDK={})}(this,function(e){"use strict";const t={READY:"DROPP_SDK_READY",PAYMENT_SUCCESS:"PAYMENT_SUCCESS",PAYMENT_FAILED:"PAYMENT_FAILED",PAYMENT_CANCELLED:"PAYMENT_CANCELLED",CLOSE_WEBVIEW:"CLOSE_WEBVIEW",AUTO_CLOSE_WEBVIEW:"AUTO_CLOSE_WEBVIEW",PAYMENT_PAGE_LOADED:"PAYMENT_PAGE_LOADED"},n="DROPP_SDK_INIT",i="DROPP_SDK_CLOSE",s={PRODUCTION:"production",QA:"qa",SANDBOX:"sandbox"},o={[s.PRODUCTION]:"https://wv.dropp.cc",[s.QA]:"https://wv.qa.dropp.cc",[s.SANDBOX]:"https://wv.sandbox.dropp.cc"},r={[s.PRODUCTION]:["https://wv.dropp.cc"],[s.QA]:["https://wv.qa.dropp.cc"],[s.SANDBOX]:["https://wv.sandbox.dropp.cc"]},a=3e4,l=6e5,c={STANDARD:"standard",PREAUTH:"preauth",RECURRING:"recurring"},d="INIT_TIMEOUT",p="PAYMENT_TIMEOUT",h="INVALID_CONFIG",u="ALREADY_OPEN",m="UNKNOWN_ERROR",g="1.0.2";const y=new class{constructor(e,t={}){this.environment=e,this.forceEnabled=!!t.enabled,this.enabled=this._shouldEnableLogging()}_shouldEnableLogging(){return this.forceEnabled}setEnvironment(e,t={}){this.environment=e,"boolean"==typeof t.enabled&&(this.forceEnabled=t.enabled),this.enabled=this._shouldEnableLogging()}setEnabled(e){this.forceEnabled=!!e,this.enabled=this._shouldEnableLogging()}log(...e){this.enabled&&console.log(...e)}warn(...e){this.enabled&&console.warn(...e)}error(...e){this.enabled&&console.error(...e)}debug(...e){this.enabled&&console.debug(...e)}info(...e){this.enabled&&console.info(...e)}}("qa",{enabled:!1}),f=["USD","HBAR","USDC"],D=["NONE","HALF_HOURLY","HOURLY","DAILY","WEEKLY","MONTHLY","YEARLY"],S=[c.STANDARD,c.PREAUTH,c.RECURRING];function b(e,t={}){const{isProduction:n=!1,allowLocalCallbacksInNonProd:i=!1}=t;if("string"!=typeof e||!e.trim())return!1;try{const t=new URL(e.trim()),s="https:"===t.protocol;if(!("http:"===t.protocol)&&!s)return!1;return function(e){if(!e)return!1;const t=e.trim().toLowerCase();if("localhost"===t||"127.0.0.1"===t||"::1"===t||t.endsWith(".local"))return!0;if(!/^(\d{1,3}\.){3}\d{1,3}$/.test(t))return!1;const n=t.split(".").map(e=>Number(e));if(n.some(e=>Number.isNaN(e)||e<0||e>255))return!1;const[i,s]=n;return 10===i||127===i||172===i&&s>=16&&s<=31||192===i&&168===s||169===i&&254===s}(t.hostname)?!n&&i:!n||s}catch{return!1}}function v(e={},t={}){const n=[],i=e.paymentType||c.STANDARD,s="production"===(t.environment||"").toLowerCase(),o=!!t.allowLocalCallbacksInNonProd,r="string"==typeof e.currency?e.currency.trim().toUpperCase():"";if(S.includes(i)||n.push(`paymentType must be one of: ${S.join(", ")}`),void 0===e.amount||null===e.amount||""===e.amount?n.push("amount is required"):function(e){const t="number"==typeof e?e:parseFloat(e);return"number"==typeof t&&!Number.isNaN(t)&&t>0}(e.amount)||n.push("amount must be a positive number"),e.currency&&"string"==typeof e.currency&&e.currency.trim()?f.includes(r)||n.push(`currency must be one of: ${f.join(", ")}`):n.push("currency is required"),e.itemName&&"string"==typeof e.itemName&&e.itemName.trim()||n.push("itemName is required"),i===c.PREAUTH&&(r&&"USD"!==r&&n.push("currency must be USD for preauth payments"),e.callbackUrl&&String(e.callbackUrl).trim()?b(e.callbackUrl,{isProduction:s,allowLocalCallbacksInNonProd:o})||n.push(s?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for preauth payments"),void 0===e.authHoldTimeInSeconds||null===e.authHoldTimeInSeconds||""===e.authHoldTimeInSeconds?n.push("authHoldTimeInSeconds is required for preauth payments"):function(e){const t="number"==typeof e?e:parseInt(e,10);return Number.isInteger(t)&&t>0}(e.authHoldTimeInSeconds)||n.push("authHoldTimeInSeconds must be a positive integer (seconds)")),i===c.RECURRING){e.callbackUrl&&String(e.callbackUrl).trim()?b(e.callbackUrl,{isProduction:s,allowLocalCallbacksInNonProd:o})||n.push(s?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for recurring payments");const t=(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase();t?D.includes(t)||n.push(`frequency must be one of: ${D.join(", ")}`):n.push("frequency is required for recurring payments"),e.recurringEndDate&&String(e.recurringEndDate).trim()?!function(e){if("string"!=typeof e||!e.trim())return!1;const t=new Date(e.trim());return!Number.isNaN(t.getTime())}(e.recurringEndDate)?n.push("recurringEndDate must be a valid ISO date-time string"):new Date(e.recurringEndDate.trim())<=new Date&&n.push("recurringEndDate must be in the future"):n.push("recurringEndDate (expiry) is required for recurring payments")}return{valid:0===n.length,errors:n}}function w(e,t,n={}){return{code:e,message:t,details:n,timestamp:(new Date).toISOString(),toString(){return this.message||"Dropp SDK error"}}}class E{constructor(e,t,n=null){this.environment=e,this.onMessage=t,this.sessionId=`dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2,15)}`,y.log("[MessageHandler] Session initialized"),this.iframe=null,this.allowedOrigins=n?.length>0?n:r[e]||[],this.messageListener=null,this.pendingMessages=new Map}init(e){this.iframe=e,this.messageListener=this._handleMessage.bind(this),window.addEventListener("message",this.messageListener)}destroy(){this.messageListener&&(window.removeEventListener("message",this.messageListener),this.messageListener=null),this.iframe=null,this.pendingMessages.clear()}_handleMessage(e){if(y.log("[MessageHandler] Received postMessage event"),e.source===window)return void y.log("[MessageHandler] Ignoring message from self");if(!this._validateOrigin(e.origin))return void y.warn("[Dropp SDK] Rejected message from untrusted origin:",e.origin);if(!this.iframe||e.source!==this.iframe.contentWindow)return void y.warn("[Dropp SDK] Rejected message from unexpected source",{eventOrigin:e.origin});const t=e.data;this._validateMessageStructure(t)?t.sessionId&&t.sessionId!==this.sessionId?y.warn("[Dropp SDK] Rejected message with invalid session ID"):(y.log("[MessageHandler] Message passed validation"),this._processMessage(t)):y.warn("[Dropp SDK] Rejected message with invalid structure")}_validateOrigin(e){return!(!e.startsWith("http://localhost:")&&!e.startsWith("http://127.0.0.1:"))||this.allowedOrigins.includes(e)}_validateMessageStructure(e){if(!e||"object"!=typeof e)return!1;if(!e.type||"string"!=typeof e.type)return!1;return!!Object.values(t).includes(e.type)&&!!e.timestamp}_processMessage(e){y.log("[Dropp SDK] Received message:",e.type),this.onMessage&&this.onMessage(e)}sendToPaymentApp(e,t={}){if(!this.iframe||!this.iframe.contentWindow)return y.error("[Dropp SDK] Cannot send message: iframe not ready"),!1;const n={type:e,data:t,sessionId:this.sessionId,timestamp:(new Date).toISOString(),sdkVersion:"1.0.0"},i=this.allowedOrigins[0]||"*";try{return this.iframe.contentWindow.postMessage(n,i),y.log("[Dropp SDK] Sent message:",e),!0}catch(e){return y.error("[Dropp SDK] Error sending message:",e),!1}}sendInit(e){return this.sendToPaymentApp(n,{mode:"sdk",config:e})}sendClose(){return this.sendToPaymentApp(i,{})}getSessionId(){return this.sessionId}}class T{constructor(e){this.onClose=e,this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,this.isOpen=!1,this.escapeListener=null}open(){return this.isOpen?(y.warn("[Dropp SDK] Modal is already open"),null):(this._createModal(),this._attachEventListeners(),this._show(),this.isOpen=!0,this.iframe)}close(){y.log("[ModalManager] ๐ฆ close() called, isOpen:",this.isOpen),this.isOpen?(y.log("[ModalManager] ๐ฆ Hiding modal..."),this._hide(),y.log("[ModalManager] ๐ฆ Removing event listeners..."),this._removeEventListeners(),y.log("[ModalManager] ๐ฆ Destroying modal..."),this._destroyModal(),this.isOpen=!1,y.log("[ModalManager] โ
Modal close sequence initiated")):y.log("[ModalManager] โ ๏ธ Modal is not open, skipping close")}_createModal(){this.overlay=document.createElement("div"),this.overlay.id="dropp-payment-overlay",this._applyOverlayStyles(this.overlay),this.container=document.createElement("div"),this.container.id="dropp-payment-container",this._applyContainerStyles(this.container),this.iframe=document.createElement("iframe"),this.iframe.id="dropp-payment-iframe",this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups"),this.iframe.setAttribute("referrerpolicy","no-referrer"),this.iframe.setAttribute("title","Dropp Payment"),this._applyIframeStyles(this.iframe),this.container.appendChild(this.iframe),this.overlay.appendChild(this.container),document.body.appendChild(this.overlay)}_applyOverlayStyles(e){Object.assign(e.style,{position:"fixed",inset:"0",width:"100vw",height:"100vh",margin:"0",padding:"20px",boxSizing:"border-box",backgroundColor:"rgba(0, 0, 0, 0.6)",zIndex:999999..toString(),display:"flex",alignItems:"center",justifyContent:"center",opacity:"0",transition:"opacity 0.3s ease",backdropFilter:"blur(4px)",overflow:"auto"})}_applyContainerStyles(e){const t=window.innerWidth<768;this._isMobile=t,Object.assign(e.style,{position:"relative",flex:"0 0 auto",alignSelf:"center",margin:"auto",width:"100%",maxWidth:t?"100%":"400px",height:t?"100%":"auto",minHeight:t?"100%":"800px",maxHeight:t?"100%":"min(1000px, calc(100vh - 40px))",backgroundColor:"#ffffff",borderRadius:t?"0":"16px",boxShadow:"0 20px 60px rgba(0, 0, 0, 0.3)",overflow:"hidden",transform:"scale(0.95)",transition:"transform 0.3s ease, opacity 0.3s ease",display:"flex",flexDirection:"column"})}_getContainerTransform(e){return`scale(${e})`}_applyCloseButtonStyles(e){Object.assign(e.style,{position:"absolute",top:"16px",right:"16px",zIndex:"10",width:"40px",height:"40px",border:"none",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.9)",color:"#333",fontSize:"28px",lineHeight:"1",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.15)",transition:"all 0.2s ease",fontFamily:"Arial, sans-serif",padding:"0"}),e.addEventListener("mouseenter",()=>{Object.assign(e.style,{backgroundColor:"#f5f5f5",transform:"scale(1.1)"})}),e.addEventListener("mouseleave",()=>{Object.assign(e.style,{backgroundColor:"rgba(255, 255, 255, 0.9)",transform:"scale(1)"})})}_applyIframeStyles(e){const t=this._isMobile;Object.assign(e.style,{width:"100%",flex:"1 1 auto",minHeight:t?"100%":"min(520px, calc(90vh - 40px))",height:t?"100%":"min(520px, calc(90vh - 40px))",border:"none",display:"block"})}_show(){document.body.style.overflow="hidden",requestAnimationFrame(()=>{this.overlay&&(this.overlay.style.opacity="1"),this.container&&(this.container.style.transform=this._getContainerTransform(1))})}_hide(){y.log("[ModalManager] ๐ญ _hide() called"),this.overlay&&(this.overlay.style.opacity="0",y.log("[ModalManager] ๐ญ Overlay opacity set to 0")),this.container&&(this.container.style.transform=this._getContainerTransform(.95),y.log("[ModalManager] ๐ญ Container transform set to scale(0.95)")),document.body.style.overflow="",y.log("[ModalManager] ๐ญ Body scroll restored")}_destroyModal(){y.log("[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation"),setTimeout(()=>{y.log("[ModalManager] ๐๏ธ Animation complete, removing from DOM"),this.overlay&&this.overlay.parentNode&&(this.overlay.parentNode.removeChild(this.overlay),y.log("[ModalManager] ๐๏ธ Overlay removed from DOM")),this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,y.log("[ModalManager] โ
Modal destroyed")},300)}_attachEventListeners(){}_removeEventListeners(){this.escapeListener&&(document.removeEventListener("keydown",this.escapeListener),this.escapeListener=null)}_handleCloseClick(e){e.stopPropagation(),this.onClose&&this.onClose("user_closed")}_handleOverlayClick(e){e.target===this.overlay&&this.onClose&&this.onClose("user_closed")}_handleEscapeKey(e){"Escape"===e.key&&this.isOpen&&this.onClose&&this.onClose("user_closed")}getIframe(){return this.iframe}getIsOpen(){return this.isOpen}}class _{constructor(e={}){if("undefined"==typeof window||"undefined"==typeof document)throw new Error("Dropp Payment SDK can only be used in a browser environment");if(!e.merchantId||!e.apiKey||!e.packageName)throw new Error("merchantId, apiKey, and packageName are required to initialize SDK");if(this.merchantId=e.merchantId,this.apiKey=e.apiKey,this.packageName=e.packageName,this.environment=e.environment||s.QA,this.baseUrl=e.paymentAppUrl||e.baseUrl||o[this.environment],this.isInitialized=!1,this.initializationPromise=null,this.getServerAuthToken="function"==typeof e.getServerAuthToken?e.getServerAuthToken:null,this.requireServerAuthToken="boolean"==typeof e.requireServerAuthToken?e.requireServerAuthToken:this.environment===s.PRODUCTION,this.allowLocalCallbacksInNonProd=!!e.allowLocalCallbacksInNonProd,e.allowedOrigins?.length)this.allowedOrigins=e.allowedOrigins;else try{this.allowedOrigins=[new URL(this.baseUrl).origin]}catch{this.allowedOrigins=r[this.environment]||[]}this.isOpen=!1,this.currentSession=null,this.currentFlowType=null,this.initTimeout=null,this.paymentTimeout=null,this.messageHandler=null,this.modalManager=null,y.setEnvironment(this.environment,{enabled:!!e.debugLogging}),y.log(`[Dropp SDK] Initialized v${g} - Environment: ${this.environment}`)}pay(e={}){return new Promise((t,n)=>{if(this.isOpen){const e=w(u,"A payment session is already in progress",{currentSession:this.currentSession});return void n(e)}(async()=>{try{await this.initialize();const i=v(e,{environment:this.environment,allowLocalCallbacksInNonProd:this.allowLocalCallbacksInNonProd});if(!i.valid){const e=w(h,"Invalid payment configuration",{errors:i.errors});return void n(e)}this.onSuccess=e.onSuccess||null,this.onFailure=e.onFailure||null,this.onCancel=e.onCancel||null,this.onClose=e.onClose||null,this.currentSession={resolve:t,reject:n,options:e,startTime:Date.now()},await this._initializePayment(e)}catch(e){const t=e&&e.code===h?e:w(m,"Failed to initialize payment",{originalError:e?.message||String(e)});n(t),this._cleanup()}})()})}async initialize(){return this.initializationPromise||(this.initializationPromise=(async()=>(await this._validateInitializationCredentials(),this.isInitialized=!0,{status:"success",code:"INITIALIZED",message:"Dropp SDK initialized successfully"}))().catch(e=>{throw this.isInitialized=!1,this.initializationPromise=null,e})),this.initializationPromise}_getValidationUrl(){const e={[s.QA]:"https://main.qa.dropp.cc/payer/webview/validate",[s.SANDBOX]:"https://sandbox.api.dropp.cc/payer/webview/validate",[s.PRODUCTION]:"https://api.dropp.cc/payer/webview/validate"};return e[this.environment]||e[s.QA]}async _validateInitializationCredentials(){const e=this._getValidationUrl();let t,n=null;try{t=await fetch(e,{method:"POST",headers:{accept:"application/json, text/plain, */*","content-type":"application/json","x-api-key":this.apiKey,"x-app-package":this.packageName},body:JSON.stringify({id:this.merchantId})})}catch(t){throw w(h,"Unable to validate merchant credentials",{endpoint:e,originalError:t?.message||String(t)})}try{n=await t.json()}catch{n=null}if(!t.ok)throw w(h,"Merchant validation failed for merchantId/apiKey/packageName",{endpoint:e,status:t.status,response:n});const i=Number(n?.responseCode),s=n?.errors,o=!Array.isArray(s)||0===s.length;if(!(n&&0===i&&o))throw w(h,"Merchant validation returned an unsuccessful response",{endpoint:e,status:t.status,response:n});y.log("[Dropp SDK] Merchant credentials validated successfully")}closePayment(){if(this.isOpen){if("page"===this.currentFlowType)return void this._cleanup();this._handleCancel("sdk_close")}}dashboard(e={}){return this._openHostedPage("/firsttimeflow",e)}unlinkAccount(e={}){return this._openHostedPage("/unlink",e)}transactions(e={}){return this._openHostedPage("/transactions",e)}offers(e={}){return this._openHostedPage("/offers",e)}async _initializePayment(e){y.log("[Dropp SDK] Initializing payment session"),this.currentFlowType="payment",this.messageHandler=new E(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new T(this._handleModalClose.bind(this));const t=this.modalManager.open();if(!t)throw new Error("Failed to create modal iframe");this.messageHandler.init(t);const n=e.paymentType||c.STANDARD;let i="/payViaUrl";n===c.PREAUTH?i="/preAuthPayment":n===c.RECURRING&&(i="/recurringPayment");const s=n===c.RECURRING?(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase():"",o=n===c.RECURRING&&"NONE"===s,r=e.appUrl||("undefined"!=typeof window&&window.location?window.location.href:void 0),d={merchantAccount:this.merchantId,amount:n===c.PREAUTH?void 0:e.amount,maxAmount:n===c.PREAUTH||o?e.amount:void 0,fixAmount:n!==c.RECURRING||o?void 0:e.amount,acceptPaymentDelay:n===c.STANDARD&&!0===e.acceptPaymentDelay||void 0,currency:e.currency,itemName:e.itemName,description:e.description,invoiceId:e.invoiceId||`INV-${Date.now()}`,invoiceType:n===c.PREAUTH?"PREAUTH":void 0,apiKey:this.apiKey,packageName:this.packageName,sdkVersion:g,platform:"web",appUrl:r,sessionId:this.messageHandler.getSessionId()};if(y.log("[Dropp SDK] Including SDK session context in payment params"),e.successURL&&(d.successURL=e.successURL),e.failureURL&&(d.failureURL=e.failureURL),n===c.RECURRING){const t=e.frequency||e.recurringInterval;t&&(d.frequency=t),e.recurringEndDate&&(d.expiry=e.recurringEndDate)}n===c.PREAUTH&&e.authHoldTimeInSeconds&&(d.authHoldTimeInSeconds=e.authHoldTimeInSeconds),e.callbackUrl&&(d.url=e.callbackUrl,d.submitToCallBack="post");const p={sessionId:d.sessionId,merchantAccount:this.merchantId,amount:e.amount,paymentType:n,invoiceId:d.invoiceId,expiry:e.recurringEndDate||null,issuedAt:Date.now()};let u="string"==typeof e.serverAuthToken?e.serverAuthToken.trim():"";if(!u&&this.getServerAuthToken)try{const e=await this.getServerAuthToken(p);u="string"==typeof e?e.trim():""}catch(e){throw w(h,"Failed to obtain server auth token",{originalError:e?.message||String(e)})}if(this.requireServerAuthToken&&!u)throw w(h,"serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.",{environment:this.environment,paymentType:n,invoiceId:d.invoiceId});const m=await async function(e,t,n,i,s={}){try{const{serverAuthToken:o=""}=s,r={};Object.keys(n).forEach(e=>{const t=n[e];null!=t&&(r[e]=t)}),y.log("[buildPaymentUrl] Building payment URL payload");const a=JSON.stringify(r),l=btoa(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""),c=Date.now().toString(),d=new URLSearchParams({pay:l,sdkTs:c,sdkVersion:i,platform:"web"});return o&&d.set("authToken",o),`${e}/#${t}?${d.toString()}`}catch(e){throw y.error("Error building payment URL:",e),e}}(this.baseUrl,i,d,g,{serverAuthToken:u});y.log("[Dropp SDK] Loading payment flow iframe"),t.src=m,this.isOpen=!0,this.initTimeout=setTimeout(()=>{this._handleTimeout("init")},a),this.paymentTimeout=setTimeout(()=>{this._handleTimeout("payment")},l)}async _openHostedPage(e,t={}){if(this.isOpen)throw w(u,"A Dropp session is already in progress",{currentSession:this.currentSession,route:e});await this.initialize(),this.currentFlowType="page",this.currentSession=null,this.onSuccess=null,this.onFailure=null,this.onCancel=null,this.onClose="function"==typeof t.onClose?t.onClose:null,this.messageHandler=new E(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new T(this._handleModalClose.bind(this));const n=this.modalManager.open();if(!n)throw new Error("Failed to create modal iframe");this.messageHandler.init(n);const i=this.baseUrl.replace(/\/+$/,"");return n.src=`${i}/#${e}`,this.isOpen=!0,y.log("[Dropp SDK] Hosted page opened",{route:e}),{status:"opened",route:e}}_handleMessage(e){const{type:n,data:i}=e;switch(n){case t.READY:this._handleReady(i);break;case t.PAYMENT_PAGE_LOADED:this._handlePageLoaded(i);break;case t.PAYMENT_SUCCESS:this._handleSuccess(i);break;case t.PAYMENT_FAILED:this._handleFailure(i);break;case t.PAYMENT_CANCELLED:this._handleCancel("user_cancelled");break;case t.AUTO_CLOSE_WEBVIEW:y.log("[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal"),this._cleanup(),y.log("[Dropp SDK] Cleanup completed");break;case t.CLOSE_WEBVIEW:y.log("[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal"),this._handleCancel("app_close");break;default:y.warn("[Dropp SDK] Unknown message type:",n)}}_handleReady(e){if(y.log("[Dropp SDK] Payment app ready"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.messageHandler&&this.currentSession){const e={};Object.keys(this.currentSession.options).forEach(t=>{const n=this.currentSession.options[t];"function"!=typeof n&&(e[t]=n)}),y.log("[Dropp SDK] Sending init config to payment app"),this.messageHandler.sendInit(e)}}_handlePageLoaded(e){y.log("[Dropp SDK] Payment page loaded")}_handleSuccess(e){y.log("[Dropp SDK] Payment successful");const t={status:"success",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onSuccess&&this.onSuccess(t)}_handleFailure(e){y.log("[Dropp SDK] Payment failed");const t={status:"failed",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onFailure&&this.onFailure(t)}_handleCancel(e){y.log("[Dropp SDK] Payment cancelled");const t={status:"cancelled",reason:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0};this.currentSession&&this.currentSession.resolve(t),this.onCancel&&this.onCancel(t),this._cleanup()}_handleModalClose(e){y.log("[Dropp SDK] Modal closed by user"),"page"!==this.currentFlowType?this._handleCancel(e):this._cleanup()}_handleTimeout(e){y.error("[Dropp SDK] Timeout:",e);const t=w("init"===e?d:p,"init"===e?"Payment app failed to load within timeout period":"Payment session timed out",{type:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0});this.currentSession&&this.currentSession.reject(t),this.onFailure&&this.onFailure({status:"failed",error:t}),this._cleanup()}_cleanup(){y.log("[Dropp SDK] ๐งน Cleaning up session - starting cleanup"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.paymentTimeout&&(clearTimeout(this.paymentTimeout),this.paymentTimeout=null),this.messageHandler&&(y.log("[Dropp SDK] ๐งน Destroying message handler"),this.messageHandler.destroy(),this.messageHandler=null),this.modalManager&&(y.log("[Dropp SDK] ๐งน Closing modal manager"),this.modalManager.close(),y.log("[Dropp SDK] ๐งน Modal manager closed"),this.modalManager=null),this.currentSession=null,this.currentFlowType=null,this.isOpen=!1,this.onClose&&this.onClose()}static getVersion(){return g}static getEnvironments(){return{...s}}static getPaymentTypes(){return{...c}}}let I=null;async function A(e){I=new _(e);return{...await I.initialize(),sdk:I}}const C={init:e=>A(e),pay(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.pay(e)},dashboard(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.dashboard(e)},unlinkAccount(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.unlinkAccount(e)},transactions(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.transactions(e)},offers(e){if(!I){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).");throw e.code="SDK_NOT_INITIALIZED",e}return I.offers(e)},getInstance:()=>I};var N={DroppPaymentSDK:_,createPaymentSDK:A,Dropp:C,ENVIRONMENTS:s,PAYMENT_TYPES:c};e.Dropp=C,e.DroppPaymentSDK=_,e.ENVIRONMENTS=s,e.PAYMENT_TYPES=c,e.createPaymentSDK=A,e.default=N,e.getDroppInstance=function(){return I},Object.defineProperty(e,"__esModule",{value:!0})});
|
|
2
2
|
//# sourceMappingURL=dropp-payment-sdk.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropp-payment-sdk.js","sources":["../src/constants.js","../src/logger.js","../src/utils.js","../src/messageHandler.js","../src/modalManager.js","../src/DroppPaymentSDK.js","../src/index.js"],"sourcesContent":["/**\n * Constants for Dropp Payment SDK\n */\n\n// Message types from payment app to SDK\nexport const MESSAGE_TYPES = {\n READY: 'DROPP_SDK_READY',\n PAYMENT_SUCCESS: 'PAYMENT_SUCCESS',\n PAYMENT_FAILED: 'PAYMENT_FAILED',\n PAYMENT_CANCELLED: 'PAYMENT_CANCELLED',\n CLOSE_WEBVIEW: 'CLOSE_WEBVIEW',\n AUTO_CLOSE_WEBVIEW: 'AUTO_CLOSE_WEBVIEW',\n PAYMENT_PAGE_LOADED: 'PAYMENT_PAGE_LOADED'\n};\n\n// Message types from SDK to payment app\nexport const SDK_MESSAGE_TYPES = {\n INIT: 'DROPP_SDK_INIT',\n CLOSE: 'DROPP_SDK_CLOSE'\n};\n\n// Environment configurations\nexport const ENVIRONMENTS = {\n PRODUCTION: 'production',\n QA: 'qa',\n SANDBOX: 'sandbox'\n};\n\n// Payment app URLs by environment\nexport const PAYMENT_APP_URLS = {\n [ENVIRONMENTS.PRODUCTION]: 'https://wv.dropp.cc',\n [ENVIRONMENTS.QA]: 'https://wv.qa.dropp.cc', // Assuming local QA server\n [ENVIRONMENTS.SANDBOX]: 'https://wv.sandbox.dropp.cc'\n};\n\n// Allowed origins for message validation (by environment)\nexport const ALLOWED_ORIGINS = {\n [ENVIRONMENTS.PRODUCTION]: ['https://wv.dropp.cc'],\n [ENVIRONMENTS.QA]: ['https://wv.qa.dropp.cc'], // Match QA server origin\n [ENVIRONMENTS.SANDBOX]: ['https://wv.sandbox.dropp.cc']\n};\n\n// Timeouts\nexport const TIMEOUTS = {\n INIT: 30000, // 30 seconds for app to load and send READY\n PAYMENT: 600000, // 10 minutes max for payment completion\n CLOSE_DELAY: 10000 // 10 seconds delay before closing modal after success/failure\n};\n\n// Payment types\nexport const PAYMENT_TYPES = {\n STANDARD: 'standard',\n PREAUTH: 'preauth',\n RECURRING: 'recurring'\n};\n\n// Error codes\nexport const ERROR_CODES = {\n INIT_TIMEOUT: 'INIT_TIMEOUT',\n PAYMENT_TIMEOUT: 'PAYMENT_TIMEOUT',\n INVALID_CONFIG: 'INVALID_CONFIG',\n ALREADY_OPEN: 'ALREADY_OPEN',\n ORIGIN_MISMATCH: 'ORIGIN_MISMATCH',\n MESSAGE_VALIDATION_FAILED: 'MESSAGE_VALIDATION_FAILED',\n IFRAME_BLOCKED: 'IFRAME_BLOCKED',\n UNKNOWN_ERROR: 'UNKNOWN_ERROR'\n};\n\n// SDK version\nexport const SDK_VERSION = '1.0.2';\n\n// CSS z-index for modal\nexport const MODAL_Z_INDEX = 999999;\n","/**\n * Logger utility for Dropp Payment SDK\n * Logging is disabled by default and can be enabled explicitly.\n */\n\nclass Logger {\n constructor(environment, options = {}) {\n this.environment = environment;\n this.forceEnabled = !!options.enabled;\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Determine if logging should be enabled\n * @private\n */\n _shouldEnableLogging() {\n return this.forceEnabled;\n }\n\n /**\n * Update environment and recalculate logging state\n */\n setEnvironment(environment, options = {}) {\n this.environment = environment;\n if (typeof options.enabled === 'boolean') {\n this.forceEnabled = options.enabled;\n }\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Explicitly enable or disable logging.\n */\n setEnabled(enabled) {\n this.forceEnabled = !!enabled;\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Log info messages\n */\n log(...args) {\n if (this.enabled) {\n console.log(...args);\n }\n }\n\n /**\n * Log warning messages\n */\n warn(...args) {\n if (this.enabled) {\n console.warn(...args);\n }\n }\n\n /**\n * Log error messages\n */\n error(...args) {\n if (this.enabled) {\n console.error(...args);\n }\n }\n\n /**\n * Log debug messages\n */\n debug(...args) {\n if (this.enabled) {\n console.debug(...args);\n }\n }\n\n /**\n * Log info messages\n */\n info(...args) {\n if (this.enabled) {\n console.info(...args);\n }\n }\n}\n\n// Create singleton instance with default environment\nconst logger = new Logger('qa', { enabled: false });\n\nexport default logger;\n","/**\n * Utility functions for Dropp Payment SDK\n */\n\nimport logger from './logger.js';\nimport { PAYMENT_TYPES } from './constants.js';\n\nconst SUPPORTED_CURRENCIES = ['USD', 'HBAR', 'USDC'];\n\nconst RECURRING_FREQUENCY_VALUES = [\n 'NONE',\n 'HALF_HOURLY',\n 'HOURLY',\n 'DAILY',\n 'WEEKLY',\n 'MONTHLY',\n 'YEARLY'\n];\n\nconst PAYMENT_TYPE_VALUES = [\n PAYMENT_TYPES.STANDARD,\n PAYMENT_TYPES.PREAUTH,\n PAYMENT_TYPES.RECURRING\n];\n\nfunction isPositiveNumber(value) {\n const num = typeof value === 'number' ? value : parseFloat(value);\n return typeof num === 'number' && !Number.isNaN(num) && num > 0;\n}\n\nfunction isPositiveInteger(value) {\n const num = typeof value === 'number' ? value : parseInt(value, 10);\n return Number.isInteger(num) && num > 0;\n}\n\nfunction isIpV4(value) {\n return /^(\\d{1,3}\\.){3}\\d{1,3}$/.test(value);\n}\n\nfunction isPrivateOrLoopbackHost(hostname) {\n if (!hostname) {\n return false;\n }\n\n const normalized = hostname.trim().toLowerCase();\n if (\n normalized === 'localhost' ||\n normalized === '127.0.0.1' ||\n normalized === '::1' ||\n normalized.endsWith('.local')\n ) {\n return true;\n }\n\n if (!isIpV4(normalized)) {\n return false;\n }\n\n const octets = normalized.split('.').map(part => Number(part));\n if (octets.some(octet => Number.isNaN(octet) || octet < 0 || octet > 255)) {\n return false;\n }\n\n const [a, b] = octets;\n // RFC1918 private ranges + loopback + link-local\n if (a === 10 || a === 127) {\n return true;\n }\n if (a === 172 && b >= 16 && b <= 31) {\n return true;\n }\n if (a === 192 && b === 168) {\n return true;\n }\n if (a === 169 && b === 254) {\n return true;\n }\n\n return false;\n}\n\nfunction isValidCallbackUrl(url, options = {}) {\n const {\n isProduction = false,\n allowLocalCallbacksInNonProd = false\n } = options;\n\n if (typeof url !== 'string' || !url.trim()) {\n return false;\n }\n\n try {\n const parsed = new URL(url.trim());\n const isHttps = parsed.protocol === 'https:';\n const isHttp = parsed.protocol === 'http:';\n\n if (!isHttp && !isHttps) {\n return false;\n }\n\n const isPrivateOrLoopback = isPrivateOrLoopbackHost(parsed.hostname);\n if (isPrivateOrLoopback) {\n return !isProduction && allowLocalCallbacksInNonProd;\n }\n\n if (isProduction) {\n return isHttps;\n }\n\n // Non-production can allow HTTP for public hosts by default.\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidIsoDateTime(value) {\n if (typeof value !== 'string' || !value.trim()) {\n return false;\n }\n const date = new Date(value.trim());\n return !Number.isNaN(date.getTime());\n}\n\n/**\n * Generate a unique session ID\n */\nexport function generateSessionId() {\n return `dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n\n/**\n * Build payment URL with base64 payload (matching Android SDK pattern)\n */\nexport async function buildPaymentUrl(baseUrl, route, params, sdkVersion, authOptions = {}) {\n try {\n const { serverAuthToken = '' } = authOptions;\n\n // Create JSON payload\n const payload = {};\n Object.keys(params).forEach(key => {\n const value = params[key];\n if (value !== null && value !== undefined) {\n payload[key] = value;\n }\n });\n \n logger.log('[buildPaymentUrl] Building payment URL payload');\n \n // Base64 encode payload (URL-safe, no padding)\n const jsonString = JSON.stringify(payload);\n const base64Payload = btoa(jsonString)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n \n const timestamp = Date.now().toString();\n const queryParams = new URLSearchParams({\n pay: base64Payload,\n sdkTs: timestamp,\n sdkVersion,\n platform: 'web'\n });\n\n if (serverAuthToken) {\n queryParams.set('authToken', serverAuthToken);\n }\n\n const url = `${baseUrl}/#${route}?${queryParams.toString()}`;\n \n return url;\n } catch (error) {\n logger.error('Error building payment URL:', error);\n throw error;\n }\n}\n\n/**\n * Validate payment configuration for standard, preauth, and recurring payments\n */\nexport function validateConfig(config = {}, options = {}) {\n const errors = [];\n const paymentType = config.paymentType || PAYMENT_TYPES.STANDARD;\n const isProduction = (options.environment || '').toLowerCase() === 'production';\n const allowLocalCallbacksInNonProd = !!options.allowLocalCallbacksInNonProd;\n const normalizedCurrency =\n typeof config.currency === 'string' ? config.currency.trim().toUpperCase() : '';\n\n if (!PAYMENT_TYPE_VALUES.includes(paymentType)) {\n errors.push(\n `paymentType must be one of: ${PAYMENT_TYPE_VALUES.join(', ')}`\n );\n }\n\n if (config.amount === undefined || config.amount === null || config.amount === '') {\n errors.push('amount is required');\n } else if (!isPositiveNumber(config.amount)) {\n errors.push('amount must be a positive number');\n }\n\n if (!config.currency || typeof config.currency !== 'string' || !config.currency.trim()) {\n errors.push('currency is required');\n } else if (!SUPPORTED_CURRENCIES.includes(normalizedCurrency)) {\n errors.push(`currency must be one of: ${SUPPORTED_CURRENCIES.join(', ')}`);\n }\n\n if (!config.itemName || typeof config.itemName !== 'string' || !config.itemName.trim()) {\n errors.push('itemName is required');\n }\n\n if (paymentType === PAYMENT_TYPES.PREAUTH) {\n if (normalizedCurrency && normalizedCurrency !== 'USD') {\n errors.push('currency must be USD for preauth payments');\n }\n\n if (!config.callbackUrl || !String(config.callbackUrl).trim()) {\n errors.push('callbackUrl (signing URL) is required for preauth payments');\n } else if (!isValidCallbackUrl(config.callbackUrl, {\n isProduction,\n allowLocalCallbacksInNonProd\n })) {\n errors.push(\n isProduction\n ? 'callbackUrl must be HTTPS in production and cannot target loopback/private hosts'\n : 'callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled'\n );\n }\n\n if (\n config.authHoldTimeInSeconds === undefined ||\n config.authHoldTimeInSeconds === null ||\n config.authHoldTimeInSeconds === ''\n ) {\n errors.push('authHoldTimeInSeconds is required for preauth payments');\n } else if (!isPositiveInteger(config.authHoldTimeInSeconds)) {\n errors.push('authHoldTimeInSeconds must be a positive integer (seconds)');\n }\n }\n\n if (paymentType === PAYMENT_TYPES.RECURRING) {\n if (!config.callbackUrl || !String(config.callbackUrl).trim()) {\n errors.push('callbackUrl (signing URL) is required for recurring payments');\n } else if (!isValidCallbackUrl(config.callbackUrl, {\n isProduction,\n allowLocalCallbacksInNonProd\n })) {\n errors.push(\n isProduction\n ? 'callbackUrl must be HTTPS in production and cannot target loopback/private hosts'\n : 'callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled'\n );\n }\n\n const frequency = (config.frequency || config.recurringInterval || '')\n .toString()\n .trim()\n .toUpperCase();\n\n if (!frequency) {\n errors.push('frequency is required for recurring payments');\n } else if (!RECURRING_FREQUENCY_VALUES.includes(frequency)) {\n errors.push(\n `frequency must be one of: ${RECURRING_FREQUENCY_VALUES.join(', ')}`\n );\n }\n\n if (!config.recurringEndDate || !String(config.recurringEndDate).trim()) {\n errors.push('recurringEndDate (expiry) is required for recurring payments');\n } else if (!isValidIsoDateTime(config.recurringEndDate)) {\n errors.push('recurringEndDate must be a valid ISO date-time string');\n } else if (new Date(config.recurringEndDate.trim()) <= new Date()) {\n errors.push('recurringEndDate must be in the future');\n }\n }\n\n return {\n valid: errors.length === 0,\n errors\n };\n}\n\n/**\n * Create error object\n */\nexport function createError(code, message, details = {}) {\n return {\n code,\n message,\n details,\n timestamp: new Date().toISOString(),\n toString() {\n return this.message || 'Dropp SDK error';\n }\n };\n}\n\n/**\n * Deep clone object\n */\nexport function deepClone(obj) {\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * Check if running in browser environment\n */\nexport function isBrowser() {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Sanitize HTML to prevent XSS\n */\nexport function sanitizeHTML(str) {\n if (!str) return '';\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n}\n\n/**\n * Format amount for display\n */\nexport function formatAmount(amount, currency) {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: currency || 'USD'\n }).format(amount);\n } catch (error) {\n return `${amount} ${currency}`;\n }\n}\n","/**\n * Secure Message Handler for SDK โ Payment App Communication\n * \n * Implements:\n * - Origin validation\n * - Message schema validation\n * - Session correlation\n * - Anti-spoofing protection\n */\n\nimport { MESSAGE_TYPES, SDK_MESSAGE_TYPES, ALLOWED_ORIGINS } from './constants.js';\nimport { generateSessionId } from './utils.js';\nimport logger from './logger.js';\n\nexport class MessageHandler {\n constructor(environment, onMessage, allowedOrigins = null) {\n this.environment = environment;\n this.onMessage = onMessage;\n this.sessionId = generateSessionId();\n logger.log('[MessageHandler] Session initialized');\n this.iframe = null;\n this.allowedOrigins =\n allowedOrigins?.length > 0\n ? allowedOrigins\n : ALLOWED_ORIGINS[environment] || [];\n this.messageListener = null;\n this.pendingMessages = new Map(); // Track correlation IDs for request/response\n }\n\n /**\n * Initialize message listener\n */\n init(iframe) {\n this.iframe = iframe;\n this.messageListener = this._handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n }\n\n /**\n * Clean up message listener\n */\n destroy() {\n if (this.messageListener) {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n this.iframe = null;\n this.pendingMessages.clear();\n }\n\n /**\n * Handle incoming postMessage events\n * @private\n */\n _handleMessage(event) {\n logger.log('[MessageHandler] Received postMessage event');\n\n // Ignore messages from self (parent window)\n if (event.source === window) {\n logger.log('[MessageHandler] Ignoring message from self');\n return;\n }\n\n // 1. Validate origin\n if (!this._validateOrigin(event.origin)) {\n logger.warn('[Dropp SDK] Rejected message from untrusted origin:', event.origin);\n return;\n }\n\n // 2. Validate event source\n if (!this.iframe || event.source !== this.iframe.contentWindow) {\n logger.warn('[Dropp SDK] Rejected message from unexpected source', {\n eventOrigin: event.origin\n });\n return;\n }\n\n // 3. Validate message structure\n const message = event.data;\n if (!this._validateMessageStructure(message)) {\n logger.warn('[Dropp SDK] Rejected message with invalid structure');\n return;\n }\n\n // 4. Validate session ID (if present)\n if (message.sessionId && message.sessionId !== this.sessionId) {\n logger.warn('[Dropp SDK] Rejected message with invalid session ID');\n return;\n }\n\n // 5. Process valid message\n logger.log('[MessageHandler] Message passed validation');\n this._processMessage(message);\n }\n\n /**\n * Validate message origin against allowed list\n * @private\n */\n _validateOrigin(origin) {\n // In development/testing, allow localhost\n if (origin.startsWith('http://localhost:') || origin.startsWith('http://127.0.0.1:')) {\n return true;\n }\n\n // Enforce exact scheme + host + port origin match.\n return this.allowedOrigins.includes(origin);\n }\n\n /**\n * Validate message structure and type\n * @private\n */\n _validateMessageStructure(message) {\n if (!message || typeof message !== 'object') {\n return false;\n }\n\n // Must have a type field\n if (!message.type || typeof message.type !== 'string') {\n return false;\n }\n\n // Must be a known message type from payment app\n const validTypes = Object.values(MESSAGE_TYPES);\n if (!validTypes.includes(message.type)) {\n return false;\n }\n\n // Must have timestamp\n if (!message.timestamp) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Process validated message\n * @private\n */\n _processMessage(message) {\n logger.log('[Dropp SDK] Received message:', message.type);\n\n // Invoke callback\n if (this.onMessage) {\n this.onMessage(message);\n }\n }\n\n /**\n * Send message to payment app\n */\n sendToPaymentApp(type, data = {}) {\n if (!this.iframe || !this.iframe.contentWindow) {\n logger.error('[Dropp SDK] Cannot send message: iframe not ready');\n return false;\n }\n\n const message = {\n type,\n data,\n sessionId: this.sessionId,\n timestamp: new Date().toISOString(),\n sdkVersion: '1.0.0'\n };\n\n // Get target origin from allowed origins\n const targetOrigin = this.allowedOrigins[0] || '*';\n\n try {\n this.iframe.contentWindow.postMessage(message, targetOrigin);\n logger.log('[Dropp SDK] Sent message:', type);\n return true;\n } catch (error) {\n logger.error('[Dropp SDK] Error sending message:', error);\n return false;\n }\n }\n\n /**\n * Send init message to payment app\n */\n sendInit(config) {\n return this.sendToPaymentApp(SDK_MESSAGE_TYPES.INIT, {\n mode: 'sdk',\n config\n });\n }\n\n /**\n * Send close request to payment app\n */\n sendClose() {\n return this.sendToPaymentApp(SDK_MESSAGE_TYPES.CLOSE, {});\n }\n\n /**\n * Get session ID\n */\n getSessionId() {\n return this.sessionId;\n }\n}\n","/**\n * Modal Manager - Creates and manages the payment modal UI\n * \n * Responsibilities:\n * - Create modal overlay and container\n * - Manage modal lifecycle (open/close/destroy)\n * - Handle focus trapping\n * - Clean up DOM and event listeners\n * - Responsive design\n */\n\nimport { MODAL_Z_INDEX } from './constants.js';\nimport logger from './logger.js';\n\nexport class ModalManager {\n constructor(onClose) {\n this.onClose = onClose;\n this.overlay = null;\n this.container = null;\n this.iframe = null;\n this.closeButton = null;\n this.isOpen = false;\n this.escapeListener = null;\n }\n\n /**\n * Create and show modal\n */\n open() {\n if (this.isOpen) {\n logger.warn('[Dropp SDK] Modal is already open');\n return null;\n }\n\n this._createModal();\n this._attachEventListeners();\n this._show();\n\n this.isOpen = true;\n return this.iframe;\n }\n\n /**\n * Close and cleanup modal\n */\n close() {\n logger.log('[ModalManager] ๐ฆ close() called, isOpen:', this.isOpen);\n \n if (!this.isOpen) {\n logger.log('[ModalManager] โ ๏ธ Modal is not open, skipping close');\n return;\n }\n\n logger.log('[ModalManager] ๐ฆ Hiding modal...');\n this._hide();\n logger.log('[ModalManager] ๐ฆ Removing event listeners...');\n this._removeEventListeners();\n logger.log('[ModalManager] ๐ฆ Destroying modal...');\n this._destroyModal();\n\n this.isOpen = false;\n logger.log('[ModalManager] โ
Modal close sequence initiated');\n }\n\n /**\n * Create modal DOM elements\n * @private\n */\n _createModal() {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.id = 'dropp-payment-overlay';\n this._applyOverlayStyles(this.overlay);\n\n // Create container\n this.container = document.createElement('div');\n this.container.id = 'dropp-payment-container';\n this._applyContainerStyles(this.container);\n\n // Close button removed - will be rendered by chrome app instead\n\n // Create iframe\n this.iframe = document.createElement('iframe');\n this.iframe.id = 'dropp-payment-iframe';\n this.iframe.setAttribute('allow', 'payment');\n this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');\n this.iframe.setAttribute('referrerpolicy', 'no-referrer');\n this.iframe.setAttribute('title', 'Dropp Payment');\n this._applyIframeStyles(this.iframe);\n\n // Assemble modal\n this.container.appendChild(this.iframe);\n this.overlay.appendChild(this.container);\n\n // Add to DOM\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Apply styles to overlay\n * @private\n */\n _applyOverlayStyles(element) {\n Object.assign(element.style, {\n position: 'fixed',\n inset: '0',\n width: '100vw',\n height: '100vh',\n margin: '0',\n padding: '20px',\n boxSizing: 'border-box',\n backgroundColor: 'rgba(0, 0, 0, 0.6)',\n zIndex: MODAL_Z_INDEX.toString(),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n opacity: '0',\n transition: 'opacity 0.3s ease',\n backdropFilter: 'blur(4px)',\n overflow: 'auto'\n });\n }\n\n /**\n * Apply styles to container\n * @private\n */\n _applyContainerStyles(element) {\n const isMobile = window.innerWidth < 768;\n this._isMobile = isMobile;\n\n Object.assign(element.style, {\n position: 'relative',\n flex: '0 0 auto',\n alignSelf: 'center',\n margin: 'auto',\n width: '100%',\n maxWidth: isMobile ? '100%' : '400px',\n height: isMobile ? '100%' : 'auto',\n minHeight: isMobile ? '100%' : '800px',\n maxHeight: isMobile ? '100%' : 'min(1000px, calc(100vh - 40px))',\n backgroundColor: '#ffffff',\n borderRadius: isMobile ? '0' : '16px',\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.3)',\n overflow: 'hidden',\n transform: 'scale(0.95)',\n transition: 'transform 0.3s ease, opacity 0.3s ease',\n display: 'flex',\n flexDirection: 'column'\n });\n }\n\n _getContainerTransform(scale) {\n return `scale(${scale})`;\n }\n\n /**\n * Apply styles to close button\n * @private\n */\n _applyCloseButtonStyles(element) {\n Object.assign(element.style, {\n position: 'absolute',\n top: '16px',\n right: '16px',\n zIndex: '10',\n width: '40px',\n height: '40px',\n border: 'none',\n borderRadius: '50%',\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n color: '#333',\n fontSize: '28px',\n lineHeight: '1',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',\n transition: 'all 0.2s ease',\n fontFamily: 'Arial, sans-serif',\n padding: '0'\n });\n\n // Hover effect\n element.addEventListener('mouseenter', () => {\n Object.assign(element.style, {\n backgroundColor: '#f5f5f5',\n transform: 'scale(1.1)'\n });\n });\n\n element.addEventListener('mouseleave', () => {\n Object.assign(element.style, {\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n transform: 'scale(1)'\n });\n });\n }\n\n /**\n * Apply styles to iframe\n * @private\n */\n _applyIframeStyles(element) {\n const isMobile = this._isMobile;\n Object.assign(element.style, {\n width: '100%',\n flex: '1 1 auto',\n minHeight: isMobile ? '100%' : 'min(520px, calc(90vh - 40px))',\n height: isMobile ? '100%' : 'min(520px, calc(90vh - 40px))',\n border: 'none',\n display: 'block'\n });\n }\n\n /**\n * Show modal with animation\n * @private\n */\n _show() {\n // Prevent body scroll\n document.body.style.overflow = 'hidden';\n\n // Trigger animation\n requestAnimationFrame(() => {\n if (this.overlay) {\n this.overlay.style.opacity = '1';\n }\n if (this.container) {\n this.container.style.transform = this._getContainerTransform(1);\n }\n });\n }\n\n /**\n * Hide modal with animation\n * @private\n */\n _hide() {\n logger.log('[ModalManager] ๐ญ _hide() called');\n if (this.overlay) {\n this.overlay.style.opacity = '0';\n logger.log('[ModalManager] ๐ญ Overlay opacity set to 0');\n }\n if (this.container) {\n this.container.style.transform = this._getContainerTransform(0.95);\n logger.log('[ModalManager] ๐ญ Container transform set to scale(0.95)');\n }\n\n // Restore body scroll\n document.body.style.overflow = '';\n logger.log('[ModalManager] ๐ญ Body scroll restored');\n }\n\n /**\n * Destroy modal DOM elements\n * @private\n */\n _destroyModal() {\n logger.log('[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation');\n // Wait for animation to complete\n setTimeout(() => {\n logger.log('[ModalManager] ๐๏ธ Animation complete, removing from DOM');\n if (this.overlay && this.overlay.parentNode) {\n this.overlay.parentNode.removeChild(this.overlay);\n logger.log('[ModalManager] ๐๏ธ Overlay removed from DOM');\n }\n this.overlay = null;\n this.container = null;\n this.iframe = null;\n this.closeButton = null;\n logger.log('[ModalManager] โ
Modal destroyed');\n }, 300);\n }\n\n /**\n * Attach event listeners\n * @private\n */\n _attachEventListeners() {\n // Close button removed - will be handled by chrome app\n // Close button click\n // if (this.closeButton) {\n // this.closeButton.addEventListener('click', this._handleCloseClick.bind(this));\n // }\n\n // Backdrop click disabled for payment security\n // Users must use close button or complete/cancel payment\n // if (this.overlay) {\n // this.overlay.addEventListener('click', this._handleOverlayClick.bind(this));\n // }\n\n // Escape key disabled for payment security\n // Users must use close button or complete/cancel payment\n // this.escapeListener = this._handleEscapeKey.bind(this);\n // document.addEventListener('keydown', this.escapeListener);\n }\n\n /**\n * Remove event listeners\n * @private\n */\n _removeEventListeners() {\n if (this.escapeListener) {\n document.removeEventListener('keydown', this.escapeListener);\n this.escapeListener = null;\n }\n }\n\n /**\n * Handle close button click\n * @private\n */\n _handleCloseClick(event) {\n event.stopPropagation();\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n\n /**\n * Handle overlay click (backdrop)\n * @private\n */\n _handleOverlayClick(event) {\n // Only close if clicking directly on overlay (not container)\n if (event.target === this.overlay) {\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n }\n\n /**\n * Handle escape key press\n * @private\n */\n _handleEscapeKey(event) {\n if (event.key === 'Escape' && this.isOpen) {\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n }\n\n /**\n * Get iframe element\n */\n getIframe() {\n return this.iframe;\n }\n\n /**\n * Check if modal is open\n */\n getIsOpen() {\n return this.isOpen;\n }\n}\n","/**\n * Dropp Payment SDK - Main SDK Class\n * \n * Public API for integrating Dropp payments into web applications\n */\n\nimport { \n ENVIRONMENTS, \n PAYMENT_APP_URLS,\n ALLOWED_ORIGINS,\n MESSAGE_TYPES, \n ERROR_CODES, \n TIMEOUTS, \n PAYMENT_TYPES,\n SDK_VERSION\n} from './constants.js';\nimport { MessageHandler } from './messageHandler.js';\nimport { ModalManager } from './modalManager.js';\nimport { \n buildPaymentUrl, \n validateConfig, \n createError, \n isBrowser \n} from './utils.js';\nimport logger from './logger.js';\n\nexport class DroppPaymentSDK {\n /**\n * Create SDK instance\n * @param {Object} config - SDK configuration\n * @param {string} config.merchantId - Merchant Hedera account ID (required, e.g., '0.0.123456')\n * @param {string} config.apiKey - API Key (required)\n * @param {string} config.packageName - Package name (required)\n * @param {string} config.environment - Environment: 'production', 'qa', or 'sandbox'\n * @param {Function} [config.getServerAuthToken] - Optional async callback that returns a server-issued auth token\n * @param {boolean} [config.requireServerAuthToken] - Require server auth token (defaults to true in production)\n * @param {boolean} [config.allowLocalCallbacksInNonProd] - Allow loopback/private callback URLs in non-production\n */\n constructor(config = {}) {\n if (!isBrowser()) {\n throw new Error('Dropp Payment SDK can only be used in a browser environment');\n }\n\n // Validate required credentials\n if (!config.merchantId || !config.apiKey || !config.packageName) {\n throw new Error('merchantId, apiKey, and packageName are required to initialize SDK');\n }\n\n // Store credentials\n this.merchantId = config.merchantId;\n this.apiKey = config.apiKey;\n this.packageName = config.packageName;\n\n this.environment = config.environment || ENVIRONMENTS.QA;\n this.baseUrl =\n config.paymentAppUrl ||\n config.baseUrl ||\n PAYMENT_APP_URLS[this.environment];\n\n // Initialization state\n this.isInitialized = false;\n this.initializationPromise = null;\n\n this.getServerAuthToken =\n typeof config.getServerAuthToken === 'function'\n ? config.getServerAuthToken\n : null;\n this.requireServerAuthToken =\n typeof config.requireServerAuthToken === 'boolean'\n ? config.requireServerAuthToken\n : this.environment === ENVIRONMENTS.PRODUCTION;\n this.allowLocalCallbacksInNonProd = !!config.allowLocalCallbacksInNonProd;\n\n if (config.allowedOrigins?.length) {\n this.allowedOrigins = config.allowedOrigins;\n } else {\n try {\n // Derive allowed origin from the effective payment URL to keep a\n // single source of truth for iframe loading and postMessage validation.\n this.allowedOrigins = [new URL(this.baseUrl).origin];\n } catch {\n this.allowedOrigins = ALLOWED_ORIGINS[this.environment] || [];\n }\n }\n\n // State\n this.isOpen = false;\n this.currentSession = null;\n this.currentFlowType = null;\n this.initTimeout = null;\n this.paymentTimeout = null;\n\n // Managers\n this.messageHandler = null;\n this.modalManager = null;\n\n // Set logger environment\n logger.setEnvironment(this.environment, { enabled: !!config.debugLogging });\n logger.log(`[Dropp SDK] Initialized v${SDK_VERSION} - Environment: ${this.environment}`);\n }\n\n /**\n * Open payment modal\n * @param {Object} options - Payment options\n * @param {number} options.amount - Payment amount (required)\n * @param {string} options.currency - Currency code (required)\n * @param {string} options.itemName - Item/service name (required)\n * @param {string} options.description - Payment description\n * @param {string} options.invoiceId - Invoice ID\n * @param {string} options.paymentType - Payment type: 'standard', 'preauth', or 'recurring'\n * @param {string} options.thumbnail - Product image URL\n * @param {number} options.authHoldTimeInSeconds - For preauth: hold time in seconds\n * @param {string} options.callbackUrl - Server callback URL\n * @param {boolean} [options.acceptPaymentDelay=false] - Allow delayed payment acceptance for standard payments (sent only when true)\n * @param {string} [options.serverAuthToken] - Server-issued short-lived token bound to payment context\n * @param {Function} options.onSuccess - Callback for successful payment\n * @param {Function} options.onFailure - Callback for failed payment\n * @param {Function} options.onCancel - Callback for cancelled payment\n * @param {Function} options.onClose - Callback for modal close\n * @returns {Promise<PaymentResult>}\n */\n pay(options = {}) {\n return new Promise((resolve, reject) => {\n // Check if already open\n if (this.isOpen) {\n const error = createError(\n ERROR_CODES.ALREADY_OPEN,\n 'A payment session is already in progress',\n { currentSession: this.currentSession }\n );\n reject(error);\n return;\n }\n\n (async () => {\n try {\n await this.initialize();\n\n // Validate payment configuration\n const validation = validateConfig(options, {\n environment: this.environment,\n allowLocalCallbacksInNonProd: this.allowLocalCallbacksInNonProd\n });\n if (!validation.valid) {\n const error = createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Invalid payment configuration',\n { errors: validation.errors }\n );\n reject(error);\n return;\n }\n\n // Store callbacks from options\n this.onSuccess = options.onSuccess || null;\n this.onFailure = options.onFailure || null;\n this.onCancel = options.onCancel || null;\n this.onClose = options.onClose || null;\n\n // Store resolve/reject for later\n this.currentSession = {\n resolve,\n reject,\n options,\n startTime: Date.now()\n };\n\n await this._initializePayment(options);\n } catch (error) {\n const isInitValidationError =\n error && error.code === ERROR_CODES.INVALID_CONFIG;\n const sdkError = isInitValidationError\n ? error\n : createError(\n ERROR_CODES.UNKNOWN_ERROR,\n 'Failed to initialize payment',\n { originalError: error?.message || String(error) }\n );\n\n reject(sdkError);\n this._cleanup();\n }\n })();\n });\n }\n\n /**\n * Initialize and validate merchant credentials with Dropp backend.\n * @returns {Promise<{status: string, code: string, message: string}>}\n */\n async initialize() {\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n\n this.initializationPromise = (async () => {\n await this._validateInitializationCredentials();\n this.isInitialized = true;\n return {\n status: 'success',\n code: 'INITIALIZED',\n message: 'Dropp SDK initialized successfully'\n };\n })().catch(error => {\n this.isInitialized = false;\n this.initializationPromise = null;\n throw error;\n });\n\n return this.initializationPromise;\n }\n\n /**\n * Resolve validation endpoint from configured base URL.\n * @private\n */\n _getValidationUrl() {\n const validationUrls = {\n [ENVIRONMENTS.QA]: 'https://main.qa.dropp.cc/payer/webview/validate',\n [ENVIRONMENTS.SANDBOX]: 'https://sandbox.api.dropp.cc/payer/webview/validate',\n [ENVIRONMENTS.PRODUCTION]: 'https://api.dropp.cc/payer/webview/validate'\n };\n\n return (\n validationUrls[this.environment] ||\n validationUrls[ENVIRONMENTS.QA]\n );\n }\n\n /**\n * Validate merchant credentials and app package before any payment flow.\n * @private\n */\n async _validateInitializationCredentials() {\n const validationUrl = this._getValidationUrl();\n\n let response;\n let responseBody = null;\n try {\n response = await fetch(validationUrl, {\n method: 'POST',\n headers: {\n accept: 'application/json, text/plain, */*',\n 'content-type': 'application/json',\n 'x-api-key': this.apiKey,\n 'x-app-package': this.packageName\n },\n body: JSON.stringify({ id: this.merchantId })\n });\n } catch (error) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Unable to validate merchant credentials',\n {\n endpoint: validationUrl,\n originalError: error?.message || String(error)\n }\n );\n }\n\n try {\n responseBody = await response.json();\n } catch {\n responseBody = null;\n }\n\n if (!response.ok) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Merchant validation failed for merchantId/apiKey/packageName',\n {\n endpoint: validationUrl,\n status: response.status,\n response: responseBody\n }\n );\n }\n\n const responseCode = Number(responseBody?.responseCode);\n const errors = responseBody?.errors;\n const hasNoErrors = !Array.isArray(errors) || errors.length === 0;\n const isValidationSuccess = responseBody && responseCode === 0 && hasNoErrors;\n\n if (!isValidationSuccess) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Merchant validation returned an unsuccessful response',\n {\n endpoint: validationUrl,\n status: response.status,\n response: responseBody\n }\n );\n }\n\n logger.log('[Dropp SDK] Merchant credentials validated successfully');\n }\n\n /**\n * Close payment modal programmatically\n */\n closePayment() {\n if (this.isOpen) {\n if (this.currentFlowType === 'page') {\n this._cleanup();\n return;\n }\n this._handleCancel('sdk_close');\n }\n }\n\n /**\n * Open the dashboard/home page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n dashboard(options = {}) {\n return this._openHostedPage('/firsttimeflow', options);\n }\n\n /**\n * Open the unlink account page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n unlinkAccount(options = {}) {\n return this._openHostedPage('/unlink', options);\n }\n\n /**\n * Open the transactions page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n transactions(options = {}) {\n return this._openHostedPage('/transactions', options);\n }\n\n /**\n * Open the offers page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n offers(options = {}) {\n return this._openHostedPage('/offers', options);\n }\n\n /**\n * Initialize payment session\n * @private\n */\n async _initializePayment(options) {\n logger.log('[Dropp SDK] Initializing payment session');\n this.currentFlowType = 'payment';\n\n // Create message handler\n this.messageHandler = new MessageHandler(\n this.environment,\n this._handleMessage.bind(this),\n this.allowedOrigins\n );\n\n // Create modal manager\n this.modalManager = new ModalManager(\n this._handleModalClose.bind(this)\n );\n\n // Open modal and get iframe\n const iframe = this.modalManager.open();\n if (!iframe) {\n throw new Error('Failed to create modal iframe');\n }\n\n // Initialize message handler with iframe\n this.messageHandler.init(iframe);\n\n // Determine payment route based on type\n const paymentType = options.paymentType || PAYMENT_TYPES.STANDARD;\n let route = '/payViaUrl';\n if (paymentType === PAYMENT_TYPES.PREAUTH) {\n route = '/preAuthPayment';\n } else if (paymentType === PAYMENT_TYPES.RECURRING) {\n route = '/recurringPayment';\n }\n\n // Build payment parameters (matching Android SDK)\n // For recurring payments with frequency NONE, use maxAmount instead of fixAmount\n const recurringFrequency = paymentType === PAYMENT_TYPES.RECURRING \n ? (options.frequency || options.recurringInterval || '').toString().trim().toUpperCase()\n : '';\n const isRecurringNone = paymentType === PAYMENT_TYPES.RECURRING && recurringFrequency === 'NONE';\n const detectedAppUrl =\n options.appUrl ||\n (typeof window !== 'undefined' && window.location ? window.location.href : undefined);\n \n const params = {\n merchantAccount: this.merchantId,\n amount: paymentType === PAYMENT_TYPES.PREAUTH ? undefined : options.amount,\n maxAmount: (paymentType === PAYMENT_TYPES.PREAUTH || isRecurringNone) ? options.amount : undefined,\n fixAmount: (paymentType === PAYMENT_TYPES.RECURRING && !isRecurringNone) ? options.amount : undefined,\n acceptPaymentDelay:\n paymentType === PAYMENT_TYPES.STANDARD && options.acceptPaymentDelay === true\n ? true\n : undefined,\n currency: options.currency,\n itemName: options.itemName,\n description: options.description,\n invoiceId: options.invoiceId || `INV-${Date.now()}`,\n invoiceType: paymentType === PAYMENT_TYPES.PREAUTH ? 'PREAUTH' : undefined,\n apiKey: this.apiKey,\n packageName: this.packageName,\n sdkVersion: SDK_VERSION,\n platform: 'web',\n appUrl: detectedAppUrl,\n sessionId: this.messageHandler.getSessionId() // Include SDK session ID for message validation\n };\n \n logger.log('[Dropp SDK] Including SDK session context in payment params');\n\n // Add optional parameters\n if (options.successURL) params.successURL = options.successURL;\n if (options.failureURL) params.failureURL = options.failureURL;\n \n // Recurring payment specific fields\n if (paymentType === PAYMENT_TYPES.RECURRING) {\n const frequency = options.frequency || options.recurringInterval;\n if (frequency) params.frequency = frequency;\n if (options.recurringEndDate) params.expiry = options.recurringEndDate;\n }\n \n // Pre-auth specific fields\n if (paymentType === PAYMENT_TYPES.PREAUTH && options.authHoldTimeInSeconds) {\n params.authHoldTimeInSeconds = options.authHoldTimeInSeconds;\n }\n \n // Callback URL for server-side submission\n if (options.callbackUrl) {\n params.url = options.callbackUrl;\n params.submitToCallBack = 'post';\n }\n\n const authContext = {\n sessionId: params.sessionId,\n merchantAccount: this.merchantId,\n amount: options.amount,\n paymentType,\n invoiceId: params.invoiceId,\n expiry: options.recurringEndDate || null,\n issuedAt: Date.now()\n };\n\n let serverAuthToken =\n typeof options.serverAuthToken === 'string'\n ? options.serverAuthToken.trim()\n : '';\n\n if (!serverAuthToken && this.getServerAuthToken) {\n try {\n const tokenFromCallback = await this.getServerAuthToken(authContext);\n serverAuthToken = typeof tokenFromCallback === 'string'\n ? tokenFromCallback.trim()\n : '';\n } catch (error) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Failed to obtain server auth token',\n {\n originalError: error?.message || String(error)\n }\n );\n }\n }\n\n if (this.requireServerAuthToken && !serverAuthToken) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.',\n {\n environment: this.environment,\n paymentType,\n invoiceId: params.invoiceId\n }\n );\n }\n\n // Build payment URL with base64 payload and optional server-issued auth token.\n const paymentUrl = await buildPaymentUrl(\n this.baseUrl,\n route,\n params,\n SDK_VERSION,\n { serverAuthToken }\n );\n\n logger.log('[Dropp SDK] Loading payment flow iframe');\n\n // Load payment app in iframe\n iframe.src = paymentUrl;\n\n this.isOpen = true;\n\n // Set initialization timeout\n this.initTimeout = setTimeout(() => {\n this._handleTimeout('init');\n }, TIMEOUTS.INIT);\n\n // Set payment timeout\n this.paymentTimeout = setTimeout(() => {\n this._handleTimeout('payment');\n }, TIMEOUTS.PAYMENT);\n }\n\n /**\n * Open a hosted Dropp page in the modal.\n * @private\n */\n async _openHostedPage(route, options = {}) {\n if (this.isOpen) {\n throw createError(\n ERROR_CODES.ALREADY_OPEN,\n 'A Dropp session is already in progress',\n { currentSession: this.currentSession, route }\n );\n }\n\n await this.initialize();\n\n this.currentFlowType = 'page';\n this.currentSession = null;\n this.onSuccess = null;\n this.onFailure = null;\n this.onCancel = null;\n this.onClose = typeof options.onClose === 'function' ? options.onClose : null;\n\n this.modalManager = new ModalManager(\n this._handleModalClose.bind(this)\n );\n\n const iframe = this.modalManager.open();\n if (!iframe) {\n throw new Error('Failed to create modal iframe');\n }\n\n const normalizedBaseUrl = this.baseUrl.replace(/\\/+$/, '');\n iframe.src = `${normalizedBaseUrl}/#${route}`;\n this.isOpen = true;\n\n logger.log('[Dropp SDK] Hosted page opened', { route });\n\n return {\n status: 'opened',\n route\n };\n }\n\n /**\n * Handle messages from payment app\n * @private\n */\n _handleMessage(message) {\n const { type, data } = message;\n\n switch (type) {\n case MESSAGE_TYPES.READY:\n this._handleReady(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_PAGE_LOADED:\n this._handlePageLoaded(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_SUCCESS:\n this._handleSuccess(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_FAILED:\n this._handleFailure(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_CANCELLED:\n this._handleCancel('user_cancelled');\n break;\n\n case MESSAGE_TYPES.AUTO_CLOSE_WEBVIEW:\n // Auto-close from payment app after success/failure countdown\n // Just close the modal without triggering callbacks (already called)\n logger.log('[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal');\n this._cleanup();\n logger.log('[Dropp SDK] Cleanup completed');\n break;\n\n case MESSAGE_TYPES.CLOSE_WEBVIEW:\n // Manual close request from chrome app\n logger.log('[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal');\n this._handleCancel('app_close');\n break;\n\n default:\n logger.warn('[Dropp SDK] Unknown message type:', type);\n }\n }\n\n /**\n * Handle ready message from payment app\n * @private\n */\n _handleReady(data) {\n logger.log('[Dropp SDK] Payment app ready');\n \n // Clear init timeout\n if (this.initTimeout) {\n clearTimeout(this.initTimeout);\n this.initTimeout = null;\n }\n\n // Send init message to payment app\n // Filter out non-serializable data (functions) from options\n if (this.messageHandler && this.currentSession) {\n const serializableOptions = {};\n Object.keys(this.currentSession.options).forEach(key => {\n const value = this.currentSession.options[key];\n // Only include serializable values (exclude functions)\n if (typeof value !== 'function') {\n serializableOptions[key] = value;\n }\n });\n \n logger.log('[Dropp SDK] Sending init config to payment app');\n this.messageHandler.sendInit(serializableOptions);\n }\n }\n\n /**\n * Handle page loaded message\n * @private\n */\n _handlePageLoaded(data) {\n logger.log('[Dropp SDK] Payment page loaded');\n }\n\n /**\n * Handle successful payment\n * @private\n */\n _handleSuccess(data) {\n logger.log('[Dropp SDK] Payment successful');\n\n const result = {\n status: 'success',\n ...data,\n sessionDuration: Date.now() - this.currentSession.startTime\n };\n\n // Resolve promise\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onSuccess) {\n this.onSuccess(result);\n }\n\n // Note: Modal will be closed by AUTO_CLOSE_WEBVIEW message from payment app\n // after the countdown completes (no need for timeout here)\n }\n\n /**\n * Handle failed payment\n * @private\n */\n _handleFailure(data) {\n logger.log('[Dropp SDK] Payment failed');\n\n const result = {\n status: 'failed',\n ...data,\n sessionDuration: Date.now() - this.currentSession.startTime\n };\n\n // Resolve promise (not reject - failed payment is still a valid result)\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onFailure) {\n this.onFailure(result);\n }\n\n // Note: Modal will be closed by AUTO_CLOSE_WEBVIEW message from payment app\n // after the countdown completes (no need for timeout here)\n }\n\n /**\n * Handle cancelled payment\n * @private\n */\n _handleCancel(reason) {\n logger.log('[Dropp SDK] Payment cancelled');\n\n const result = {\n status: 'cancelled',\n reason,\n sessionDuration: this.currentSession ? Date.now() - this.currentSession.startTime : 0\n };\n\n // Resolve promise (not reject - cancellation is a valid result)\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onCancel) {\n this.onCancel(result);\n }\n\n // Close immediately\n this._cleanup();\n }\n\n /**\n * Handle modal close by user\n * @private\n */\n _handleModalClose(reason) {\n logger.log('[Dropp SDK] Modal closed by user');\n if (this.currentFlowType === 'page') {\n this._cleanup();\n return;\n }\n this._handleCancel(reason);\n }\n\n /**\n * Handle timeout\n * @private\n */\n _handleTimeout(type) {\n logger.error('[Dropp SDK] Timeout:', type);\n\n const errorCode = type === 'init' ? ERROR_CODES.INIT_TIMEOUT : ERROR_CODES.PAYMENT_TIMEOUT;\n const errorMessage = type === 'init' \n ? 'Payment app failed to load within timeout period'\n : 'Payment session timed out';\n\n const error = createError(errorCode, errorMessage, {\n type,\n sessionDuration: this.currentSession ? Date.now() - this.currentSession.startTime : 0\n });\n\n // Reject promise\n if (this.currentSession) {\n this.currentSession.reject(error);\n }\n\n // Invoke failure callback\n if (this.onFailure) {\n this.onFailure({ status: 'failed', error });\n }\n\n this._cleanup();\n }\n\n /**\n * Cleanup resources\n * @private\n */\n _cleanup() {\n logger.log('[Dropp SDK] ๐งน Cleaning up session - starting cleanup');\n\n // Clear timeouts\n if (this.initTimeout) {\n clearTimeout(this.initTimeout);\n this.initTimeout = null;\n }\n\n if (this.paymentTimeout) {\n clearTimeout(this.paymentTimeout);\n this.paymentTimeout = null;\n }\n\n // Destroy managers\n if (this.messageHandler) {\n logger.log('[Dropp SDK] ๐งน Destroying message handler');\n this.messageHandler.destroy();\n this.messageHandler = null;\n }\n\n if (this.modalManager) {\n logger.log('[Dropp SDK] ๐งน Closing modal manager');\n this.modalManager.close();\n logger.log('[Dropp SDK] ๐งน Modal manager closed');\n this.modalManager = null;\n }\n\n // Clear state\n this.currentSession = null;\n this.currentFlowType = null;\n this.isOpen = false;\n\n // Invoke onClose callback\n if (this.onClose) {\n this.onClose();\n }\n }\n\n /**\n * Get SDK version\n */\n static getVersion() {\n return SDK_VERSION;\n }\n\n /**\n * Get available environments\n */\n static getEnvironments() {\n return { ...ENVIRONMENTS };\n }\n\n /**\n * Get payment types\n */\n static getPaymentTypes() {\n return { ...PAYMENT_TYPES };\n }\n}\n\nexport default DroppPaymentSDK;\n","/**\n * Dropp Payment SDK for Web\n * \n * Main entry point - exports SDK class and factory functions\n */\n\nimport { DroppPaymentSDK } from './DroppPaymentSDK.js';\nimport { ENVIRONMENTS, PAYMENT_TYPES } from './constants.js';\n\n// Export main SDK class\nexport { DroppPaymentSDK };\n\n// Export constants\nexport { ENVIRONMENTS, PAYMENT_TYPES };\n\n// Global Dropp instance\nlet globalDroppInstance = null;\n\n/**\n * Factory function to create and initialize SDK instance\n * @param {Object} config - SDK configuration\n * @param {string} config.merchantId - Merchant Hedera account ID (required, e.g., '0.0.123456')\n * @param {string} config.apiKey - API Key (required)\n * @param {string} config.packageName - Package name (required)\n * @param {string} config.environment - Environment: 'production', 'qa', or 'sandbox'\n * @returns {Promise<{status: string, code: string, message: string, sdk: DroppPaymentSDK}>}\n */\nexport async function createPaymentSDK(config) {\n globalDroppInstance = new DroppPaymentSDK(config);\n const initResult = await globalDroppInstance.initialize();\n return {\n ...initResult,\n sdk: globalDroppInstance\n };\n}\n\n/**\n * Get the global Dropp instance\n * @returns {DroppPaymentSDK|null}\n */\nexport function getDroppInstance() {\n return globalDroppInstance;\n}\n\n/**\n * Global Dropp object with pay method\n */\nexport const Dropp = {\n /**\n * Initialize SDK (sets global instance)\n * @param {Object} config - SDK configuration\n * @returns {Promise<{status: string, code: string, message: string, sdk: DroppPaymentSDK}>}\n */\n init(config) {\n return createPaymentSDK(config);\n },\n \n /**\n * Make a payment using the initialized SDK\n * @param {Object} options - Payment options\n * @returns {Promise<PaymentResult>}\n */\n pay(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.pay(options);\n },\n\n /**\n * Open the dashboard/home page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n dashboard(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.dashboard(options);\n },\n\n /**\n * Open the unlink account page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n unlinkAccount(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.unlinkAccount(options);\n },\n\n /**\n * Open the transactions page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n transactions(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.transactions(options);\n },\n\n /**\n * Open the offers page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n offers(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.offers(options);\n },\n \n /**\n * Get the current SDK instance\n * @returns {DroppPaymentSDK|null}\n */\n getInstance() {\n return globalDroppInstance;\n }\n};\n\n// Default export\nexport default {\n DroppPaymentSDK,\n createPaymentSDK,\n Dropp,\n ENVIRONMENTS,\n PAYMENT_TYPES\n};\n"],"names":["MESSAGE_TYPES","READY","PAYMENT_SUCCESS","PAYMENT_FAILED","PAYMENT_CANCELLED","CLOSE_WEBVIEW","AUTO_CLOSE_WEBVIEW","PAYMENT_PAGE_LOADED","SDK_MESSAGE_TYPES","ENVIRONMENTS","PRODUCTION","QA","SANDBOX","PAYMENT_APP_URLS","ALLOWED_ORIGINS","TIMEOUTS","PAYMENT_TYPES","STANDARD","PREAUTH","RECURRING","ERROR_CODES","SDK_VERSION","logger","constructor","environment","options","this","forceEnabled","enabled","_shouldEnableLogging","setEnvironment","setEnabled","log","args","console","warn","error","debug","info","SUPPORTED_CURRENCIES","RECURRING_FREQUENCY_VALUES","PAYMENT_TYPE_VALUES","isValidCallbackUrl","url","isProduction","allowLocalCallbacksInNonProd","trim","parsed","URL","isHttps","protocol","hostname","normalized","toLowerCase","endsWith","test","octets","split","map","part","Number","some","octet","isNaN","a","b","isPrivateOrLoopbackHost","validateConfig","config","errors","paymentType","normalizedCurrency","currency","toUpperCase","includes","push","join","undefined","amount","value","num","parseFloat","isPositiveNumber","itemName","callbackUrl","String","authHoldTimeInSeconds","parseInt","isInteger","isPositiveInteger","frequency","recurringInterval","toString","recurringEndDate","date","Date","getTime","isValidIsoDateTime","valid","length","createError","code","message","details","timestamp","toISOString","MessageHandler","onMessage","allowedOrigins","sessionId","now","Math","random","substring","iframe","messageListener","pendingMessages","Map","init","_handleMessage","bind","window","addEventListener","destroy","removeEventListener","clear","event","source","_validateOrigin","origin","contentWindow","eventOrigin","data","_validateMessageStructure","_processMessage","startsWith","type","Object","values","sendToPaymentApp","sdkVersion","targetOrigin","postMessage","sendInit","mode","sendClose","getSessionId","ModalManager","onClose","overlay","container","closeButton","isOpen","escapeListener","open","_createModal","_attachEventListeners","_show","close","_hide","_removeEventListeners","_destroyModal","document","createElement","id","_applyOverlayStyles","_applyContainerStyles","setAttribute","_applyIframeStyles","appendChild","body","element","assign","style","position","inset","width","height","margin","padding","boxSizing","backgroundColor","zIndex","display","alignItems","justifyContent","opacity","transition","backdropFilter","overflow","isMobile","innerWidth","_isMobile","flex","alignSelf","maxWidth","minHeight","maxHeight","borderRadius","boxShadow","transform","flexDirection","_getContainerTransform","scale","_applyCloseButtonStyles","top","right","border","color","fontSize","lineHeight","cursor","fontFamily","requestAnimationFrame","setTimeout","parentNode","removeChild","_handleCloseClick","stopPropagation","_handleOverlayClick","target","_handleEscapeKey","key","getIframe","getIsOpen","DroppPaymentSDK","Error","merchantId","apiKey","packageName","baseUrl","paymentAppUrl","isInitialized","initializationPromise","getServerAuthToken","requireServerAuthToken","currentSession","currentFlowType","initTimeout","paymentTimeout","messageHandler","modalManager","debugLogging","pay","Promise","resolve","reject","initialize","validation","onSuccess","onFailure","onCancel","startTime","_initializePayment","sdkError","originalError","_cleanup","_validateInitializationCredentials","status","catch","_getValidationUrl","validationUrls","validationUrl","response","responseBody","fetch","method","headers","accept","JSON","stringify","endpoint","json","ok","responseCode","hasNoErrors","Array","isArray","closePayment","_handleCancel","dashboard","_openHostedPage","unlinkAccount","transactions","offers","_handleModalClose","route","recurringFrequency","isRecurringNone","detectedAppUrl","appUrl","location","href","params","merchantAccount","maxAmount","fixAmount","acceptPaymentDelay","description","invoiceId","invoiceType","platform","successURL","failureURL","expiry","submitToCallBack","authContext","issuedAt","serverAuthToken","tokenFromCallback","paymentUrl","async","authOptions","payload","keys","forEach","jsonString","base64Payload","btoa","replace","queryParams","URLSearchParams","sdkTs","set","buildPaymentUrl","src","_handleTimeout","normalizedBaseUrl","_handleReady","_handlePageLoaded","_handleSuccess","_handleFailure","clearTimeout","serializableOptions","result","sessionDuration","reason","getVersion","getEnvironments","getPaymentTypes","globalDroppInstance","createPaymentSDK","sdk","Dropp","getInstance","index"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropp-payment-sdk.js","sources":["../src/constants.js","../src/logger.js","../src/utils.js","../src/messageHandler.js","../src/modalManager.js","../src/DroppPaymentSDK.js","../src/index.js"],"sourcesContent":["/**\n * Constants for Dropp Payment SDK\n */\n\n// Message types from payment app to SDK\nexport const MESSAGE_TYPES = {\n READY: 'DROPP_SDK_READY',\n PAYMENT_SUCCESS: 'PAYMENT_SUCCESS',\n PAYMENT_FAILED: 'PAYMENT_FAILED',\n PAYMENT_CANCELLED: 'PAYMENT_CANCELLED',\n CLOSE_WEBVIEW: 'CLOSE_WEBVIEW',\n AUTO_CLOSE_WEBVIEW: 'AUTO_CLOSE_WEBVIEW',\n PAYMENT_PAGE_LOADED: 'PAYMENT_PAGE_LOADED'\n};\n\n// Message types from SDK to payment app\nexport const SDK_MESSAGE_TYPES = {\n INIT: 'DROPP_SDK_INIT',\n CLOSE: 'DROPP_SDK_CLOSE'\n};\n\n// Environment configurations\nexport const ENVIRONMENTS = {\n PRODUCTION: 'production',\n QA: 'qa',\n SANDBOX: 'sandbox'\n};\n\n// Payment app URLs by environment\nexport const PAYMENT_APP_URLS = {\n [ENVIRONMENTS.PRODUCTION]: 'https://wv.dropp.cc',\n [ENVIRONMENTS.QA]: 'https://wv.qa.dropp.cc', // Assuming local QA server\n [ENVIRONMENTS.SANDBOX]: 'https://wv.sandbox.dropp.cc'\n};\n\n// Allowed origins for message validation (by environment)\nexport const ALLOWED_ORIGINS = {\n [ENVIRONMENTS.PRODUCTION]: ['https://wv.dropp.cc'],\n [ENVIRONMENTS.QA]: ['https://wv.qa.dropp.cc'], // Match QA server origin\n [ENVIRONMENTS.SANDBOX]: ['https://wv.sandbox.dropp.cc']\n};\n\n// Timeouts\nexport const TIMEOUTS = {\n INIT: 30000, // 30 seconds for app to load and send READY\n PAYMENT: 600000, // 10 minutes max for payment completion\n CLOSE_DELAY: 10000 // 10 seconds delay before closing modal after success/failure\n};\n\n// Payment types\nexport const PAYMENT_TYPES = {\n STANDARD: 'standard',\n PREAUTH: 'preauth',\n RECURRING: 'recurring'\n};\n\n// Error codes\nexport const ERROR_CODES = {\n INIT_TIMEOUT: 'INIT_TIMEOUT',\n PAYMENT_TIMEOUT: 'PAYMENT_TIMEOUT',\n INVALID_CONFIG: 'INVALID_CONFIG',\n ALREADY_OPEN: 'ALREADY_OPEN',\n ORIGIN_MISMATCH: 'ORIGIN_MISMATCH',\n MESSAGE_VALIDATION_FAILED: 'MESSAGE_VALIDATION_FAILED',\n IFRAME_BLOCKED: 'IFRAME_BLOCKED',\n UNKNOWN_ERROR: 'UNKNOWN_ERROR'\n};\n\n// SDK version\nexport const SDK_VERSION = '1.0.2';\n\n// CSS z-index for modal\nexport const MODAL_Z_INDEX = 999999;\n","/**\n * Logger utility for Dropp Payment SDK\n * Logging is disabled by default and can be enabled explicitly.\n */\n\nclass Logger {\n constructor(environment, options = {}) {\n this.environment = environment;\n this.forceEnabled = !!options.enabled;\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Determine if logging should be enabled\n * @private\n */\n _shouldEnableLogging() {\n return this.forceEnabled;\n }\n\n /**\n * Update environment and recalculate logging state\n */\n setEnvironment(environment, options = {}) {\n this.environment = environment;\n if (typeof options.enabled === 'boolean') {\n this.forceEnabled = options.enabled;\n }\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Explicitly enable or disable logging.\n */\n setEnabled(enabled) {\n this.forceEnabled = !!enabled;\n this.enabled = this._shouldEnableLogging();\n }\n\n /**\n * Log info messages\n */\n log(...args) {\n if (this.enabled) {\n console.log(...args);\n }\n }\n\n /**\n * Log warning messages\n */\n warn(...args) {\n if (this.enabled) {\n console.warn(...args);\n }\n }\n\n /**\n * Log error messages\n */\n error(...args) {\n if (this.enabled) {\n console.error(...args);\n }\n }\n\n /**\n * Log debug messages\n */\n debug(...args) {\n if (this.enabled) {\n console.debug(...args);\n }\n }\n\n /**\n * Log info messages\n */\n info(...args) {\n if (this.enabled) {\n console.info(...args);\n }\n }\n}\n\n// Create singleton instance with default environment\nconst logger = new Logger('qa', { enabled: false });\n\nexport default logger;\n","/**\n * Utility functions for Dropp Payment SDK\n */\n\nimport logger from './logger.js';\nimport { PAYMENT_TYPES } from './constants.js';\n\nconst SUPPORTED_CURRENCIES = ['USD', 'HBAR', 'USDC'];\n\nconst RECURRING_FREQUENCY_VALUES = [\n 'NONE',\n 'HALF_HOURLY',\n 'HOURLY',\n 'DAILY',\n 'WEEKLY',\n 'MONTHLY',\n 'YEARLY'\n];\n\nconst PAYMENT_TYPE_VALUES = [\n PAYMENT_TYPES.STANDARD,\n PAYMENT_TYPES.PREAUTH,\n PAYMENT_TYPES.RECURRING\n];\n\nfunction isPositiveNumber(value) {\n const num = typeof value === 'number' ? value : parseFloat(value);\n return typeof num === 'number' && !Number.isNaN(num) && num > 0;\n}\n\nfunction isPositiveInteger(value) {\n const num = typeof value === 'number' ? value : parseInt(value, 10);\n return Number.isInteger(num) && num > 0;\n}\n\nfunction isIpV4(value) {\n return /^(\\d{1,3}\\.){3}\\d{1,3}$/.test(value);\n}\n\nfunction isPrivateOrLoopbackHost(hostname) {\n if (!hostname) {\n return false;\n }\n\n const normalized = hostname.trim().toLowerCase();\n if (\n normalized === 'localhost' ||\n normalized === '127.0.0.1' ||\n normalized === '::1' ||\n normalized.endsWith('.local')\n ) {\n return true;\n }\n\n if (!isIpV4(normalized)) {\n return false;\n }\n\n const octets = normalized.split('.').map(part => Number(part));\n if (octets.some(octet => Number.isNaN(octet) || octet < 0 || octet > 255)) {\n return false;\n }\n\n const [a, b] = octets;\n // RFC1918 private ranges + loopback + link-local\n if (a === 10 || a === 127) {\n return true;\n }\n if (a === 172 && b >= 16 && b <= 31) {\n return true;\n }\n if (a === 192 && b === 168) {\n return true;\n }\n if (a === 169 && b === 254) {\n return true;\n }\n\n return false;\n}\n\nfunction isValidCallbackUrl(url, options = {}) {\n const {\n isProduction = false,\n allowLocalCallbacksInNonProd = false\n } = options;\n\n if (typeof url !== 'string' || !url.trim()) {\n return false;\n }\n\n try {\n const parsed = new URL(url.trim());\n const isHttps = parsed.protocol === 'https:';\n const isHttp = parsed.protocol === 'http:';\n\n if (!isHttp && !isHttps) {\n return false;\n }\n\n const isPrivateOrLoopback = isPrivateOrLoopbackHost(parsed.hostname);\n if (isPrivateOrLoopback) {\n return !isProduction && allowLocalCallbacksInNonProd;\n }\n\n if (isProduction) {\n return isHttps;\n }\n\n // Non-production can allow HTTP for public hosts by default.\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidIsoDateTime(value) {\n if (typeof value !== 'string' || !value.trim()) {\n return false;\n }\n const date = new Date(value.trim());\n return !Number.isNaN(date.getTime());\n}\n\n/**\n * Generate a unique session ID\n */\nexport function generateSessionId() {\n return `dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n\n/**\n * Build payment URL with base64 payload (matching Android SDK pattern)\n */\nexport async function buildPaymentUrl(baseUrl, route, params, sdkVersion, authOptions = {}) {\n try {\n const { serverAuthToken = '' } = authOptions;\n\n // Create JSON payload\n const payload = {};\n Object.keys(params).forEach(key => {\n const value = params[key];\n if (value !== null && value !== undefined) {\n payload[key] = value;\n }\n });\n \n logger.log('[buildPaymentUrl] Building payment URL payload');\n \n // Base64 encode payload (URL-safe, no padding)\n const jsonString = JSON.stringify(payload);\n const base64Payload = btoa(jsonString)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n \n const timestamp = Date.now().toString();\n const queryParams = new URLSearchParams({\n pay: base64Payload,\n sdkTs: timestamp,\n sdkVersion,\n platform: 'web'\n });\n\n if (serverAuthToken) {\n queryParams.set('authToken', serverAuthToken);\n }\n\n const url = `${baseUrl}/#${route}?${queryParams.toString()}`;\n \n return url;\n } catch (error) {\n logger.error('Error building payment URL:', error);\n throw error;\n }\n}\n\n/**\n * Validate payment configuration for standard, preauth, and recurring payments\n */\nexport function validateConfig(config = {}, options = {}) {\n const errors = [];\n const paymentType = config.paymentType || PAYMENT_TYPES.STANDARD;\n const isProduction = (options.environment || '').toLowerCase() === 'production';\n const allowLocalCallbacksInNonProd = !!options.allowLocalCallbacksInNonProd;\n const normalizedCurrency =\n typeof config.currency === 'string' ? config.currency.trim().toUpperCase() : '';\n\n if (!PAYMENT_TYPE_VALUES.includes(paymentType)) {\n errors.push(\n `paymentType must be one of: ${PAYMENT_TYPE_VALUES.join(', ')}`\n );\n }\n\n if (config.amount === undefined || config.amount === null || config.amount === '') {\n errors.push('amount is required');\n } else if (!isPositiveNumber(config.amount)) {\n errors.push('amount must be a positive number');\n }\n\n if (!config.currency || typeof config.currency !== 'string' || !config.currency.trim()) {\n errors.push('currency is required');\n } else if (!SUPPORTED_CURRENCIES.includes(normalizedCurrency)) {\n errors.push(`currency must be one of: ${SUPPORTED_CURRENCIES.join(', ')}`);\n }\n\n if (!config.itemName || typeof config.itemName !== 'string' || !config.itemName.trim()) {\n errors.push('itemName is required');\n }\n\n if (paymentType === PAYMENT_TYPES.PREAUTH) {\n if (normalizedCurrency && normalizedCurrency !== 'USD') {\n errors.push('currency must be USD for preauth payments');\n }\n\n if (!config.callbackUrl || !String(config.callbackUrl).trim()) {\n errors.push('callbackUrl (signing URL) is required for preauth payments');\n } else if (!isValidCallbackUrl(config.callbackUrl, {\n isProduction,\n allowLocalCallbacksInNonProd\n })) {\n errors.push(\n isProduction\n ? 'callbackUrl must be HTTPS in production and cannot target loopback/private hosts'\n : 'callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled'\n );\n }\n\n if (\n config.authHoldTimeInSeconds === undefined ||\n config.authHoldTimeInSeconds === null ||\n config.authHoldTimeInSeconds === ''\n ) {\n errors.push('authHoldTimeInSeconds is required for preauth payments');\n } else if (!isPositiveInteger(config.authHoldTimeInSeconds)) {\n errors.push('authHoldTimeInSeconds must be a positive integer (seconds)');\n }\n }\n\n if (paymentType === PAYMENT_TYPES.RECURRING) {\n if (!config.callbackUrl || !String(config.callbackUrl).trim()) {\n errors.push('callbackUrl (signing URL) is required for recurring payments');\n } else if (!isValidCallbackUrl(config.callbackUrl, {\n isProduction,\n allowLocalCallbacksInNonProd\n })) {\n errors.push(\n isProduction\n ? 'callbackUrl must be HTTPS in production and cannot target loopback/private hosts'\n : 'callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled'\n );\n }\n\n const frequency = (config.frequency || config.recurringInterval || '')\n .toString()\n .trim()\n .toUpperCase();\n\n if (!frequency) {\n errors.push('frequency is required for recurring payments');\n } else if (!RECURRING_FREQUENCY_VALUES.includes(frequency)) {\n errors.push(\n `frequency must be one of: ${RECURRING_FREQUENCY_VALUES.join(', ')}`\n );\n }\n\n if (!config.recurringEndDate || !String(config.recurringEndDate).trim()) {\n errors.push('recurringEndDate (expiry) is required for recurring payments');\n } else if (!isValidIsoDateTime(config.recurringEndDate)) {\n errors.push('recurringEndDate must be a valid ISO date-time string');\n } else if (new Date(config.recurringEndDate.trim()) <= new Date()) {\n errors.push('recurringEndDate must be in the future');\n }\n }\n\n return {\n valid: errors.length === 0,\n errors\n };\n}\n\n/**\n * Create error object\n */\nexport function createError(code, message, details = {}) {\n return {\n code,\n message,\n details,\n timestamp: new Date().toISOString(),\n toString() {\n return this.message || 'Dropp SDK error';\n }\n };\n}\n\n/**\n * Deep clone object\n */\nexport function deepClone(obj) {\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * Check if running in browser environment\n */\nexport function isBrowser() {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Sanitize HTML to prevent XSS\n */\nexport function sanitizeHTML(str) {\n if (!str) return '';\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n}\n\n/**\n * Format amount for display\n */\nexport function formatAmount(amount, currency) {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: currency || 'USD'\n }).format(amount);\n } catch (error) {\n return `${amount} ${currency}`;\n }\n}\n","/**\n * Secure Message Handler for SDK โ Payment App Communication\n * \n * Implements:\n * - Origin validation\n * - Message schema validation\n * - Session correlation\n * - Anti-spoofing protection\n */\n\nimport { MESSAGE_TYPES, SDK_MESSAGE_TYPES, ALLOWED_ORIGINS } from './constants.js';\nimport { generateSessionId } from './utils.js';\nimport logger from './logger.js';\n\nexport class MessageHandler {\n constructor(environment, onMessage, allowedOrigins = null) {\n this.environment = environment;\n this.onMessage = onMessage;\n this.sessionId = generateSessionId();\n logger.log('[MessageHandler] Session initialized');\n this.iframe = null;\n this.allowedOrigins =\n allowedOrigins?.length > 0\n ? allowedOrigins\n : ALLOWED_ORIGINS[environment] || [];\n this.messageListener = null;\n this.pendingMessages = new Map(); // Track correlation IDs for request/response\n }\n\n /**\n * Initialize message listener\n */\n init(iframe) {\n this.iframe = iframe;\n this.messageListener = this._handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n }\n\n /**\n * Clean up message listener\n */\n destroy() {\n if (this.messageListener) {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n this.iframe = null;\n this.pendingMessages.clear();\n }\n\n /**\n * Handle incoming postMessage events\n * @private\n */\n _handleMessage(event) {\n logger.log('[MessageHandler] Received postMessage event');\n\n // Ignore messages from self (parent window)\n if (event.source === window) {\n logger.log('[MessageHandler] Ignoring message from self');\n return;\n }\n\n // 1. Validate origin\n if (!this._validateOrigin(event.origin)) {\n logger.warn('[Dropp SDK] Rejected message from untrusted origin:', event.origin);\n return;\n }\n\n // 2. Validate event source\n if (!this.iframe || event.source !== this.iframe.contentWindow) {\n logger.warn('[Dropp SDK] Rejected message from unexpected source', {\n eventOrigin: event.origin\n });\n return;\n }\n\n // 3. Validate message structure\n const message = event.data;\n if (!this._validateMessageStructure(message)) {\n logger.warn('[Dropp SDK] Rejected message with invalid structure');\n return;\n }\n\n // 4. Validate session ID (if present)\n if (message.sessionId && message.sessionId !== this.sessionId) {\n logger.warn('[Dropp SDK] Rejected message with invalid session ID');\n return;\n }\n\n // 5. Process valid message\n logger.log('[MessageHandler] Message passed validation');\n this._processMessage(message);\n }\n\n /**\n * Validate message origin against allowed list\n * @private\n */\n _validateOrigin(origin) {\n // In development/testing, allow localhost\n if (origin.startsWith('http://localhost:') || origin.startsWith('http://127.0.0.1:')) {\n return true;\n }\n\n // Enforce exact scheme + host + port origin match.\n return this.allowedOrigins.includes(origin);\n }\n\n /**\n * Validate message structure and type\n * @private\n */\n _validateMessageStructure(message) {\n if (!message || typeof message !== 'object') {\n return false;\n }\n\n // Must have a type field\n if (!message.type || typeof message.type !== 'string') {\n return false;\n }\n\n // Must be a known message type from payment app\n const validTypes = Object.values(MESSAGE_TYPES);\n if (!validTypes.includes(message.type)) {\n return false;\n }\n\n // Must have timestamp\n if (!message.timestamp) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Process validated message\n * @private\n */\n _processMessage(message) {\n logger.log('[Dropp SDK] Received message:', message.type);\n\n // Invoke callback\n if (this.onMessage) {\n this.onMessage(message);\n }\n }\n\n /**\n * Send message to payment app\n */\n sendToPaymentApp(type, data = {}) {\n if (!this.iframe || !this.iframe.contentWindow) {\n logger.error('[Dropp SDK] Cannot send message: iframe not ready');\n return false;\n }\n\n const message = {\n type,\n data,\n sessionId: this.sessionId,\n timestamp: new Date().toISOString(),\n sdkVersion: '1.0.0'\n };\n\n // Get target origin from allowed origins\n const targetOrigin = this.allowedOrigins[0] || '*';\n\n try {\n this.iframe.contentWindow.postMessage(message, targetOrigin);\n logger.log('[Dropp SDK] Sent message:', type);\n return true;\n } catch (error) {\n logger.error('[Dropp SDK] Error sending message:', error);\n return false;\n }\n }\n\n /**\n * Send init message to payment app\n */\n sendInit(config) {\n return this.sendToPaymentApp(SDK_MESSAGE_TYPES.INIT, {\n mode: 'sdk',\n config\n });\n }\n\n /**\n * Send close request to payment app\n */\n sendClose() {\n return this.sendToPaymentApp(SDK_MESSAGE_TYPES.CLOSE, {});\n }\n\n /**\n * Get session ID\n */\n getSessionId() {\n return this.sessionId;\n }\n}\n","/**\n * Modal Manager - Creates and manages the payment modal UI\n * \n * Responsibilities:\n * - Create modal overlay and container\n * - Manage modal lifecycle (open/close/destroy)\n * - Handle focus trapping\n * - Clean up DOM and event listeners\n * - Responsive design\n */\n\nimport { MODAL_Z_INDEX } from './constants.js';\nimport logger from './logger.js';\n\nexport class ModalManager {\n constructor(onClose) {\n this.onClose = onClose;\n this.overlay = null;\n this.container = null;\n this.iframe = null;\n this.closeButton = null;\n this.isOpen = false;\n this.escapeListener = null;\n }\n\n /**\n * Create and show modal\n */\n open() {\n if (this.isOpen) {\n logger.warn('[Dropp SDK] Modal is already open');\n return null;\n }\n\n this._createModal();\n this._attachEventListeners();\n this._show();\n\n this.isOpen = true;\n return this.iframe;\n }\n\n /**\n * Close and cleanup modal\n */\n close() {\n logger.log('[ModalManager] ๐ฆ close() called, isOpen:', this.isOpen);\n \n if (!this.isOpen) {\n logger.log('[ModalManager] โ ๏ธ Modal is not open, skipping close');\n return;\n }\n\n logger.log('[ModalManager] ๐ฆ Hiding modal...');\n this._hide();\n logger.log('[ModalManager] ๐ฆ Removing event listeners...');\n this._removeEventListeners();\n logger.log('[ModalManager] ๐ฆ Destroying modal...');\n this._destroyModal();\n\n this.isOpen = false;\n logger.log('[ModalManager] โ
Modal close sequence initiated');\n }\n\n /**\n * Create modal DOM elements\n * @private\n */\n _createModal() {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.id = 'dropp-payment-overlay';\n this._applyOverlayStyles(this.overlay);\n\n // Create container\n this.container = document.createElement('div');\n this.container.id = 'dropp-payment-container';\n this._applyContainerStyles(this.container);\n\n // Close button removed - will be rendered by chrome app instead\n\n // Create iframe\n this.iframe = document.createElement('iframe');\n this.iframe.id = 'dropp-payment-iframe';\n this.iframe.setAttribute('allow', 'payment');\n this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');\n this.iframe.setAttribute('referrerpolicy', 'no-referrer');\n this.iframe.setAttribute('title', 'Dropp Payment');\n this._applyIframeStyles(this.iframe);\n\n // Assemble modal\n this.container.appendChild(this.iframe);\n this.overlay.appendChild(this.container);\n\n // Add to DOM\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Apply styles to overlay\n * @private\n */\n _applyOverlayStyles(element) {\n Object.assign(element.style, {\n position: 'fixed',\n inset: '0',\n width: '100vw',\n height: '100vh',\n margin: '0',\n padding: '20px',\n boxSizing: 'border-box',\n backgroundColor: 'rgba(0, 0, 0, 0.6)',\n zIndex: MODAL_Z_INDEX.toString(),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n opacity: '0',\n transition: 'opacity 0.3s ease',\n backdropFilter: 'blur(4px)',\n overflow: 'auto'\n });\n }\n\n /**\n * Apply styles to container\n * @private\n */\n _applyContainerStyles(element) {\n const isMobile = window.innerWidth < 768;\n this._isMobile = isMobile;\n\n Object.assign(element.style, {\n position: 'relative',\n flex: '0 0 auto',\n alignSelf: 'center',\n margin: 'auto',\n width: '100%',\n maxWidth: isMobile ? '100%' : '400px',\n height: isMobile ? '100%' : 'auto',\n minHeight: isMobile ? '100%' : '800px',\n maxHeight: isMobile ? '100%' : 'min(1000px, calc(100vh - 40px))',\n backgroundColor: '#ffffff',\n borderRadius: isMobile ? '0' : '16px',\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.3)',\n overflow: 'hidden',\n transform: 'scale(0.95)',\n transition: 'transform 0.3s ease, opacity 0.3s ease',\n display: 'flex',\n flexDirection: 'column'\n });\n }\n\n _getContainerTransform(scale) {\n return `scale(${scale})`;\n }\n\n /**\n * Apply styles to close button\n * @private\n */\n _applyCloseButtonStyles(element) {\n Object.assign(element.style, {\n position: 'absolute',\n top: '16px',\n right: '16px',\n zIndex: '10',\n width: '40px',\n height: '40px',\n border: 'none',\n borderRadius: '50%',\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n color: '#333',\n fontSize: '28px',\n lineHeight: '1',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',\n transition: 'all 0.2s ease',\n fontFamily: 'Arial, sans-serif',\n padding: '0'\n });\n\n // Hover effect\n element.addEventListener('mouseenter', () => {\n Object.assign(element.style, {\n backgroundColor: '#f5f5f5',\n transform: 'scale(1.1)'\n });\n });\n\n element.addEventListener('mouseleave', () => {\n Object.assign(element.style, {\n backgroundColor: 'rgba(255, 255, 255, 0.9)',\n transform: 'scale(1)'\n });\n });\n }\n\n /**\n * Apply styles to iframe\n * @private\n */\n _applyIframeStyles(element) {\n const isMobile = this._isMobile;\n Object.assign(element.style, {\n width: '100%',\n flex: '1 1 auto',\n minHeight: isMobile ? '100%' : 'min(520px, calc(90vh - 40px))',\n height: isMobile ? '100%' : 'min(520px, calc(90vh - 40px))',\n border: 'none',\n display: 'block'\n });\n }\n\n /**\n * Show modal with animation\n * @private\n */\n _show() {\n // Prevent body scroll\n document.body.style.overflow = 'hidden';\n\n // Trigger animation\n requestAnimationFrame(() => {\n if (this.overlay) {\n this.overlay.style.opacity = '1';\n }\n if (this.container) {\n this.container.style.transform = this._getContainerTransform(1);\n }\n });\n }\n\n /**\n * Hide modal with animation\n * @private\n */\n _hide() {\n logger.log('[ModalManager] ๐ญ _hide() called');\n if (this.overlay) {\n this.overlay.style.opacity = '0';\n logger.log('[ModalManager] ๐ญ Overlay opacity set to 0');\n }\n if (this.container) {\n this.container.style.transform = this._getContainerTransform(0.95);\n logger.log('[ModalManager] ๐ญ Container transform set to scale(0.95)');\n }\n\n // Restore body scroll\n document.body.style.overflow = '';\n logger.log('[ModalManager] ๐ญ Body scroll restored');\n }\n\n /**\n * Destroy modal DOM elements\n * @private\n */\n _destroyModal() {\n logger.log('[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation');\n // Wait for animation to complete\n setTimeout(() => {\n logger.log('[ModalManager] ๐๏ธ Animation complete, removing from DOM');\n if (this.overlay && this.overlay.parentNode) {\n this.overlay.parentNode.removeChild(this.overlay);\n logger.log('[ModalManager] ๐๏ธ Overlay removed from DOM');\n }\n this.overlay = null;\n this.container = null;\n this.iframe = null;\n this.closeButton = null;\n logger.log('[ModalManager] โ
Modal destroyed');\n }, 300);\n }\n\n /**\n * Attach event listeners\n * @private\n */\n _attachEventListeners() {\n // Close button removed - will be handled by chrome app\n // Close button click\n // if (this.closeButton) {\n // this.closeButton.addEventListener('click', this._handleCloseClick.bind(this));\n // }\n\n // Backdrop click disabled for payment security\n // Users must use close button or complete/cancel payment\n // if (this.overlay) {\n // this.overlay.addEventListener('click', this._handleOverlayClick.bind(this));\n // }\n\n // Escape key disabled for payment security\n // Users must use close button or complete/cancel payment\n // this.escapeListener = this._handleEscapeKey.bind(this);\n // document.addEventListener('keydown', this.escapeListener);\n }\n\n /**\n * Remove event listeners\n * @private\n */\n _removeEventListeners() {\n if (this.escapeListener) {\n document.removeEventListener('keydown', this.escapeListener);\n this.escapeListener = null;\n }\n }\n\n /**\n * Handle close button click\n * @private\n */\n _handleCloseClick(event) {\n event.stopPropagation();\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n\n /**\n * Handle overlay click (backdrop)\n * @private\n */\n _handleOverlayClick(event) {\n // Only close if clicking directly on overlay (not container)\n if (event.target === this.overlay) {\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n }\n\n /**\n * Handle escape key press\n * @private\n */\n _handleEscapeKey(event) {\n if (event.key === 'Escape' && this.isOpen) {\n if (this.onClose) {\n this.onClose('user_closed');\n }\n }\n }\n\n /**\n * Get iframe element\n */\n getIframe() {\n return this.iframe;\n }\n\n /**\n * Check if modal is open\n */\n getIsOpen() {\n return this.isOpen;\n }\n}\n","/**\n * Dropp Payment SDK - Main SDK Class\n * \n * Public API for integrating Dropp payments into web applications\n */\n\nimport { \n ENVIRONMENTS, \n PAYMENT_APP_URLS,\n ALLOWED_ORIGINS,\n MESSAGE_TYPES, \n ERROR_CODES, \n TIMEOUTS, \n PAYMENT_TYPES,\n SDK_VERSION\n} from './constants.js';\nimport { MessageHandler } from './messageHandler.js';\nimport { ModalManager } from './modalManager.js';\nimport { \n buildPaymentUrl, \n validateConfig, \n createError, \n isBrowser \n} from './utils.js';\nimport logger from './logger.js';\n\nexport class DroppPaymentSDK {\n /**\n * Create SDK instance\n * @param {Object} config - SDK configuration\n * @param {string} config.merchantId - Merchant Hedera account ID (required, e.g., '0.0.123456')\n * @param {string} config.apiKey - API Key (required)\n * @param {string} config.packageName - Package name (required)\n * @param {string} config.environment - Environment: 'production', 'qa', or 'sandbox'\n * @param {Function} [config.getServerAuthToken] - Optional async callback that returns a server-issued auth token\n * @param {boolean} [config.requireServerAuthToken] - Require server auth token (defaults to true in production)\n * @param {boolean} [config.allowLocalCallbacksInNonProd] - Allow loopback/private callback URLs in non-production\n */\n constructor(config = {}) {\n if (!isBrowser()) {\n throw new Error('Dropp Payment SDK can only be used in a browser environment');\n }\n\n // Validate required credentials\n if (!config.merchantId || !config.apiKey || !config.packageName) {\n throw new Error('merchantId, apiKey, and packageName are required to initialize SDK');\n }\n\n // Store credentials\n this.merchantId = config.merchantId;\n this.apiKey = config.apiKey;\n this.packageName = config.packageName;\n\n this.environment = config.environment || ENVIRONMENTS.QA;\n this.baseUrl =\n config.paymentAppUrl ||\n config.baseUrl ||\n PAYMENT_APP_URLS[this.environment];\n\n // Initialization state\n this.isInitialized = false;\n this.initializationPromise = null;\n\n this.getServerAuthToken =\n typeof config.getServerAuthToken === 'function'\n ? config.getServerAuthToken\n : null;\n this.requireServerAuthToken =\n typeof config.requireServerAuthToken === 'boolean'\n ? config.requireServerAuthToken\n : this.environment === ENVIRONMENTS.PRODUCTION;\n this.allowLocalCallbacksInNonProd = !!config.allowLocalCallbacksInNonProd;\n\n if (config.allowedOrigins?.length) {\n this.allowedOrigins = config.allowedOrigins;\n } else {\n try {\n // Derive allowed origin from the effective payment URL to keep a\n // single source of truth for iframe loading and postMessage validation.\n this.allowedOrigins = [new URL(this.baseUrl).origin];\n } catch {\n this.allowedOrigins = ALLOWED_ORIGINS[this.environment] || [];\n }\n }\n\n // State\n this.isOpen = false;\n this.currentSession = null;\n this.currentFlowType = null;\n this.initTimeout = null;\n this.paymentTimeout = null;\n\n // Managers\n this.messageHandler = null;\n this.modalManager = null;\n\n // Set logger environment\n logger.setEnvironment(this.environment, { enabled: !!config.debugLogging });\n logger.log(`[Dropp SDK] Initialized v${SDK_VERSION} - Environment: ${this.environment}`);\n }\n\n /**\n * Open payment modal\n * @param {Object} options - Payment options\n * @param {number} options.amount - Payment amount (required)\n * @param {string} options.currency - Currency code (required)\n * @param {string} options.itemName - Item/service name (required)\n * @param {string} options.description - Payment description\n * @param {string} options.invoiceId - Invoice ID\n * @param {string} options.paymentType - Payment type: 'standard', 'preauth', or 'recurring'\n * @param {string} options.thumbnail - Product image URL\n * @param {number} options.authHoldTimeInSeconds - For preauth: hold time in seconds\n * @param {string} options.callbackUrl - Server callback URL\n * @param {boolean} [options.acceptPaymentDelay=false] - Allow delayed payment acceptance for standard payments (sent only when true)\n * @param {string} [options.serverAuthToken] - Server-issued short-lived token bound to payment context\n * @param {Function} options.onSuccess - Callback for successful payment\n * @param {Function} options.onFailure - Callback for failed payment\n * @param {Function} options.onCancel - Callback for cancelled payment\n * @param {Function} options.onClose - Callback for modal close\n * @returns {Promise<PaymentResult>}\n */\n pay(options = {}) {\n return new Promise((resolve, reject) => {\n // Check if already open\n if (this.isOpen) {\n const error = createError(\n ERROR_CODES.ALREADY_OPEN,\n 'A payment session is already in progress',\n { currentSession: this.currentSession }\n );\n reject(error);\n return;\n }\n\n (async () => {\n try {\n await this.initialize();\n\n // Validate payment configuration\n const validation = validateConfig(options, {\n environment: this.environment,\n allowLocalCallbacksInNonProd: this.allowLocalCallbacksInNonProd\n });\n if (!validation.valid) {\n const error = createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Invalid payment configuration',\n { errors: validation.errors }\n );\n reject(error);\n return;\n }\n\n // Store callbacks from options\n this.onSuccess = options.onSuccess || null;\n this.onFailure = options.onFailure || null;\n this.onCancel = options.onCancel || null;\n this.onClose = options.onClose || null;\n\n // Store resolve/reject for later\n this.currentSession = {\n resolve,\n reject,\n options,\n startTime: Date.now()\n };\n\n await this._initializePayment(options);\n } catch (error) {\n const isInitValidationError =\n error && error.code === ERROR_CODES.INVALID_CONFIG;\n const sdkError = isInitValidationError\n ? error\n : createError(\n ERROR_CODES.UNKNOWN_ERROR,\n 'Failed to initialize payment',\n { originalError: error?.message || String(error) }\n );\n\n reject(sdkError);\n this._cleanup();\n }\n })();\n });\n }\n\n /**\n * Initialize and validate merchant credentials with Dropp backend.\n * @returns {Promise<{status: string, code: string, message: string}>}\n */\n async initialize() {\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n\n this.initializationPromise = (async () => {\n await this._validateInitializationCredentials();\n this.isInitialized = true;\n return {\n status: 'success',\n code: 'INITIALIZED',\n message: 'Dropp SDK initialized successfully'\n };\n })().catch(error => {\n this.isInitialized = false;\n this.initializationPromise = null;\n throw error;\n });\n\n return this.initializationPromise;\n }\n\n /**\n * Resolve validation endpoint from configured base URL.\n * @private\n */\n _getValidationUrl() {\n const validationUrls = {\n [ENVIRONMENTS.QA]: 'https://main.qa.dropp.cc/payer/webview/validate',\n [ENVIRONMENTS.SANDBOX]: 'https://sandbox.api.dropp.cc/payer/webview/validate',\n [ENVIRONMENTS.PRODUCTION]: 'https://api.dropp.cc/payer/webview/validate'\n };\n\n return (\n validationUrls[this.environment] ||\n validationUrls[ENVIRONMENTS.QA]\n );\n }\n\n /**\n * Validate merchant credentials and app package before any payment flow.\n * @private\n */\n async _validateInitializationCredentials() {\n const validationUrl = this._getValidationUrl();\n\n let response;\n let responseBody = null;\n try {\n response = await fetch(validationUrl, {\n method: 'POST',\n headers: {\n accept: 'application/json, text/plain, */*',\n 'content-type': 'application/json',\n 'x-api-key': this.apiKey,\n 'x-app-package': this.packageName\n },\n body: JSON.stringify({ id: this.merchantId })\n });\n } catch (error) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Unable to validate merchant credentials',\n {\n endpoint: validationUrl,\n originalError: error?.message || String(error)\n }\n );\n }\n\n try {\n responseBody = await response.json();\n } catch {\n responseBody = null;\n }\n\n if (!response.ok) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Merchant validation failed for merchantId/apiKey/packageName',\n {\n endpoint: validationUrl,\n status: response.status,\n response: responseBody\n }\n );\n }\n\n const responseCode = Number(responseBody?.responseCode);\n const errors = responseBody?.errors;\n const hasNoErrors = !Array.isArray(errors) || errors.length === 0;\n const isValidationSuccess = responseBody && responseCode === 0 && hasNoErrors;\n\n if (!isValidationSuccess) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Merchant validation returned an unsuccessful response',\n {\n endpoint: validationUrl,\n status: response.status,\n response: responseBody\n }\n );\n }\n\n logger.log('[Dropp SDK] Merchant credentials validated successfully');\n }\n\n /**\n * Close payment modal programmatically\n */\n closePayment() {\n if (this.isOpen) {\n if (this.currentFlowType === 'page') {\n this._cleanup();\n return;\n }\n this._handleCancel('sdk_close');\n }\n }\n\n /**\n * Open the dashboard/home page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n dashboard(options = {}) {\n return this._openHostedPage('/firsttimeflow', options);\n }\n\n /**\n * Open the unlink account page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n unlinkAccount(options = {}) {\n return this._openHostedPage('/unlink', options);\n }\n\n /**\n * Open the transactions page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n transactions(options = {}) {\n return this._openHostedPage('/transactions', options);\n }\n\n /**\n * Open the offers page in the Dropp modal.\n * @param {Object} [options] - Hosted page options\n * @param {Function} [options.onClose] - Callback for modal close\n * @returns {Promise<{status: string, route: string}>}\n */\n offers(options = {}) {\n return this._openHostedPage('/offers', options);\n }\n\n /**\n * Initialize payment session\n * @private\n */\n async _initializePayment(options) {\n logger.log('[Dropp SDK] Initializing payment session');\n this.currentFlowType = 'payment';\n\n // Create message handler\n this.messageHandler = new MessageHandler(\n this.environment,\n this._handleMessage.bind(this),\n this.allowedOrigins\n );\n\n // Create modal manager\n this.modalManager = new ModalManager(\n this._handleModalClose.bind(this)\n );\n\n // Open modal and get iframe\n const iframe = this.modalManager.open();\n if (!iframe) {\n throw new Error('Failed to create modal iframe');\n }\n\n // Initialize message handler with iframe\n this.messageHandler.init(iframe);\n\n // Determine payment route based on type\n const paymentType = options.paymentType || PAYMENT_TYPES.STANDARD;\n let route = '/payViaUrl';\n if (paymentType === PAYMENT_TYPES.PREAUTH) {\n route = '/preAuthPayment';\n } else if (paymentType === PAYMENT_TYPES.RECURRING) {\n route = '/recurringPayment';\n }\n\n // Build payment parameters (matching Android SDK)\n // For recurring payments with frequency NONE, use maxAmount instead of fixAmount\n const recurringFrequency = paymentType === PAYMENT_TYPES.RECURRING \n ? (options.frequency || options.recurringInterval || '').toString().trim().toUpperCase()\n : '';\n const isRecurringNone = paymentType === PAYMENT_TYPES.RECURRING && recurringFrequency === 'NONE';\n const detectedAppUrl =\n options.appUrl ||\n (typeof window !== 'undefined' && window.location ? window.location.href : undefined);\n \n const params = {\n merchantAccount: this.merchantId,\n amount: paymentType === PAYMENT_TYPES.PREAUTH ? undefined : options.amount,\n maxAmount: (paymentType === PAYMENT_TYPES.PREAUTH || isRecurringNone) ? options.amount : undefined,\n fixAmount: (paymentType === PAYMENT_TYPES.RECURRING && !isRecurringNone) ? options.amount : undefined,\n acceptPaymentDelay:\n paymentType === PAYMENT_TYPES.STANDARD && options.acceptPaymentDelay === true\n ? true\n : undefined,\n currency: options.currency,\n itemName: options.itemName,\n description: options.description,\n invoiceId: options.invoiceId || `INV-${Date.now()}`,\n invoiceType: paymentType === PAYMENT_TYPES.PREAUTH ? 'PREAUTH' : undefined,\n apiKey: this.apiKey,\n packageName: this.packageName,\n sdkVersion: SDK_VERSION,\n platform: 'web',\n appUrl: detectedAppUrl,\n sessionId: this.messageHandler.getSessionId() // Include SDK session ID for message validation\n };\n \n logger.log('[Dropp SDK] Including SDK session context in payment params');\n\n // Add optional parameters\n if (options.successURL) params.successURL = options.successURL;\n if (options.failureURL) params.failureURL = options.failureURL;\n \n // Recurring payment specific fields\n if (paymentType === PAYMENT_TYPES.RECURRING) {\n const frequency = options.frequency || options.recurringInterval;\n if (frequency) params.frequency = frequency;\n if (options.recurringEndDate) params.expiry = options.recurringEndDate;\n }\n \n // Pre-auth specific fields\n if (paymentType === PAYMENT_TYPES.PREAUTH && options.authHoldTimeInSeconds) {\n params.authHoldTimeInSeconds = options.authHoldTimeInSeconds;\n }\n \n // Callback URL for server-side submission\n if (options.callbackUrl) {\n params.url = options.callbackUrl;\n params.submitToCallBack = 'post';\n }\n\n const authContext = {\n sessionId: params.sessionId,\n merchantAccount: this.merchantId,\n amount: options.amount,\n paymentType,\n invoiceId: params.invoiceId,\n expiry: options.recurringEndDate || null,\n issuedAt: Date.now()\n };\n\n let serverAuthToken =\n typeof options.serverAuthToken === 'string'\n ? options.serverAuthToken.trim()\n : '';\n\n if (!serverAuthToken && this.getServerAuthToken) {\n try {\n const tokenFromCallback = await this.getServerAuthToken(authContext);\n serverAuthToken = typeof tokenFromCallback === 'string'\n ? tokenFromCallback.trim()\n : '';\n } catch (error) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'Failed to obtain server auth token',\n {\n originalError: error?.message || String(error)\n }\n );\n }\n }\n\n if (this.requireServerAuthToken && !serverAuthToken) {\n throw createError(\n ERROR_CODES.INVALID_CONFIG,\n 'serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.',\n {\n environment: this.environment,\n paymentType,\n invoiceId: params.invoiceId\n }\n );\n }\n\n // Build payment URL with base64 payload and optional server-issued auth token.\n const paymentUrl = await buildPaymentUrl(\n this.baseUrl,\n route,\n params,\n SDK_VERSION,\n { serverAuthToken }\n );\n\n logger.log('[Dropp SDK] Loading payment flow iframe');\n\n // Load payment app in iframe\n iframe.src = paymentUrl;\n\n this.isOpen = true;\n\n // Set initialization timeout\n this.initTimeout = setTimeout(() => {\n this._handleTimeout('init');\n }, TIMEOUTS.INIT);\n\n // Set payment timeout\n this.paymentTimeout = setTimeout(() => {\n this._handleTimeout('payment');\n }, TIMEOUTS.PAYMENT);\n }\n\n /**\n * Open a hosted Dropp page in the modal.\n * @private\n */\n async _openHostedPage(route, options = {}) {\n if (this.isOpen) {\n throw createError(\n ERROR_CODES.ALREADY_OPEN,\n 'A Dropp session is already in progress',\n { currentSession: this.currentSession, route }\n );\n }\n\n await this.initialize();\n\n this.currentFlowType = 'page';\n this.currentSession = null;\n this.onSuccess = null;\n this.onFailure = null;\n this.onCancel = null;\n this.onClose = typeof options.onClose === 'function' ? options.onClose : null;\n\n this.messageHandler = new MessageHandler(\n this.environment,\n this._handleMessage.bind(this),\n this.allowedOrigins\n );\n\n this.modalManager = new ModalManager(\n this._handleModalClose.bind(this)\n );\n\n const iframe = this.modalManager.open();\n if (!iframe) {\n throw new Error('Failed to create modal iframe');\n }\n\n this.messageHandler.init(iframe);\n\n const normalizedBaseUrl = this.baseUrl.replace(/\\/+$/, '');\n iframe.src = `${normalizedBaseUrl}/#${route}`;\n this.isOpen = true;\n\n logger.log('[Dropp SDK] Hosted page opened', { route });\n\n return {\n status: 'opened',\n route\n };\n }\n\n /**\n * Handle messages from payment app\n * @private\n */\n _handleMessage(message) {\n const { type, data } = message;\n\n switch (type) {\n case MESSAGE_TYPES.READY:\n this._handleReady(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_PAGE_LOADED:\n this._handlePageLoaded(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_SUCCESS:\n this._handleSuccess(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_FAILED:\n this._handleFailure(data);\n break;\n\n case MESSAGE_TYPES.PAYMENT_CANCELLED:\n this._handleCancel('user_cancelled');\n break;\n\n case MESSAGE_TYPES.AUTO_CLOSE_WEBVIEW:\n // Auto-close from payment app after success/failure countdown\n // Just close the modal without triggering callbacks (already called)\n logger.log('[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal');\n this._cleanup();\n logger.log('[Dropp SDK] Cleanup completed');\n break;\n\n case MESSAGE_TYPES.CLOSE_WEBVIEW:\n // Manual close request from chrome app\n logger.log('[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal');\n this._handleCancel('app_close');\n break;\n\n default:\n logger.warn('[Dropp SDK] Unknown message type:', type);\n }\n }\n\n /**\n * Handle ready message from payment app\n * @private\n */\n _handleReady(data) {\n logger.log('[Dropp SDK] Payment app ready');\n \n // Clear init timeout\n if (this.initTimeout) {\n clearTimeout(this.initTimeout);\n this.initTimeout = null;\n }\n\n // Send init message to payment app\n // Filter out non-serializable data (functions) from options\n if (this.messageHandler && this.currentSession) {\n const serializableOptions = {};\n Object.keys(this.currentSession.options).forEach(key => {\n const value = this.currentSession.options[key];\n // Only include serializable values (exclude functions)\n if (typeof value !== 'function') {\n serializableOptions[key] = value;\n }\n });\n \n logger.log('[Dropp SDK] Sending init config to payment app');\n this.messageHandler.sendInit(serializableOptions);\n }\n }\n\n /**\n * Handle page loaded message\n * @private\n */\n _handlePageLoaded(data) {\n logger.log('[Dropp SDK] Payment page loaded');\n }\n\n /**\n * Handle successful payment\n * @private\n */\n _handleSuccess(data) {\n logger.log('[Dropp SDK] Payment successful');\n\n const result = {\n status: 'success',\n ...data,\n sessionDuration: Date.now() - this.currentSession.startTime\n };\n\n // Resolve promise\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onSuccess) {\n this.onSuccess(result);\n }\n\n // Note: Modal will be closed by AUTO_CLOSE_WEBVIEW message from payment app\n // after the countdown completes (no need for timeout here)\n }\n\n /**\n * Handle failed payment\n * @private\n */\n _handleFailure(data) {\n logger.log('[Dropp SDK] Payment failed');\n\n const result = {\n status: 'failed',\n ...data,\n sessionDuration: Date.now() - this.currentSession.startTime\n };\n\n // Resolve promise (not reject - failed payment is still a valid result)\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onFailure) {\n this.onFailure(result);\n }\n\n // Note: Modal will be closed by AUTO_CLOSE_WEBVIEW message from payment app\n // after the countdown completes (no need for timeout here)\n }\n\n /**\n * Handle cancelled payment\n * @private\n */\n _handleCancel(reason) {\n logger.log('[Dropp SDK] Payment cancelled');\n\n const result = {\n status: 'cancelled',\n reason,\n sessionDuration: this.currentSession ? Date.now() - this.currentSession.startTime : 0\n };\n\n // Resolve promise (not reject - cancellation is a valid result)\n if (this.currentSession) {\n this.currentSession.resolve(result);\n }\n\n // Invoke callback\n if (this.onCancel) {\n this.onCancel(result);\n }\n\n // Close immediately\n this._cleanup();\n }\n\n /**\n * Handle modal close by user\n * @private\n */\n _handleModalClose(reason) {\n logger.log('[Dropp SDK] Modal closed by user');\n if (this.currentFlowType === 'page') {\n this._cleanup();\n return;\n }\n this._handleCancel(reason);\n }\n\n /**\n * Handle timeout\n * @private\n */\n _handleTimeout(type) {\n logger.error('[Dropp SDK] Timeout:', type);\n\n const errorCode = type === 'init' ? ERROR_CODES.INIT_TIMEOUT : ERROR_CODES.PAYMENT_TIMEOUT;\n const errorMessage = type === 'init' \n ? 'Payment app failed to load within timeout period'\n : 'Payment session timed out';\n\n const error = createError(errorCode, errorMessage, {\n type,\n sessionDuration: this.currentSession ? Date.now() - this.currentSession.startTime : 0\n });\n\n // Reject promise\n if (this.currentSession) {\n this.currentSession.reject(error);\n }\n\n // Invoke failure callback\n if (this.onFailure) {\n this.onFailure({ status: 'failed', error });\n }\n\n this._cleanup();\n }\n\n /**\n * Cleanup resources\n * @private\n */\n _cleanup() {\n logger.log('[Dropp SDK] ๐งน Cleaning up session - starting cleanup');\n\n // Clear timeouts\n if (this.initTimeout) {\n clearTimeout(this.initTimeout);\n this.initTimeout = null;\n }\n\n if (this.paymentTimeout) {\n clearTimeout(this.paymentTimeout);\n this.paymentTimeout = null;\n }\n\n // Destroy managers\n if (this.messageHandler) {\n logger.log('[Dropp SDK] ๐งน Destroying message handler');\n this.messageHandler.destroy();\n this.messageHandler = null;\n }\n\n if (this.modalManager) {\n logger.log('[Dropp SDK] ๐งน Closing modal manager');\n this.modalManager.close();\n logger.log('[Dropp SDK] ๐งน Modal manager closed');\n this.modalManager = null;\n }\n\n // Clear state\n this.currentSession = null;\n this.currentFlowType = null;\n this.isOpen = false;\n\n // Invoke onClose callback\n if (this.onClose) {\n this.onClose();\n }\n }\n\n /**\n * Get SDK version\n */\n static getVersion() {\n return SDK_VERSION;\n }\n\n /**\n * Get available environments\n */\n static getEnvironments() {\n return { ...ENVIRONMENTS };\n }\n\n /**\n * Get payment types\n */\n static getPaymentTypes() {\n return { ...PAYMENT_TYPES };\n }\n}\n\nexport default DroppPaymentSDK;\n","/**\n * Dropp Payment SDK for Web\n * \n * Main entry point - exports SDK class and factory functions\n */\n\nimport { DroppPaymentSDK } from './DroppPaymentSDK.js';\nimport { ENVIRONMENTS, PAYMENT_TYPES } from './constants.js';\n\n// Export main SDK class\nexport { DroppPaymentSDK };\n\n// Export constants\nexport { ENVIRONMENTS, PAYMENT_TYPES };\n\n// Global Dropp instance\nlet globalDroppInstance = null;\n\n/**\n * Factory function to create and initialize SDK instance\n * @param {Object} config - SDK configuration\n * @param {string} config.merchantId - Merchant Hedera account ID (required, e.g., '0.0.123456')\n * @param {string} config.apiKey - API Key (required)\n * @param {string} config.packageName - Package name (required)\n * @param {string} config.environment - Environment: 'production', 'qa', or 'sandbox'\n * @returns {Promise<{status: string, code: string, message: string, sdk: DroppPaymentSDK}>}\n */\nexport async function createPaymentSDK(config) {\n globalDroppInstance = new DroppPaymentSDK(config);\n const initResult = await globalDroppInstance.initialize();\n return {\n ...initResult,\n sdk: globalDroppInstance\n };\n}\n\n/**\n * Get the global Dropp instance\n * @returns {DroppPaymentSDK|null}\n */\nexport function getDroppInstance() {\n return globalDroppInstance;\n}\n\n/**\n * Global Dropp object with pay method\n */\nexport const Dropp = {\n /**\n * Initialize SDK (sets global instance)\n * @param {Object} config - SDK configuration\n * @returns {Promise<{status: string, code: string, message: string, sdk: DroppPaymentSDK}>}\n */\n init(config) {\n return createPaymentSDK(config);\n },\n \n /**\n * Make a payment using the initialized SDK\n * @param {Object} options - Payment options\n * @returns {Promise<PaymentResult>}\n */\n pay(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.pay(options);\n },\n\n /**\n * Open the dashboard/home page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n dashboard(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.dashboard(options);\n },\n\n /**\n * Open the unlink account page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n unlinkAccount(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.unlinkAccount(options);\n },\n\n /**\n * Open the transactions page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n transactions(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.transactions(options);\n },\n\n /**\n * Open the offers page in the initialized SDK modal\n * @param {Object} [options] - Hosted page options\n * @returns {Promise<{status: string, route: string}>}\n */\n offers(options) {\n if (!globalDroppInstance) {\n const error = new Error('Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).');\n error.code = 'SDK_NOT_INITIALIZED';\n throw error;\n }\n return globalDroppInstance.offers(options);\n },\n \n /**\n * Get the current SDK instance\n * @returns {DroppPaymentSDK|null}\n */\n getInstance() {\n return globalDroppInstance;\n }\n};\n\n// Default export\nexport default {\n DroppPaymentSDK,\n createPaymentSDK,\n Dropp,\n ENVIRONMENTS,\n PAYMENT_TYPES\n};\n"],"names":["MESSAGE_TYPES","READY","PAYMENT_SUCCESS","PAYMENT_FAILED","PAYMENT_CANCELLED","CLOSE_WEBVIEW","AUTO_CLOSE_WEBVIEW","PAYMENT_PAGE_LOADED","SDK_MESSAGE_TYPES","ENVIRONMENTS","PRODUCTION","QA","SANDBOX","PAYMENT_APP_URLS","ALLOWED_ORIGINS","TIMEOUTS","PAYMENT_TYPES","STANDARD","PREAUTH","RECURRING","ERROR_CODES","SDK_VERSION","logger","constructor","environment","options","this","forceEnabled","enabled","_shouldEnableLogging","setEnvironment","setEnabled","log","args","console","warn","error","debug","info","SUPPORTED_CURRENCIES","RECURRING_FREQUENCY_VALUES","PAYMENT_TYPE_VALUES","isValidCallbackUrl","url","isProduction","allowLocalCallbacksInNonProd","trim","parsed","URL","isHttps","protocol","hostname","normalized","toLowerCase","endsWith","test","octets","split","map","part","Number","some","octet","isNaN","a","b","isPrivateOrLoopbackHost","validateConfig","config","errors","paymentType","normalizedCurrency","currency","toUpperCase","includes","push","join","undefined","amount","value","num","parseFloat","isPositiveNumber","itemName","callbackUrl","String","authHoldTimeInSeconds","parseInt","isInteger","isPositiveInteger","frequency","recurringInterval","toString","recurringEndDate","date","Date","getTime","isValidIsoDateTime","valid","length","createError","code","message","details","timestamp","toISOString","MessageHandler","onMessage","allowedOrigins","sessionId","now","Math","random","substring","iframe","messageListener","pendingMessages","Map","init","_handleMessage","bind","window","addEventListener","destroy","removeEventListener","clear","event","source","_validateOrigin","origin","contentWindow","eventOrigin","data","_validateMessageStructure","_processMessage","startsWith","type","Object","values","sendToPaymentApp","sdkVersion","targetOrigin","postMessage","sendInit","mode","sendClose","getSessionId","ModalManager","onClose","overlay","container","closeButton","isOpen","escapeListener","open","_createModal","_attachEventListeners","_show","close","_hide","_removeEventListeners","_destroyModal","document","createElement","id","_applyOverlayStyles","_applyContainerStyles","setAttribute","_applyIframeStyles","appendChild","body","element","assign","style","position","inset","width","height","margin","padding","boxSizing","backgroundColor","zIndex","display","alignItems","justifyContent","opacity","transition","backdropFilter","overflow","isMobile","innerWidth","_isMobile","flex","alignSelf","maxWidth","minHeight","maxHeight","borderRadius","boxShadow","transform","flexDirection","_getContainerTransform","scale","_applyCloseButtonStyles","top","right","border","color","fontSize","lineHeight","cursor","fontFamily","requestAnimationFrame","setTimeout","parentNode","removeChild","_handleCloseClick","stopPropagation","_handleOverlayClick","target","_handleEscapeKey","key","getIframe","getIsOpen","DroppPaymentSDK","Error","merchantId","apiKey","packageName","baseUrl","paymentAppUrl","isInitialized","initializationPromise","getServerAuthToken","requireServerAuthToken","currentSession","currentFlowType","initTimeout","paymentTimeout","messageHandler","modalManager","debugLogging","pay","Promise","resolve","reject","initialize","validation","onSuccess","onFailure","onCancel","startTime","_initializePayment","sdkError","originalError","_cleanup","_validateInitializationCredentials","status","catch","_getValidationUrl","validationUrls","validationUrl","response","responseBody","fetch","method","headers","accept","JSON","stringify","endpoint","json","ok","responseCode","hasNoErrors","Array","isArray","closePayment","_handleCancel","dashboard","_openHostedPage","unlinkAccount","transactions","offers","_handleModalClose","route","recurringFrequency","isRecurringNone","detectedAppUrl","appUrl","location","href","params","merchantAccount","maxAmount","fixAmount","acceptPaymentDelay","description","invoiceId","invoiceType","platform","successURL","failureURL","expiry","submitToCallBack","authContext","issuedAt","serverAuthToken","tokenFromCallback","paymentUrl","async","authOptions","payload","keys","forEach","jsonString","base64Payload","btoa","replace","queryParams","URLSearchParams","sdkTs","set","buildPaymentUrl","src","_handleTimeout","normalizedBaseUrl","_handleReady","_handlePageLoaded","_handleSuccess","_handleFailure","clearTimeout","serializableOptions","result","sessionDuration","reason","getVersion","getEnvironments","getPaymentTypes","globalDroppInstance","createPaymentSDK","sdk","Dropp","getInstance","index"],"mappings":"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"}
|
package/package.json
CHANGED