[
  {
    "path": ".eslintignore",
    "content": "# don't ever lint node_modules\nnode_modules\n# don't lint build output (make sure it's set to your correct build folder name)\ndist\n# don't lint nyc coverage output\ncoverage\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  parser: '@typescript-eslint/parser',\n  extends: ['airbnb-typescript/base'],\n  parserOptions: {\n    project: './tsconfig.eslint.json'\n  },\n  env: {\n    node: true\n  },\n  rules: {\n    'max-len': ['error', { code: 120 }],\n    'comma-dangle': ['error', 'never'],\n    semi: 'off',\n    '@typescript-eslint/semi': ['error', 'never'],\n    'import/prefer-default-export': 'off'\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.DS_Store\n.vscode\ndist/**"
  },
  {
    "path": ".npmignore",
    "content": "src/**\ntests/**\ncoverage/**\n.babelrc\n.eslint*\ndebug.js"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js: \n  - v12.18.2\n\nsudo: false\n\ncache:\n  directories:\n    [node_modules]\n\ninstall:\n  - npm install\n  - npm install -g codecov\n\nafter_script:\n  - npm run cov\n  - codecov\n\nscript:\n  - npm run lint\n  - npm run test"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 linchen\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# alipay\n\n[![NPM version][npm-image]][npm-url]\n[![Build Status][travis-image]][travis-url]\n[![David Status][david-image]][david-url]\n<!--[![Codecov Status][codecov-image]][codecov-url]-->\n<!--[![NPM download][download-image]][download-url]-->\n\n[npm-url]: https://www.npmjs.com/package/alipay-mobile\n[npm-image]: https://img.shields.io/npm/v/alipay-mobile.svg?style=flat\n[download-url]: https://www.npmjs.com/package/alipay-mobile\n[download-image]: https://img.shields.io/npm/dm/alipay-mobile.svg?style=flat\n[david-url]: https://david-dm.org/Luncher/alipay-mobile\n[david-image]: https://david-dm.org/Luncher/alipay-mobile.svg?style=flat\n[travis-url]: https://travis-ci.org/Luncher/alipay\n[travis-image]: https://img.shields.io/travis/Luncher/alipay.svg?style=flat\n[codecov-url]: https://codecov.io/gh/Luncher/alipay\n[codecov-image]: https://img.shields.io/codecov/c/github/Luncher/alipay.svg?style=flat\n\n\n[蚂蚁金服开放平台](https://openhome.alipay.com/platform/home.htm)`Node.js` SDK。\n\n---\n\n## 安装\n\n``` javascript\n\nnpm i alipay-mobile -S\n\n```\n\n## 基本使用\n\n``` javascript\nconst fs = require('fs')\nconst Alipay = require('alipay-mobile').default\n\nconst read = filename => {\n  return fs.readFileSync(path.resolve(__dirname, filename))\n}\n//notify_url: 异步通知url\n//app_id: 开放平台 appid\n//appPrivKeyFile: 你的应用私钥\n//alipayPubKeyFile: 蚂蚁金服公钥\nconst options = {\n  app_id: '2016080100137766',\n  appPrivKeyFile: read('./keys/app_priv_key.pem'),\n  alipayPubKeyFile: read('./keys/alipay_public_key.pem')\n}\n\nconst service = new Alipay(options)\nconst data = {\n  subject: '辣条',\n  out_trade_no: '1232423',\n  total_amount: '100'\n}\nconst result = service.createOrder(data)\nassert(result.code == 0, result.message)\n\n```\n\n## 说明\n\n>详细参数请参考接口对应的官方文档\n\n### 构造函数支持的参数\n\n```ts\nexport interface AlipayOption {\n  appPrivKeyFile:   string      // 应用私钥\n  alipayPubKeyFile: string      // 支付宝公钥\n  appId:            string      // 应用ID\n  notifyUrl?:       string      // 支付宝异步通知URL\n  gatewayUrl?:      string      // 接口网关地址\n}\n```\n\n### 接口返回错误码以及错误信息\n\n``` ts\n\nexport enum AlipayNormalResponseCode {\n  OK                            = 0,\n  EXCEPTION                     = -1,\n  SIGNATURE_ERROR               = -2,\n  SUCCESS                       = 10000,\n  UNAVALIABLE                   = 20000,\n  INSUFFICIENT_AUTHORIZATION    = 20001,\n  MISSING_REQUIRED_ARGS         = 40001,\n  INVALID_ARGS                  = 40002,\n  PROCESSING_FAILURE            = 40004,\n  PERMISSION_DENIED             = 40006\n}\n\nexport enum AlipayPaymentResponseCode {\n  SUCCESS         = '9000',\n  PROCESSING      = '8000',\n  FAILURE         = '4000',\n  REPEAT_REQ      = '5000',\n  USER_CANCEL     = '6001',\n  NETWORK_ERROR   = '6002',\n  UNKNOW          = '6004'\n}\n\n```\n\n### 接口返回格式\n\n``` javascript\n{\n  code: 错误码,\n  message: 错误信息,\n  data: 蚂蚁金服返回的原始数据//可能为空对象\n}\n```\n\n---\n\n\n## 功能列表\n\n- [x] 创建订单\n- [x] 取消订单\n- [x] 订单查询\n- [x] 验证支付状态\n- [x] 订单状态异步推送\n- [x] 预创建订单\n- [x] 申请退款\n- [x] 退款查询\n- [x] 交易结算\n- [x] 关闭交易\n- [x] 账单下载地址查询\n- [x] 单笔转账到支付宝账户\n\n---\n\n## API 说明\n\n### 创建订单`createOrder`\n\n[APP支付官方文档](https://docs.open.alipay.com/204/105465/)\n\n>用于返回给APP,传递给支付宝端发起交易申请 \n\n```javascript\nconst service = new Alipay(options)\nconst data = {\n  subject: '辣条',\n  out_trade_no: '1232423',\n  total_amount: '100'\n}\nconst result = service.createOrder(data)\nassert(result.code == 0, result.message)\n//result.data 用于返回给APP,传递给支付宝端发起交易申请\n```\n\n---\n\n### 创建网页订单`createWebOrderURL`\n\n[手机网页支付官方文档](https://docs.open.alipay.com/203/107090/)\n\n>该接口用于支付宝手机网页支付，服务端调用该接口生成一个`URL`返回给客户端, 客户端拿到该`URL`之后跳转到该URL发起支付请求。支付结束支付宝会跳转到客户端填写的`return_url`。\n\n``` javascript\nconst service = new Alipay(options)\nconst data = {\n  subject: '辣条',\n  out_trade_no: '1232423',\n  total_amount: '100'\n}\nconst basicParams = {\n  return_url: 'http://xxx.com'\n}\nconst result = service.createWebOrderURL(data, basicParams)\nassert(result.code == 0, result.message)\n```\n\n---\n\n### 创建pc端订单`createPageOrderURL`\n[创建pc端订单官方文档](https://docs.open.alipay.com/270/105899/)\n\n``` javascript\nconst service = new Alipay(options)\nconst data = {\n  subject: '辣条',\n  out_trade_no: '1232423',\n  total_amount: '100'\n}\nconst basicParams = {\n  return_url: 'http://xxx.com'\n}\nconst result = service.createPageOrderURL(data, basicParams)\nassert(result.code == 0, result.message)\n```\n\n---\n\n### 订单查询`queryOrder`\n\n[订单查询官方文档](https://docs.open.alipay.com/api_1/alipay.trade.query)\n\n``` javascript\nconst outTradeNo = '1232423'\nreturn service.queryOrder({ out_trade_no: outTradeNo })\n.then(result => {\n  assert(result.code == '40004', result.message)\n})\n```\n\n---\n\n### 取消订单`cancelOrder`\n\n[取消订单官方文档](https://docs.open.alipay.com/api_1/alipay.trade.cancel)\n\n``` javascript\nconst outTradeNo = 'foobar'\nreturn service.cancelOrder({ out_trade_no: outTradeNo })\n.then(result => {\n  assert(result.code == '40004', result.message)\n})\n```\n\n---\n\n### 验证支付结果`verifyPayment`\n\n[App支付同步通知参数校验](https://docs.open.alipay.com/204/105302)\n\n```javascript\nconst params = {\n  memo: \"xxxx\",\n  result: \"xxxx\",\n  resultStatus: \"xxx\"\n}\nreturn utils.verifyPayment(params)\n\n```\n\n---\n\n### 异步通知校验`makeNotifyResponse`\n\n[异步通知官方文档](https://docs.open.alipay.com/204/105301/)\n\n```javascript\nconst params = {\n  sign: 'xxxxxxxx',\n  sign_type: 'xxxxx',\n  ...\n}\n\nreturn service.makeNotifyResponse(params)\n\n```\n\n### 交易关闭`tradeClose`\n\n[关闭交易官方文档](https://docs.open.alipay.com/api_1/alipay.trade.close/)\n\n```javascript\nconst params = {\n  out_trade_no: 'xxxxx'\n}\nreturn service.tradeClose(params)\n\n```\n\n---\n\n### 交易退款`tradeRefund`\n\n[交易退款官方文档](https://docs.open.alipay.com/api_1/alipay.trade.refund/)\n\n```javascript\nconst params = {\n  out_trade_no: 'xxxxx'\n}\nreturn service.tradeRefund(params)\n```\n\n---\n\n### 交易退款查询`tradeRefundQuery`\n\n[交易退款查询官方文档](https://docs.open.alipay.com/api_1/alipay.trade.fastpay.refund.query/)\n\n```javascript\nconst params = {\n  out_trade_no: 'xxxxx'\n}\nreturn service.tradeRefundQuery(params)\n```\n\n---\n\n### 查询账单下载地址`billDownloadQuery`\n\n[查询账单下载地址文档](https://docs.open.alipay.com/api_15/alipay.data.dataservice.bill.downloadurl.query)\n\n```javascript\nconst params = {\n  bill_type: 'trade',\n  bill_date: '2017-05-06'\n}\nreturn service.billDownloadQuery(params)\n\n```\n\n---\n\n### 交易预创建`tradePrecreate`\n\n[交易预创建官方文档](https://docs.open.alipay.com/api_1/alipay.trade.create/)\n\n```javascript\nconst params = {\n  out_trade_no: 'xxx',\n  seller_id: 'asad',\n  total_amount: '231wawsda',\n  subject: '面包'\n}\nreturn service.tradePrecreate(params)\n\n```\n\n---\n\n### 交易结算`tradeSettle`\n\n[交易结算官方文档](https://docs.open.alipay.com/api_1/alipay.trade.order.settle/)\n\n```javascript\nconst params = {\n  out_request_no: 'xxx'\n}\nreturn service.tradeSettle(params)\n```\n\n---\n\n### 单笔转账到支付宝账户接口`toaccountTransfer`\n\n[接口文档](https://opendocs.alipay.com/open/309/alipay.fund.trans.toaccount.transfer)\n\n```javascript\nconst params = {\n  out_biz_no: \"1234\",\n  payee_type: 'ALIPAY_LOGONID',\n  payee_account: \"user666\",\n  amount: \"100\"\n}\n\nreturn service.toaccountTransfer(params)\n\n```\n\n---\n\n## LICENSE\n\n  [MIT](https://mit-license.org/)\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  verbose: true,\n  roots: [\n    '<rootDir>/src/',\n    '<rootDir>/tests/'\n  ],\n  transform: {\n    '^.+\\\\.ts$': 'ts-jest'\n  },\n  modulePaths: [\n    '<rootDir>'\n  ],\n  testEnvironment: 'node',\n  testRegex: '/tests/.*(test|spec).ts$',\n  moduleFileExtensions: ['ts', 'js']\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"alipay-mobile\",\n  \"version\": \"4.0.2\",\n  \"description\": \"\",\n  \"main\": \"dist/index.js\",\n  \"engines\": {\n    \"node\": \">=12.18\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc --outDir ./dist\",\n    \"lint\": \"yarn eslint . --ext .js,.ts\",\n    \"test\": \"jest --no-cache\"\n  },\n  \"keywords\": [\n    \"alipay\",\n    \"mobile\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/Luncher/alipay-mobile\"\n  },\n  \"author\": {\n    \"name\": \"linchen\",\n    \"email\": \"gakiclin@gmail.com\",\n    \"url\": \"https://github.com/Luncher\"\n  },\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@types/bluebird\": \"^3.5.32\",\n    \"@types/jest\": \"^26.0.20\",\n    \"@types/joi\": \"^14.3.4\",\n    \"@types/node\": \"^12.18\",\n    \"@types/urllib\": \"^2.33.0\",\n    \"@typescript-eslint/eslint-plugin\": \"^3.6.1\",\n    \"@typescript-eslint/parser\": \"^3.8.0\",\n    \"debug\": \"^2.6.9\",\n    \"eslint\": \"^7.6.0\",\n    \"eslint-config-airbnb-typescript\": \"^9.0.0\",\n    \"eslint-plugin-import\": \"^2.22.0\",\n    \"jest\": \"^26.6.3\",\n    \"ts-jest\": \"^26.5.3\",\n    \"typescript\": \"^3.9.7\"\n  },\n  \"dependencies\": {\n    \"joi\": \"^14.3.1\",\n    \"moment\": \"^2.19.3\",\n    \"urllib\": \"^2.21.1\"\n  }\n}\n"
  },
  {
    "path": "src/config/env.ts",
    "content": "enum NodeEnv {\n  TEST = 'test',\n  DEVELOPMENT = 'development',\n  PRODUCTION = 'production'\n}\n\nexport function getEnv(): NodeEnv {\n  return <NodeEnv>process.env.NODE_ENV || NodeEnv.DEVELOPMENT\n}\n\nexport function isTest() {\n  return getEnv() === NodeEnv.TEST\n}\n\nexport function isProd() {\n  return getEnv() === NodeEnv.PRODUCTION\n}\n"
  },
  {
    "path": "src/config/index.ts",
    "content": "export { isTest, isProd } from './env'\n\ntype ApiResponseMessage = string\ntype ApiResponseData = string | number | object\ntype ApiResponseCode = AlipayNormalResponseCode | AlipayPaymentResponseCode\nexport interface ApiResponse {\n  code: ApiResponseCode,\n  message: ApiResponseMessage,\n  data: ApiResponseData\n}\n\nexport interface AlipayOption {\n  appPrivKeyFile: string // 应用私钥\n  alipayPubKeyFile: string // 支付宝公钥\n  appId: string // 应用ID\n  notifyUrl?: string // 支付宝异步通知URL\n  gatewayUrl?: string // 接口网关地址\n}\n\nexport enum AlipayNormalResponseCode {\n  OK = 0,\n  EXCEPTION = -1,\n  SIGNATURE_ERROR = -2,\n  SUCCESS = 10000,\n  UNAVALIABLE = 20000,\n  INSUFFICIENT_AUTHORIZATION = 20001,\n  MISSING_REQUIRED_ARGS = 40001,\n  INVALID_ARGS = 40002,\n  PROCESSING_FAILURE = 40004,\n  PERMISSION_DENIED = 40006\n}\n\nexport const alipayResponseMessage = {\n  0: '请求成功',\n  '-1': '异常',\n  '-2': '签名错误',\n  10000: '接口调用成功',\n  20000: '服务不可用',\n  20001: '授权权限不足',\n  40001: '缺少必选参数',\n  40002: '非法的参数',\n  40004: '业务处理失败',\n  40006: '权限不足',\n\n  // 支付结果信息\n  9000: '订单支付成功',\n  8000: '正在处理中，支付结果未知（有可能已经支付成功），请查询商户订单列表中订单的支付状态',\n  4000: '订单支付失败',\n  5000: '重复请求',\n  6001: '用户中途取消',\n  6002: '网络连接出错',\n  6004: '支付结果未知（有可能已经支付成功），请查询商户订单列表中订单的支付状态'\n}\n\nexport type AlipayAPIArgs = VerifyPamentArgs\n| AlipayNotifyArgs\n| AlipayPublicArgs\n| AlipayCreateOrderArgs\n| AlipayQueryOrderArgs\n| AlipayCancelOrderArgs\n| AlipayTradeCloseArgs\n| AlipayTradeRefundArgs\n| AlipayTradeRefundQueryArgs\n| AlipayBillQueryArgs\n| AlipayTradePrecreateArgs\n| AlipayTradeSettleArgs\n| AlipayToaccountTransferArgs\n\n// App支付同步通知参数\nexport type VerifyPamentResult = string | PaymentResult\nexport interface VerifyPamentArgs {\n  memo: string, // 描述信息\n  result: VerifyPamentResult, // 处理结果(类型为json结构字符串)\n  resultStatus: AlipayPaymentResponseCode // 结果码(类型为字符串)\n}\n\nexport interface PaymentResult {\n  alipay_trade_app_pay_response: AlipayTradeAppPayResponse,\n  sign: string,\n  sign_type: AlipaySignType\n}\n\nexport type AlipayTradeAppPayResponse = AlipayTradeAppPayResponseImpl & AlipayResponseTypeMap\n\nexport interface AlipayTradeAppPayResponseImpl {\n  code: AlipayNormalResponseCode,\n  msg: string,\n  app_id: string,\n  out_trade_no: string,\n  trade_no: string,\n  total_amount: number,\n  seller_id: string,\n  charset: string,\n  timestamp: string\n}\n\n// App支付同步通知状态码\nexport enum AlipayPaymentResponseCode {\n  SUCCESS = '9000',\n  PROCESSING = '8000',\n  FAILURE = '4000',\n  REPEAT_REQ = '5000',\n  USER_CANCEL = '6001',\n  NETWORK_ERROR = '6002',\n  UNKNOW = '6004'\n}\n\n// 支付宝异步通知参数\nexport interface AlipayNotifyArgs {\n  notify_time: string, // 通知的发送时间。格式为yyyy-MM-dd HH:mm:ss\n  notify_type: string, // 通知的类型\n  notify_id: string, // 通知校验ID\n  app_id: string, // 支付宝分配给开发者的应用Id\n  charset: string, // 编码格式，如utf-8、gbk、gb2312等\n  version: string, // 调用的接口版本，固定为：1.0\n  sign_type: AlipaySignType, // 签名类型\n  trade_no: string, // 支付宝交易凭证号\n  out_trade_no: string, // 原支付请求的商户订单号\n  sign: string, // 签名\n  [key: string]: string | number// 可选参数\n}\n\n// 校验签名的参数\nexport interface AlipayVerifySignArgs {\n  sign: string,\n  msg?: string,\n  sign_type: string,\n  async_notify_response: object\n}\n\n// 支付宝接口公共请求参数\nexport interface AlipayPublicArgs {\n  app_id: string, // 支付宝分配给开发者的应用ID\n  method: MethodType, // 接口名称\n  format?: string, // 仅支持JSON\n  return_url?: string, // HTTP/HTTPS开头字符串\n  charset: string, // 请求使用的编码格式，如utf-8,gbk,gb2312等\n  sign_type: AlipaySignType, // 商户生成签名字符串所使用的签名算法类型\n  sign: string, // 商户请求参数的签名串\n  timestamp: string, // 发送请求的时间，格式\"yyyy-MM-dd HH:mm:ss\"\n  version: string, // 调用的接口版本，固定为：1.0\n  notify_url: string, // 支付宝服务器主动通知商户服务器里指定的页面http/https路径。\n  biz_content: string // 业务请求参数的集合，最大长度不限\n}\n\nexport type AlipayResponse = AlipayPublicResponse | AlipayTradeAppPayResponse\n\nexport type AlipayResponseType =\n  | 'alipay_trade_query_response'\n  | 'alipay_trade_refund_response'\n  | 'alipay_trade_cancel_response'\n  | 'alipay_trade_precreate_response'\n  | 'alipay_trade_close_response'\n  | 'alipay_trade_create_response'\n  | 'alipay_trade_order_settle_response'\n  | 'alipay_trade_fastpay_refund_query_response'\n  | 'alipay_trade_app_pay_response'\n  | 'alipay_fund_trans_toaccount_transfer_response'\n  | 'alipay_data_dataservice_bill_downloadurl_query_response'\n  | 'async_notify_response'\n\nexport type AlipayResponseTypeMap = {\n  [key in AlipayResponseType]: string\n}\n\nexport type AlipayPublicResponse = AlipayPublicResponseImpl & AlipayResponseTypeMap\n\n// 支付宝接口公共响应参数\nexport interface AlipayPublicResponseImpl {\n  code: ApiResponseCode,\n  msg: string,\n  sub_code?: string,\n  sub_msg?: string,\n  sign: string\n}\n\ntype OrderTotalAmount = string | number\n// 创建订单参数\nexport interface AlipayCreateOrderArgs {\n  body?: string, // 对一笔交易的具体描述信息\n  subject: string, // 商品的标题/交易标题/订单标题/订单关键字等\n  out_trade_no: string, // 商户网站唯一订单号\n  total_amount: OrderTotalAmount, // 订单总金额，单位为元\n  timeout_express?: string, // 该笔订单允许的最晚付款时间，逾期将关闭交易\n  time_expire?: string, // 绝对超时时间，格式为yyyy-MM-dd HH:mm\n  auth_token?: string, // 针对用户授权接口，获取用户相关数据时，用于标识用户授权关系\n  product_code?: string, // 销售产品码\n  goods_type?: GoodsType, // 商品主类型\n  passback_params?: string, // 公用回传参数，如果请求时传递了该参数，则返回给商户时会回传该参数\n  promo_params?: string, // 优惠参数注：仅与支付宝协商后可用\n  extend_params?: string, // 业务扩展参数\n  enable_pay_channels?: string, // 可用渠道\n  disable_pay_channels?: string, // 禁用渠道\n  quit_url?: string, // 添加该参数后在h5支付收银台会出现返回按钮，可用于用户付款中途退出并返回到该参数指定的商户网站地址\n  store_id?: string, // 商户门店编号\n  ext_user_info?: string // 外部指定买家\n}\n\n// 查询订单参数\nexport interface AlipayQueryOrderArgs {\n  out_trade_no?: string, // 订单支付时传入的商户订单号,和支付宝交易号不能同时为空\n  trade_no?: string, // 支付宝交易号，和商户订单号不能同时为空\n  org_pid?: string, // 银行间联模式下有用，其它场景请不要使用\n}\n\n// 取消订单\nexport interface AlipayCancelOrderArgs {\n  out_trade_no?: string, // 订单支付时传入的商户订单号,和支付宝交易号不能同时为空\n  trade_no?: string // 支付宝交易号，和商户订单号不能同时为空\n}\n\n// 统一收单交易关闭接口\nexport interface AlipayTradeCloseArgs {\n  out_trade_no?: string, // 订单支付时传入的商户订单号,和支付宝交易号不能同时为空\n  trade_no?: string, // 支付宝交易号，和商户订单号不能同时为空\n  operator_id?: string // 卖家端自定义的的操作员 ID\n}\n\n// 统一收单交易退款接口\nexport interface AlipayTradeRefundArgs {\n  out_trade_no?: string, // 订单支付时传入的商户订单号,和支付宝交易号不能同时为空\n  trade_no?: string, // 支付宝交易号，和商户订单号不能同时为空\n  refund_amount?: number, // 需要退款的金额\n  refund_currency?: string, // 订单退款币种信息\n  refund_reason?: string, // 退款的原因说明\n  out_request_no?: string, // 标识一次退款请求\n  operator_id?: string, // 商户的操作员编号\n  store_id?: string, // 商户的门店编号\n  terminal_id?: string, // 商户的终端编号\n  goods_detail?: Map<string, string | number>[], // 退款包含的商品列表信息\n  refund_royalty_parameters?: Map<string, string | number>[], // 退分账明细信息\n  org_pid?: string // 银行间联模式下有用，其它场景请不要使用\n}\n\n// 统一收单交易退款查询\nexport interface AlipayTradeRefundQueryArgs {\n  out_trade_no?: string, // 订单支付时传入的商户订单号,和支付宝交易号不能同时为空\n  trade_no?: string, // 支付宝交易号，和商户订单号不能同时为空\n  out_request_no: string, // 请求退款接口时，传入的退款请求号\n  org_pid?: string // 银行间联模式下有用，其它场景请不要使用\n}\n\n// 查询对账单下载地址\nexport interface AlipayBillQueryArgs {\n  bill_type: string, // 账单类型\n  bill_date: string // 账单时间\n}\n\n// 交易预创建接口\nexport interface AlipayTradePrecreateArgs {\n  out_trade_no: string, // 商户订单号\n  seller_id?: string, // 卖家支付宝用户ID\n  total_amount: number, // 订单总金额\n  discountable_amount?: number, // 可打折金额\n  subject: string, // 订单标题\n  goods_detail?: Map<string, string | number>[], // 订单包含的商品列表信息\n  body?: string, // 对交易或商品的描述\n  operator_id?: string, // 商户操作员编号\n  store_id?: string, // 商户门店编号\n  disable_pay_channels?: string, // 禁用渠道\n  enable_pay_channels?: string, // 可用渠道，用户只能在指定渠道范围内支付\n  terminal_id?: string, // 商户机具终端编号\n  extend_params?: string, // 业务扩展参数\n  timeout_express?: string, // 该笔订单允许的最晚付款时间\n  settle_info?: any, // 描述结算信息\n  merchant_order_no?: string, // 商户原始订单号\n  business_params?: string, // 商户传入业务信息\n  qr_code_timeout_express?: string // 该笔订单允许的最晚付款时间\n}\n\n// 统一收单交易结算接口\nexport interface AlipayTradeSettleArgs {\n  out_request_no: string, // 结算请求流水号\n  trade_no: string, // 支付宝订单号\n  royalty_parameters: any, // 分账明细信息\n  operator_id?: string // 操作员id\n}\n\n// 单笔转账到支付宝账户接口\nexport interface AlipayToaccountTransferArgs {\n  out_biz_no: string, // 商户转账唯一订单号\n  payee_type: string, // 收款方账户类型\n  payee_account: string, // 收款方账户\n  amount: string, // 转账金额\n  payer_show_name?: string, // 付款方姓名\n  payee_real_name?: string, // 收款方真实姓名\n  remark?: string// 转账备注\n}\n\nexport enum AlipayPayType {\n  ALIPAY_USERID = 'ALIPAY_USERID',\n  ALIPAY_LOGONID = 'ALIPAY_LOGONID'\n}\n\nexport enum GoodsType {\n  VIRTUAL = 0,\n  PARTICALITY = 1\n}\n\nexport enum PayChannel {\n  balance = 'balance',\n  moneyFund = 'moneyFund',\n  coupon = 'coupon',\n  pcredit = 'pcredit',\n  pcreditpayInstallment = 'pcreditpayInstallment',\n  creditCard = 'creditCard',\n  creditCardExpress = 'creditCardExpress',\n  creditCardCartoon = 'creditCardCartoon',\n  credit_group = 'credit_group',\n  debitCardExpress = 'debitCardExpress',\n  mcard = 'mcard',\n  pcard = 'pcard',\n  promotion = 'promotion',\n  voucher = 'voucher',\n  point = 'point',\n  mdiscount = 'mdiscount',\n  bankPay = 'bankPay'\n}\n\nexport enum MethodType {\n  QUERY_ORDER = 'alipay.trade.query',\n  CREATE_APP_ORDER = 'alipay.trade.app.pay',\n  CREATE_WEB_ORDER = 'alipay.trade.wap.pay',\n  CREATE_PAGE_ORDER = 'alipay.trade.page.pay',\n  CANCEL_ORDER = 'alipay.trade.cancel',\n  TRADE_CLOSE = 'alipay.trade.close',\n  TRADE_SETTLE = 'alipay.trade.order.settle',\n  TRADE_REFUND = 'alipay.trade.refund',\n  TRADE_PRECREATE = 'alipay.trade.precreate',\n  TRADE_REFUND_QUERY = 'alipay.trade.fastpay.refund.query',\n  BILL_DOWNLOAD_QUERY = 'alipay.data.dataservice.bill.downloadurl.query',\n  FUND_TRANS_TOACCOUNT_TRANSFER = 'alipay.fund.trans.toaccount.transfer',\n\n  // self define\n  VERIFY_PAYMENT = 'verify.payment.status',\n  NOTIFY_RESPONSE = 'notify.response'\n}\n\nexport type GateWay = string\nexport enum GateWayDefault {\n  ALIPAY_GETWAY = 'https://openapi.alipay.com/gateway.do',\n  ALIPAY_DEV_GETWAY = 'https://openapi.alipaydev.com/gateway.do'\n}\n\nexport enum AlipayAPIList {\n  'alipay.trade.query' = '订单查询',\n  'alipay.trade.refund' = '交易退款',\n  'alipay.trade.cancel' = '取消订单',\n  'alipay.trade.precreate' = '预创建订单',\n  'alipay.trade.close' = '关闭交易',\n  'alipay.trade.create' = '创建交易',\n  'alipay.trade.order.settle' = '交易结算',\n  'alipay.trade.fastpay.refund.query' = '交易退款查询',\n  'alipay.trade.app.pay' = '生成创建订单所需参数',\n  'alipay.fund.trans.toaccount.transfer' = '单笔转账到支付宝账户接口',\n  'alipay.data.dataservice.bill.downloadurl.query' = '查询账单下载地址接口',\n  'async.notify' = '异步通知' // 自定义\n}\n\nexport type GetResponseTypeArgs = AlipayResponse | AlipayVerifySignArgs\n\nexport enum AlipayNotifyResult {\n  SUCCESS = 'success',\n  FAILURE = 'failure'\n}\n\nexport enum AlipayAlgorithm {\n  RSA = 'RSA-SHA1',\n  RSA2 = 'RSA-SHA256'\n}\n\nexport enum AlipaySignType {\n  RSA2 = 'RSA2',\n  RSA = 'RSA'\n}\n\nexport enum AlipayPrivKey {\n  BEGIN = '-----BEGIN RSA PRIVATE KEY-----\\n',\n  END = '\\n-----END RSA PRIVATE KEY-----'\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "/**\n * @file alipay implement\n * @author linchen <gakiclin@gmail.com>\n */\n\nimport * as urllib from 'urllib'\nimport {\n  isProd,\n  AlipayOption,\n  MethodType,\n  GateWay,\n  GateWayDefault,\n  AlipayPrivKey,\n  AlipayTradeSettleArgs,\n  AlipayBillQueryArgs,\n  AlipayPublicArgs,\n  AlipayPublicResponse,\n  AlipayToaccountTransferArgs,\n  AlipayTradeRefundArgs,\n  AlipayTradeCloseArgs,\n  AlipayQueryOrderArgs,\n  AlipayCancelOrderArgs,\n  AlipayCreateOrderArgs,\n  AlipayTradePrecreateArgs,\n  alipayResponseMessage,\n  AlipayNormalResponseCode,\n  AlipayTradeRefundQueryArgs,\n  ApiResponse,\n  AlipayNotifyArgs,\n  AlipayVerifySignArgs,\n  AlipayAPIArgs\n} from './config'\nimport * as utils from './utils'\nimport * as Validator from './validator'\n\nexport * from './utils'\n\nexport default class Alipay {\n  public gateWay: GateWay\n\n  public options: AlipayOption\n\n  constructor(options: AlipayOption) {\n    this.options = this.normalizeOptions(options)\n  }\n\n  private normalizeOptions(options: AlipayOption): AlipayOption {\n    let { appPrivKeyFile: privKey, alipayPubKeyFile: publicKey } = options\n\n    if (publicKey.indexOf('BEGIN PUBLIC KEY') === -1) {\n      publicKey = `-----BEGIN PUBLIC KEY-----\\n${publicKey}\\n-----END PUBLIC KEY-----`\n    }\n    if (privKey.indexOf('BEGIN RSA PRIVATE KEY') === -1\n      && privKey.indexOf('BEGIN PRIVATE KEY') === -1) {\n      privKey = AlipayPrivKey.BEGIN + privKey + AlipayPrivKey.END\n    }\n\n    this.gateWay = options.gatewayUrl\n    if (!this.gateWay) {\n      this.gateWay = isProd() ? GateWayDefault.ALIPAY_GETWAY : GateWayDefault.ALIPAY_DEV_GETWAY\n    }\n\n    return {\n      ...options,\n      appPrivKeyFile: privKey,\n      alipayPubKeyFile: publicKey\n    }\n  }\n\n  get appId(): string {\n    return this.options.appId\n  }\n\n  get privKey(): string {\n    return this.options.appPrivKeyFile\n  }\n\n  get publicKey(): string {\n    return this.options.alipayPubKeyFile\n  }\n\n  get notifyUrl(): string {\n    return this.options.notifyUrl\n  }\n\n  private validateBasicParams(method: MethodType, publicParams: AlipayPublicArgs): AlipayPublicArgs {\n    const newOptions = { ...this.options }\n    // remove keys from basic parameters\n    delete newOptions.appPrivKeyFile\n    delete newOptions.alipayPubKeyFile\n    const params: AlipayPublicArgs = { ...newOptions, ...publicParams, method }\n\n    return Validator.validateBasicParams(params)\n  }\n\n  private validateParams(method: MethodType, apiParams: AlipayAPIArgs, publicParams: AlipayPublicArgs) {\n    const validateBasicParams: AlipayPublicArgs = this.validateBasicParams(method, publicParams)\n    const validateApiParams: AlipayAPIArgs = Validator.validateAPIParams(method, apiParams)\n\n    validateBasicParams.biz_content = JSON.stringify(validateApiParams)\n    validateBasicParams.sign = utils.makeSign(this.privKey, validateBasicParams)\n\n    return validateBasicParams\n  }\n\n  private makeRequest(params: AlipayPublicArgs, options: urllib.RequestOptions = {}) {\n    const httpclient: urllib.HttpClient2 = new urllib.HttpClient2()\n\n    return httpclient.request(this.gateWay, {\n      data: params, dataType: 'json', dataAsQueryString: true, ...options\n    })\n      .then((resp: urllib.HttpClientResponse<AlipayPublicResponse>) => utils.makeResponse(resp.data))\n  }\n\n  public makeNotifyResponse(params: AlipayNotifyArgs): ApiResponse {\n    // Validator.validateAPIParams(MethodType.NOTIFY_RESPONSE, params)\n    const resp: AlipayVerifySignArgs = { sign: params.sign, async_notify_response: params, sign_type: params.sign_type }\n    const valid = utils.verifySign(this.publicKey, resp, ['sign', 'sign_type'], params)\n    const code = valid ? AlipayNormalResponseCode.OK : AlipayNormalResponseCode.SIGNATURE_ERROR\n\n    return { code, message: alipayResponseMessage[code], data: params }\n  }\n\n  public createWebOrderURL(apiParams: AlipayCreateOrderArgs, publicParams?: AlipayPublicArgs): ApiResponse {\n    const result = this.createWebOrder(apiParams, publicParams)\n    result.data = `${this.gateWay}?${String(result.data)}`\n    return result\n  }\n\n  public createPageOrderURL(apiParams: AlipayCreateOrderArgs, publicParams?: AlipayPublicArgs): ApiResponse {\n    const result = this.createPageOrder(apiParams, publicParams)\n    result.data = `${this.gateWay}?${String(result.data)}`\n    return result\n  }\n\n  public createPageOrder(apiParams: AlipayCreateOrderArgs, publicParams?: AlipayPublicArgs): ApiResponse {\n    const params = this.validateParams(MethodType.CREATE_PAGE_ORDER, apiParams, publicParams)\n    const { sign } = params\n    const signStr = utils.makeSignStr(params)\n    const value = signStr.split('&')\n      .reduce(\n        (acc, cur) => {\n          const [k, v] = cur.split('=')\n          return `${acc + k}=${encodeURIComponent(v)}&`\n        },\n        ''\n      ).slice(0, -1)\n    const data = `${value}&sign=${encodeURIComponent(sign)}`\n    return { code: 0, message: alipayResponseMessage[0], data }\n  }\n\n  public createWebOrder(apiParams: AlipayCreateOrderArgs, publicParams?: AlipayPublicArgs): ApiResponse {\n    const params = this.validateParams(MethodType.CREATE_WEB_ORDER, apiParams, publicParams)\n    const { sign } = params\n    const signStr = utils.makeSignStr(params)\n    const value = signStr.split('&').reduce(\n      (acc, cur) => {\n        const [k, v] = cur.split('=')\n        return `${acc}${k}=${encodeURIComponent(v)}&`\n      },\n      ''\n    ).slice(0, -1)\n    const data = `${value}&sign=${encodeURIComponent(sign)}`\n    return { code: 0, message: alipayResponseMessage[0], data }\n  }\n\n  // Compat\n  public createOrder(apiParams: AlipayCreateOrderArgs, publicParams?: AlipayPublicArgs): ApiResponse {\n    return this.createAppOrder(apiParams, publicParams)\n  }\n\n  public createAppOrder(apiParams: AlipayCreateOrderArgs, publicParams?: AlipayPublicArgs): ApiResponse {\n    const params = this.validateParams(MethodType.CREATE_APP_ORDER, apiParams, publicParams)\n    const { sign } = params\n    const signStr = utils.makeSignStr(params)\n    const value = signStr.split('&').reduce(\n      (acc, cur) => {\n        const [k, v] = cur.split('=')\n        return `${acc + k}=${encodeURIComponent(v)}&`\n      },\n      ''\n    ).slice(0, -1)\n\n    const data = `${value}&sign=${encodeURIComponent(sign)}`\n    return { code: AlipayNormalResponseCode.OK, message: alipayResponseMessage[AlipayNormalResponseCode.OK], data }\n  }\n\n  public queryOrder(apiParams: AlipayQueryOrderArgs, publicParams?: AlipayPublicArgs) {\n    return Promise.resolve()\n      .then(() => {\n        if (!apiParams.out_trade_no && !apiParams.trade_no) {\n          throw new Error('outTradeNo and tradeNo can not both omit.')\n        }\n        const params = this.validateParams(MethodType.QUERY_ORDER, apiParams, publicParams)\n        return this.makeRequest(params)\n      })\n  }\n\n  public cancelOrder(apiParams: AlipayCancelOrderArgs, publicParams?: AlipayPublicArgs) {\n    const params = this.validateParams(MethodType.CANCEL_ORDER, apiParams, publicParams)\n    return this.makeRequest(params)\n  }\n\n  public tradeClose(apiParams: AlipayTradeCloseArgs, publicParams?: AlipayPublicArgs) {\n    const params = this.validateParams(MethodType.TRADE_CLOSE, apiParams, publicParams)\n    return this.makeRequest(params)\n  }\n\n  public tradeRefund(apiParams: AlipayTradeRefundArgs, publicParams?: AlipayPublicArgs) {\n    const params = this.validateParams(MethodType.TRADE_REFUND, apiParams, publicParams)\n    return this.makeRequest(params)\n  }\n\n  public tradeRefundQuery(apiParams: AlipayTradeRefundQueryArgs, publicParams?: AlipayPublicArgs) {\n    const params = this.validateParams(MethodType.TRADE_REFUND_QUERY, apiParams, publicParams)\n    return this.makeRequest(params)\n  }\n\n  public billDownloadQuery(apiParams: AlipayBillQueryArgs, publicParams?: AlipayPublicArgs) {\n    const params = this.validateParams(MethodType.BILL_DOWNLOAD_QUERY, apiParams, publicParams)\n    return this.makeRequest(params)\n  }\n\n  public tradePrecreate(apiParams: AlipayTradePrecreateArgs, publicParams?: AlipayPublicArgs) {\n    const params = this.validateParams(MethodType.TRADE_PRECREATE, apiParams, publicParams)\n    return this.makeRequest(params)\n  }\n\n  public tradeSettle(apiParams: AlipayTradeSettleArgs, publicParams?: AlipayPublicArgs) {\n    const params = this.validateParams(MethodType.TRADE_SETTLE, apiParams, publicParams)\n    return this.makeRequest(params)\n  }\n\n  public toaccountTransfer(apiParams: AlipayToaccountTransferArgs, publicParams?: AlipayPublicArgs) {\n    const params = this.validateParams(MethodType.FUND_TRANS_TOACCOUNT_TRANSFER, apiParams, publicParams)\n    return this.makeRequest(params)\n  }\n}\n"
  },
  {
    "path": "src/utils.ts",
    "content": "/**\n * @file alipay utils\n * @author linchen <gakiclin@gmail.com>\n */\n\nimport { isString } from 'util'\nimport * as crypto from 'crypto'\nimport * as config from './config'\nimport * as Validator from './validator'\nimport {\n  MethodType,\n  ApiResponse,\n  PaymentResult,\n  AlipayResponse,\n  VerifyPamentArgs,\n  alipayResponseMessage\n} from './config'\n\nexport function makeSignStr(params: object, omit = ['sign']) {\n  return Object.keys(params)\n    .sort()\n    .filter((key) => params[key] && omit.indexOf(key) === -1)\n    .map((key) => {\n      const value = typeof params[key] === 'object'\n        ? JSON.stringify(params[key]) : params[key]\n      return `${String(key)}=${String(value)}`\n    })\n    .join('&')\n    .trim()\n}\n\nexport function getSignAlgorithm(signType: config.AlipaySignType): config.AlipayAlgorithm {\n  return config.AlipayAlgorithm[signType]\n}\n\nexport function makeSign(privKey: string, params: config.AlipayPublicArgs) {\n  const signStr = makeSignStr(params)\n  const algorithm = getSignAlgorithm(params.sign_type)\n  const signer = crypto.createSign(algorithm as string)\n  signer.update(signStr, <crypto.Utf8AsciiLatin1Encoding>params.charset)\n  return signer.sign(privKey, 'base64')\n}\n\nexport function verifySign(\n  publicKey: string, response: config.AlipayVerifySignArgs,\n  omit: string[], options: config.AlipayNotifyArgs\n): boolean {\n  if (!response.async_notify_response || !response.sign) {\n    return false\n  }\n  const { sign } = response\n  const resp = makeSignStr(response.async_notify_response, omit)\n  const algorithm = getSignAlgorithm(options.sign_type)\n  const verify = crypto.createVerify(algorithm)\n  verify.update(resp, <crypto.Utf8AsciiLatin1Encoding>options.charset)\n  return verify.verify(publicKey, sign, 'base64')\n}\n\nexport function getResponseType(response: config.GetResponseTypeArgs): config.AlipayResponseType {\n  const respType: string = Object.keys(config.AlipayAPIList)\n    .map((name) => name.replace(/\\./g, '_'))\n    .find((api) => `${api}_response` in response)\n  if (respType) {\n    return <config.AlipayResponseType>(`${respType}_response`)\n  }\n  throw new Error(`Not Found responseType: ${String(response.msg)}`)\n}\n\nexport function makeResponse(response: AlipayResponse): ApiResponse {\n  return {\n    code: response.code,\n    message: alipayResponseMessage[response.code],\n    data: response[getResponseType(response)]\n  }\n}\n\nexport function verifyPayment(params: VerifyPamentArgs): ApiResponse {\n  Validator.validateAPIParams(MethodType.VERIFY_PAYMENT, params)\n  const data = isString(params.result)\n    ? (<PaymentResult>JSON.parse(params.result))\n    : params.result\n\n  return makeResponse(data.alipay_trade_app_pay_response)\n}\n"
  },
  {
    "path": "src/validator/index.ts",
    "content": "import * as Joi from 'joi'\nimport * as Schema from './schema'\nimport { MethodType, AlipayPublicArgs, AlipayAPIArgs } from '../config'\n\ntype AlipayArgs = AlipayPublicArgs | AlipayAPIArgs\n\nfunction validate(schema: Joi.ObjectSchema, params: AlipayArgs): AlipayArgs {\n  const result: Joi.ValidationResult<AlipayArgs> = Joi.validate(params, schema)\n  if (result.error) {\n    throw result.error\n  }\n\n  return result.value\n}\n\nexport function validateBasicParams(params: AlipayPublicArgs): AlipayPublicArgs {\n  return <AlipayPublicArgs>validate(Schema.basicSchema.options({ allowUnknown: true }), params)\n}\n\nexport function validateAPIParams(method: MethodType, params: AlipayAPIArgs): AlipayAPIArgs {\n  switch (method) {\n    case MethodType.CREATE_WEB_ORDER: {\n      return validate(Schema.createWebOrderSchema, params)\n    }\n    case MethodType.CREATE_APP_ORDER: {\n      return validate(Schema.createAppOrderSchema, params)\n    }\n    case MethodType.CREATE_PAGE_ORDER: {\n      return validate(Schema.createPageOrderSchema, params)\n    }\n    case MethodType.QUERY_ORDER: {\n      return validate(Schema.queryOrderSchema, params)\n    }\n    case MethodType.CANCEL_ORDER: {\n      return validate(Schema.cancelOrderSchema, params)\n    }\n    case MethodType.VERIFY_PAYMENT: {\n      return validate(Schema.verifyPaymentSchema, params)\n    }\n    case MethodType.NOTIFY_RESPONSE: {\n      return validate(Schema.notifySchema, params)\n    }\n    case MethodType.TRADE_CLOSE: {\n      return validate(Schema.tradeCloseSchema, params)\n    }\n    case MethodType.TRADE_REFUND: {\n      return validate(Schema.tradeRefundSchema, params)\n    }\n    case MethodType.TRADE_REFUND_QUERY: {\n      return validate(Schema.tradeRefundQuery, params)\n    }\n    case MethodType.BILL_DOWNLOAD_QUERY: {\n      return validate(Schema.billDownloadSchema, params)\n    }\n    case MethodType.TRADE_PRECREATE: {\n      return validate(Schema.tradePrecreateSchema, params)\n    }\n    case MethodType.TRADE_SETTLE: {\n      return validate(Schema.tradeSettleSchema, params)\n    }\n    case MethodType.FUND_TRANS_TOACCOUNT_TRANSFER: {\n      return validate(Schema.toaccountTransferSchema, params)\n    }\n    default: {\n      throw new Error(`Parser Unknow method type:${method}`)\n    }\n  }\n}\n"
  },
  {
    "path": "src/validator/schema/bill_download_query.ts",
    "content": "import * as Joi from 'joi'\n\nexport const billDownloadSchema: Joi.ObjectSchema = Joi.object({\n  bill_type: Joi.string().max(10).required(),\n  bill_date: Joi.string().max(15).required()\n})\n"
  },
  {
    "path": "src/validator/schema/cancel_order.ts",
    "content": "import * as Joi from 'joi'\n\nexport const cancelOrderSchema: Joi.ObjectSchema = Joi.object({\n  out_trade_no: Joi.string().max(64),\n  trade_no: Joi.string().max(64)\n}).or('out_trade_no', 'trade_no')\n"
  },
  {
    "path": "src/validator/schema/create_app_order.ts",
    "content": "import * as Joi from 'joi'\nimport { GoodsType } from '../../config'\n\nexport const createAppOrderSchema: Joi.ObjectSchema = Joi.object({\n  body: Joi.string().max(128),\n  subject: Joi.string().max(256).required(),\n  out_trade_no: Joi.string().max(64).required(),\n  timeout_express: Joi.string().max(6),\n  total_amount: Joi.string().max(9).regex(/^[0-9]+(.[0-9]{1,2}?)$/),\n  seller_id: Joi.string().max(16),\n  product_code: Joi.string().max(64).default('QUICK_MSECURITY_PAY'),\n  goods_type: Joi.string().max(2).allow(GoodsType),\n  passback_params: Joi.string().max(512),\n  extend_params: Joi.object({\n    sys_service_provider_id: Joi.string().max(64),\n    needBuyerRealnamed: Joi.string().max(1),\n    TRANS_MEMO: Joi.string().max(128),\n    hb_fq_num: Joi.string().max(5),\n    hb_fq_seller_percent: Joi.string().max(3)\n  }),\n  enable_pay_channels: Joi.string().max(128),\n  disable_pay_channels: Joi.string().max(128),\n  promo_params: Joi.string().max(512),\n  store_id: Joi.string().max(32)\n})\n"
  },
  {
    "path": "src/validator/schema/create_page_order.ts",
    "content": "import * as Joi from 'joi'\nimport { GoodsType } from '../../config'\n\nexport const createPageOrderSchema: Joi.ObjectSchema = Joi.object({\n  body: Joi.string().max(128),\n  subject: Joi.string().max(256).required(),\n  out_trade_no: Joi.string().max(64).required(),\n  timeout_express: Joi.string().max(6),\n  total_amount: Joi.string().max(9).regex(/^[0-9]+(.[0-9]{1,2}?)$/),\n  seller_id: Joi.string().max(16),\n  product_code: Joi.string().max(64).default('FAST_INSTANT_TRADE_PAY'),\n  goods_type: Joi.string().max(2).allow(GoodsType),\n  passback_params: Joi.string().max(512),\n  extend_params: Joi.object({\n    sys_service_provider_id: Joi.string().max(64),\n    needBuyerRealnamed: Joi.string().max(1),\n    TRANS_MEMO: Joi.string().max(128),\n    hb_fq_num: Joi.string().max(5),\n    hb_fq_seller_percent: Joi.string().max(3)\n  }),\n  enable_pay_channels: Joi.string().max(128),\n  disable_pay_channels: Joi.string().max(128),\n  promo_params: Joi.string().max(512),\n  store_id: Joi.string().max(32),\n  qr_pay_mode: Joi.string().max(2),\n  qrcode_width: Joi.string().max(4)\n})\n"
  },
  {
    "path": "src/validator/schema/create_web_order.ts",
    "content": "import * as Joi from 'joi'\nimport { GoodsType } from '../../config'\n\nexport const createWebOrderSchema: Joi.ObjectSchema = Joi.object({\n  body: Joi.string().max(128),\n  subject: Joi.string().max(256).required(),\n  out_trade_no: Joi.string().max(64).required(),\n  timeout_express: Joi.string().max(6),\n  total_amount: Joi.string().max(9).regex(/^[0-9]+(.[0-9]{1,2}?)$/),\n  seller_id: Joi.string().max(16),\n  product_code: Joi.string().max(64).default('QUICK_WAP_PAY'),\n  goods_type: Joi.string().max(2).allow(GoodsType),\n  passback_params: Joi.string().max(512),\n  extend_params: Joi.object({\n    sys_service_provider_id: Joi.string().max(64),\n    needBuyerRealnamed: Joi.string().max(1),\n    TRANS_MEMO: Joi.string().max(128),\n    hb_fq_num: Joi.string().max(5),\n    hb_fq_seller_percent: Joi.string().max(3)\n  }),\n  enable_pay_channels: Joi.string().max(128),\n  disable_pay_channels: Joi.string().max(128),\n  promo_params: Joi.string().max(512),\n  store_id: Joi.string().max(32)\n})\n"
  },
  {
    "path": "src/validator/schema/index.ts",
    "content": "/**\n * @alipay api validator schema\n * @author linchen <gakiclin@gmail.com>\n */\n\nimport * as Joi from 'joi'\nimport * as moment from 'moment'\nimport { AlipaySignType } from '../../config'\n\nexport * from './notify'\nexport * from './trade_close'\nexport * from './trade_settle'\nexport * from './trade_refund'\nexport * from './query_order'\nexport * from './create_app_order'\nexport * from './create_web_order'\nexport * from './create_page_order'\nexport * from './cancel_order'\nexport * from './verify_payment'\nexport * from './trade_precreate'\nexport * from './trade_refund_query'\nexport * from './bill_download_query'\nexport * from './toaccount_transfer'\n\nexport const basicSchema: Joi.ObjectSchema = Joi.object({\n  app_id: Joi.string().max(32).required(),\n  method: Joi.string().max(128).required(),\n  format: Joi.string().max(40),\n  return_url: Joi.string().max(256),\n  charset: Joi.string().max(10).default('utf-8', '请求使用的编码格式'),\n  sign_type: Joi.string().allow(\n    Object.keys(AlipaySignType)\n  ).default('RSA2', '商户生成签名字符串所使用的签名算法类型，目前支持RSA2和RSA，推荐使用RSA2'),\n  timestamp: Joi.string().max(19).default(() => moment().format('YYYY-MM-DD HH:mm:ss'), '时间戳'),\n  version: Joi.string().max(3).default('1.0', '调用的接口版本，固定为：1.0'),\n  notify_url: Joi.string().max(256)\n})\n"
  },
  {
    "path": "src/validator/schema/notify.ts",
    "content": "import * as Joi from 'joi'\n\nexport const notifySchema: Joi.ObjectSchema = Joi.object({\n  notify_time: Joi.string().required(),\n  notify_type: Joi.string().required(),\n  notify_id: Joi.string().required(),\n  app_id: Joi.string().required(),\n  version: Joi.string().required(),\n  sign_type: Joi.string().required(),\n  sign: Joi.string().required(),\n  trade_no: Joi.string().required(),\n  out_trade_no: Joi.string().required()\n})\n"
  },
  {
    "path": "src/validator/schema/query_order.ts",
    "content": "import * as Joi from 'joi'\n\nexport const queryOrderSchema: Joi.ObjectSchema = Joi.object({\n  out_trade_no: Joi.string().max(64),\n  trade_no: Joi.string().max(64)\n}).or('out_trade_no', 'trade_no')\n"
  },
  {
    "path": "src/validator/schema/toaccount_transfer.ts",
    "content": "import * as Joi from 'joi'\nimport { AlipayPayType } from '../../config'\n\nexport const toaccountTransferSchema: Joi.ObjectSchema = Joi.object({\n  out_biz_no: Joi.string().required(),\n  payee_type: Joi.string().allow(Object.keys(AlipayPayType)).required(),\n  payee_account: Joi.string().max(100).required(),\n  amount: Joi.string().max(16).required(),\n  payer_show_name: Joi.string().max(100),\n  payee_real_name: Joi.string().max(100),\n  remark: Joi.string().max(200)\n})\n"
  },
  {
    "path": "src/validator/schema/trade_close.ts",
    "content": "import * as Joi from 'joi'\n\nexport const tradeCloseSchema: Joi.ObjectSchema = Joi.object({\n  out_trade_no: Joi.string().max(64),\n  trade_no: Joi.string().max(64),\n  operator_id: Joi.string().max(28)\n}).or('out_trade_no', 'trade_no')\n"
  },
  {
    "path": "src/validator/schema/trade_precreate.ts",
    "content": "import * as Joi from 'joi'\n\nexport const tradePrecreateSchema: Joi.ObjectSchema = Joi.object({\n  out_trade_no: Joi.string().max(64).required(),\n  seller_id: Joi.string().max(128),\n  total_amount: Joi.string().max(11).regex(/^[0-9]+(.[0-9]{1,2}?)$/),\n  discountable_amount: Joi.string().max(11).regex(/^[0-9]+(.[0-9]{1,2}?)$/),\n  undiscountable_amount: Joi.string().max(11).regex(/^[0-9]+(.[0-9]{1,2}?)$/),\n  buyer_logon_id: Joi.string().max(100),\n  subject: Joi.string().max(256).required(),\n  body: Joi.string().max(128),\n  operator_id: Joi.string().max(28),\n  store_id: Joi.string().max(32),\n  disable_pay_channels: Joi.string().max(128),\n  enable_pay_channels: Joi.string().max(128),\n  terminal_id: Joi.string().max(32),\n  extend_params: Joi.object(),\n  timeout_express: Joi.string().max(6),\n  settle_info: Joi.any(),\n  merchant_order_no: Joi.string().max(32),\n  business_params: Joi.string().max(512),\n  qr_code_timeout_express: Joi.string().max(6)\n})\n"
  },
  {
    "path": "src/validator/schema/trade_refund.ts",
    "content": "import * as Joi from 'joi'\n\nexport const tradeRefundSchema: Joi.ObjectSchema = Joi.object({\n  out_trade_no: Joi.string().max(64),\n  trade_no: Joi.string().max(64),\n  refund_amount: Joi.number(),\n  refund_reason: Joi.string().max(256),\n  out_request_no: Joi.string().max(64),\n  operator_id: Joi.string().max(30),\n  store_id: Joi.string().max(32),\n  terminal_id: Joi.string().max(32)\n}).or('trade_no', 'out_trade_no')\n"
  },
  {
    "path": "src/validator/schema/trade_refund_query.ts",
    "content": "import * as Joi from 'joi'\n\nexport const tradeRefundQuery: Joi.ObjectSchema = Joi.object({\n  out_trade_no: Joi.string().max(64),\n  trade_no: Joi.string().max(64),\n  out_request_no: Joi.string().max(64).required(),\n  org_pid: Joi.string().max(16)\n}).or('trade_no', 'out_trade_no')\n"
  },
  {
    "path": "src/validator/schema/trade_settle.ts",
    "content": "import * as Joi from 'joi'\n\nexport const tradeSettleSchema: Joi.ObjectSchema = Joi.object({\n  out_request_no: Joi.string().max(64).required(),\n  trade_no: Joi.string().max(64).required(),\n  royalty_parameters: Joi.any().required(),\n  operator_id: Joi.string().max(64)\n})\n"
  },
  {
    "path": "src/validator/schema/verify_payment.ts",
    "content": "import * as Joi from 'joi'\nimport { AlipayPaymentResponseCode } from '../../config'\n\nexport const verifyPaymentSchema: Joi.ObjectSchema = Joi.object({\n  memo: Joi.string().required(),\n  result: Joi.any().required(),\n  resultStatus: Joi.string().allow(Object.keys(AlipayPaymentResponseCode))\n})\n"
  },
  {
    "path": "tests/index.spec.ts",
    "content": "import * as fs from 'fs'\nimport * as path from 'path'\nimport Alipay from '../src/index'\nimport { AlipayOption } from '../src/config'\n\nconst read = (filename) => fs.readFileSync(path.resolve(__dirname, filename))\n\nfunction createService(optons?: AlipayOption) {\n  const defaultOptions = {\n    app_id: '2016080100137766',\n    appPrivKeyFile: read('./keys/app_priv_key.pem'),\n    alipayPubKeyFile: read('./keys/alipay_public_key.pem')\n  }\n  return new Alipay({ ...defaultOptions, ...optons })\n}\n\nfunction testCreateAppOrderOk(options) {\n  const data = {\n    subject: '辣条',\n    out_trade_no: '1232423',\n    total_amount: '100'\n  }\n  const result = createService(options).createAppOrder(data)\n  expect(result.code).toEqual(0)\n  expect(result.message).toEqual('请求成功')\n}\n\ndescribe('ALIPAY unit test', () => {\n  it('should use private key with ras header', () => {\n    const vOptions = {\n      app_id: '2016080100137766',\n      appPrivKeyFile: read('./keys/app_priv_key_with_rsa_head.pem'),\n      alipayPubKeyFile: read('./keys/alipay_public_key.pem')\n    }\n    return testCreateAppOrderOk(vOptions)\n  })\n\n  it('should use private key with header', () => {\n    const vOptions = {\n      app_id: '2016080100137766',\n      appPrivKeyFile: read('./keys/app_priv_key_with_head.pem'),\n      alipayPubKeyFile: read('./keys/alipay_public_key.pem')\n    }\n    return testCreateAppOrderOk(vOptions)\n  })\n\n  it('should allow create order', () => {\n    const data = {\n      subject: '辣条',\n      out_trade_no: '1232423',\n      total_amount: '100'\n    }\n    const result = createService().createAppOrder(data)\n    expect(result.code).toEqual(0)\n    expect(result.message).toEqual('请求成功')\n  })\n})\n"
  },
  {
    "path": "tests/keys/alipay_public_key.pem",
    "content": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsJLMw7HyJbTab9xBBw9jzw3F37obRwx4DVsZ0AihqcWJicUCLhPIyPmzC0A6f3FjoBcncn0a2w5neLBu0tpYm7qrFeY/QSy92WUzX6PmzFsotxxtq0SnWyMqfzlxkpSZPGoxxDB5vl40S8QEMceWH5ANzL+CT6VB8tNJ3ImCos2DeanjAiq5QBC/n2ZnCm8QUBAJ4hCTJwI850sSkwSETlHrtbVka4h02eY3Nmm120se5zhBc2MPaPMdDZWRiFeyXPWiFkijI4wXrEtSIwEWVECzqhnBuUHAq+0qfzvu+EejyTjGmp0u5+yJccDG6ES/LHFRjk54/9PbNngMEmxFMwIDAQAB"
  },
  {
    "path": "tests/keys/app_priv_key.pem",
    "content": "MIIEogIBAAKCAQEAw9ju1PnQEysiWxopYQbPIHiNRcbYwV2AYTz+WhRMVaTagmyGNYANmskjixQ+pKvvrl0KPa8CVX47h2AhUp3L2tSygh6C2bEpo7oaB77zZ84XmnUKotfwFUekUZUHjDhX91kVgun0LAIezWMDdRkZ9KC/0/8YnCfHUz9ecfYFd4fu17UlA9JJeEBQuyXDUzvdCtv7VEc9/KZ4sShyQoigaxG4HfRb8Iqmr+J2rARGwBAsjkH+bV609TVPTLCrpZT/rj0ua//1G7cv7Nhh2NcWK7nA2zksLvt/W9vLRYl7/3QXD96qUe2/vARzPp0L/QH3QtIv9NE87xVLmGk+TmxIAQIDAQABAoIBADok8Js4Y4cdWkDT3o8Y12ubfs3FgFrAKLo1won51sPigqEQGTRPBTr8FlpXM1XuWeVZaA3yJG4/YOsLJjmB8aDRXwH0jwKUb3lVah78mQUrkaRgtTytgXC/6U/zP99oZu1ffFx2mvBp3L07dS5Runv/MZR9+s95m9riSGbrFKpsorTtOIEd8Uck8O3ble/iB1G9hmX2qaMEqnppiY0gh7iTl5a9ji+TvZc+4Kfmv4jVKuQ1vGpVtDVNlgzq8RkuWxnm4UHFY2dZ1kU8gNBOImuVT4qfFAvpbBcyB69817kM8vh5/JBJEL+3JyJIvWq7v24T0w/Q1Fx7uqsH5Bb/9VUCgYEA8Mp2QkA99pZvehycabgHPfRdtMHcAqv1fLLHykKF4RPcKqhowKkBzSCFV5s0tOaMoGtkum6b5KDDibO7JDuZSG+MFgRGE3NOr/ixzN8kDfIPswmud8Ukkas/OVoBotH7IZsaPbgURJaMFXSFWBNv8OniqRds052PBbtsdiUJMAMCgYEA0De+kiiOHxt3w1VcygqsiJ5N2vPfo40Gv+4P+gbMfTKq35GpEQjoPMq8clqQm1CyJAgD7St0WaN0yxqOzBR0kwUJfyDQOFqsFIzlVapV7213wJYnttWhZ6Ywguadtn8haRAg1woPJh04zkqCOkEn5YJgppdzK+V9SNcFFR6jEqsCgYAPZfMgE3mi7kXcuj2qaRFVfe4MJCWMqjB9s/Ug0xY6qYl31OM2BtjNpFnCm3NIakHt9FAxt+cSPNGkWbELBSCtSCzeL5HHpqUOjcnY/yAQID2uxly43guToS7e3QmjvuffY0rPTZlGNZZpvNTWKBANiPdstsnH0piV1kF+YKnwvwKBgA9i/y831gDQe9IwfbHkhgl2gVRbzzv70PLf+chFNllOJDhvQColGVxcsv5UWPlRRkjJWtjs7CUvohLcPI8yN8chiSke2KRBdxPxsYTaGI2f7kiKEBc/xDSvoEgcGK2CyYpFCdg6QxJS+H6uHN+HLxaTwuasrHMi+1YlpZeA8xYPAoGAMOb9j0EHaVsAr2OyTSxfRho4ZfxZBlN05Q4NX3Fjl+eSBNzyJhz0+MxvSG9Dp6DSAnVJd5lpB8m3PYSHHyTqbq21VJm2+8TcysjQhhpFm3/KErGxLpgb9YFTPbsLGmOeSOL7QHHo3bczZe3NLJnzj55r1ITntoAsGpl3gQD5JS0="
  },
  {
    "path": "tests/keys/app_priv_key_with_head.pem",
    "content": "-----BEGIN PRIVATE KEY-----\n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\nwW6XS6BtZ1EOxnJbXGbR1C8ly1nH7hCW8Q==\n-----END PRIVATE KEY-----\n\n"
  },
  {
    "path": "tests/keys/app_priv_key_with_rsa_head.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAw9ju1PnQEysiWxopYQbPIHiNRcbYwV2AYTz+WhRMVaTagmyGNYANmskjixQ+pKvvrl0KPa8CVX47h2AhUp3L2tSygh6C2bEpo7oaB77zZ84XmnUKotfwFUekUZUHjDhX91kVgun0LAIezWMDdRkZ9KC/0/8YnCfHUz9ecfYFd4fu17UlA9JJeEBQuyXDUzvdCtv7VEc9/KZ4sShyQoigaxG4HfRb8Iqmr+J2rARGwBAsjkH+bV609TVPTLCrpZT/rj0ua//1G7cv7Nhh2NcWK7nA2zksLvt/W9vLRYl7/3QXD96qUe2/vARzPp0L/QH3QtIv9NE87xVLmGk+TmxIAQIDAQABAoIBADok8Js4Y4cdWkDT3o8Y12ubfs3FgFrAKLo1won51sPigqEQGTRPBTr8FlpXM1XuWeVZaA3yJG4/YOsLJjmB8aDRXwH0jwKUb3lVah78mQUrkaRgtTytgXC/6U/zP99oZu1ffFx2mvBp3L07dS5Runv/MZR9+s95m9riSGbrFKpsorTtOIEd8Uck8O3ble/iB1G9hmX2qaMEqnppiY0gh7iTl5a9ji+TvZc+4Kfmv4jVKuQ1vGpVtDVNlgzq8RkuWxnm4UHFY2dZ1kU8gNBOImuVT4qfFAvpbBcyB69817kM8vh5/JBJEL+3JyJIvWq7v24T0w/Q1Fx7uqsH5Bb/9VUCgYEA8Mp2QkA99pZvehycabgHPfRdtMHcAqv1fLLHykKF4RPcKqhowKkBzSCFV5s0tOaMoGtkum6b5KDDibO7JDuZSG+MFgRGE3NOr/ixzN8kDfIPswmud8Ukkas/OVoBotH7IZsaPbgURJaMFXSFWBNv8OniqRds052PBbtsdiUJMAMCgYEA0De+kiiOHxt3w1VcygqsiJ5N2vPfo40Gv+4P+gbMfTKq35GpEQjoPMq8clqQm1CyJAgD7St0WaN0yxqOzBR0kwUJfyDQOFqsFIzlVapV7213wJYnttWhZ6Ywguadtn8haRAg1woPJh04zkqCOkEn5YJgppdzK+V9SNcFFR6jEqsCgYAPZfMgE3mi7kXcuj2qaRFVfe4MJCWMqjB9s/Ug0xY6qYl31OM2BtjNpFnCm3NIakHt9FAxt+cSPNGkWbELBSCtSCzeL5HHpqUOjcnY/yAQID2uxly43guToS7e3QmjvuffY0rPTZlGNZZpvNTWKBANiPdstsnH0piV1kF+YKnwvwKBgA9i/y831gDQe9IwfbHkhgl2gVRbzzv70PLf+chFNllOJDhvQColGVxcsv5UWPlRRkjJWtjs7CUvohLcPI8yN8chiSke2KRBdxPxsYTaGI2f7kiKEBc/xDSvoEgcGK2CyYpFCdg6QxJS+H6uHN+HLxaTwuasrHMi+1YlpZeA8xYPAoGAMOb9j0EHaVsAr2OyTSxfRho4ZfxZBlN05Q4NX3Fjl+eSBNzyJhz0+MxvSG9Dp6DSAnVJd5lpB8m3PYSHHyTqbq21VJm2+8TcysjQhhpFm3/KErGxLpgb9YFTPbsLGmOeSOL7QHHo3bczZe3NLJnzj55r1ITntoAsGpl3gQD5JS0=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "tests/keys/app_public_key.pem",
    "content": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw9ju1PnQEysiWxopYQbPIHiNRcbYwV2AYTz+WhRMVaTagmyGNYANmskjixQ+pKvvrl0KPa8CVX47h2AhUp3L2tSygh6C2bEpo7oaB77zZ84XmnUKotfwFUekUZUHjDhX91kVgun0LAIezWMDdRkZ9KC/0/8YnCfHUz9ecfYFd4fu17UlA9JJeEBQuyXDUzvdCtv7VEc9/KZ4sShyQoigaxG4HfRb8Iqmr+J2rARGwBAsjkH+bV609TVPTLCrpZT/rj0ua//1G7cv7Nhh2NcWK7nA2zksLvt/W9vLRYl7/3QXD96qUe2/vARzPp0L/QH3QtIv9NE87xVLmGk+TmxIAQIDAQAB"
  },
  {
    "path": "tsconfig.eslint.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"files\": [\n    \".eslintrc.js\",\n    \"jest.config.js\",\n    \"tests/index.spec.ts\"\n  ]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"types\": [\"node\", \"jest\"],\n    \"lib\":[\"es2015\"],\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"sourceMap\":true,\n    \"removeComments\": true,\n    \"declaration\": true,\n    \"target\": \"es5\",\n    \"noUnusedLocals\":true,\n    \"noUnusedParameters\": true,\n    \"outDir\": \"./dist/\"\n  },\n  \"include\": [\n    \"src/\"\n  ],\n  \"exclude\": [\n    \"node_modules\",\n    \"**/*.spec.ts\"\n  ]\n}"
  }
]