{
  "version": 3,
  "sources": ["../src/core/CipherService.ts", "../src/core/PayloadEncoder.ts", "../src/core/Response.ts", "../src/exceptions/LogisticsException.ts", "../src/index.ts"],
  "sourcesContent": [
    "import { createCipheriv, createDecipheriv } from 'node:crypto'\nimport { Buffer } from 'node:buffer'\n\n/**\n * Service for AES encryption and decryption\n *\n * Implements AES-128-CBC encryption compatible with ECPay's specification.\n */\nexport class CipherService {\n  private readonly algorithm = 'aes-128-cbc'\n  private readonly key: Buffer\n  private readonly iv: Buffer\n\n  /**\n   * @param hashKey 16-byte HashKey\n   * @param hashIv 16-byte HashIV\n   */\n  constructor(hashKey: string, hashIv: string) {\n    if (hashKey.length !== 16) {\n      throw new Error('HashKey must be 16 characters long')\n    }\n    if (hashIv.length !== 16) {\n      throw new Error('HashIV must be 16 characters long')\n    }\n\n    this.key = Buffer.from(hashKey, 'utf8')\n    this.iv = Buffer.from(hashIv, 'utf8')\n  }\n\n  /**\n   * Encrypts plaintext using AES-128-CBC\n   *\n   * @param plaintext Text to encrypt\n   * @returns Base64 encoded encrypted string\n   */\n  encrypt(plaintext: string): string {\n    // URL Encode the plaintext first according to ECPay spec\n    const encodedText = encodeURIComponent(plaintext).replace(/%20/g, '+')\n\n    const cipher = createCipheriv(this.algorithm, this.key, this.iv)\n    cipher.setAutoPadding(true) // PKCS7 padding is default in Node.js\n\n    const encrypted = Buffer.concat([cipher.update(encodedText, 'utf8'), cipher.final()])\n\n    return encrypted.toString('base64')\n  }\n\n  /**\n   * Decrypts ciphertext using AES-128-CBC\n   *\n   * @param ciphertext Base64 encoded encrypted string\n   * @returns Decrypted plaintext\n   */\n  decrypt(ciphertext: string): string {\n    const decipher = createDecipheriv(this.algorithm, this.key, this.iv)\n    decipher.setAutoPadding(true)\n\n    const encryptedBuffer = Buffer.from(ciphertext, 'base64')\n    const decrypted = Buffer.concat([decipher.update(encryptedBuffer), decipher.final()])\n\n    // URL Decode the result\n    return decodeURIComponent(decrypted.toString('utf8').replace(/\\+/g, '%20'))\n  }\n}\n",
    "import { CipherService } from './CipherService.js'\n\nexport interface RqHeader {\n  Timestamp: number\n  Revision: string\n}\n\nexport interface EncryptedPayload {\n  MerchantID: string\n  RqHeader: RqHeader\n  Data: string\n}\n\n/**\n * Service for encoding and decoding API payloads\n */\nexport class PayloadEncoder {\n  private readonly cipher: CipherService\n\n  /**\n   * @param hashKey Merchant HashKey\n   * @param hashIv Merchant HashIV\n   */\n  constructor(hashKey: string, hashIv: string) {\n    this.cipher = new CipherService(hashKey, hashIv)\n  }\n\n  /**\n   * Encodes request data into encrypted payload\n   *\n   * @param merchantId Merchant ID\n   * @param data Request data object\n   * @returns Encrypted payload ready for API\n   */\n  encode(merchantId: string, data: Record<string, unknown>): EncryptedPayload {\n    // 1. JSON Stringify the data\n    const jsonString = JSON.stringify(data)\n\n    // 2. Encrypt the JSON string\n    const encryptedData = this.cipher.encrypt(jsonString)\n\n    // 3. Construct the full payload\n    return {\n      MerchantID: merchantId,\n      RqHeader: {\n        Timestamp: Math.floor(Date.now() / 1000),\n        Revision: '1.0.0',\n      },\n      Data: encryptedData,\n    }\n  }\n\n  /**\n   * Decodes encrypted response payload\n   *\n   * @param encryptedData Encrypted Data string\n   * @returns Decrypted data object\n   */\n  decode<T = Record<string, unknown>>(encryptedData: string): T {\n    // 1. Decrypt the data\n    const jsonString = this.cipher.decrypt(encryptedData)\n\n    // 2. Parse JSON\n    try {\n      return JSON.parse(jsonString) as T\n    } catch {\n      // If parsing fails, it might be an empty string or invalid JSON\n      // Return empty object or throw error based on requirement\n      // For now, let JSON.parse throw syntax error if invalid\n      throw new Error('Failed to parse decrypted response data as JSON')\n    }\n  }\n}\n",
    "import { PayloadEncoder } from './PayloadEncoder.js'\n\nexport interface BaseResponseData {\n  RtnCode: number\n  RtnMsg: string\n  [key: string]: unknown\n}\n\nexport interface EncryptedResponse {\n  TransCode: number\n  TransMsg: string\n  Data: string | Record<string, unknown> // Can be encrypted string or plain object\n  [key: string]: unknown\n}\n\n/**\n * API Response Wrapper\n *\n * Wraps the raw API response and provides helper methods to access data.\n * Handles automatic decryption of the 'Data' field if it is encrypted.\n */\nexport class Response<T = Record<string, unknown>> {\n  protected data: T & BaseResponseData\n  protected rawResponse: EncryptedResponse\n\n  /**\n   * @param response Raw API response\n   * @param encoder PayloadEncoder for decryption (optional)\n   */\n  constructor(response: EncryptedResponse, encoder?: PayloadEncoder) {\n    this.rawResponse = response\n\n    // Handle Data field\n    let decryptedData: Record<string, unknown> = {}\n\n    if (typeof response.Data === 'string' && encoder) {\n      // Decrypt if it's a string and we have an encoder\n      try {\n        decryptedData = encoder.decode(response.Data)\n      } catch (e) {\n        console.warn('Failed to decrypt response data:', e)\n        // Keep as empty object or handle error\n      }\n    } else if (typeof response.Data === 'object' && response.Data !== null) {\n      // It's already an object (sometimes happens in error cases or specific APIs)\n      decryptedData = response.Data as Record<string, unknown>\n    }\n\n    // Merge everything into a single data object for easy access\n    this.data = {\n      ...response, // Include top-level fields like TransCode\n      ...decryptedData, // Include decrypted fields\n    } as unknown as T & BaseResponseData\n\n    // Map TransCode/TransMsg to RtnCode/RtnMsg if needed\n    if (response.TransCode !== undefined && this.data.RtnCode === undefined) {\n      this.data.RtnCode = response.TransCode\n    }\n    if (response.TransMsg !== undefined && this.data.RtnMsg === undefined) {\n      this.data.RtnMsg = response.TransMsg\n    }\n  }\n\n  /**\n   * Check if the request was successful\n   */\n  isSuccess(): boolean {\n    return this.data.RtnCode === 1\n  }\n\n  /**\n   * Get return code\n   */\n  getRtnCode(): number {\n    return this.data.RtnCode\n  }\n\n  /**\n   * Get return message\n   */\n  getRtnMsg(): string {\n    return this.data.RtnMsg\n  }\n\n  /**\n   * Get the full data object\n   */\n  getData(): T & BaseResponseData {\n    return this.data\n  }\n\n  /**\n   * Get a specific field\n   */\n  get<K extends keyof (T & BaseResponseData)>(key: K): (T & BaseResponseData)[K] {\n    return this.data[key]\n  }\n\n  // Common Getter Methods\n\n  /**\n   * Get ECPay Logistics ID\n   */\n  getAllPayLogisticsID(): string | undefined {\n    return this.data['AllPayLogisticsID'] as string | undefined\n  }\n\n  /**\n   * Get Logistics Status\n   */\n  getLogisticsStatus(): string | undefined {\n    return this.data['LogisticsStatus'] as string | undefined\n  }\n\n  /**\n   * Get Merchant Trade No\n   */\n  getMerchantTradeNo(): string | undefined {\n    return this.data['MerchantTradeNo'] as string | undefined\n  }\n\n  /**\n   * Get Shipment No\n   */\n  getShipmentNo(): string | undefined {\n    return this.data['ShipmentNo'] as string | undefined\n  }\n\n  /**\n   * Get Print URL\n   */\n  getPrintUrl(): string | undefined {\n    return this.data['PrintUrl'] as string | undefined\n  }\n\n  /**\n   * Get CVS Validation No\n   */\n  getCVSValidationNo(): string | undefined {\n    return this.data['CVSValidationNo'] as string | undefined\n  }\n\n  /**\n   * Get Receiver Store ID\n   */\n  getReceiverStoreID(): string | undefined {\n    return this.data['ReceiverStoreID'] as string | undefined\n  }\n\n  /**\n   * Get Receiver Store Name\n   */\n  getReceiverStoreName(): string | undefined {\n    return this.data['ReceiverStoreName'] as string | undefined\n  }\n}\n",
    "/**\n * Logistics Exception\n *\n * Base exception class for all logistics-related errors.\n */\nexport class LogisticsException extends Error {\n  constructor(message: string) {\n    super(message)\n    this.name = 'LogisticsException'\n    Object.setPrototypeOf(this, LogisticsException.prototype)\n  }\n\n  /**\n   * Required field is missing\n   */\n  static required(field: string): LogisticsException {\n    return new LogisticsException(`${field} 為必填欄位。`)\n  }\n\n  /**\n   * Field value is invalid\n   */\n  static invalid(field: string, reason: string = ''): LogisticsException {\n    const message = reason !== '' ? `${field} 格式無效：${reason}` : `${field} 格式無效。`\n\n    return new LogisticsException(message)\n  }\n\n  /**\n   * Field value exceeds maximum length\n   */\n  static tooLong(field: string, maxLength: number): LogisticsException {\n    return new LogisticsException(`${field} 不可超過 ${maxLength} 個字元。`)\n  }\n\n  /**\n   * HTTP request failed\n   */\n  static httpError(message: string): LogisticsException {\n    return new LogisticsException(`HTTP 請求錯誤：${message}`)\n  }\n\n  /**\n   * API returned an error\n   */\n  static apiError(code: string | number, message: string): LogisticsException {\n    return new LogisticsException(`API 錯誤 [${code}]：${message}`)\n  }\n\n  /**\n   * Value is not in the allowed range\n   */\n  static notInRange(field: string, allowedValues: (string | number)[]): LogisticsException {\n    const values = allowedValues.join(', ')\n    return new LogisticsException(`${field} 必須為下列值之一：${values}`)\n  }\n}\n",
    "export * from './core/CipherService.js'\nexport * from './core/PayloadEncoder.js'\nexport * from './core/Response.js'\nexport * from './exceptions/LogisticsException.js'\n\n/**\n * SDK Version\n */\nexport const VERSION = '0.0.1'\n\n/**\n * ECPay Full Logistics API Modes\n */\nexport const enum ApiMode {\n  /** Production environment */\n  Production = 'production',\n  /** Staging/Test environment */\n  Staging = 'staging',\n}\n\n/**\n * ECPay Full Logistics API URLs\n */\nexport const API_URLS = {\n  [ApiMode.Production]: 'https://logistics.ecpay.com.tw',\n  [ApiMode.Staging]: 'https://logistics-stage.ecpay.com.tw',\n} as const\n\n/**\n * Configuration for the ECPay Full Logistics client\n */\nexport interface EcPayConfig {\n  /** Merchant ID provided by ECPay */\n  merchantId: string\n  /** Hash Key for request signing */\n  hashKey: string\n  /** Hash IV for request signing */\n  hashIv: string\n  /** API mode (production or staging) */\n  mode?: ApiMode\n}\n\n/**\n * Validates the ECPay configuration\n */\nexport function validateConfig(config: EcPayConfig): boolean {\n  if (!config.merchantId || config.merchantId.length === 0) {\n    return false\n  }\n  if (!config.hashKey || config.hashKey.length === 0) {\n    return false\n  }\n  if (!config.hashIv || config.hashIv.length === 0) {\n    return false\n  }\n  return true\n}\n\n/**\n * Creates the API base URL based on the mode\n */\nexport function getApiUrl(mode: ApiMode = ApiMode.Staging): string {\n  return API_URLS[mode]\n}\n"
  ],
  "mappings": "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",
  "debugId": "10A28FD42B04FEE364756E2164756E21",
  "names": []
}