├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── index.ts ├── lib ├── constants.ts ├── interface.ts ├── module.ts ├── providers.ts └── util.ts ├── package.json └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | *.json 3 | *.md 4 | yarn.lock 5 | **/*.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | 'prettier/@typescript-eslint', 13 | ], 14 | root: true, 15 | env: { 16 | node: true, 17 | jest: true, 18 | }, 19 | rules: { 20 | '@typescript-eslint/no-namespace': 'off', 21 | '@typescript-eslint/interface-name-prefix': 'off', 22 | '@typescript-eslint/explicit-function-return-type': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | '@typescript-eslint/explicit-module-boundary-types': 'off', 25 | '@typescript-eslint/no-empty-function': 'off', 26 | '@typescript-eslint/no-unused-vars': 'off', 27 | '@typescript-eslint/no-var-requires': 'off', 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .vscode 4 | yarn.lock 5 | test -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "printWidth": 150 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 klover 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nest-wechatpay-node-v3 2 | 3 | ## 安装 4 | 5 | `npm install nest-wechatpay-node-v3` 6 | 7 | `npm install wechatpay-node-v3` 8 | 9 | ## 注册 10 | 11 | ```js 12 | import { WeChatPayModule } from 'nest-wechatpay-node-v3'; 13 | 14 | @Module({ 15 | imports: [ 16 | WeChatPayModule.registerAsync({ 17 | useFactory: async () => { 18 | return { 19 | appid: '直连商户申请的公众号或移动应用appid', 20 | mchid: '商户号', 21 | publicKey: fs.readFileSync('./apiclient_cert.pem'), // 公钥 22 | privateKey: fs.readFileSync('./apiclient_key.pem'), // 秘钥 23 | }; 24 | }, 25 | }), 26 | ], 27 | }) 28 | export class AppModule {} 29 | 30 | // 或者动态配置 useFactory: async (configService: ConfigService) 31 | ``` 32 | 33 | ## 交互 34 | 35 | `import WxPay from 'wechatpay-node-v3';` 36 | 37 | `import { WECHAT_PAY_MANAGER } from 'nest-wechatpay-node-v3';` 38 | 39 | `constructor(@Inject(WECHAT_PAY_MANAGER) private wxPay: WxPay) {}` 40 | 41 | ## 使用 42 | 43 | `const res = await this.wxPay.batches_transfer();` 44 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/interface'; 2 | export * from './lib/module'; 3 | export * from './lib/constants'; 4 | -------------------------------------------------------------------------------- /lib/constants.ts: -------------------------------------------------------------------------------- 1 | export const WECHAT_PAY_MANAGER = 'WECHAT_PAY_MANAGER'; 2 | export const WECHAT_PAY_MODULE_OPTIONS = 'WECHAT_PAY_MODULE_OPTIONS'; 3 | -------------------------------------------------------------------------------- /lib/interface.ts: -------------------------------------------------------------------------------- 1 | import { ModuleMetadata, Provider, Type } from '@nestjs/common'; 2 | 3 | export interface WeChatPayModuleOptions { 4 | /** 直连商户申请的公众号或移动应用appid。 */ 5 | appid: string; 6 | /** 商户号 */ 7 | mchid: string; 8 | /** 证书序列号 */ 9 | serial_no?: string; 10 | /** 公钥 */ 11 | publicKey: Buffer; 12 | /** 密钥 */ 13 | privateKey: Buffer; 14 | /** 认证类型,目前为WECHATPAY2-SHA256-RSA2048 */ 15 | authType?: string; 16 | /** 自定义请求头 */ 17 | userAgent?: string; 18 | /** v3回调key */ 19 | key?: string; 20 | } 21 | 22 | /** 23 | * Interface describing a `WeChatPayOptionsFactory`. Providers supplying configuration 24 | * options for the WeChatPay module must implement this interface. 25 | * @publicApi 26 | */ 27 | export interface WeChatPayOptionsFactory { 28 | createWeChatPayOptions(): Promise | WeChatPayModuleOptions; 29 | } 30 | 31 | /** 32 | * Options for dynamically configuring the WeChatPay module. 33 | * @publicApi 34 | */ 35 | export interface WeChatPayModuleAsyncOptions extends Pick { 36 | /** 37 | * When "true", makes a module global-scoped. 38 | * 39 | * Once imported into any module, a global-scoped module will be visible 40 | * in all modules. Thereafter, modules that wish to inject a service exported 41 | * from a global module do not need to import the provider module. 42 | * 43 | * @default false 44 | */ 45 | global?: boolean; 46 | name?: string; 47 | /** 48 | * Injection token resolving to an existing provider. The provider must implement 49 | * the `WeChatPayOptionsFactory` interface. 50 | */ 51 | useExisting?: Type; 52 | /** 53 | * Injection token resolving to a class that will be instantiated as a provider. 54 | * The class must implement the `WeChatPayOptionsFactory` interface. 55 | */ 56 | useClass?: Type; 57 | /** 58 | * Function returning options (or a Promise resolving to options) to configure the 59 | * cache module. 60 | */ 61 | useFactory?: (...args: any[]) => Promise | WeChatPayModuleOptions; 62 | /** 63 | * Dependencies that a Factory may inject. 64 | */ 65 | inject?: any[]; 66 | extraProviders?: Provider[]; 67 | } 68 | -------------------------------------------------------------------------------- /lib/module.ts: -------------------------------------------------------------------------------- 1 | import { DynamicModule, Module, Provider } from '@nestjs/common'; 2 | import { WECHAT_PAY_MANAGER, WECHAT_PAY_MODULE_OPTIONS } from './constants'; 3 | import { WeChatPayModuleAsyncOptions, WeChatPayOptionsFactory } from './interface'; 4 | import { createWeChatPayManager } from './providers'; 5 | 6 | @Module({}) 7 | export class WeChatPayModule { 8 | static registerAsync(options: WeChatPayModuleAsyncOptions): DynamicModule { 9 | return { 10 | global: !!options.global, 11 | module: WeChatPayModule, 12 | imports: options.imports, 13 | providers: [...this.createAsyncProviders(options), ...(options.extraProviders ?? [])], 14 | exports: [options?.name ?? WECHAT_PAY_MANAGER], 15 | }; 16 | } 17 | 18 | private static createAsyncProviders(options: WeChatPayModuleAsyncOptions): Provider[] { 19 | if (options.useExisting || options.useFactory) { 20 | return [this.createAsyncOptionsProvider(options), createWeChatPayManager(options.name)]; 21 | } 22 | if (options.useClass) { 23 | return [ 24 | this.createAsyncOptionsProvider(options), 25 | { 26 | provide: options.useClass, 27 | useClass: options.useClass, 28 | }, 29 | createWeChatPayManager(options.name), 30 | ]; 31 | } 32 | return []; 33 | } 34 | 35 | private static createAsyncOptionsProvider(options: WeChatPayModuleAsyncOptions): Provider { 36 | if (options.useFactory) { 37 | return { 38 | provide: WECHAT_PAY_MODULE_OPTIONS, 39 | useFactory: options.useFactory, 40 | inject: options.inject || [], 41 | }; 42 | } 43 | return { 44 | provide: WECHAT_PAY_MODULE_OPTIONS, 45 | useFactory: async (optionsFactory: WeChatPayOptionsFactory) => optionsFactory.createWeChatPayOptions(), 46 | inject: [options?.useExisting || options?.useClass || ''], 47 | }; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/providers.ts: -------------------------------------------------------------------------------- 1 | import { Provider } from '@nestjs/common'; 2 | import { WECHAT_PAY_MANAGER, WECHAT_PAY_MODULE_OPTIONS } from './constants'; 3 | import { WeChatPayModuleOptions } from './interface'; 4 | import { loadPackage } from './util'; 5 | 6 | /** 7 | * Creates a WeChatPayManager Provider. 8 | * 9 | * @publicApi 10 | */ 11 | export function createWeChatPayManager(name?: string): Provider { 12 | return { 13 | provide: name || WECHAT_PAY_MANAGER, 14 | useFactory: (options: WeChatPayModuleOptions) => { 15 | const WeChatPayManager = loadPackage('wechatpay-node-v3', 'WeChatPayModule', () => require('wechatpay-node-v3')); 16 | return new WeChatPayManager({ 17 | appid: options.appid, 18 | mchid: options.mchid, 19 | publicKey: options.publicKey, 20 | privateKey: options.privateKey, 21 | ...(options.serial_no && { serial_no: options.serial_no }), 22 | ...(options.authType && { authType: options.authType }), 23 | ...(options.userAgent && { userAgent: options.userAgent }), 24 | ...(options.key && { key: options.key }), 25 | }); 26 | }, 27 | inject: [WECHAT_PAY_MODULE_OPTIONS], 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /lib/util.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-types */ 2 | import { Logger } from '@nestjs/common'; 3 | 4 | const MISSING_REQUIRED_DEPENDENCY = (name: string, reason: string) => 5 | `The "${name}" package is missing. Please, make sure to install this library ($ npm install ${name}) to take advantage of ${reason}.`; 6 | 7 | const logger = new Logger('PackageLoader'); 8 | 9 | export function loadPackage(packageName: string, context: string, loaderFn?: Function) { 10 | try { 11 | return loaderFn ? loaderFn() : require(packageName); 12 | } catch (e) { 13 | logger.error(MISSING_REQUIRED_DEPENDENCY(packageName, context)); 14 | process.exit(1); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nest-wechatpay-node-v3", 3 | "version": "1.0.2", 4 | "description": "nest支持wechatpay-node-v3的使用", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build": "rm -rf ./dist && tsc", 10 | "lint": "eslint \"*.ts\" --fix", 11 | "release": "npm publish" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/klover2/nest-wechatpay-node-v3-ts.git" 16 | }, 17 | "keywords": [ 18 | "node", 19 | "wechat", 20 | "微信支付", 21 | "微信提现" 22 | ], 23 | "author": "klover", 24 | "license": "ISC", 25 | "bugs": { 26 | "url": "https://github.com/klover2/nest-wechatpay-node-v3-ts/issues" 27 | }, 28 | "homepage": "https://github.com/klover2/nest-wechatpay-node-v3-ts#readme", 29 | "files": [ 30 | "dist" 31 | ], 32 | "dependencies": {}, 33 | "devDependencies": { 34 | "@nestjs/common": "^8.2.4", 35 | "@types/node": "^13.9.1", 36 | "@typescript-eslint/eslint-plugin": "3.0.2", 37 | "@typescript-eslint/parser": "3.0.2", 38 | "eslint": "7.1.0", 39 | "eslint-config-prettier": "^6.10.0", 40 | "eslint-plugin-import": "^2.20.1", 41 | "prettier": "^1.19.1", 42 | "ts-node": "^8.6.2", 43 | "typescript": "^3.7.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true, 4 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 5 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 6 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 7 | "outDir": "dist", /* Redirect output structure to the directory. */ 8 | "strict": true, /* Enable all strict type-checking options. */ 9 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 10 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 11 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 12 | }, 13 | "exclude": ["node_modules", "dist", "test"] 14 | } 15 | --------------------------------------------------------------------------------