wechatpay-axios-plugin
Version:
微信支付APIv2及v3 NodeJS SDK,支持CLI模式请求OpenAPI,支持v3证书下载,v2付款码支付、企业付款、退款,企业微信-企业支付-企业红包/向员工付款,v2&v3 Native支付、扫码支付、H5支付、JSAPI/小程序支付、合单支付...
169 lines (153 loc) • 6.21 kB
JavaScript
const Decorator = require('./decorator');
const chain = 'chain';
const CLIENT = Symbol('CLIENT');
const enumerable = true;
/**
* Normalize the `str` by the rules: `PascalCase` -> `camelCase` & `camelCase` -> `camel-case` & `$dynamic$` -> `{dynamic}`
* @param {string} str - The string waiting for normalization
* @returns {string} - The transformed string
*/
function normalize(str) {
return (str || '')
// PascalCase` to `camelCase`
.replace(/^[A-Z]/, (w) => w.toLowerCase())
// `camelCase` to `camel-case`
.replace(/[A-Z]/g, (w) => `-${w.toLowerCase()}`)
// `$dynamic_variable$` to `{dynamic_variable}`
.replace(/^(\$|_)(.*)\1$/, '{$2}');
}
/**
* Promise based and chained WeChatPay OpenAPI v2&v3's client.
*
* @example
* const {Wechatpay,Rsa} = require('wechatpay-axios-plugin');
* const wxpay = new Wechatpay({
* mchid,
* serial,
* privateKey: Rsa.from('file:///path/to/wechatpay/apiclient_key.pem', Rsa.KEY_TYPE_PRIVATE),
* certs: {
* [`${pubkey_id}`]: Rsa.from('file:///path/to/wechatpay/publickey.pem', Rsa.KEY_TYPE_PUBLIC),
* },
* secret,
* merchant: {
* cert,
* key,
* // pfx,
* // passphase,
* }
* });
*
* wxpay.v2.pay.micropay({}).then(console.info).catch(console.error);
*
* wxpay.v2.secapi.pay.refund.post({}).then(console.info).catch(console.error);
*
* wxpay.v3.marketing.busifavor.stocks.post({})
* .then(({data}) => console.info(data))
* .catch(({response: {data}}) => console.error(data));
*
* wxpay.v3.pay.transactions.native.post({})
* .then(({data: {code_url}}) => console.info(code_url))
* .catch(({ response: {data}}) => console.error(data));
*
* (async () => {
* try {
* const {data: detail} = await wxpay.v3.pay.transactions.id._transaction_id_
* .get({params: {mchid: '1230000109'}, transaction_id: '1217752501201407033233368018'});
* // or simple like this
* // const {data: detail} = await wxpay.v3.pay.transactions.id['{transaction_id}']
* // .get({params: {mchid: '1230000109'}, transaction_id: '1217752501201407033233368018'});
* console.info(detail);
* } catch({response: {status, statusText, data}}) {
* console.error(status, statusText, data);
* }
* })();
*/
class Wechatpay {
/**
* @property {Decorator} client - The Decorator instance
*/
get client() { return this[CLIENT]; }
static normalize = normalize
/**
* Compose a named function with `prefix` and `suffix` whose joined by a `slash(/)`
*
* @param {string} [prefix] - The prefix string.
* @param {string} [suffix] - The suffix string.
*
* @returns {Proxy} - With a special `Getter` Function.
*/
compose(prefix = '', suffix = '') {
const name = (prefix && suffix) ? `${prefix}/${suffix}` : `${suffix}`;
return new Proxy(this.chain(name), this.handler);
}
/**
* Chain the input pathname with several HTTP verbs onto a `Function` object.
*
* @param {string} pathname - The pathname string.
*
* @returns {Function} - Named as given `pathname` function
*/
chain(pathname) {
const client = this[CLIENT];
/* eslint-disable object-curly-newline, arrow-body-style, object-property-newline */
return ['post', 'put', 'patch'].reduce((resource, method) => {
return Object.defineProperty(resource, method, { enumerable, value: { async [method](data, config) {
return client.request(pathname, method, data, config);
} }[method] });
}, ['delete', 'get'].reduce((resource, method) => {
return Object.defineProperty(resource, method, { enumerable, value: { async [method](config) {
return client.request(pathname, method, undefined, config);
} }[method] });
}, Object.defineProperty({ async [pathname](data, config) {
return client.request(pathname, 'post', data, config);
} }[pathname], chain, { enumerable, value: { [chain]: (thing) => this.compose(pathname, thing) }[chain] })));
/* eslint-enable object-curly-newline, arrow-body-style, object-property-newline */
}
/**
* @property {object} handler - A `Getter` handler object
*/
get handler() {
return {
/**
* Object's `getter` handler
* @memberof Wechatpay.handler#
* @param {object} target - The object
* @param {string} property - The property
* @returns {object} - An object or object's property
*/
get: (target, property) => {
if (typeof property === 'symbol' || property === 'inspect') {
return target;
}
if (property === 'client' && !target.name/* only from the tree root */) { return this[property]; }
if (!Object.prototype.hasOwnProperty.call(target, property)) {
Reflect.set(target, property, this.compose(target.name, normalize(property)));
}
return Reflect.get(target, property);
},
};
}
/**
* Constructor of the magic APIv2&v3's `chain`.
*
* @param {object} config - configuration
* @param {string} config.mchid - The merchant ID
* @param {string} config.serial - The serial number of the merchant certificate
* @param {string|Buffer} config.privateKey - The merchant private key certificate
* @param {object} config.certs - The wechatpay provider size configuration, `{serial: publicKey}` pair
* @param {string} [config.secret] - The merchant secret key string
* @param {object} [config.merchant] - The merchant certificates, more @see {import('tls').createSecureContext}
* @param {string|Buffer} [config.merchant.cert] - The merchant cert chains in PEM format
* @param {string|Buffer} [config.merchant.key] - The merchant private keys in PEM format
* @param {string|Buffer} [config.merchant.pfx] - The merchant PFX or PKCS12 encoded private key and certificate chain.
* @param {string|Buffer} [config.merchant.passphrase] - The merchant shared passphrase used for a single private key and/or a PFX.
*
* @constructor
*/
constructor(config = {}) {
/* eslint no-constructor-return: 0 */
return Object.defineProperty(this, CLIENT, { value: new Decorator(config) }).compose();
}
static get default() { return this; }
}
module.exports = Wechatpay;