UNPKG

@openlib.dev/mn-payment-sdk

Version:

Монголын төлбөрийн хэрэгсэлүүд SDK

1 lines 117 kB
{"version":3,"sources":["../src/qpay/apis.ts","../src/qpay/client.ts","../src/common/errors/payment-error.ts","../src/common/errors/http-error-handler.ts","../src/qpay/index.ts","../src/golomt/client.ts","../src/golomt/apis.ts","../src/ebarimt/client.ts","../src/hipay/client.ts","../src/hipay/apis.ts","../src/mongolchat/client.ts","../src/mongolchat/apis.ts","../src/pass/client.ts","../src/pass/apis.ts","../src/socialpay/apis.ts","../src/socialpay/client.ts","../src/storepay/apis.ts","../src/storepay/client.ts","../src/tokipay/client.ts","../src/tokipay/apis.ts","../src/monpay/types.ts","../src/monpay/client.ts","../src/monpay/apis.ts","../src/tdb-cg/client.ts"],"sourcesContent":["import { API } from \"../types\";\n\nexport const QPayAuthToken = {\n url: '/auth/token',\n method: 'POST'\n} as const;\n\nexport const QPayAuthRefresh = {\n url: '/auth/refresh',\n method: 'POST'\n} as const;\n\nexport const QPayPaymentGet = {\n url: '/payment/get/',\n method: 'GET'\n} as const;\n\nexport const QPayPaymentCheck = {\n url: '/payment/check',\n method: 'POST'\n} as const;\n\nexport const QPayPaymentCancel = {\n url: '/payment/cancel',\n method: 'DELETE'\n} as const;\n\nexport const QPayPaymentRefund = {\n url: '/payment/refund/',\n method: 'DELETE'\n} as const;\n\nexport const QPayPaymentList = {\n url: '/payment/url',\n method: 'POST'\n} as const;\n\nexport const QPayInvoiceCreate = {\n url: '/invoice',\n method: 'POST'\n} as const;\n\nexport const QPayInvoiceGet = {\n url: '/invoice/',\n method: 'GET'\n} as const;\n\nexport const QPayInvoiceCancel = {\n url: '/invoice/',\n method: 'DELETE'\n} as const;\n","import axios, { AxiosRequestConfig } from 'axios';\nimport {\n QPayConfig,\n QPayLoginResponse,\n QPayCreateInvoiceInput,\n QPaySimpleInvoiceRequest,\n QPaySimpleInvoiceResponse,\n QPayInvoiceGetResponse,\n QPayPaymentCheckRequest,\n QPayPaymentCheckResponse,\n QPayPaymentCancelRequest,\n QPayPaymentListRequest\n} from './types';\nimport {\n QPayAuthToken,\n QPayAuthRefresh,\n QPayPaymentGet,\n QPayPaymentCheck,\n QPayPaymentCancel,\n QPayPaymentRefund,\n QPayPaymentList,\n QPayInvoiceCreate,\n QPayInvoiceGet,\n QPayInvoiceCancel\n} from './apis';\nimport { HttpErrorHandler, PaymentError, PaymentErrorCode } from '../common/errors';\nimport { API } from '../types';\n\nconst MAX_RETRIES = 3;\nconst TIMEOUT_MS = 30000; // 30 seconds\nconst RETRY_DELAY_MS = 1000; // 1 second\n\nexport class QpayClient {\n private endpoint: string;\n private password: string;\n private username: string;\n private callback: string;\n private invoiceCode: string;\n private merchantId: string;\n private loginObject: QPayLoginResponse | null;\n\n constructor(config: QPayConfig) {\n this.endpoint = config.endpoint;\n this.password = config.password;\n this.username = config.username;\n this.callback = config.callback;\n this.invoiceCode = config.invoiceCode;\n this.merchantId = config.merchantId;\n this.loginObject = null;\n }\n\n private async sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n private async makeRequest<T>(config: AxiosRequestConfig): Promise<T> {\n let lastError: any;\n \n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n console.log(`[QPayClient] Making ${config.method} request to ${config.url} (Attempt ${attempt}/${MAX_RETRIES})`);\n const response = await axios(config);\n const data = response.data;\n\n if (data.error) {\n throw new PaymentError({\n code: PaymentErrorCode.PAYMENT_FAILED,\n message: data.error || 'Payment failed',\n provider: 'qpay',\n requestId: data.id || data.error\n });\n }\n\n console.log(`[QPayClient] Successfully completed ${config.method} request to ${config.url}`);\n return data;\n } catch (error: any) {\n lastError = error;\n \n // Don't retry if it's a business logic error\n if (error instanceof PaymentError) {\n throw error;\n }\n\n // Check if we should retry\n const isRetryable = error.code === 'ECONNABORTED' || // Timeout\n error.code === 'ECONNRESET' || // Connection reset\n error.code === 'ETIMEDOUT' || // Connection timeout\n (error.response && error.response.status >= 500); // Server errors\n\n if (!isRetryable || attempt === MAX_RETRIES) {\n break;\n }\n\n console.log(`[QPayClient] Request failed, retrying in ${RETRY_DELAY_MS}ms... (Error: ${error.message})`);\n await this.sleep(RETRY_DELAY_MS * attempt); // Exponential backoff\n }\n }\n\n HttpErrorHandler.handleError('qpay', lastError);\n }\n\n private async httpRequest<T>(body: any, api: API, urlExt: string = ''): Promise<T> {\n try {\n const authObj = await this.authQpayV2();\n this.loginObject = authObj;\n\n const config: AxiosRequestConfig = {\n method: api.method,\n url: this.endpoint + api.url + urlExt,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.loginObject.accessToken}`\n },\n timeout: TIMEOUT_MS\n };\n\n if (body) {\n config.data = body;\n }\n\n return this.makeRequest<T>(config);\n } catch (error) {\n HttpErrorHandler.handleError('qpay', error);\n }\n }\n\n private async authQpayV2(): Promise<QPayLoginResponse> {\n // Check if loginObject is valid\n if (this.loginObject) {\n const expireInA = new Date(this.loginObject.expiresIn * 1000);\n const expireInB = new Date(expireInA.getTime() - 12 * 60 * 60 * 1000);\n const now = new Date();\n if (now < expireInB) {\n return this.loginObject;\n }\n }\n\n try {\n const config: AxiosRequestConfig = {\n method: QPayAuthToken.method,\n url: this.endpoint + QPayAuthToken.url,\n headers: {\n 'Content-Type': 'application/json'\n },\n auth: {\n username: this.username,\n password: this.password\n },\n timeout: TIMEOUT_MS\n };\n\n console.log(`[QPayClient] Making authentication request (Attempt 1/1)`);\n const response = await axios(config);\n const data = response.data;\n\n if (data.error) {\n throw new PaymentError({\n code: PaymentErrorCode.UNAUTHORIZED,\n message: data.error || 'Authentication failed',\n provider: 'qpay'\n });\n }\n\n console.log(`[QPayClient] Successfully authenticated`);\n return data;\n } catch (error) {\n HttpErrorHandler.handleError('qpay', error);\n }\n }\n\n private async refreshToken(): Promise<QPayLoginResponse> {\n if (!this.loginObject) {\n throw new Error('No login object available');\n }\n\n const config: AxiosRequestConfig = {\n method: QPayAuthRefresh.method,\n url: this.endpoint + QPayAuthRefresh.url,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.loginObject.refreshToken}`\n }\n };\n\n try {\n const response = await axios(config);\n return response.data;\n } catch (error: any) {\n if (error.response?.data) {\n throw new Error(error.response.data.error || error.response.data);\n }\n throw error;\n }\n }\n\n async createInvoice(input: QPayCreateInvoiceInput): Promise<QPaySimpleInvoiceResponse> {\n const vals = new URLSearchParams();\n for (const [key, value] of Object.entries(input.callbackParam)) {\n vals.append(key, value);\n }\n\n const request: QPaySimpleInvoiceRequest = {\n invoiceCode: this.invoiceCode,\n senderInvoiceCode: input.senderCode,\n senderBranchCode: input.senderBranchCode,\n invoiceReceiverCode: input.receiverCode,\n invoiceDescription: input.description,\n amount: input.amount,\n callbackUrl: `${this.callback}?${vals.toString()}`\n };\n\n return this.httpRequest<QPaySimpleInvoiceResponse>(\n request,\n QPayInvoiceCreate\n );\n }\n\n async getInvoice(invoiceId: string): Promise<QPayInvoiceGetResponse> {\n return this.httpRequest<QPayInvoiceGetResponse>(\n null,\n QPayInvoiceGet,\n invoiceId\n );\n }\n\n async cancelInvoice(invoiceId: string): Promise<any> {\n return this.httpRequest<any>(\n null,\n QPayInvoiceCancel,\n invoiceId\n );\n }\n\n async getPayment(invoiceId: string): Promise<any> {\n return this.httpRequest<any>(\n null,\n QPayPaymentGet,\n invoiceId\n );\n }\n\n async checkPayment(invoiceId: string, pageLimit: number, pageNumber: number): Promise<QPayPaymentCheckResponse> {\n const request: QPayPaymentCheckRequest = {\n objectID: invoiceId,\n objectType: 'INVOICE',\n offset: {\n pageLimit,\n pageNumber\n }\n };\n\n return this.httpRequest<QPayPaymentCheckResponse>(\n request,\n QPayPaymentCheck\n );\n }\n\n async cancelPayment(invoiceId: string, paymentUUID: string): Promise<QPayPaymentCheckResponse> {\n const request: QPayPaymentCancelRequest = {\n callbackUrl: this.callback + paymentUUID,\n note: `Cancel payment - ${invoiceId}`\n };\n\n return this.httpRequest<QPayPaymentCheckResponse>(\n request,\n QPayPaymentCancel,\n invoiceId\n );\n }\n\n async refundPayment(invoiceId: string, paymentUUID: string): Promise<any> {\n const request: QPayPaymentCancelRequest = {\n callbackUrl: this.callback + paymentUUID,\n note: `Cancel payment - ${invoiceId}`\n };\n\n return this.httpRequest<any>(\n request,\n QPayPaymentRefund,\n invoiceId\n );\n }\n} ","export enum PaymentErrorCode {\n // Common errors\n INVALID_REQUEST = 'INVALID_REQUEST',\n UNAUTHORIZED = 'UNAUTHORIZED',\n INTERNAL_ERROR = 'INTERNAL_ERROR',\n NETWORK_ERROR = 'NETWORK_ERROR',\n TIMEOUT = 'TIMEOUT',\n INVALID_RESPONSE = 'INVALID_RESPONSE',\n \n // Payment specific errors\n PAYMENT_FAILED = 'PAYMENT_FAILED',\n PAYMENT_CANCELLED = 'PAYMENT_CANCELLED',\n PAYMENT_EXPIRED = 'PAYMENT_EXPIRED',\n PAYMENT_DUPLICATE = 'PAYMENT_DUPLICATE',\n INSUFFICIENT_FUNDS = 'INSUFFICIENT_FUNDS',\n INVALID_AMOUNT = 'INVALID_AMOUNT',\n INVALID_CURRENCY = 'INVALID_CURRENCY',\n \n // Provider specific errors\n PROVIDER_ERROR = 'PROVIDER_ERROR',\n PROVIDER_UNAVAILABLE = 'PROVIDER_UNAVAILABLE',\n PROVIDER_TIMEOUT = 'PROVIDER_TIMEOUT'\n}\n\nexport interface PaymentErrorDetails {\n code: PaymentErrorCode;\n message: string;\n provider?: string;\n originalError?: any;\n requestId?: string;\n timestamp?: number;\n}\n\nexport class PaymentError extends Error {\n public readonly code: PaymentErrorCode;\n public readonly provider?: string;\n public readonly originalError?: any;\n public readonly requestId?: string;\n public readonly timestamp: number;\n\n constructor(details: PaymentErrorDetails) {\n super(details.message);\n this.name = 'PaymentError';\n this.code = details.code;\n this.provider = details.provider;\n this.originalError = details.originalError;\n this.requestId = details.requestId;\n this.timestamp = details.timestamp || Date.now();\n }\n\n public toJSON(): PaymentErrorDetails {\n return {\n code: this.code,\n message: this.message,\n provider: this.provider,\n originalError: this.originalError,\n requestId: this.requestId,\n timestamp: this.timestamp\n };\n }\n\n public static fromProviderError(provider: string, error: any): PaymentError {\n const details: PaymentErrorDetails = {\n code: PaymentErrorCode.PROVIDER_ERROR,\n message: error.message || 'Unknown provider error',\n provider,\n originalError: error\n };\n\n if (error.response?.data) {\n details.message = error.response.data.error || error.response.data.message || details.message;\n }\n\n return new PaymentError(details);\n }\n\n public static fromNetworkError(error: any): PaymentError {\n return new PaymentError({\n code: PaymentErrorCode.NETWORK_ERROR,\n message: error.message || 'Network error occurred',\n originalError: error\n });\n }\n\n public static fromTimeoutError(error: any): PaymentError {\n return new PaymentError({\n code: PaymentErrorCode.TIMEOUT,\n message: error.message || 'Request timed out',\n originalError: error\n });\n }\n} ","import axios, { AxiosError } from 'axios';\nimport { PaymentError, PaymentErrorCode } from './payment-error';\n\ninterface ErrorResponse {\n message?: string;\n error?: string;\n [key: string]: any;\n}\n\nexport class HttpErrorHandler {\n public static handleError(provider: string, error: unknown): never {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError;\n \n // Handle network errors\n if (!axiosError.response) {\n throw PaymentError.fromNetworkError(error);\n }\n\n // Handle timeout errors\n if (axiosError.code === 'ECONNABORTED') {\n throw PaymentError.fromTimeoutError(error);\n }\n\n // Handle HTTP status code errors\n const status = axiosError.response.status;\n const data = axiosError.response.data as ErrorResponse;\n\n switch (status) {\n case 400:\n throw new PaymentError({\n code: PaymentErrorCode.INVALID_REQUEST,\n message: data?.message || data?.error || 'Invalid request',\n provider,\n originalError: error\n });\n\n case 401:\n case 403:\n throw new PaymentError({\n code: PaymentErrorCode.UNAUTHORIZED,\n message: data?.message || data?.error || 'Unauthorized access',\n provider,\n originalError: error\n });\n\n case 404:\n throw new PaymentError({\n code: PaymentErrorCode.INVALID_REQUEST,\n message: data?.message || data?.error || 'Resource not found',\n provider,\n originalError: error\n });\n\n case 408:\n throw PaymentError.fromTimeoutError(error);\n\n case 429:\n throw new PaymentError({\n code: PaymentErrorCode.PROVIDER_ERROR,\n message: data?.message || data?.error || 'Too many requests',\n provider,\n originalError: error\n });\n\n case 500:\n case 502:\n case 503:\n case 504:\n throw new PaymentError({\n code: PaymentErrorCode.PROVIDER_UNAVAILABLE,\n message: data?.message || data?.error || 'Payment provider is currently unavailable',\n provider,\n originalError: error\n });\n\n default:\n throw PaymentError.fromProviderError(provider, error);\n }\n }\n\n // Handle non-Axios errors\n if (error instanceof Error) {\n throw new PaymentError({\n code: PaymentErrorCode.INTERNAL_ERROR,\n message: error.message,\n provider,\n originalError: error\n });\n }\n\n // Handle unknown errors\n throw new PaymentError({\n code: PaymentErrorCode.INTERNAL_ERROR,\n message: 'An unknown error occurred',\n provider,\n originalError: error\n });\n }\n} ","import { API } from \"../types\";\nimport {\n QPayInvoiceCreate,\n QPayInvoiceGet,\n QPayInvoiceCancel,\n QPayPaymentGet,\n QPayPaymentCheck,\n QPayPaymentCancel,\n QPayPaymentRefund,\n QPayAuthRefresh,\n QPayAuthToken,\n} from \"./apis\";\nimport {\n QPayCreateInvoiceInput,\n QPayInvoiceGetResponse,\n QPayLoginResponse,\n QPayPaymentCancelRequest,\n QPayPaymentCheckRequest,\n QPayPaymentCheckResponse,\n QPaySimpleInvoiceRequest,\n QPaySimpleInvoiceResponse,\n} from \"./types\";\n\nexport class QPay {\n private endpoint: string;\n private password: string;\n private username: string;\n private callback: string;\n private invoiceCode: string;\n private merchantId: string;\n private loginObject: QPayLoginResponse | null;\n\n constructor(\n username: string,\n password: string,\n endpoint: string,\n callback: string,\n invoiceCode: string,\n merchantId: string\n ) {\n this.endpoint = endpoint;\n this.password = password;\n this.username = username;\n this.callback = callback;\n this.invoiceCode = invoiceCode;\n this.merchantId = merchantId;\n this.loginObject = null;\n }\n\n public async createInvoice(\n input: QPayCreateInvoiceInput\n ): Promise<QPaySimpleInvoiceResponse> {\n const vals = new URLSearchParams();\n\n for (const [k, v] of Object.entries(input.callbackParam)) {\n vals.append(k, v);\n }\n\n const amountInt = input.amount;\n const request: QPaySimpleInvoiceRequest = {\n invoiceCode: this.invoiceCode,\n senderInvoiceCode: input.senderCode,\n senderBranchCode: input.senderBranchCode,\n invoiceReceiverCode: input.receiverCode,\n invoiceDescription: input.description,\n amount: amountInt,\n callbackUrl: `${this.callback}?${vals.toString()}`,\n };\n\n const response = await this.httpRequestQPay<QPaySimpleInvoiceResponse>(\n QPayInvoiceCreate,\n \"\",\n request\n );\n\n return response;\n }\n\n public async getInvoice(invoiceId: string): Promise<QPayInvoiceGetResponse> {\n const response = await this.httpRequestQPay<QPayInvoiceGetResponse>(\n QPayInvoiceGet,\n invoiceId\n );\n\n return response;\n }\n\n public async cancelInvoice(invoiceId: string): Promise<{}> {\n const response = await this.httpRequestQPay<{}>(\n QPayInvoiceCancel,\n invoiceId\n );\n\n return response;\n }\n\n public async getPayment(invoiceId: string): Promise<{}> {\n const response = await this.httpRequestQPay<{}>(QPayPaymentGet, invoiceId);\n\n return response;\n }\n\n public async checkPayment(\n invoiceId: string,\n pageLimit: number,\n pageNumber: number\n ): Promise<QPayPaymentCheckResponse> {\n const req: QPayPaymentCheckRequest = {\n objectID: invoiceId,\n objectType: \"INVOICE\",\n offset: {\n pageLimit: pageLimit,\n pageNumber: pageNumber,\n },\n };\n\n const response = await this.httpRequestQPay<QPayPaymentCheckResponse>(\n QPayPaymentCheck,\n \"\",\n req\n );\n\n return response;\n }\n\n public async cancelPayment(\n invoiceId: string,\n paymentUUID: string\n ): Promise<QPayPaymentCheckResponse> {\n const req: QPayPaymentCancelRequest = {\n callbackUrl: `${this.callback}${paymentUUID}`,\n note: `Cancel payment - ${invoiceId}`,\n };\n\n const response = await this.httpRequestQPay<QPayPaymentCheckResponse>(\n QPayPaymentCancel,\n invoiceId,\n req\n );\n\n return response;\n }\n\n public async refundPayment(\n invoiceId: string,\n paymentUUID: string\n ): Promise<{}> {\n const req: QPayPaymentCancelRequest = {\n callbackUrl: `${this.callback}${paymentUUID}`,\n note: `Cancel payment - ${invoiceId}`,\n };\n\n const response = await this.httpRequestQPay<{}>(\n QPayPaymentRefund,\n invoiceId,\n req\n );\n\n return response;\n }\n\n private async authQPayV2(): Promise<QPayLoginResponse> {\n if (this.loginObject) {\n const expireInA = new Date(this.loginObject?.expiresIn * 1000);\n const expireInB = new Date(expireInA.getTime() - 12 * 60 * 60 * 1000);\n const now = new Date();\n\n if (now < expireInB) {\n return this.loginObject;\n }\n }\n\n const url = `${this.endpoint}/${QPayAuthToken.url}`;\n const headers = {\n \"Content-Type\": \"application/json\",\n };\n const basicAuth = btoa(`${this.username}:${this.password}`);\n\n const requestOptions: RequestInit = {\n method: QPayAuthToken.method,\n headers: {\n ...headers,\n Authorization: `Basic ${basicAuth}`,\n },\n };\n\n const response = await fetch(url, requestOptions);\n\n if (!response.ok) {\n const errorMessage = await response.text();\n throw new Error(\n `${new Date().toISOString()}-QPay auth response: ${errorMessage}`\n );\n }\n\n return response.json();\n }\n\n private async httpRequestQPay<T>(\n api: API,\n urlExt: string,\n body?: object\n ): Promise<T> {\n let authObj: QPayLoginResponse | undefined;\n\n authObj = await this.authQPayV2();\n this.loginObject = authObj;\n\n const requestBody = body ? JSON.stringify(body) : \"\";\n const headers = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.loginObject.accessToken}`,\n };\n\n const requestOptions: RequestInit = {\n method: api.method,\n headers,\n body: requestBody,\n };\n\n const response = await fetch(\n `${this.endpoint}${api.url}${urlExt}`,\n requestOptions\n );\n\n if (!response.ok) {\n const errorMessage = await response.text();\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n private async refreshToken(): Promise<QPayLoginResponse> {\n const url = `${this.endpoint}/${QPayAuthRefresh.url}`;\n const headers = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.loginObject?.refreshToken}`,\n };\n\n const requestOptions: RequestInit = {\n method: QPayAuthRefresh.method,\n headers,\n };\n\n const response = await fetch(url, requestOptions);\n\n if (!response.ok) {\n const errorMessage = await response.text();\n throw new Error(\n `${new Date().toISOString()}-QPay token refresh response: ${errorMessage}`\n );\n }\n\n return response.json();\n }\n}\n\nexport * from './types';\nexport * from './client';\nexport * from './apis';\n","import axios from 'axios';\nimport crypto from 'crypto';\nimport {\n GolomtConfig,\n CreateInvoiceInput,\n CreateInvoiceResponse,\n CreateInvoiceRequest,\n InquiryResponse,\n InquiryRequest,\n ByTokenRequest,\n ByTokenResponse,\n Lang,\n PaymentMethod\n} from './types';\nimport {\n ECommerceInvoiceCreate,\n ECommerceInquiry,\n ECommercePayByToken\n} from './apis';\nimport { API } from '../types';\nimport { HttpErrorHandler, PaymentError, PaymentErrorCode } from '../common/errors';\n\nexport class GolomtClient {\n private endpoint: string;\n private secret: string;\n private bearerToken: string;\n\n constructor(config: GolomtConfig) {\n this.endpoint = config.endpoint;\n this.secret = config.secret;\n this.bearerToken = config.bearerToken;\n }\n\n private boolToString(v: boolean): string {\n return v ? 'Y' : 'N';\n }\n\n private generateHMAC(secret: string, data: string): string {\n return crypto\n .createHmac('sha256', secret)\n .update(data)\n .digest('hex');\n }\n\n private appendAsString(...args: any[]): string {\n return args.join('');\n }\n\n getUrlByInvoiceId(invoice: string, lang: Lang, paymentMethod: PaymentMethod): string {\n return `${this.endpoint}/${paymentMethod}/${lang}/${invoice}`;\n }\n\n async payByToken(amount: number, token: string, transactionId: string, lang: string): Promise<ByTokenResponse> {\n const checksum = this.generateHMAC(\n this.secret,\n this.appendAsString(amount, transactionId, token)\n );\n\n const request: ByTokenRequest = {\n amount: amount.toString(),\n checksum,\n token,\n transactionId,\n lang,\n invoice: '' // This will be set by the server\n };\n\n const response = await this.httpRequestGolomtEcommerce<ByTokenResponse>(request, ECommercePayByToken);\n \n if (response.errorCode !== '000') {\n throw new PaymentError({\n code: PaymentErrorCode.PAYMENT_FAILED,\n message: response.errorDesc,\n provider: 'golomt',\n requestId: transactionId\n });\n }\n\n return response;\n }\n\n async createInvoice(input: CreateInvoiceInput): Promise<CreateInvoiceResponse> {\n const amount = input.amount.toFixed(2);\n const checksum = this.generateHMAC(\n this.secret,\n this.appendAsString(\n input.transactionId,\n amount,\n input.returnType,\n input.callback\n )\n );\n\n const request: CreateInvoiceRequest = {\n amount,\n checksum,\n transactionId: input.transactionId,\n returnType: input.returnType,\n callback: input.callback,\n genToken: this.boolToString(input.getToken),\n socialDeeplink: this.boolToString(input.socialDeeplink)\n };\n\n return this.httpRequestGolomtEcommerce<CreateInvoiceResponse>(request, ECommerceInvoiceCreate);\n }\n\n async inquiry(transactionId: string): Promise<InquiryResponse> {\n const checksum = this.generateHMAC(\n this.secret,\n this.appendAsString(transactionId, transactionId)\n );\n\n const request: InquiryRequest = {\n checksum,\n transactionId\n };\n\n const response = await this.httpRequestGolomtEcommerce<InquiryResponse>(request, ECommerceInquiry);\n \n if (response.errorCode !== '000') {\n throw new PaymentError({\n code: PaymentErrorCode.PAYMENT_FAILED,\n message: response.errorDesc,\n provider: 'golomt',\n requestId: transactionId\n });\n }\n\n return response;\n }\n\n private async httpRequestGolomtEcommerce<T>(body: any, api: API): Promise<T> {\n try {\n const response = await axios({\n method: api.method,\n url: `${this.endpoint}${api.url}`,\n data: body,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.bearerToken}`\n }\n });\n\n return response.data;\n } catch (error) {\n HttpErrorHandler.handleError('golomt', error);\n }\n }\n} ","export const ECommerceInvoiceCreate = {\n url: '/api/invoice',\n method: 'POST'\n} as const;\n\nexport const ECommerceInquiry = {\n url: '/api/inquiry',\n method: 'POST'\n} as const;\n\nexport const ECommercePayByToken = {\n url: '/api/pay',\n method: 'POST'\n} as const; ","import axios from 'axios';\nimport {\n EbarimtConfig,\n CreateEbarimtInput,\n CreateEbarimtResponse,\n CreateEbarimtRequest,\n Stock,\n StockInput,\n CheckResponse,\n ReturnBillResponse,\n} from './types';\n\nexport class EbarimtClient {\n private endpoint: string;\n\n constructor(config: EbarimtConfig) {\n this.endpoint = config.endpoint;\n }\n\n private float64ToString(f: number): string {\n return f.toFixed(2);\n }\n\n private stockInputToStock(input: StockInput[]): { stocks: Stock[]; amount: number; vat: number; citytax: number } {\n let amount = 0;\n let vat = 0;\n let citytax = 0;\n const stocks: Stock[] = [];\n\n for (const v of input) {\n amount += v.unitPrice * v.qty;\n vat += v.vat;\n citytax += v.cityTax;\n stocks.push({\n code: v.code,\n name: v.name,\n qty: this.float64ToString(v.qty),\n measureUnit: v.measureUnit,\n unitPrice: this.float64ToString(v.unitPrice),\n cityTax: this.float64ToString(v.cityTax),\n vat: this.float64ToString(v.vat),\n barCode: v.barCode,\n totalAmount: this.float64ToString(v.unitPrice * v.qty)\n });\n }\n\n return { stocks, amount, vat, citytax };\n }\n\n private createInputToRequestBody(input: CreateEbarimtInput): CreateEbarimtRequest {\n const districtCode = input.districtCode || '34';\n const branchNo = input.branchNo || '001';\n const { stocks, amount, vat, citytax } = this.stockInputToStock(input.stocks);\n\n return {\n amount: this.float64ToString(amount),\n vat: this.float64ToString(vat),\n cashAmount: this.float64ToString(0),\n nonCashAmount: this.float64ToString(amount),\n cityTax: this.float64ToString(citytax),\n customerNo: input.customerNo,\n billType: input.billType,\n branchNo,\n districtCode,\n billIdSuffix: input.billIdSuffix,\n stocks\n };\n }\n\n async getNewEbarimt(input: CreateEbarimtInput): Promise<CreateEbarimtResponse> {\n const body = this.createInputToRequestBody(input);\n\n if (input.billType === '3' && !body.customerNo) {\n throw new Error('CustomerNo is required for organization type bills');\n }\n\n const response = await axios.post<CreateEbarimtResponse>(`${this.endpoint}/put`, body, {\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n return response.data;\n }\n\n async sendData(): Promise<void> {\n await axios.get(`${this.endpoint}/sendData`);\n }\n\n async returnBill(billId: string, date: string): Promise<boolean> {\n const response = await axios.post<ReturnBillResponse>(\n `${this.endpoint}/returnBill`,\n {\n returnBillId: billId,\n date\n },\n {\n headers: {\n 'Content-Type': 'application/json'\n }\n }\n );\n\n return response.data.success;\n }\n\n async checkApi(): Promise<CheckResponse> {\n const response = await axios.get<CheckResponse>(`${this.endpoint}/checkApi`);\n return response.data;\n }\n} ","import axios from 'axios';\nimport {\n HipayConfig,\n HipayCheckoutRequest,\n HipayCheckoutResponse,\n HipayCheckoutGetResponse,\n HipayPaymentGetResponse,\n HipayPaymentCorrectionRequest,\n HipayPaymentCorrectionResponse,\n HipayStatementRequest,\n HipayStatementResponse\n} from './types';\nimport {\n HipayCheckout,\n HipayCheckoutGet,\n HipayPaymentGet,\n HipayPaymentCorrection,\n HipayStatement\n} from './apis';\nimport { API } from '../types';\nimport { HttpErrorHandler, PaymentError, PaymentErrorCode } from '../common/errors';\n\nconst MAX_RETRIES = 3;\nconst TIMEOUT_MS = 30000; // 30 seconds\nconst RETRY_DELAY_MS = 1000; // 1 second\n\nexport class HipayClient {\n private endpoint: string;\n private token: string;\n private entityId: string;\n\n constructor(config: HipayConfig) {\n this.endpoint = config.endpoint;\n this.token = config.token;\n this.entityId = config.entityId;\n }\n\n private async sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n private async makeRequest<T>(config: any): Promise<T> {\n let lastError: any;\n \n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n console.log(`[HipayClient] Making ${config.method} request to ${config.url} (Attempt ${attempt}/${MAX_RETRIES})`);\n const response = await axios(config);\n const data = response.data;\n\n if (data.result?.code && data.result.code !== '000.000.000') {\n throw new PaymentError({\n code: PaymentErrorCode.PAYMENT_FAILED,\n message: `${data.result.code}: ${data.result.description || 'Payment failed'}`,\n provider: 'hipay',\n requestId: data.id || data.result.code\n });\n }\n\n console.log(`[HipayClient] Successfully completed ${config.method} request to ${config.url}`);\n return data;\n } catch (error: any) {\n lastError = error;\n \n // Don't retry if it's a business logic error\n if (error instanceof PaymentError) {\n throw error;\n }\n\n // Check if we should retry\n const isRetryable = error.code === 'ECONNABORTED' || // Timeout\n error.code === 'ECONNRESET' || // Connection reset\n error.code === 'ETIMEDOUT' || // Connection timeout\n (error.response && error.response.status >= 500); // Server errors\n\n if (!isRetryable || attempt === MAX_RETRIES) {\n break;\n }\n\n console.log(`[HipayClient] Request failed, retrying in ${RETRY_DELAY_MS}ms... (Error: ${error.message})`);\n await this.sleep(RETRY_DELAY_MS * attempt); // Exponential backoff\n }\n }\n\n HttpErrorHandler.handleError('hipay', lastError);\n }\n\n private async httpRequest<T>(body: any, api: API): Promise<T> {\n const config = {\n method: api.method,\n url: this.endpoint + api.url,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.token}`\n },\n data: body,\n timeout: TIMEOUT_MS\n };\n\n return this.makeRequest<T>(config);\n }\n\n async checkout(amount: number): Promise<HipayCheckoutResponse> {\n const request: HipayCheckoutRequest = {\n entityId: this.entityId,\n amount,\n currency: 'MNT',\n qrData: true,\n signal: false\n };\n\n return this.httpRequest<HipayCheckoutResponse>(request, HipayCheckout);\n }\n\n async checkoutGet(checkoutId: string): Promise<HipayCheckoutGetResponse> {\n const ext = `${checkoutId}?entityId=${this.entityId}`;\n return this.httpRequest<HipayCheckoutGetResponse>(null, HipayCheckoutGet);\n }\n\n async paymentGet(paymentId: string): Promise<HipayPaymentGetResponse> {\n const ext = `${paymentId}?entityId=${this.entityId}`;\n return this.httpRequest<HipayPaymentGetResponse>(null, HipayPaymentGet);\n }\n\n async paymentCorrection(paymentId: string): Promise<HipayPaymentCorrectionResponse> {\n const request: HipayPaymentCorrectionRequest = {\n entityId: this.entityId,\n paymentId\n };\n\n return this.httpRequest<HipayPaymentCorrectionResponse>(request, HipayPaymentCorrection);\n }\n\n async statement(date: string): Promise<HipayStatementResponse> {\n const request: HipayStatementRequest = {\n entityId: this.entityId,\n date\n };\n\n return this.httpRequest<HipayStatementResponse>(request, HipayStatement);\n }\n} ","export const HipayCheckout = {\n url: '/checkout',\n method: 'POST'\n} as const;\n\nexport const HipayCheckoutGet = {\n url: '/checkout/get/',\n method: 'GET'\n} as const;\n\nexport const HipayPaymentGet = {\n url: '/payment/get/',\n method: 'GET'\n} as const;\n\nexport const HipayPaymentCorrection = {\n url: '/pos/correction',\n method: 'POST'\n} as const;\n\nexport const HipayStatement = {\n url: '/pos/statement',\n method: 'POST'\n} as const; ","import axios, { AxiosRequestConfig } from 'axios';\nimport {\n MongolchatConfig,\n MchatOnlineQrGenerateRequest,\n MchatOnlineQrGenerateResponse,\n MchatOnlineQrCheckResponse\n} from './types';\nimport {\n MchatOnlineQrGenerate,\n MchatOnlineQrcheck\n} from './apis';\nimport { HttpErrorHandler, PaymentError, PaymentErrorCode } from '../common/errors';\nimport { API } from '../types';\nconst MAX_RETRIES = 3;\nconst TIMEOUT_MS = 30000; // 30 seconds\nconst RETRY_DELAY_MS = 1000; // 1 second\n\nexport class MongolchatClient {\n private endpoint: string;\n private apiKey: string;\n private workerKey: string;\n private appSecret: string;\n private branchNo: string;\n\n constructor(config: MongolchatConfig) {\n this.endpoint = config.endpoint;\n this.apiKey = config.apiKey;\n this.workerKey = config.workerKey;\n this.appSecret = config.appSecret;\n this.branchNo = config.branchNo;\n }\n\n private async sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n private async makeRequest<T>(config: AxiosRequestConfig): Promise<T> {\n let lastError: any;\n \n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n console.log(`[MongolchatClient] Making ${config.method} request to ${config.url} (Attempt ${attempt}/${MAX_RETRIES})`);\n const response = await axios(config);\n const data = response.data;\n\n if (data.code !== 1000) {\n throw new PaymentError({\n code: PaymentErrorCode.PAYMENT_FAILED,\n message: data.message || 'Payment failed',\n provider: 'mongolchat',\n requestId: data.referenceNumber || data.code\n });\n }\n\n console.log(`[MongolchatClient] Successfully completed ${config.method} request to ${config.url}`);\n return data;\n } catch (error: any) {\n lastError = error;\n \n // Don't retry if it's a business logic error\n if (error instanceof PaymentError) {\n throw error;\n }\n\n // Check if we should retry\n const isRetryable = error.code === 'ECONNABORTED' || // Timeout\n error.code === 'ECONNRESET' || // Connection reset\n error.code === 'ETIMEDOUT' || // Connection timeout\n (error.response && error.response.status >= 500); // Server errors\n\n if (!isRetryable || attempt === MAX_RETRIES) {\n break;\n }\n\n console.log(`[MongolchatClient] Request failed, retrying in ${RETRY_DELAY_MS}ms... (Error: ${error.message})`);\n await this.sleep(RETRY_DELAY_MS * attempt); // Exponential backoff\n }\n }\n\n HttpErrorHandler.handleError('mongolchat', lastError);\n }\n\n private async httpRequest<T>(body: any, api: API): Promise<T> {\n const config: AxiosRequestConfig = {\n method: api.method,\n url: this.endpoint + api.url,\n headers: {\n 'Content-Type': 'application/json',\n 'api-key': this.apiKey,\n 'Authorization': `WorkerKey ${this.workerKey}`\n },\n data: body,\n timeout: TIMEOUT_MS\n };\n\n return this.makeRequest<T>(config);\n }\n\n async generateQR(input: MchatOnlineQrGenerateRequest): Promise<MchatOnlineQrGenerateResponse> {\n return this.httpRequest<MchatOnlineQrGenerateResponse>(input, MchatOnlineQrGenerate);\n }\n\n async checkQR(qr: string): Promise<MchatOnlineQrCheckResponse> {\n return this.httpRequest<MchatOnlineQrCheckResponse>({ qr }, MchatOnlineQrcheck);\n }\n} ","export const MchatAuth = {\n url: '/application/auth',\n method: 'GET'\n} as const;\n\nexport const MchatOnlineQrGenerate = {\n url: '/worker/onlineqr/generate',\n method: 'POST'\n} as const;\n\nexport const MchatOnlineQrcheck = {\n url: '/worker/onlineqr/status',\n method: 'POST'\n} as const;\n\nexport const MchatTransactionSettlement = {\n url: '/worker/settle/upload',\n method: 'POST'\n} as const; ","import axios, { AxiosRequestConfig } from 'axios';\nimport {\n PassConfig,\n CreateOrderInput,\n CreateOrderResponse,\n OrderInqueryInput,\n OrderInqueryResponse,\n OrderNotifyInput,\n OrderNotifyResponse,\n OrderCancelInput,\n OrderCancelResponse,\n OrderVoidInput,\n OrderVoidResponse\n} from './types';\nimport {\n PassCreateOrder,\n PassInqueryOrder,\n PassNotifyOrder,\n PassCancelOrder,\n PassVoidOrder\n} from './apis';\nimport { HttpErrorHandler, PaymentError, PaymentErrorCode } from '../common/errors';\nimport { API } from '../types';\n\nconst MAX_RETRIES = 3;\nconst TIMEOUT_MS = 30000; // 30 seconds\nconst RETRY_DELAY_MS = 1000; // 1 second\n\nexport class PassClient {\n private endpoint: string;\n private ecommerceToken: string;\n private callback: string;\n\n constructor(config: PassConfig) {\n this.endpoint = config.endpoint;\n this.ecommerceToken = config.ecommerceToken;\n this.callback = config.callback;\n }\n\n private async sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n private async makeRequest<T>(config: AxiosRequestConfig): Promise<T> {\n let lastError: any;\n \n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n console.log(`[PassClient] Making ${config.method} request to ${config.url} (Attempt ${attempt}/${MAX_RETRIES})`);\n const response = await axios(config);\n const data = response.data;\n\n if (data.msg?.code) {\n throw new PaymentError({\n code: PaymentErrorCode.PAYMENT_FAILED,\n message: `[${data.msg.code}] (${data.msg.level}) ${data.msg.body}`,\n provider: 'pass',\n requestId: data.orderId || data.msg.code\n });\n }\n\n console.log(`[PassClient] Successfully completed ${config.method} request to ${config.url}`);\n return data;\n } catch (error: any) {\n lastError = error;\n \n // Don't retry if it's a business logic error\n if (error instanceof PaymentError) {\n throw error;\n }\n\n // Check if we should retry\n const isRetryable = error.code === 'ECONNABORTED' || // Timeout\n error.code === 'ECONNRESET' || // Connection reset\n error.code === 'ETIMEDOUT' || // Connection timeout\n (error.response && error.response.status >= 500); // Server errors\n\n if (!isRetryable || attempt === MAX_RETRIES) {\n break;\n }\n\n console.log(`[PassClient] Request failed, retrying in ${RETRY_DELAY_MS}ms... (Error: ${error.message})`);\n await this.sleep(RETRY_DELAY_MS * attempt); // Exponential backoff\n }\n }\n\n HttpErrorHandler.handleError('pass', lastError);\n }\n\n private async httpRequestPass<T>(body: any, api: API): Promise<T> {\n const config: AxiosRequestConfig = {\n method: api.method,\n url: this.endpoint + api.url,\n headers: {\n 'Content-Type': 'application/json'\n },\n data: body,\n timeout: TIMEOUT_MS\n };\n\n return this.makeRequest<T>(config);\n }\n\n async createOrder(amount: number, callbackParams: Record<string, string>): Promise<CreateOrderResponse> {\n const params = new URLSearchParams(callbackParams);\n const request: CreateOrderInput = {\n ecommerceToken: this.ecommerceToken,\n amount: amount * 100, // Convert to cents\n callbackUrl: `${this.callback}?${params.toString()}`\n };\n\n return this.httpRequestPass<CreateOrderResponse>(request, PassCreateOrder);\n }\n\n async inqueryOrder(orderId: string): Promise<OrderInqueryResponse> {\n const request: OrderInqueryInput = {\n ecommerceToken: this.ecommerceToken,\n orderId\n };\n\n return this.httpRequestPass<OrderInqueryResponse>(request, PassInqueryOrder);\n }\n\n async notifyOrder(orderId: string, phone: string): Promise<OrderNotifyResponse> {\n const request: OrderNotifyInput = {\n ecommerceToken: this.ecommerceToken,\n orderId,\n phone\n };\n\n return this.httpRequestPass<OrderNotifyResponse>(request, PassNotifyOrder);\n }\n\n async cancelOrder(orderId: string): Promise<OrderCancelResponse> {\n const request: OrderCancelInput = {\n ecommerceToken: this.ecommerceToken,\n orderId\n };\n\n return this.httpRequestPass<OrderCancelResponse>(request, PassCancelOrder);\n }\n\n async voidOrder(orderId: string): Promise<OrderVoidResponse> {\n const request: OrderVoidInput = {\n ecommerceToken: this.ecommerceToken,\n orderId\n };\n\n return this.httpRequestPass<OrderVoidResponse>(request, PassVoidOrder);\n }\n} ","export const PassCreateOrder = {\n url: '/create_order',\n method: 'POST'\n} as const;\n\nexport const PassInqueryOrder = {\n url: '/order_inquiry',\n method: 'POST'\n} as const;\n\nexport const PassNotifyOrder = {\n url: '/order_notify',\n method: 'POST'\n} as const;\n\nexport const PassCancelOrder = {\n url: '/cancel_order',\n method: 'POST'\n} as const;\n\nexport const PassVoidOrder = {\n url: '/void',\n method: 'POST'\n} as const; ","export const SocialPayInvoicePhone = {\n url: '/pos/invoice/phone',\n method: 'POST'\n} as const;\n\nexport const SocialPayInvoiceQr = {\n url: '/pos/invoice/qr',\n method: 'POST'\n} as const;\n\nexport const SocialPayInvoiceCancel = {\n url: '/pos/invoice/cancel',\n method: 'POST'\n} as const;\n\nexport const SocialPayInvoiceCheck = {\n url: '/pos/invoice/check',\n method: 'POST'\n} as const;\n\nexport const SocialPayPaymentCancel = {\n url: '/pos/payment/cancel',\n method: 'POST'\n} as const;\n\nexport const SocialPayPaymentSettlement = {\n url: '/pos/settlement',\n method: 'POST'\n} as const; ","import {\n SocialPayConfig,\n SocialPayInvoicePhoneRequest,\n SocialPayInvoiceSimpleRequest,\n SocialPaySettlementRequest,\n SocialPaySimpleResponse,\n SocialPayTransactionResponse,\n SocialPayPaymentSettlementResponse\n} from './types';\nimport {\n SocialPayInvoicePhone,\n SocialPayInvoiceQr,\n SocialPayInvoiceCancel,\n SocialPayInvoiceCheck,\n SocialPayPaymentCancel,\n SocialPayPaymentSettlement\n} from './apis';\nimport { API } from '../types';\n\nimport { HttpErrorHandler, PaymentError, PaymentErrorCode } from '../common/errors';\n\nexport class SocialPayClient {\n private endpoint: string;\n\n constructor(config: SocialPayConfig) {\n this.endpoint = config.endpoint;\n }\n\n private async httpRequest<T>(body: any, api: API): Promise<T> {\n try {\n const response = await fetch(this.endpoint + api.url, {\n method: api.method,\n headers: {\n 'Content-Type': 'application/json'\n },\n body: body ? JSON.stringify(body) : undefined\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new PaymentError({\n code: PaymentErrorCode.PROVIDER_ERROR,\n message: `HTTP error! status: ${response.status} - ${errorText}`,\n provider: 'socialpay'\n });\n }\n\n const data = await response.json();\n if (data.code && data.code !== 0) {\n throw new PaymentError({\n code: PaymentErrorCode.PAYMENT_FAILED,\n message: data.message || 'Payment failed',\n provider: 'socialpay',\n requestId: data.id\n });\n }\n return data;\n } catch (error) {\n HttpErrorHandler.handleError('socialpay', error);\n }\n }\n\n async createInvoicePhone(request: SocialPayInvoicePhoneRequest): Promise<SocialPayTransactionResponse> {\n return this.httpRequest<SocialPayTransactionResponse>(request, SocialPayInvoicePhone);\n }\n\n async createInvoiceQr(request: SocialPayInvoiceSimpleRequest): Promise<SocialPayTransactionResponse> {\n return this.httpRequest<SocialPayTransactionResponse>(request, SocialPayInvoiceQr);\n }\n\n async cancelInvoice(request: SocialPayInvoiceSimpleRequest): Promise<SocialPaySimpleResponse> {\n return this.httpRequest<SocialPaySimpleResponse>(request, SocialPayInvoiceCancel);\n }\n\n async checkInvoice(request: SocialPayInvoiceSimpleRequest): Promise<SocialPayTransactionResponse> {\n return this.httpRequest<SocialPayTransactionResponse>(request, SocialPayInvoiceCheck);\n }\n\n async cancelPayment(request: SocialPayInvoiceSimpleRequest): Promise<SocialPaySimpleResponse> {\n return this.httpRequest<SocialPaySimpleResponse>(request, SocialPayPaymentCancel);\n }\n\n async settlement(request: SocialPaySettlementRequest): Promise<SocialPayPaymentSettlementResponse> {\n return this.httpRequest<SocialPayPaymentSettlementResponse>(request, SocialPayPaymentSettlement);\n }\n} ","export const StorepayAuth = {\n url: '/oauth/token',\n method: 'POST'\n} as const;\n\nexport const StorepayLoan = {\n url: '/merchant/loan',\n method: 'POST'\n} as const;\n\nexport const StorepayLoanCheck = {\n url: '/merchant/loan/check/',\n method: 'GET'\n} as const;\n\nexport const StorepayUserPossibleAmount = {\n url: '/user/possibleAmount',\n method: 'POST'\n} as const; ","import {\n StorepayConfig,\n StorepayLoginResponse,\n StorepayLoanInput,\n StorepayLoanRequest,\n StorepayLoanResponse,\n StorepayCheckResponse,\n StorepayUserCheckRequest,\n StorepayUserCheckResponse\n} from './types';\nimport {\n StorepayAuth,\n StorepayLoan,\n StorepayLoanCheck,\n StorepayUserPossibleAmount\n} from './apis';\nimport { API } from '../types';\nimport { HttpErrorHandler, PaymentError, PaymentErrorCode } from '../common/errors';\n\nconst MAX_RETRIES = 3;\nconst TIMEOUT_MS = 30000; // 30 seconds\nconst RETRY_DELAY_MS = 1000; // 1 second\n\nexport class StorepayClient {\n private appUsername: string;\n private appPassword: string;\n private username: string;\n private password: string;\n private authUrl: string;\n private baseUrl: string;\n private storeId: string;\n private callbackUrl: string;\n private expireIn: number | null;\n private loginObject: StorepayLoginResponse | null;\n\n constructor(config: StorepayConfig) {\n this.appUsername = config.appUsername;\n this.appPassword = config.appPassword;\n this.username = config.username;\n this.password = config.password;\n this.authUrl = config.authUrl;\n this.baseUrl = config.baseUrl;\n this.storeId = config.storeId;\n this.callbackUrl = config.callbackUrl;\n this.expireIn = null;\n this.loginObject = null;\n }\n\n private async sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n private async makeRequest<T>(url: string, options: RequestInit): Promise<T> {\n let lastError: any;\n \n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n console.log(`[StorepayClient] Making ${options.method} request to ${url} (Attempt ${attempt}/${MAX_RETRIES})`);\n \n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);\n \n const response = await fetch(url, {\n ...options,\n signal: controller.signal\n });\n \n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new PaymentError({\n code: PaymentErrorCode.PROVIDER_ERROR,\n me