@ojire/pg-js-sdk 1.0.0

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.
@@ -0,0 +1,9 @@
1
+ export interface SDKConfig {
2
+ sandbox: boolean;
3
+ sandboxPaymentUrl: string;
4
+ productionPaymentUrl: string;
5
+ }
6
+ export declare function configure(config: Partial<SDKConfig>): void;
7
+ export declare function getConfig(): SDKConfig;
8
+ export declare function getPaymentUrl(paymentId: string): string;
9
+ export declare function isSandboxMode(): boolean;
@@ -0,0 +1,10 @@
1
+ import type { OpenPaymentOptions, OPGSDK, SDKConfiguration } from './types';
2
+ export type { TransactionStatus, PaymentResultStatus, PaymentResult, PaymentCallbacks, OpenPaymentOptions, OPGSDK, SDKConfiguration, } from './types';
3
+ declare function openPayment(options: OpenPaymentOptions): void;
4
+ declare function closePayment(): void;
5
+ declare function isPaymentOpen(): boolean;
6
+ declare function configure(config: Partial<SDKConfiguration>): void;
7
+ declare function isSandbox(): boolean;
8
+ declare const OPG: OPGSDK;
9
+ export { openPayment, closePayment, isPaymentOpen, configure, isSandbox };
10
+ export default OPG;
@@ -0,0 +1,2 @@
1
+ export declare function createModal(clientSecret: string, paymentId: string, publicKey: string, token: string): void;
2
+ export declare function closeModal(): void;
@@ -0,0 +1,2 @@
1
+ const n={isOpen:!1,url:null,callbacks:{}};let e={...n};function t(){return e.isOpen}const o=["settlement","capture"],a=["pending","challenge"],r=["deny","cancel","expire","failure"];var i,d;let s={...{sandbox:!0,sandboxPaymentUrl:null!==(i="https://pay-dev.ojire.online/pay")?i:"",productionPaymentUrl:null!==(d="https://pay.ojire.online/pay")?d:""}};function c(n){s={...s,...n}}const l="opg-payment-modal",u="opg-payment-backdrop",p="opg-payment-container",m="opg-payment-iframe",f="opg-payment-close",b="opg-payment-spinner";let y=null,g=null;function v(n){var t,i,d,s,c,l,u;const p=e.callbacks;if("COPY_TEXT"===n.data.type)return void navigator.clipboard.writeText(n.data.value);if("PAYMENT_SUCCESS"===(null===(t=n.data)||void 0===t?void 0:t.type)){const n={transactionStatus:"settlement",status:"success",rawData:{type:"PAYMENT_SUCCESS"}};return null===(i=p.onSuccess)||void 0===i||i.call(p,n),void E()}if("PAYMENT_RESULT"===(null===(d=n.data)||void 0===d?void 0:d.type)){const e=n.data.status;let t,o;switch(e){case"expired":t="expire",o="error";break;case"failed":default:t="failure",o="error";break;case"canceled":t="cancel",o="error"}const a={transactionStatus:t,status:o,rawData:{type:"PAYMENT_RESULT",status:e}};return null===(s=p.onError)||void 0===s||s.call(p,a),void E()}if("object"!=typeof(m=n.data)||null===m||"string"!=typeof m.transaction_status)return;var m;const f=function(n){const e=n.transaction_status;return{transactionStatus:e,status:(t=e,o.includes(t)?"success":a.includes(t)?"pending":(r.includes(t),"error")),rawData:n};var t}(n.data);switch(f.status){case"success":null===(c=p.onSuccess)||void 0===c||c.call(p,f);break;case"pending":null===(l=p.onPending)||void 0===l||l.call(p,f);break;case"error":null===(u=p.onError)||void 0===u||u.call(p,f)}}function h(n){"Escape"===n.key&&E()}function x(n){n.target.id===u&&E()}function w(n,t,o,a){const r=function(n){return`${s.sandbox?s.sandboxPaymentUrl:s.productionPaymentUrl}/${n}`}(t);if(document.getElementById(l))return;!function(){if(document.getElementById("opg-sdk-styles"))return;const n=document.createElement("style");n.id="opg-sdk-styles",n.textContent=`\n #${u} {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.6);\n z-index: 999998;\n }\n\n #${p} {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 90%;\n max-width: 480px;\n height: 80%;\n max-height: 700px;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n z-index: 999999;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n #${f} {\n position: absolute;\n top: 12px;\n right: 12px;\n width: 32px;\n height: 32px;\n border: none;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n transition: background 0.2s;\n }\n\n #${f}:hover {\n background: rgba(0, 0, 0, 0.2);\n }\n\n #${f}::before,\n #${f}::after {\n content: '';\n position: absolute;\n width: 16px;\n height: 2px;\n background: #333;\n }\n\n #${f}::before {\n transform: rotate(45deg);\n }\n\n #${f}::after {\n transform: rotate(-45deg);\n }\n\n #${m} {\n width: 100%;\n height: 100%;\n border: none;\n flex: 1;\n }\n\n #${b} {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 40px;\n height: 40px;\n border: 3px solid #f3f3f3;\n border-top: 3px solid #3498db;\n border-radius: 50%;\n animation: opg-spin 1s linear infinite;\n }\n\n @keyframes opg-spin {\n 0% { transform: translate(-50%, -50%) rotate(0deg); }\n 100% { transform: translate(-50%, -50%) rotate(360deg); }\n }\n\n #${b}.hidden {\n display: none;\n }\n `,document.head.appendChild(n)}(),document.body.style.overflow="hidden";const i=document.createElement("div");i.id=l;const d=document.createElement("div");d.id=u,d.addEventListener("click",x);const c=document.createElement("div");c.id=p;const w=document.createElement("button");w.id=f,w.type="button",w.setAttribute("aria-label","Close payment"),w.addEventListener("click",()=>E());const k=document.createElement("div");k.id=b;const S=document.createElement("iframe");var P;S.id=m,S.src=r,S.setAttribute("allow","payment"),S.setAttribute("allow","clipboard-write"),S.addEventListener("load",()=>{k.classList.add("hidden")}),S.onload=()=>{var e;null===(e=S.contentWindow)||void 0===e||e.postMessage({type:"INIT",clientSecret:n,publicKey:o,token:a},r)},c.appendChild(w),c.appendChild(k),c.appendChild(S),i.appendChild(d),i.appendChild(c),document.body.appendChild(i),y=v,g=h,window.addEventListener("message",y),document.addEventListener("keydown",g),P={isOpen:!0,url:r},e={...e,...P}}function E(){const t=document.getElementById(l);t&&(y&&(window.removeEventListener("message",y),y=null),g&&(document.removeEventListener("keydown",g),g=null),t.remove(),document.body.style.overflow="",e={...n,isOpen:!1,callbacks:e.callbacks})}var k,S,P;const C=null!==(S=null===(k=document.currentScript)||void 0===k?void 0:k.getAttribute("data-client-key"))&&void 0!==S?S:void 0;function $(n){if(t())return void console.warn("[opg-sdk] Payment modal is already open");if(!n.token)throw new Error("[opg-sdk] Payment token is required");if(!n.clientSecret)throw new Error("[opg-sdk] Payment clientSecret is required");if(!n.paymentId)throw new Error("[opg-sdk] Payment paymentId is required");if(!C)throw new Error("[opg-sdk] Payment publicKey is required");void 0!==n.sandbox&&c({sandbox:n.sandbox});const{clientSecret:o,paymentId:a,token:r,onSuccess:i,onPending:d,onError:s}=n;var l;l={onSuccess:i,onPending:d,onError:s},e.callbacks=l,w(o,a,C,r)}function L(){E()}function T(){return t()}function A(n){c(n)}function I(){return s.sandbox}c({sandbox:"false"!==(null===(P=document.currentScript)||void 0===P?void 0:P.getAttribute("data-sandbox"))});const U={openPayment:$,closePayment:L,isPaymentOpen:T,configure:A,isSandbox:I};export{L as closePayment,A as configure,U as default,T as isPaymentOpen,I as isSandbox,$ as openPayment};
2
+ //# sourceMappingURL=opg-sdk.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opg-sdk.esm.js","sources":["../src/state.ts","../src/utils.ts","../src/config.ts","../src/modal.ts","../src/index.ts"],"sourcesContent":["import type { ModalState, PaymentCallbacks } from './types';\n\nconst initialState: ModalState = {\n isOpen: false,\n url: null,\n callbacks: {},\n};\n\nlet state: ModalState = { ...initialState };\n\nexport function getState(): ModalState {\n return state;\n}\n\nexport function setState(newState: Partial<ModalState>): void {\n state = { ...state, ...newState };\n}\n\nexport function resetState(): void {\n state = { ...initialState, isOpen: false, callbacks: state.callbacks };\n}\n\nexport function isOpen(): boolean {\n return state.isOpen;\n}\n\nexport function getCallbacks(): PaymentCallbacks {\n return state.callbacks;\n}\n\nexport function setCallbacks(callbacks: PaymentCallbacks): void {\n state.callbacks = callbacks;\n}\n","import type { TransactionStatus, PaymentResultStatus, PaymentResult, PaymentMessage } from './types';\n\nconst SUCCESS_STATUSES: TransactionStatus[] = ['settlement', 'capture'];\nconst PENDING_STATUSES: TransactionStatus[] = ['pending', 'challenge'];\nconst ERROR_STATUSES: TransactionStatus[] = ['deny', 'cancel', 'expire', 'failure'];\n\nexport function mapTransactionStatus(status: TransactionStatus): PaymentResultStatus {\n if (SUCCESS_STATUSES.includes(status)) return 'success';\n if (PENDING_STATUSES.includes(status)) return 'pending';\n if (ERROR_STATUSES.includes(status)) return 'error';\n return 'error';\n}\n\nexport function isValidPaymentMessage(data: unknown): data is PaymentMessage {\n if (typeof data !== 'object' || data === null) return false;\n const msg = data as Record<string, unknown>;\n return typeof msg.transaction_status === 'string';\n}\n\nexport function createPaymentResult(message: PaymentMessage): PaymentResult {\n const transactionStatus = message.transaction_status;\n return {\n transactionStatus,\n status: mapTransactionStatus(transactionStatus),\n rawData: message,\n };\n}\n\nexport function lockBodyScroll(): void {\n document.body.style.overflow = 'hidden';\n}\n\nexport function unlockBodyScroll(): void {\n document.body.style.overflow = '';\n}\n","export interface SDKConfig {\n sandbox: boolean;\n sandboxPaymentUrl: string;\n productionPaymentUrl: string;\n}\n\nconst DEFAULT_CONFIG: SDKConfig = {\n sandbox: true,\n sandboxPaymentUrl: process.env.OPG_SANDBOX_PAYMENT_URL ?? \"\",\n productionPaymentUrl: process.env.OPG_PRODUCTION_PAYMENT_URL ?? \"\",\n};\n\nlet currentConfig: SDKConfig = { ...DEFAULT_CONFIG };\n\nexport function configure(config: Partial<SDKConfig>): void {\n currentConfig = { ...currentConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return currentConfig;\n}\n\nexport function getPaymentUrl(paymentId: string): string {\n const baseUrl = currentConfig.sandbox \n ? currentConfig.sandboxPaymentUrl \n : currentConfig.productionPaymentUrl;\n \n return `${baseUrl}/${paymentId}`;\n}\n\nexport function isSandboxMode(): boolean {\n return currentConfig.sandbox;\n}\n","import { getCallbacks, setState, resetState } from './state';\nimport { isValidPaymentMessage, createPaymentResult, lockBodyScroll, unlockBodyScroll } from './utils';\nimport { getPaymentUrl } from './config';\n\nconst MODAL_ID = 'opg-payment-modal';\nconst BACKDROP_ID = 'opg-payment-backdrop';\nconst CONTAINER_ID = 'opg-payment-container';\nconst IFRAME_ID = 'opg-payment-iframe';\nconst CLOSE_BTN_ID = 'opg-payment-close';\nconst SPINNER_ID = 'opg-payment-spinner';\n\nlet messageHandler: ((event: MessageEvent) => void) | null = null;\nlet keyHandler: ((event: KeyboardEvent) => void) | null = null;\n\nfunction injectStyles(): void {\n if (document.getElementById('opg-sdk-styles')) return;\n\n const style = document.createElement('style');\n style.id = 'opg-sdk-styles';\n style.textContent = `\n #${BACKDROP_ID} {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.6);\n z-index: 999998;\n }\n\n #${CONTAINER_ID} {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 90%;\n max-width: 480px;\n height: 80%;\n max-height: 700px;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n z-index: 999999;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n #${CLOSE_BTN_ID} {\n position: absolute;\n top: 12px;\n right: 12px;\n width: 32px;\n height: 32px;\n border: none;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n transition: background 0.2s;\n }\n\n #${CLOSE_BTN_ID}:hover {\n background: rgba(0, 0, 0, 0.2);\n }\n\n #${CLOSE_BTN_ID}::before,\n #${CLOSE_BTN_ID}::after {\n content: '';\n position: absolute;\n width: 16px;\n height: 2px;\n background: #333;\n }\n\n #${CLOSE_BTN_ID}::before {\n transform: rotate(45deg);\n }\n\n #${CLOSE_BTN_ID}::after {\n transform: rotate(-45deg);\n }\n\n #${IFRAME_ID} {\n width: 100%;\n height: 100%;\n border: none;\n flex: 1;\n }\n\n #${SPINNER_ID} {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 40px;\n height: 40px;\n border: 3px solid #f3f3f3;\n border-top: 3px solid #3498db;\n border-radius: 50%;\n animation: opg-spin 1s linear infinite;\n }\n\n @keyframes opg-spin {\n 0% { transform: translate(-50%, -50%) rotate(0deg); }\n 100% { transform: translate(-50%, -50%) rotate(360deg); }\n }\n\n #${SPINNER_ID}.hidden {\n display: none;\n }\n `;\n document.head.appendChild(style);\n}\n\nfunction handleMessage(event: MessageEvent): void {\n const callbacks = getCallbacks();\n\n if (event.data.type === \"COPY_TEXT\") {\n navigator.clipboard.writeText(event.data.value);\n return;\n }\n\n if (event.data?.type === 'PAYMENT_SUCCESS') {\n\n const result = {\n transactionStatus: 'settlement' as const,\n status: 'success' as const,\n rawData: { type: 'PAYMENT_SUCCESS' },\n };\n\n callbacks.onSuccess?.(result);\n closeModal();\n return;\n }\n\n if (event.data?.type === 'PAYMENT_RESULT') {\n const status = event.data.status;\n let transactionStatus: string;\n let mappedStatus: 'success' | 'pending' | 'error';\n\n switch (status) {\n case 'expired':\n transactionStatus = 'expire';\n mappedStatus = 'error';\n break;\n case 'failed':\n transactionStatus = 'failure';\n mappedStatus = 'error';\n break;\n case 'canceled':\n transactionStatus = 'cancel';\n mappedStatus = 'error';\n break;\n default:\n transactionStatus = 'failure';\n mappedStatus = 'error';\n }\n\n const result = {\n transactionStatus: transactionStatus as any,\n status: mappedStatus,\n rawData: { type: 'PAYMENT_RESULT', status },\n };\n\n callbacks.onError?.(result);\n closeModal();\n return;\n }\n\n if (!isValidPaymentMessage(event.data)) return;\n\n const result = createPaymentResult(event.data);\n\n switch (result.status) {\n case 'success':\n callbacks.onSuccess?.(result);\n break;\n case 'pending':\n callbacks.onPending?.(result);\n break;\n case 'error':\n callbacks.onError?.(result);\n break;\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') {\n closeModal();\n }\n}\n\nfunction handleBackdropClick(event: MouseEvent): void {\n if ((event.target as HTMLElement).id === BACKDROP_ID) {\n closeModal();\n }\n}\n\nexport function createModal(clientSecret: string, paymentId: string, publicKey: string, token: string): void {\n const url = getPaymentUrl(paymentId);\n if (document.getElementById(MODAL_ID)) return;\n\n injectStyles();\n lockBodyScroll();\n\n const modal = document.createElement('div');\n modal.id = MODAL_ID;\n\n const backdrop = document.createElement('div');\n backdrop.id = BACKDROP_ID;\n backdrop.addEventListener('click', handleBackdropClick);\n\n const container = document.createElement('div');\n container.id = CONTAINER_ID;\n\n const closeBtn = document.createElement('button');\n closeBtn.id = CLOSE_BTN_ID;\n closeBtn.type = 'button';\n closeBtn.setAttribute('aria-label', 'Close payment');\n closeBtn.addEventListener('click', () => closeModal());\n\n const spinner = document.createElement('div');\n spinner.id = SPINNER_ID;\n const iframe = document.createElement('iframe');\n iframe.id = IFRAME_ID;\n iframe.src = url;\n iframe.setAttribute('allow', 'payment');\n iframe.setAttribute(\"allow\", \"clipboard-write\");\n iframe.addEventListener('load', () => {\n spinner.classList.add('hidden');\n });\n\n iframe.onload = () => {\n iframe.contentWindow?.postMessage(\n {\n type: \"INIT\",\n clientSecret,\n publicKey,\n token\n },\n url\n );\n };\n\n container.appendChild(closeBtn);\n container.appendChild(spinner);\n container.appendChild(iframe);\n modal.appendChild(backdrop);\n modal.appendChild(container);\n document.body.appendChild(modal);\n\n messageHandler = handleMessage;\n keyHandler = handleKeydown;\n window.addEventListener('message', messageHandler);\n document.addEventListener('keydown', keyHandler);\n\n setState({ isOpen: true, url });\n}\n\nexport function closeModal(): void {\n const modal = document.getElementById(MODAL_ID);\n if (!modal) return;\n\n if (messageHandler) {\n window.removeEventListener('message', messageHandler);\n messageHandler = null;\n }\n\n if (keyHandler) {\n document.removeEventListener('keydown', keyHandler);\n keyHandler = null;\n }\n\n modal.remove();\n unlockBodyScroll();\n\n resetState();\n}\n","import type { OpenPaymentOptions, OPGSDK, SDKConfiguration } from './types';\nimport { isOpen, setCallbacks } from './state';\nimport { createModal, closeModal } from './modal';\nimport { configure as configureSDK, isSandboxMode, getConfig } from './config';\n\nexport type {\n TransactionStatus,\n PaymentResultStatus,\n PaymentResult,\n PaymentCallbacks,\n OpenPaymentOptions,\n OPGSDK,\n SDKConfiguration,\n} from './types';\n\nconst publicKey = document.currentScript?.getAttribute(\"data-client-key\") ?? undefined;\nconst sandboxAttr = document.currentScript?.getAttribute(\"data-sandbox\");\nconst isSandboxFromAttr = sandboxAttr !== 'false';\n\nconfigureSDK({ sandbox: isSandboxFromAttr });\n\nfunction openPayment(options: OpenPaymentOptions): void {\n if (isOpen()) {\n console.warn('[opg-sdk] Payment modal is already open');\n return;\n }\n\n if (!options.token) {\n throw new Error('[opg-sdk] Payment token is required');\n }\n\n if (!options.clientSecret) {\n throw new Error('[opg-sdk] Payment clientSecret is required');\n }\n\n if (!options.paymentId) {\n throw new Error('[opg-sdk] Payment paymentId is required');\n }\n\n if (!publicKey) {\n throw new Error('[opg-sdk] Payment publicKey is required');\n }\n\n if (options.sandbox !== undefined) {\n configureSDK({ sandbox: options.sandbox });\n }\n\n const { clientSecret, paymentId, token, onSuccess, onPending, onError } = options;\n\n setCallbacks({\n onSuccess,\n onPending,\n onError,\n });\n\n createModal(clientSecret, paymentId, publicKey, token);\n}\n\nfunction closePayment(): void {\n closeModal();\n}\n\nfunction isPaymentOpen(): boolean {\n return isOpen();\n}\n\nfunction configure(config: Partial<SDKConfiguration>): void {\n configureSDK(config);\n}\n\nfunction isSandbox(): boolean {\n return isSandboxMode();\n}\n\nconst OPG: OPGSDK = {\n openPayment,\n closePayment,\n isPaymentOpen,\n configure,\n isSandbox,\n};\n\nexport { openPayment, closePayment, isPaymentOpen, configure, isSandbox };\nexport default OPG;\n"],"names":["initialState","isOpen","url","callbacks","state","SUCCESS_STATUSES","PENDING_STATUSES","ERROR_STATUSES","currentConfig","sandbox","sandboxPaymentUrl","productionPaymentUrl","configure","config","MODAL_ID","BACKDROP_ID","CONTAINER_ID","IFRAME_ID","CLOSE_BTN_ID","SPINNER_ID","messageHandler","keyHandler","handleMessage","event","data","type","navigator","clipboard","writeText","value","_a","result","transactionStatus","status","rawData","_b","onSuccess","call","closeModal","_c","mappedStatus","_d","onError","transaction_status","message","includes","createPaymentResult","_e","_f","onPending","_g","handleKeydown","key","handleBackdropClick","target","id","createModal","clientSecret","paymentId","publicKey","token","getPaymentUrl","document","getElementById","style","createElement","textContent","head","appendChild","injectStyles","body","overflow","modal","backdrop","addEventListener","container","closeBtn","setAttribute","spinner","iframe","newState","src","classList","add","onload","contentWindow","postMessage","window","removeEventListener","remove","currentScript","getAttribute","undefined","openPayment","options","console","warn","Error","configureSDK","closePayment","isPaymentOpen","isSandbox","OPG"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ !function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).OPG={})}(this,function(n){"use strict";const e={isOpen:!1,url:null,callbacks:{}};let t={...e};function o(){return t.isOpen}const a=["settlement","capture"],r=["pending","challenge"],i=["deny","cancel","expire","failure"];var d,s;let l={...{sandbox:!0,sandboxPaymentUrl:null!==(d="https://pay-dev.ojire.online/pay")?d:"",productionPaymentUrl:null!==(s="https://pay.ojire.online/pay")?s:""}};function c(n){l={...l,...n}}const u="opg-payment-modal",p="opg-payment-backdrop",f="opg-payment-container",m="opg-payment-iframe",y="opg-payment-close",b="opg-payment-spinner";let g=null,v=null;function h(n){var e,o,d,s,l,c,u;const p=t.callbacks;if("COPY_TEXT"===n.data.type)return void navigator.clipboard.writeText(n.data.value);if("PAYMENT_SUCCESS"===(null===(e=n.data)||void 0===e?void 0:e.type)){const n={transactionStatus:"settlement",status:"success",rawData:{type:"PAYMENT_SUCCESS"}};return null===(o=p.onSuccess)||void 0===o||o.call(p,n),void k()}if("PAYMENT_RESULT"===(null===(d=n.data)||void 0===d?void 0:d.type)){const e=n.data.status;let t,o;switch(e){case"expired":t="expire",o="error";break;case"failed":default:t="failure",o="error";break;case"canceled":t="cancel",o="error"}const a={transactionStatus:t,status:o,rawData:{type:"PAYMENT_RESULT",status:e}};return null===(s=p.onError)||void 0===s||s.call(p,a),void k()}if("object"!=typeof(f=n.data)||null===f||"string"!=typeof f.transaction_status)return;var f;const m=function(n){const e=n.transaction_status;return{transactionStatus:e,status:(t=e,a.includes(t)?"success":r.includes(t)?"pending":(i.includes(t),"error")),rawData:n};var t}(n.data);switch(m.status){case"success":null===(l=p.onSuccess)||void 0===l||l.call(p,m);break;case"pending":null===(c=p.onPending)||void 0===c||c.call(p,m);break;case"error":null===(u=p.onError)||void 0===u||u.call(p,m)}}function x(n){"Escape"===n.key&&k()}function w(n){n.target.id===p&&k()}function E(n,e,o,a){const r=function(n){return`${l.sandbox?l.sandboxPaymentUrl:l.productionPaymentUrl}/${n}`}(e);if(document.getElementById(u))return;!function(){if(document.getElementById("opg-sdk-styles"))return;const n=document.createElement("style");n.id="opg-sdk-styles",n.textContent=`\n #${p} {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.6);\n z-index: 999998;\n }\n\n #${f} {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 90%;\n max-width: 480px;\n height: 80%;\n max-height: 700px;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n z-index: 999999;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n #${y} {\n position: absolute;\n top: 12px;\n right: 12px;\n width: 32px;\n height: 32px;\n border: none;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n transition: background 0.2s;\n }\n\n #${y}:hover {\n background: rgba(0, 0, 0, 0.2);\n }\n\n #${y}::before,\n #${y}::after {\n content: '';\n position: absolute;\n width: 16px;\n height: 2px;\n background: #333;\n }\n\n #${y}::before {\n transform: rotate(45deg);\n }\n\n #${y}::after {\n transform: rotate(-45deg);\n }\n\n #${m} {\n width: 100%;\n height: 100%;\n border: none;\n flex: 1;\n }\n\n #${b} {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 40px;\n height: 40px;\n border: 3px solid #f3f3f3;\n border-top: 3px solid #3498db;\n border-radius: 50%;\n animation: opg-spin 1s linear infinite;\n }\n\n @keyframes opg-spin {\n 0% { transform: translate(-50%, -50%) rotate(0deg); }\n 100% { transform: translate(-50%, -50%) rotate(360deg); }\n }\n\n #${b}.hidden {\n display: none;\n }\n `,document.head.appendChild(n)}(),document.body.style.overflow="hidden";const i=document.createElement("div");i.id=u;const d=document.createElement("div");d.id=p,d.addEventListener("click",w);const s=document.createElement("div");s.id=f;const c=document.createElement("button");c.id=y,c.type="button",c.setAttribute("aria-label","Close payment"),c.addEventListener("click",()=>k());const E=document.createElement("div");E.id=b;const P=document.createElement("iframe");var S;P.id=m,P.src=r,P.setAttribute("allow","payment"),P.setAttribute("allow","clipboard-write"),P.addEventListener("load",()=>{E.classList.add("hidden")}),P.onload=()=>{var e;null===(e=P.contentWindow)||void 0===e||e.postMessage({type:"INIT",clientSecret:n,publicKey:o,token:a},r)},s.appendChild(c),s.appendChild(E),s.appendChild(P),i.appendChild(d),i.appendChild(s),document.body.appendChild(i),g=h,v=x,window.addEventListener("message",g),document.addEventListener("keydown",v),S={isOpen:!0,url:r},t={...t,...S}}function k(){const n=document.getElementById(u);n&&(g&&(window.removeEventListener("message",g),g=null),v&&(document.removeEventListener("keydown",v),v=null),n.remove(),document.body.style.overflow="",t={...e,isOpen:!1,callbacks:t.callbacks})}var P,S,C;const $=null!==(S=null===(P=document.currentScript)||void 0===P?void 0:P.getAttribute("data-client-key"))&&void 0!==S?S:void 0;function T(n){if(o())return void console.warn("[opg-sdk] Payment modal is already open");if(!n.token)throw new Error("[opg-sdk] Payment token is required");if(!n.clientSecret)throw new Error("[opg-sdk] Payment clientSecret is required");if(!n.paymentId)throw new Error("[opg-sdk] Payment paymentId is required");if(!$)throw new Error("[opg-sdk] Payment publicKey is required");void 0!==n.sandbox&&c({sandbox:n.sandbox});const{clientSecret:e,paymentId:a,token:r,onSuccess:i,onPending:d,onError:s}=n;var l;l={onSuccess:i,onPending:d,onError:s},t.callbacks=l,E(e,a,$,r)}function L(){k()}function A(){return o()}function O(n){c(n)}function _(){return l.sandbox}c({sandbox:"false"!==(null===(C=document.currentScript)||void 0===C?void 0:C.getAttribute("data-sandbox"))});const I={openPayment:T,closePayment:L,isPaymentOpen:A,configure:O,isSandbox:_};n.closePayment=L,n.configure=O,n.default=I,n.isPaymentOpen=A,n.isSandbox=_,n.openPayment=T,Object.defineProperty(n,"__esModule",{value:!0})});
2
+ //# sourceMappingURL=opg-sdk.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opg-sdk.umd.js","sources":["../src/state.ts","../src/utils.ts","../src/config.ts","../src/modal.ts","../src/index.ts"],"sourcesContent":["import type { ModalState, PaymentCallbacks } from './types';\n\nconst initialState: ModalState = {\n isOpen: false,\n url: null,\n callbacks: {},\n};\n\nlet state: ModalState = { ...initialState };\n\nexport function getState(): ModalState {\n return state;\n}\n\nexport function setState(newState: Partial<ModalState>): void {\n state = { ...state, ...newState };\n}\n\nexport function resetState(): void {\n state = { ...initialState, isOpen: false, callbacks: state.callbacks };\n}\n\nexport function isOpen(): boolean {\n return state.isOpen;\n}\n\nexport function getCallbacks(): PaymentCallbacks {\n return state.callbacks;\n}\n\nexport function setCallbacks(callbacks: PaymentCallbacks): void {\n state.callbacks = callbacks;\n}\n","import type { TransactionStatus, PaymentResultStatus, PaymentResult, PaymentMessage } from './types';\n\nconst SUCCESS_STATUSES: TransactionStatus[] = ['settlement', 'capture'];\nconst PENDING_STATUSES: TransactionStatus[] = ['pending', 'challenge'];\nconst ERROR_STATUSES: TransactionStatus[] = ['deny', 'cancel', 'expire', 'failure'];\n\nexport function mapTransactionStatus(status: TransactionStatus): PaymentResultStatus {\n if (SUCCESS_STATUSES.includes(status)) return 'success';\n if (PENDING_STATUSES.includes(status)) return 'pending';\n if (ERROR_STATUSES.includes(status)) return 'error';\n return 'error';\n}\n\nexport function isValidPaymentMessage(data: unknown): data is PaymentMessage {\n if (typeof data !== 'object' || data === null) return false;\n const msg = data as Record<string, unknown>;\n return typeof msg.transaction_status === 'string';\n}\n\nexport function createPaymentResult(message: PaymentMessage): PaymentResult {\n const transactionStatus = message.transaction_status;\n return {\n transactionStatus,\n status: mapTransactionStatus(transactionStatus),\n rawData: message,\n };\n}\n\nexport function lockBodyScroll(): void {\n document.body.style.overflow = 'hidden';\n}\n\nexport function unlockBodyScroll(): void {\n document.body.style.overflow = '';\n}\n","export interface SDKConfig {\n sandbox: boolean;\n sandboxPaymentUrl: string;\n productionPaymentUrl: string;\n}\n\nconst DEFAULT_CONFIG: SDKConfig = {\n sandbox: true,\n sandboxPaymentUrl: process.env.OPG_SANDBOX_PAYMENT_URL ?? \"\",\n productionPaymentUrl: process.env.OPG_PRODUCTION_PAYMENT_URL ?? \"\",\n};\n\nlet currentConfig: SDKConfig = { ...DEFAULT_CONFIG };\n\nexport function configure(config: Partial<SDKConfig>): void {\n currentConfig = { ...currentConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return currentConfig;\n}\n\nexport function getPaymentUrl(paymentId: string): string {\n const baseUrl = currentConfig.sandbox \n ? currentConfig.sandboxPaymentUrl \n : currentConfig.productionPaymentUrl;\n \n return `${baseUrl}/${paymentId}`;\n}\n\nexport function isSandboxMode(): boolean {\n return currentConfig.sandbox;\n}\n","import { getCallbacks, setState, resetState } from './state';\nimport { isValidPaymentMessage, createPaymentResult, lockBodyScroll, unlockBodyScroll } from './utils';\nimport { getPaymentUrl } from './config';\n\nconst MODAL_ID = 'opg-payment-modal';\nconst BACKDROP_ID = 'opg-payment-backdrop';\nconst CONTAINER_ID = 'opg-payment-container';\nconst IFRAME_ID = 'opg-payment-iframe';\nconst CLOSE_BTN_ID = 'opg-payment-close';\nconst SPINNER_ID = 'opg-payment-spinner';\n\nlet messageHandler: ((event: MessageEvent) => void) | null = null;\nlet keyHandler: ((event: KeyboardEvent) => void) | null = null;\n\nfunction injectStyles(): void {\n if (document.getElementById('opg-sdk-styles')) return;\n\n const style = document.createElement('style');\n style.id = 'opg-sdk-styles';\n style.textContent = `\n #${BACKDROP_ID} {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.6);\n z-index: 999998;\n }\n\n #${CONTAINER_ID} {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 90%;\n max-width: 480px;\n height: 80%;\n max-height: 700px;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n z-index: 999999;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n #${CLOSE_BTN_ID} {\n position: absolute;\n top: 12px;\n right: 12px;\n width: 32px;\n height: 32px;\n border: none;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n transition: background 0.2s;\n }\n\n #${CLOSE_BTN_ID}:hover {\n background: rgba(0, 0, 0, 0.2);\n }\n\n #${CLOSE_BTN_ID}::before,\n #${CLOSE_BTN_ID}::after {\n content: '';\n position: absolute;\n width: 16px;\n height: 2px;\n background: #333;\n }\n\n #${CLOSE_BTN_ID}::before {\n transform: rotate(45deg);\n }\n\n #${CLOSE_BTN_ID}::after {\n transform: rotate(-45deg);\n }\n\n #${IFRAME_ID} {\n width: 100%;\n height: 100%;\n border: none;\n flex: 1;\n }\n\n #${SPINNER_ID} {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 40px;\n height: 40px;\n border: 3px solid #f3f3f3;\n border-top: 3px solid #3498db;\n border-radius: 50%;\n animation: opg-spin 1s linear infinite;\n }\n\n @keyframes opg-spin {\n 0% { transform: translate(-50%, -50%) rotate(0deg); }\n 100% { transform: translate(-50%, -50%) rotate(360deg); }\n }\n\n #${SPINNER_ID}.hidden {\n display: none;\n }\n `;\n document.head.appendChild(style);\n}\n\nfunction handleMessage(event: MessageEvent): void {\n const callbacks = getCallbacks();\n\n if (event.data.type === \"COPY_TEXT\") {\n navigator.clipboard.writeText(event.data.value);\n return;\n }\n\n if (event.data?.type === 'PAYMENT_SUCCESS') {\n\n const result = {\n transactionStatus: 'settlement' as const,\n status: 'success' as const,\n rawData: { type: 'PAYMENT_SUCCESS' },\n };\n\n callbacks.onSuccess?.(result);\n closeModal();\n return;\n }\n\n if (event.data?.type === 'PAYMENT_RESULT') {\n const status = event.data.status;\n let transactionStatus: string;\n let mappedStatus: 'success' | 'pending' | 'error';\n\n switch (status) {\n case 'expired':\n transactionStatus = 'expire';\n mappedStatus = 'error';\n break;\n case 'failed':\n transactionStatus = 'failure';\n mappedStatus = 'error';\n break;\n case 'canceled':\n transactionStatus = 'cancel';\n mappedStatus = 'error';\n break;\n default:\n transactionStatus = 'failure';\n mappedStatus = 'error';\n }\n\n const result = {\n transactionStatus: transactionStatus as any,\n status: mappedStatus,\n rawData: { type: 'PAYMENT_RESULT', status },\n };\n\n callbacks.onError?.(result);\n closeModal();\n return;\n }\n\n if (!isValidPaymentMessage(event.data)) return;\n\n const result = createPaymentResult(event.data);\n\n switch (result.status) {\n case 'success':\n callbacks.onSuccess?.(result);\n break;\n case 'pending':\n callbacks.onPending?.(result);\n break;\n case 'error':\n callbacks.onError?.(result);\n break;\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') {\n closeModal();\n }\n}\n\nfunction handleBackdropClick(event: MouseEvent): void {\n if ((event.target as HTMLElement).id === BACKDROP_ID) {\n closeModal();\n }\n}\n\nexport function createModal(clientSecret: string, paymentId: string, publicKey: string, token: string): void {\n const url = getPaymentUrl(paymentId);\n if (document.getElementById(MODAL_ID)) return;\n\n injectStyles();\n lockBodyScroll();\n\n const modal = document.createElement('div');\n modal.id = MODAL_ID;\n\n const backdrop = document.createElement('div');\n backdrop.id = BACKDROP_ID;\n backdrop.addEventListener('click', handleBackdropClick);\n\n const container = document.createElement('div');\n container.id = CONTAINER_ID;\n\n const closeBtn = document.createElement('button');\n closeBtn.id = CLOSE_BTN_ID;\n closeBtn.type = 'button';\n closeBtn.setAttribute('aria-label', 'Close payment');\n closeBtn.addEventListener('click', () => closeModal());\n\n const spinner = document.createElement('div');\n spinner.id = SPINNER_ID;\n const iframe = document.createElement('iframe');\n iframe.id = IFRAME_ID;\n iframe.src = url;\n iframe.setAttribute('allow', 'payment');\n iframe.setAttribute(\"allow\", \"clipboard-write\");\n iframe.addEventListener('load', () => {\n spinner.classList.add('hidden');\n });\n\n iframe.onload = () => {\n iframe.contentWindow?.postMessage(\n {\n type: \"INIT\",\n clientSecret,\n publicKey,\n token\n },\n url\n );\n };\n\n container.appendChild(closeBtn);\n container.appendChild(spinner);\n container.appendChild(iframe);\n modal.appendChild(backdrop);\n modal.appendChild(container);\n document.body.appendChild(modal);\n\n messageHandler = handleMessage;\n keyHandler = handleKeydown;\n window.addEventListener('message', messageHandler);\n document.addEventListener('keydown', keyHandler);\n\n setState({ isOpen: true, url });\n}\n\nexport function closeModal(): void {\n const modal = document.getElementById(MODAL_ID);\n if (!modal) return;\n\n if (messageHandler) {\n window.removeEventListener('message', messageHandler);\n messageHandler = null;\n }\n\n if (keyHandler) {\n document.removeEventListener('keydown', keyHandler);\n keyHandler = null;\n }\n\n modal.remove();\n unlockBodyScroll();\n\n resetState();\n}\n","import type { OpenPaymentOptions, OPGSDK, SDKConfiguration } from './types';\nimport { isOpen, setCallbacks } from './state';\nimport { createModal, closeModal } from './modal';\nimport { configure as configureSDK, isSandboxMode, getConfig } from './config';\n\nexport type {\n TransactionStatus,\n PaymentResultStatus,\n PaymentResult,\n PaymentCallbacks,\n OpenPaymentOptions,\n OPGSDK,\n SDKConfiguration,\n} from './types';\n\nconst publicKey = document.currentScript?.getAttribute(\"data-client-key\") ?? undefined;\nconst sandboxAttr = document.currentScript?.getAttribute(\"data-sandbox\");\nconst isSandboxFromAttr = sandboxAttr !== 'false';\n\nconfigureSDK({ sandbox: isSandboxFromAttr });\n\nfunction openPayment(options: OpenPaymentOptions): void {\n if (isOpen()) {\n console.warn('[opg-sdk] Payment modal is already open');\n return;\n }\n\n if (!options.token) {\n throw new Error('[opg-sdk] Payment token is required');\n }\n\n if (!options.clientSecret) {\n throw new Error('[opg-sdk] Payment clientSecret is required');\n }\n\n if (!options.paymentId) {\n throw new Error('[opg-sdk] Payment paymentId is required');\n }\n\n if (!publicKey) {\n throw new Error('[opg-sdk] Payment publicKey is required');\n }\n\n if (options.sandbox !== undefined) {\n configureSDK({ sandbox: options.sandbox });\n }\n\n const { clientSecret, paymentId, token, onSuccess, onPending, onError } = options;\n\n setCallbacks({\n onSuccess,\n onPending,\n onError,\n });\n\n createModal(clientSecret, paymentId, publicKey, token);\n}\n\nfunction closePayment(): void {\n closeModal();\n}\n\nfunction isPaymentOpen(): boolean {\n return isOpen();\n}\n\nfunction configure(config: Partial<SDKConfiguration>): void {\n configureSDK(config);\n}\n\nfunction isSandbox(): boolean {\n return isSandboxMode();\n}\n\nconst OPG: OPGSDK = {\n openPayment,\n closePayment,\n isPaymentOpen,\n configure,\n isSandbox,\n};\n\nexport { openPayment, closePayment, isPaymentOpen, configure, isSandbox };\nexport default OPG;\n"],"names":["initialState","isOpen","url","callbacks","state","SUCCESS_STATUSES","PENDING_STATUSES","ERROR_STATUSES","currentConfig","sandbox","sandboxPaymentUrl","productionPaymentUrl","configure","config","MODAL_ID","BACKDROP_ID","CONTAINER_ID","IFRAME_ID","CLOSE_BTN_ID","SPINNER_ID","messageHandler","keyHandler","handleMessage","event","data","type","navigator","clipboard","writeText","value","_a","result","transactionStatus","status","rawData","_b","onSuccess","call","closeModal","_c","mappedStatus","_d","onError","transaction_status","message","includes","createPaymentResult","_e","_f","onPending","_g","handleKeydown","key","handleBackdropClick","target","id","createModal","clientSecret","paymentId","publicKey","token","getPaymentUrl","document","getElementById","style","createElement","textContent","head","appendChild","injectStyles","body","overflow","modal","backdrop","addEventListener","container","closeBtn","setAttribute","spinner","iframe","newState","src","classList","add","onload","contentWindow","postMessage","window","removeEventListener","remove","currentScript","getAttribute","undefined","openPayment","options","console","warn","Error","configureSDK","closePayment","isPaymentOpen","isSandbox","OPG"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ModalState, PaymentCallbacks } from './types';
2
+ export declare function getState(): ModalState;
3
+ export declare function setState(newState: Partial<ModalState>): void;
4
+ export declare function resetState(): void;
5
+ export declare function isOpen(): boolean;
6
+ export declare function getCallbacks(): PaymentCallbacks;
7
+ export declare function setCallbacks(callbacks: PaymentCallbacks): void;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * OPG SDK Types
3
+ * Client-only payment modal SDK
4
+ */
5
+ /**
6
+ * Transaction status values from payment page postMessage
7
+ */
8
+ export type TransactionStatus = 'settlement' | 'capture' | 'pending' | 'challenge' | 'deny' | 'cancel' | 'expire' | 'failure';
9
+ /**
10
+ * Mapped payment result status
11
+ */
12
+ export type PaymentResultStatus = 'success' | 'pending' | 'error';
13
+ /**
14
+ * Payment result object passed to callbacks
15
+ */
16
+ export interface PaymentResult {
17
+ /** Original transaction status from payment page */
18
+ transactionStatus: TransactionStatus;
19
+ /** Mapped status category */
20
+ status: PaymentResultStatus;
21
+ /** Raw message data from postMessage */
22
+ rawData: Record<string, unknown>;
23
+ }
24
+ /**
25
+ * Callback functions for payment events
26
+ */
27
+ export interface PaymentCallbacks {
28
+ /** Called when payment is successful (settlement, capture) */
29
+ onSuccess?: (result: PaymentResult) => void;
30
+ /** Called when payment is pending (pending, challenge) */
31
+ onPending?: (result: PaymentResult) => void;
32
+ /** Called when payment fails (deny, cancel, expire, failure) */
33
+ onError?: (result: PaymentResult) => void;
34
+ }
35
+ /**
36
+ * Options for opening payment modal
37
+ */
38
+ export interface OpenPaymentOptions extends PaymentCallbacks {
39
+ token: string;
40
+ clientSecret: string;
41
+ paymentId: string;
42
+ sandbox?: boolean;
43
+ }
44
+ /**
45
+ * Internal modal state
46
+ */
47
+ export interface ModalState {
48
+ isOpen: boolean;
49
+ url: string | null;
50
+ callbacks: PaymentCallbacks;
51
+ }
52
+ /**
53
+ * Expected message format from payment page
54
+ */
55
+ export interface PaymentMessage {
56
+ transaction_status: TransactionStatus;
57
+ [key: string]: unknown;
58
+ }
59
+ /**
60
+ * OPG SDK public interface
61
+ */
62
+ export interface OPGSDK {
63
+ openPayment: (options: OpenPaymentOptions) => void;
64
+ closePayment: () => void;
65
+ isPaymentOpen: () => boolean;
66
+ configure: (config: Partial<SDKConfiguration>) => void;
67
+ isSandbox: () => boolean;
68
+ }
69
+ export interface SDKConfiguration {
70
+ sandbox: boolean;
71
+ sandboxPaymentUrl: string;
72
+ productionPaymentUrl: string;
73
+ }
@@ -0,0 +1,6 @@
1
+ import type { TransactionStatus, PaymentResultStatus, PaymentResult, PaymentMessage } from './types';
2
+ export declare function mapTransactionStatus(status: TransactionStatus): PaymentResultStatus;
3
+ export declare function isValidPaymentMessage(data: unknown): data is PaymentMessage;
4
+ export declare function createPaymentResult(message: PaymentMessage): PaymentResult;
5
+ export declare function lockBodyScroll(): void;
6
+ export declare function unlockBodyScroll(): void;
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@ojire/pg-js-sdk",
3
+ "version": "1.0.0",
4
+ "description": "Client-only payment modal SDK for browser environments",
5
+ "type": "module",
6
+ "main": "dist/opg-sdk.umd.js",
7
+ "module": "dist/opg-sdk.esm.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/opg-sdk.esm.js",
12
+ "require": "./dist/opg-sdk.umd.js",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "rollup -c",
21
+ "build:types": "tsc --emitDeclarationOnly",
22
+ "dev": "rollup -c -w",
23
+ "clean": "rm -rf dist",
24
+ "prepublishOnly": "npm run clean && npm run build && npm run build:types"
25
+ },
26
+ "keywords": [
27
+ "payment",
28
+ "gateway",
29
+ "ojire",
30
+ "opg",
31
+ "qris",
32
+ "virtual-account",
33
+ "credit-card"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "github.com/ojire-tech/opg-sdk"
38
+ },
39
+ "author": "Ojire",
40
+ "license": "MIT",
41
+ "devDependencies": {
42
+ "@rollup/plugin-replace": "^6.0.3",
43
+ "@rollup/plugin-terser": "^0.4.4",
44
+ "@rollup/plugin-typescript": "^11.1.6",
45
+ "dotenv": "^17.2.3",
46
+ "rollup": "^4.9.6",
47
+ "tslib": "^2.6.2",
48
+ "typescript": "^5.3.3"
49
+ },
50
+ "browserslist": [
51
+ "> 1%",
52
+ "last 2 versions",
53
+ "not dead"
54
+ ]
55
+ }