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