node-paytmpg 6.4.6 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.MD +132 -182
  2. package/app/views/layouts/index.hbs +7 -7
  3. package/app/views/result.hbs +1 -1
  4. package/dist/app/controllers/adapters/open_money.js +400 -0
  5. package/dist/app/controllers/adapters/paytm.js +34 -0
  6. package/{app → dist/app}/controllers/adapters/payu.js +208 -239
  7. package/dist/app/controllers/checksum/PaytmChecksum.js +118 -0
  8. package/dist/app/controllers/checksum/checksum.js +158 -0
  9. package/dist/app/controllers/checksum/crypt.js +117 -0
  10. package/dist/app/controllers/checksum/server.js +130 -0
  11. package/dist/app/controllers/payment.controller.js +985 -0
  12. package/dist/app/controllers/static/loadingsvg.js +54 -0
  13. package/dist/app/controllers/user.controller.js +53 -0
  14. package/dist/app/models/index.js +2 -0
  15. package/dist/app/routes/payment_route.js +46 -0
  16. package/dist/app/utils/buildConfig.js +210 -0
  17. package/dist/app/utils/utils.js +20 -0
  18. package/dist/app/views/home.hbs +22 -0
  19. package/dist/app/views/init.hbs +98 -0
  20. package/dist/app/views/layouts/index.hbs +53 -0
  21. package/dist/app/views/result.hbs +33 -0
  22. package/dist/index.js +119 -0
  23. package/dist/package.json +67 -0
  24. package/dist/public/css/style.css +455 -0
  25. package/dist/public/js/index.js +283 -0
  26. package/dist/public/layer_checkout.js +38 -0
  27. package/dist/public/pay.png +0 -0
  28. package/dist/public/start.png +0 -0
  29. package/dist/public/start2.png +0 -0
  30. package/dist/public/stat.png +0 -0
  31. package/dist/public/test.html +24 -0
  32. package/dist/public/test.html~ +24 -0
  33. package/package.json +29 -6
  34. package/public/test.html~ +24 -0
  35. package/.github/workflows/codeql-analysis.yml +0 -71
  36. package/.github/workflows/nodejs.yml +0 -24
  37. package/.github/workflows/npm-publish.yml +0 -23
  38. package/Dockerfile +0 -9
  39. package/app/controllers/adapters/open_money.js +0 -515
  40. package/app/controllers/checksum/PaytmChecksum.js +0 -94
  41. package/app/controllers/checksum/checksum.js +0 -154
  42. package/app/controllers/checksum/crypt.js +0 -98
  43. package/app/controllers/checksum/server.js +0 -132
  44. package/app/controllers/np_user.controller.js +0 -89
  45. package/app/controllers/payment_controller.js +0 -1204
  46. package/app/models/np_multidbplugin.js +0 -111
  47. package/app/models/np_transaction.model.js +0 -16
  48. package/app/models/np_user.model.js +0 -12
  49. package/app/routes/payment_route.js +0 -73
  50. package/app.yaml +0 -18
  51. package/example.js +0 -34
  52. package/index.js +0 -86
  53. package/lib/config/buildConfig.js +0 -113
  54. package/lib/config/defaults.js +0 -37
  55. package/lib/config/validator.js +0 -103
  56. package/lib/services/database.service.js +0 -153
  57. package/lib/utils/id-generator.js +0 -30
  58. package/lib/utils/sanitizer.js +0 -25
@@ -1,111 +0,0 @@
1
- module.exports = function (modelName, db, sampleData) {
2
-
3
- if (db && sampleData && db.create) {
4
- db.create(modelName, sampleData)
5
- .then(() => {
6
- console.log('Model Created in db ', modelName);
7
- })
8
- .catch((e) => {
9
- console.log('Error in creating model ', e);
10
- });
11
- }
12
-
13
- class MultiDbMapper {
14
-
15
- idFieldName
16
- objectData
17
- constructor(objectData) {
18
- MultiDbMapper.sanitizeRequest(objectData)
19
- this.objectData = objectData;
20
- }
21
-
22
-
23
- static async sanitizeRequest(body) {
24
-
25
- if (!body)
26
- return;
27
- if (body.amount)
28
- body.amount = parseFloat(body.amount);
29
- if (body.TXN_AMOUNT)
30
- body.amount = parseFloat(body.TXN_AMOUNT);
31
- }
32
-
33
- async save() {
34
- var response = await MultiDbMapper.db.insert(MultiDbMapper.modelname, this.objectData, this.objectData[MultiDbMapper.idFieldName]);
35
- if (typeof response == Object && response.ops[0])
36
- response = response.ops[0];
37
- else
38
- response = this.objectData
39
-
40
- MultiDbMapper.sanitizeRequest(response)
41
-
42
- return response;
43
- }
44
-
45
- //callback(err,resp)
46
- static async findOne(query, cb) {
47
-
48
- var response;
49
- try {
50
- response = await MultiDbMapper.db.getOne(MultiDbMapper.modelname, query);
51
- MultiDbMapper.sanitizeRequest(response)
52
- } catch (e) {
53
- if (cb)
54
- return cb(e, undefined)
55
- else
56
- throw e;
57
- }
58
- if (cb)
59
- cb(undefined, response);
60
- else
61
- return response;
62
- }
63
-
64
- static async updateOne(query, newValue, cb) {
65
-
66
- var response;
67
- try {
68
-
69
- response = await MultiDbMapper.db.update(MultiDbMapper.modelname, query, newValue['$set']);
70
-
71
- } catch (e) {
72
- if (cb)
73
- return cb(e, undefined)
74
- else
75
- throw e;
76
- }
77
-
78
- if (cb)
79
- cb(undefined, response);
80
- else
81
- return response;
82
- }
83
-
84
- static async deleteOne(query, cb) {
85
-
86
- var response;
87
- try {
88
-
89
- response = await MultiDbMapper.db.delete(MultiDbMapper.modelname, query);
90
- MultiDbMapper.sanitizeRequest(response)
91
-
92
- } catch (e) {
93
- if (cb)
94
- return cb(e, undefined)
95
- else
96
- throw e;
97
- }
98
- if (cb)
99
- cb(undefined, response)
100
- else
101
- return response;
102
-
103
- }
104
-
105
- }
106
-
107
- MultiDbMapper.modelname = modelName;
108
- MultiDbMapper.db = db;
109
- return MultiDbMapper;
110
- }
111
-
@@ -1,16 +0,0 @@
1
- const mongoose=require('mongoose')
2
- let TransactionSchema=mongoose.Schema({
3
-
4
- orderId:String,
5
- cusId:String,
6
- time:Number,
7
- status:String,
8
- name:String,
9
- email:String,
10
- phone:String,
11
- amount:Number,
12
- pname:String,
13
- extra:String
14
-
15
- });
16
- module.exports=mongoose.model('nptransaction',TransactionSchema);
@@ -1,12 +0,0 @@
1
- const mongoose = require('mongoose');
2
-
3
- const UserSchema = mongoose.Schema({
4
- email: String,
5
- id: String,
6
- name : String,
7
- phone : String,
8
- }, {
9
- timestamps: true
10
- });
11
-
12
- module.exports = mongoose.model('npuser', UserSchema);
@@ -1,73 +0,0 @@
1
- module.exports = (app, express, callbacks) => {
2
- const bodyParser = require('body-parser');
3
- var exphbs = require('express-handlebars')
4
- var path = require('path')
5
- var packageInfo = require('../../package.json')
6
- var config = (app.get('np_config'))
7
- var pc = require('../controllers/payment_controller.js')(app, callbacks)
8
- var router = express.Router()
9
- app.set('view_path', __dirname + config.view_path)
10
- var vp = app.get('view_path')
11
- if (config.db_url !== undefined) {
12
-
13
- const mongoose = require('mongoose');
14
-
15
- console.log('PaytmPG : Using MongoDB');
16
-
17
- mongoose.Promise = global.Promise;
18
-
19
- mongoose.connect(config.db_url, {
20
- useUnifiedTopology: true,
21
- useNewUrlParser: true
22
- }).then(() => {
23
- console.log("Successfully connected to the database");
24
- }).catch(err => {
25
- console.log('Could not connect to the database. Exiting now...', err);
26
- process.exit();
27
- });
28
-
29
- } else if (app.multidborm !== undefined) {
30
-
31
- console.log('PaytmPG : Using MultiDB ORM');
32
-
33
- }
34
-
35
-
36
-
37
- app.engine('hbs', exphbs({
38
- extname: 'hbs',
39
- defaultLayout: vp + '/layouts/index.hbs',
40
- helpers: {
41
- theme_color: function () {
42
- return config.theme_color;
43
- },
44
- logo: function () {
45
- return config.logo;
46
- }
47
- }
48
- }))
49
-
50
- app.set('view engine', 'handlebars');
51
-
52
- let saveRawBody = function (req, res, buf, encoding) {
53
- req.rawBody = buf.toString();
54
- }
55
- app.use(bodyParser.urlencoded({ extended: true }))
56
- app.use(bodyParser.json({ verify: saveRawBody }))
57
-
58
- app.use("/" + config.path_prefix, express.static(path.join(__dirname, '../../public')));
59
- app.use('/' + config.path_prefix, router);
60
-
61
- router.all('/', pc.init);
62
- router.all('/init', pc.init);
63
-
64
- // router.all('/home', pc.home)
65
- router.all('/callback', pc.callback)
66
- router.all('/api/webhook', pc.webhook)
67
- router.all('/api/status', pc.status)
68
- router.all('/api/createTxn/token', pc.createTxnToken)
69
- router.all('/api/createTxn', pc.createTxn)
70
-
71
-
72
- return router
73
- }
package/app.yaml DELETED
@@ -1,18 +0,0 @@
1
- # Copyright 2017, Google, Inc.
2
- # Licensed under the Apache License, Version 2.0 (the "License");
3
- # you may not use this file except in compliance with the License.
4
- # You may obtain a copy of the License at
5
- #
6
- # http://www.apache.org/licenses/LICENSE-2.0
7
- #
8
- # Unless required by applicable law or agreed to in writing, software
9
- # distributed under the License is distributed on an "AS IS" BASIS,
10
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- # See the License for the specific language governing permissions and
12
- # limitations under the License.
13
- #
14
- # [START runtime]
15
- runtime: nodejs
16
- env: flex
17
- # [END runtime]
18
-
package/example.js DELETED
@@ -1,34 +0,0 @@
1
- const express = require('express');
2
- const { SQLiteDB } = require('multi-db-orm');
3
- const { createPaymentMiddleware } = require('./index');
4
-
5
- try { require('dotenv').config(); } catch (e) { }
6
-
7
- const app = express();
8
-
9
- // Local SQLite sample DB via multi-db-orm; swap for your own adapter
10
- const db = new SQLiteDB('test.db');
11
-
12
- const payment = createPaymentMiddleware({
13
- host_url: process.env.NP_HOST_URL || 'http://localhost:5543',
14
- path_prefix: process.env.NP_PATH_PREFIX || '_pay',
15
- homepage: '/',
16
- payu_url: 'https://secure.payu.in', // use https://test.payu.in for sandbox
17
- MID: process.env.NP_MID || '12345',
18
- WEBSITE: process.env.NP_WEBSITE || 'WEBSTAGING',
19
- KEY: process.env.NP_KEY || 'abcdef',
20
- SECRET: process.env.NP_SECRET || 'abcdef', // salt for payu / razor
21
- CHANNEL_ID: process.env.NP_CHANNEL_ID || 'WAP',
22
- INDUSTRY_TYPE_ID: process.env.NP_INDUSTRY_TYPE_ID || 'Retail',
23
- theme: {
24
- primary: '#231530',
25
- accent: '#5ce1e6',
26
- },
27
- brand: 'DemoPay',
28
- }, db);
29
-
30
- app.use('/_pay',payment);
31
-
32
- app.listen(process.env.PORT || 5543, function () {
33
- console.log('Server started at', process.env.PORT || 5543);
34
- });
package/index.js DELETED
@@ -1,86 +0,0 @@
1
- const express = require('express');
2
- const path = require('path');
3
- const bodyParser = require('body-parser');
4
- const exphbs = require('express-handlebars');
5
- const mongoose = require('mongoose');
6
-
7
- const buildConfig = require('./lib/config/buildConfig');
8
-
9
- /**
10
- * Creates an isolated payment middleware that can be mounted on any Express app.
11
- * This keeps the payment creation/verification logic intact while exposing a cleaner API.
12
- *
13
- * @param {object} userConfig - configuration overrides (gateway keys, branding, hooks, etc.)
14
- * @param {object} db - optional multi-db-orm instance; if omitted and db_url is provided, MongoDB is used
15
- * @returns {import('express').Application} configured sub-application ready to mount
16
- */
17
- function createPaymentMiddleware(userConfig = {}, db) {
18
- const config = buildConfig(userConfig);
19
- const subApp = express();
20
-
21
- // expose config + optional db handle for downstream controllers
22
- subApp.set('np_config', config);
23
- subApp.locals.theme = config.theme || {};
24
- subApp.locals.brand = config.brand || 'Secure Pay';
25
- subApp.locals.logo = config.logo;
26
- subApp.locals.themeName = config.themeName || (config.theme && config.theme.name) || 'dark';
27
- if (config.db_url) {
28
- mongoose.Promise = global.Promise;
29
- mongoose.connect(config.db_url, {
30
- useUnifiedTopology: true,
31
- useNewUrlParser: true,
32
- }).then(() => {
33
- console.log('PaytmPG : Connected to MongoDB');
34
- }).catch(err => {
35
- console.log('PaytmPG : Failed to connect MongoDB', err);
36
- });
37
- } else if (db) {
38
- subApp.multidborm = db;
39
- }
40
-
41
- // view engine + theming
42
- const viewRoot = config.templateDir
43
- ? path.resolve(config.templateDir)
44
- : path.join(__dirname, 'app', 'views');
45
- const layoutPath = path.join(viewRoot, 'layouts', 'index.hbs');
46
-
47
- subApp.engine('hbs', exphbs({
48
- extname: 'hbs',
49
- defaultLayout: layoutPath,
50
- helpers: {
51
- theme_color: () => config.theme_color,
52
- logo: () => config.logo,
53
- brand: () => config.brand || 'Secure Pay',
54
- },
55
- }));
56
- subApp.set('view engine', 'handlebars');
57
-
58
- // body parsing with raw body capture (needed for webhooks)
59
- const saveRawBody = (req, res, buf) => {
60
- req.rawBody = buf.toString();
61
- };
62
- subApp.use(bodyParser.urlencoded({ extended: true }));
63
- subApp.use(bodyParser.json({ verify: saveRawBody }));
64
- // wire routes against existing payment controller (logic unchanged)
65
- const callbacks = config.callbacks || userConfig.callbacks;
66
- const pc = require('./app/controllers/payment_controller')(subApp, callbacks);
67
- subApp.use((req, res, next) => {
68
- console.log('Received request at', req.originalUrl);
69
- next();
70
- });
71
- subApp.all('/init', pc.init);
72
- subApp.all('/callback', pc.callback);
73
- subApp.all('/api/webhook', pc.webhook);
74
- subApp.all('/api/status', pc.status);
75
- subApp.all('/api/createTxn/token', pc.createTxnToken);
76
- subApp.all('/api/createTxn', pc.createTxn);
77
- subApp.all('/', pc.init);
78
-
79
- subApp.use(express.static(path.join(__dirname, 'public')), pc.init);
80
-
81
- return subApp;
82
- }
83
-
84
- module.exports = { createPaymentMiddleware };
85
-
86
-
@@ -1,113 +0,0 @@
1
- const defaults = require('./defaults');
2
- const { validateConfig } = require('./validator');
3
-
4
- function pickEnv(keys) {
5
- const output = {};
6
- keys.forEach((key) => {
7
- if (process.env[key] !== undefined) {
8
- output[key] = process.env[key];
9
- }
10
- });
11
- return output;
12
- }
13
-
14
- function buildConfig(userConfig = {}) {
15
- const envOverrides = pickEnv([
16
- 'NP_HOST_URL',
17
- 'NP_PATH_PREFIX',
18
- 'NP_HOMEPAGE',
19
- 'NP_TEMPLATE_DIR',
20
- 'NP_THEME_COLOR',
21
- 'NP_LOGO',
22
- 'NP_DB_URL',
23
- 'NP_PAYTM_URL',
24
- 'NP_RAZOR_URL',
25
- 'NP_PAYU_URL',
26
- 'NP_OPEN_MONEY_URL',
27
- 'NP_MID',
28
- 'NP_WEBSITE',
29
- 'NP_KEY',
30
- 'NP_SECRET',
31
- 'NP_CHANNEL_ID',
32
- 'NP_INDUSTRY_TYPE_ID',
33
- 'NP_MODE',
34
- 'NP_THEME_NAME',
35
- ]);
36
-
37
- const merged = {
38
- ...defaults,
39
- ...normalizeEnv(envOverrides),
40
- ...userConfig,
41
- };
42
-
43
- // theme normalization
44
- const themeName = (userConfig.themeName || userConfig.theme?.name || merged.theme_name || 'dark').toLowerCase();
45
- const theme = {
46
- primary: getThemeColor(userConfig, merged),
47
- accent: userConfig?.theme?.accent || merged.theme_accent || '#4ae0ff',
48
- surface: userConfig?.theme?.surface || '#0f1021',
49
- text: userConfig?.theme?.text || '#e9ecf2',
50
- success: userConfig?.theme?.success || '#24cf5f',
51
- danger: userConfig?.theme?.danger || '#ff6b6b',
52
- name: themeName,
53
- };
54
-
55
- merged.theme = theme;
56
- merged.theme_color = theme.primary;
57
- merged.logo = userConfig.logo || merged.logo;
58
- merged.brand = userConfig.brand || 'Secure Pay';
59
- merged.callbacks = userConfig.callbacks || userConfig.hooks || merged.callbacks || {};
60
- merged.templateDir = userConfig.templateDir || merged.templateDir;
61
- merged.themeName = themeName;
62
-
63
- // ensure view path remains compatible with legacy controllers
64
- if (!merged.view_path) {
65
- merged.view_path = '/../views/';
66
- }
67
-
68
- if (userConfig.host_url) {
69
- merged.host_url = userConfig.host_url;
70
- } else if (process.env.NP_HOST_URL) {
71
- merged.host_url = process.env.NP_HOST_URL;
72
- }
73
-
74
- return validateConfig(merged);
75
- }
76
-
77
- function getThemeColor(userConfig, merged) {
78
- if (userConfig?.theme?.primary) return userConfig.theme.primary;
79
- if (userConfig.theme_color) return userConfig.theme_color;
80
- if (merged.NP_THEME_COLOR) return merged.NP_THEME_COLOR;
81
- return merged.theme_color;
82
- }
83
-
84
- function normalizeEnv(env) {
85
- const mapping = {
86
- NP_HOST_URL: 'host_url',
87
- NP_PATH_PREFIX: 'path_prefix',
88
- NP_HOMEPAGE: 'homepage',
89
- NP_TEMPLATE_DIR: 'templateDir',
90
- NP_THEME_COLOR: 'theme_color',
91
- NP_LOGO: 'logo',
92
- NP_DB_URL: 'db_url',
93
- NP_PAYTM_URL: 'paytm_url',
94
- NP_RAZOR_URL: 'razor_url',
95
- NP_PAYU_URL: 'payu_url',
96
- NP_OPEN_MONEY_URL: 'open_money_url',
97
- NP_MID: 'MID',
98
- NP_WEBSITE: 'WEBSITE',
99
- NP_KEY: 'KEY',
100
- NP_SECRET: 'SECRET',
101
- NP_CHANNEL_ID: 'CHANNEL_ID',
102
- NP_INDUSTRY_TYPE_ID: 'INDUSTRY_TYPE_ID',
103
- NP_MODE: 'mode',
104
- NP_THEME_NAME: 'themeName',
105
- };
106
- return Object.keys(env).reduce((acc, key) => {
107
- const target = mapping[key];
108
- if (target) acc[target] = env[key];
109
- return acc;
110
- }, {});
111
- }
112
-
113
- module.exports = buildConfig;
@@ -1,37 +0,0 @@
1
- module.exports = {
2
- // Server configuration
3
- host_url: 'http://localhost:3000',
4
- path_prefix: '_pay',
5
- homepage: '/',
6
-
7
- // Template configuration
8
- templateDir: null, // null = use built-in views, or provide path to custom templates
9
- templateEngine: 'handlebars',
10
-
11
- // UI Customization
12
- theme_color: '#3399cc',
13
- logo: '/favicon.ico',
14
-
15
- // Transaction ID configuration
16
- id_length: 10,
17
-
18
- // Database
19
- db_url: null, // MongoDB URL (legacy), leave null to use multidborm
20
-
21
- // Payment Gateway URLs
22
- // paytm_url: null, // e.g., 'https://securegw-stage.paytm.in' for test, 'https://securegw.paytm.in' for production
23
- // razor_url: null, // e.g., 'https://api.razorpay.com/v1/'
24
- // payu_url: null, // e.g., 'https://test.payu.in' for test, 'https://secure.payu.in' for production
25
- // open_money_url: null, // e.g., 'https://sandbox-icp-api.bankopen.co/api' for sandbox, 'https://icp-api.bankopen.co/api' for live
26
-
27
- // Gateway Credentials (must be provided by user)
28
- // MID: null,
29
- // WEBSITE: null,
30
- // KEY: null,
31
- // SECRET: null,
32
- // CHANNEL_ID: 'WEB',
33
- // INDUSTRY_TYPE_ID: 'Retail',
34
-
35
- // Payment mode configuration (optional)
36
- // mode: null // JSON string of enabled payment modes for Paytm
37
- };
@@ -1,103 +0,0 @@
1
- const defaults = require('./defaults');
2
-
3
- /**
4
- * Validates and merges config with defaults
5
- * @param {Object} userConfig - User-provided configuration
6
- * @returns {Object} Merged and validated configuration
7
- * @throws {Error} If required fields are missing
8
- */
9
- function validateConfig(userConfig) {
10
- if (!userConfig || typeof userConfig !== 'object') {
11
- throw new Error('Config must be an object');
12
- }
13
-
14
- // Merge with defaults
15
- const config = { ...defaults, ...userConfig };
16
-
17
- // Detect which payment gateway is being used
18
- const hasPaytm = !!config.paytm_url;
19
- const hasRazorpay = !!config.razor_url;
20
- const hasPayU = !!config.payu_url;
21
- const hasOpenMoney = !!config.open_money_url;
22
-
23
- if (!hasPaytm && !hasRazorpay && !hasPayU && !hasOpenMoney) {
24
- throw new Error(
25
- 'At least one payment gateway must be configured. ' +
26
- 'Please provide one of: paytm_url, razor_url, payu_url, or open_money_url'
27
- );
28
- }
29
-
30
- // Validate required credentials based on gateway
31
- if (hasPaytm) {
32
- validatePaytmConfig(config);
33
- }
34
-
35
- if (hasRazorpay) {
36
- validateRazorpayConfig(config);
37
- }
38
-
39
- if (hasPayU) {
40
- validatePayUConfig(config);
41
- }
42
-
43
- if (hasOpenMoney) {
44
- validateOpenMoneyConfig(config);
45
- }
46
-
47
- // Validate common fields
48
- if (!config.host_url) {
49
- throw new Error('host_url is required');
50
- }
51
-
52
- if (!config.path_prefix) {
53
- throw new Error('path_prefix is required');
54
- }
55
-
56
- return config;
57
- }
58
-
59
- function validatePaytmConfig(config) {
60
- const required = ['MID', 'WEBSITE', 'KEY', 'CHANNEL_ID', 'INDUSTRY_TYPE_ID'];
61
- const missing = required.filter(field => !config[field]);
62
-
63
- if (missing.length > 0) {
64
- throw new Error(
65
- `Paytm configuration incomplete. Missing fields: ${missing.join(', ')}`
66
- );
67
- }
68
- }
69
-
70
- function validateRazorpayConfig(config) {
71
- const required = ['KEY', 'SECRET'];
72
- const missing = required.filter(field => !config[field]);
73
-
74
- if (missing.length > 0) {
75
- throw new Error(
76
- `Razorpay configuration incomplete. Missing fields: ${missing.join(', ')}`
77
- );
78
- }
79
- }
80
-
81
- function validatePayUConfig(config) {
82
- const required = ['KEY', 'SECRET'];
83
- const missing = required.filter(field => !config[field]);
84
-
85
- if (missing.length > 0) {
86
- throw new Error(
87
- `PayU configuration incomplete. Missing fields: ${missing.join(', ')}`
88
- );
89
- }
90
- }
91
-
92
- function validateOpenMoneyConfig(config) {
93
- const required = ['KEY', 'SECRET'];
94
- const missing = required.filter(field => !config[field]);
95
-
96
- if (missing.length > 0) {
97
- throw new Error(
98
- `OpenMoney configuration incomplete. Missing fields: ${missing.join(', ')}`
99
- );
100
- }
101
- }
102
-
103
- module.exports = { validateConfig };