{"version":3,"sources":["../src/utils/retry.ts","../src/errors.ts","../src/http.ts","../src/resources/sessions.ts","../src/resources/webhooks.ts","../src/index.ts"],"sourcesContent":["export const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));\r\n\r\nexport async function retry<T>(\r\n  fn: () => Promise<T>,\r\n  retries: number,\r\n): Promise<T> {\r\n  let attempt = 0;\r\n  while (true) {\r\n    try {\r\n      return await fn();\r\n    } catch (err) {\r\n      if (attempt >= retries) throw err;\r\n      const delay = Math.pow(2, attempt) * 100;\r\n      await sleep(delay);\r\n      attempt++;\r\n    }\r\n  }\r\n}\r\n","export class GMMError extends Error {\r\n  constructor(\r\n    message: string,\r\n    public status?: number,\r\n    public code?: string,\r\n  ) {\r\n    super(message);\r\n    this.name = \"GMMError\";\r\n  }\r\n}\r\nexport class APIError extends GMMError {}\r\nexport class AuthenticationError extends GMMError {}\r\nexport class RateLimitError extends GMMError {}\r\n","import { GMMConfig, RequestOptions, Interceptor } from \"./types\";\r\nimport { retry } from \"./utils/retry\";\r\nimport {\r\n  APIError,\r\n  AuthenticationError,\r\n  RateLimitError,\r\n  GMMError,\r\n} from \"./errors\";\r\n\r\nexport class HttpClient {\r\n  private baseUrl: string;\r\n  private interceptors: Interceptor[] = [];\r\n\r\n  constructor(private config: GMMConfig) {\r\n    this.baseUrl = \"https://api-payment-gateway.zsi.ai/api/v1\";\r\n  }\r\n\r\n  use(interceptor: Interceptor) {\r\n    this.interceptors.push(interceptor);\r\n  }\r\n\r\n  async request<T>(\r\n    method: string,\r\n    path: string,\r\n    body?: any,\r\n    options?: RequestOptions,\r\n  ): Promise<T> {\r\n    const exec = async () => {\r\n      let reqConfig: any = {\r\n        method,\r\n        url: `${this.baseUrl}${path}`,\r\n        headers: {\r\n          \"Content-Type\": \"application/json\",\r\n\r\n          \"gmm-api-key\": this.config.apiKey,\r\n          \"gmm-api-secret\": this.config.apiSecret,\r\n          \"gmm-origin\": this.config.origin,\r\n\r\n          ...(options?.idempotencyKey && {\r\n            \"Idempotency-Key\": options.idempotencyKey,\r\n          }),\r\n          ...options?.headers,\r\n        },\r\n        body,\r\n      };\r\n\r\n      for (const i of this.interceptors) {\r\n        if (i.onRequest) reqConfig = await i.onRequest(reqConfig);\r\n      }\r\n\r\n      const controller = new AbortController();\r\n      const timeout = this.config.timeout || 15000;\r\n      const id = setTimeout(() => controller.abort(), timeout);\r\n\r\n      try {\r\n        const res = await fetch(reqConfig.url, {\r\n          method: reqConfig.method,\r\n          headers: reqConfig.headers,\r\n          body: reqConfig.body ? JSON.stringify(reqConfig.body) : undefined,\r\n          signal: controller.signal,\r\n        });\r\n\r\n        let data = await res.json().catch(() => ({}));\r\n\r\n        if (!res.ok) {\r\n          this.handleError(res.status, data);\r\n        }\r\n\r\n        for (const i of this.interceptors) {\r\n          if (i.onResponse) data = await i.onResponse(data);\r\n        }\r\n\r\n        return data;\r\n      } catch (err: any) {\r\n        for (const i of this.interceptors) {\r\n          if (i.onError) await i.onError(err);\r\n        }\r\n\r\n        if (err.name === \"AbortError\") {\r\n          throw new APIError(\"Request timeout\", 408);\r\n        }\r\n\r\n        throw err;\r\n      } finally {\r\n        clearTimeout(id);\r\n      }\r\n    };\r\n\r\n    const retries = options?.retries ?? this.config.maxRetries ?? 2;\r\n    return retry(exec, retries);\r\n  }\r\n\r\n  private handleError(status: number, data: any): never {\r\n    if (status === 401) throw new AuthenticationError(data.message, status);\r\n    if (status === 429) throw new RateLimitError(data.message, status);\r\n    throw new GMMError(data.message || \"API Error\", status, data.code);\r\n  }\r\n}\r\n","import { HttpClient } from \"../http\";\r\nimport {\r\n  CheckoutSessionPayload,\r\n  CheckoutSessionResponse,\r\n  RequestOptions,\r\n} from \"../types\";\r\n\r\nexport class SessionsResource {\r\n  constructor(private http: HttpClient) {}\r\n\r\n  /** Creates a new checkout session and returns the checkout URL. Throws an error if the checkout URL is not found in the response.\r\n   * @param payload - An object containing the details of the checkout session to be created, including customer email, currency, items, and metadata.\r\n   * example payload:\r\n   * {\r\n   *   customer_email: \"test@example.com\",\r\n   *   currency: \"USD\",\r\n   *   items: [\r\n   *     {\r\n   *       id: 1,\r\n   *       name: \"Product A\",\r\n   *       quantity: 2,\r\n   *       price: 500,\r\n   *     },\r\n   *   ],\r\n   *   metadata: {\r\n   *     orderId: \"12345\",\r\n   *     customerId: \"67890\",\r\n   *     sessionId: \"abcde\",\r\n   *   },\r\n   * }\r\n   * @param options - Optional request options such as retries and timeout settings.\r\n   * @returns An object containing the checkout URL for the created session.\r\n   * @throws Will throw an error if the checkout URL is not found in the response from the API.\r\n  \r\n  */\r\n  async create(\r\n    payload: CheckoutSessionPayload,\r\n    options?: RequestOptions,\r\n  ): Promise<CheckoutSessionResponse> {\r\n    const res = await this.http.request<any>(\r\n      \"POST\",\r\n      \"/session/checkout\",\r\n      payload,\r\n      options,\r\n    );\r\n\r\n    if (!res?.data?.checkout_url) {\r\n      throw new Error(\"Checkout URL not found in response\");\r\n    }\r\n\r\n    return {\r\n      checkout_url: res.data.checkout_url,\r\n    };\r\n  }\r\n\r\n  /** Retrieves a checkout session using its unique tracking ID.\r\n   *\r\n   * This method is typically used on merchant success or cancel pages\r\n   * to verify and display the latest payment session status.\r\n   *\r\n   * @param trackId - The unique tracking ID generated for the checkout session.\r\n   *\r\n   * Example:\r\n   * ```ts\r\n   * const session = await gmm.sessions.findByTrackId(\r\n   *   \"7107319375257\"\r\n   * );\r\n   * ```\r\n   *\r\n   * @returns The checkout session details returned from the GMM API.\r\n   *\r\n   * Example response:\r\n   * ```json\r\n   * {\r\n   *   \"statusCode\": 200,\r\n   *   \"success\": true,\r\n   *   \"message\": \"Checkout session retrieved successfully.\",\r\n   *   \"data\": {\r\n   *     \"track_id\": \"7107319375257\",\r\n   *     \"payment_status\": \"paid\",\r\n   *     \"currency\": \"USD\",\r\n   *     \"amount\": 1000,\r\n   *     \"customer_email\": \"customer@example.com\"\r\n   *   }\r\n   * }\r\n   * ```\r\n   *\r\n   * @throws Will throw an error if the session is not found\r\n   * or if the API request fails.\r\n   */\r\n  async findByTrackId(trackId: string) {\r\n    return await this.http.request(\"GET\", `/session/track/${trackId}`);\r\n  }\r\n}\r\n","import crypto from \"crypto\";\r\nimport { GMMConfig } from \"../types\";\r\n\r\nexport class WebhooksResource {\r\n  constructor(private config: GMMConfig) {}\r\n\r\n  private verifySignature(params: {\r\n    rawBody: string;\r\n    signature: string;\r\n    timestamp: string;\r\n  }) {\r\n    const { rawBody, signature, timestamp } = params;\r\n\r\n    const FIVE_MINUTES = 5 * 60 * 1000;\r\n    const now = Date.now();\r\n\r\n    const timestampMs = new Date(timestamp).getTime();\r\n\r\n    if (Number.isNaN(timestampMs)) {\r\n      throw new Error(\"Invalid timestamp\");\r\n    }\r\n\r\n    if (Math.abs(now - timestampMs) > FIVE_MINUTES) {\r\n      throw new Error(\"Timestamp expired\");\r\n    }\r\n\r\n    const expectedSignature = crypto\r\n      .createHmac(\"sha256\", this.config.webhookSecret)\r\n      .update(`${timestamp}.${rawBody}`)\r\n      .digest(\"hex\");\r\n\r\n    return crypto.timingSafeEqual(\r\n      Buffer.from(signature, \"utf8\"),\r\n      Buffer.from(expectedSignature, \"utf8\"),\r\n    );\r\n  }\r\n\r\n  constructEvent(params: {\r\n    rawBody: string;\r\n    headers: {\r\n      \"gmm-webhook-signature\": string;\r\n      \"gmm-webhook-timestamp\": string;\r\n    };\r\n  }) {\r\n    const isValid = this.verifySignature({\r\n      rawBody: params.rawBody,\r\n      signature: params.headers[\"gmm-webhook-signature\"],\r\n      timestamp: params.headers[\"gmm-webhook-timestamp\"],\r\n    });\r\n\r\n    if (!isValid) {\r\n      throw new Error(\"Invalid webhook signature\");\r\n    }\r\n\r\n    return JSON.parse(params.rawBody);\r\n  }\r\n}\r\n","import { GMMConfig, Plugin } from \"./types\";\r\nimport { HttpClient } from \"./http\";\r\nimport { SessionsResource } from \"./resources/sessions\";\r\nimport { WebhooksResource } from \"./resources/webhooks\";\r\n\r\nclass GMMGateway {\r\n  public http: HttpClient;\r\n  public sessions: SessionsResource;\r\n  public webhooks: WebhooksResource;\r\n\r\n  constructor(private config: GMMConfig) {\r\n    if (!config.apiKey) throw new Error(\"API key is required\");\r\n\r\n    if (!config.apiSecret) throw new Error(\"API Secret is required\");\r\n\r\n    if (!config.origin) throw new Error(\"Origin is required\");\r\n\r\n    this.http = new HttpClient(config);\r\n    this.sessions = new SessionsResource(this.http);\r\n    this.webhooks = new WebhooksResource(config);\r\n  }\r\n\r\n  use(plugin: Plugin) {\r\n    plugin.setup(this);\r\n  }\r\n}\r\n\r\nexport { GMMGateway };\r\n"],"mappings":"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","names":["sleep","ms","res","retry","fn","retries","attempt","err","delay","GMMError","message","status","code","APIError","AuthenticationError","RateLimitError","HttpClient","config","interceptor","method","path","body","options","exec","reqConfig","i","controller","timeout","id","res","data","err","APIError","retries","retry","status","AuthenticationError","RateLimitError","GMMError","SessionsResource","http","payload","options","res","trackId","crypto","WebhooksResource","config","params","rawBody","signature","timestamp","FIVE_MINUTES","now","timestampMs","expectedSignature","GMMGateway","config","HttpClient","SessionsResource","WebhooksResource","plugin"]}