payment-skill 1.0.1 → 1.1.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.
@@ -75,7 +75,22 @@ export class ConfigManager {
75
75
  end: '22:00',
76
76
  timezone: 'Europe/Bucharest'
77
77
  },
78
- blockedCategories: ['gambling', 'adult', 'drugs', 'weapons', 'tobacco'],
78
+ advancedLimits: {
79
+ cumulativeBudgets: [],
80
+ domainControls: {
81
+ mode: 'blacklist',
82
+ domains: []
83
+ },
84
+ geographyControls: {
85
+ enabled: false,
86
+ mode: 'allow',
87
+ countries: []
88
+ },
89
+ categoryControls: {
90
+ blockedCategories: ['gambling', 'adult', 'drugs', 'weapons', 'tobacco'],
91
+ allowedCategories: []
92
+ }
93
+ },
79
94
  verifiedMerchantsOnly: true,
80
95
  webhookUrl: null
81
96
  };
@@ -170,22 +185,117 @@ export class ConfigManager {
170
185
  this.saveConfig();
171
186
  }
172
187
 
173
- // Blocked Categories
174
- getBlockedCategories(): string[] {
175
- return this.config.blockedCategories;
188
+ // Advanced Limits - Cumulative Budgets
189
+ getCumulativeBudgets(): any[] {
190
+ return this.config.advancedLimits?.cumulativeBudgets || [];
191
+ }
192
+
193
+ addCumulativeBudget(budget: any): void {
194
+ if (!this.config.advancedLimits) {
195
+ this.config.advancedLimits = this.getDefaultConfig().advancedLimits;
196
+ }
197
+ this.config.advancedLimits.cumulativeBudgets.push(budget);
198
+ this.saveConfig();
199
+ }
200
+
201
+ removeCumulativeBudget(index: number): void {
202
+ if (this.config.advancedLimits?.cumulativeBudgets) {
203
+ this.config.advancedLimits.cumulativeBudgets.splice(index, 1);
204
+ this.saveConfig();
205
+ }
206
+ }
207
+
208
+ // Advanced Limits - Domain Controls
209
+ getDomainControls(): any {
210
+ return this.config.advancedLimits?.domainControls || { mode: 'blacklist', domains: [] };
211
+ }
212
+
213
+ setDomainControls(controls: any): void {
214
+ if (!this.config.advancedLimits) {
215
+ this.config.advancedLimits = this.getDefaultConfig().advancedLimits;
216
+ }
217
+ this.config.advancedLimits.domainControls = controls;
218
+ this.saveConfig();
219
+ }
220
+
221
+ addDomain(domain: string): void {
222
+ if (!this.config.advancedLimits) {
223
+ this.config.advancedLimits = this.getDefaultConfig().advancedLimits;
224
+ }
225
+ if (!this.config.advancedLimits.domainControls.domains.includes(domain)) {
226
+ this.config.advancedLimits.domainControls.domains.push(domain);
227
+ this.saveConfig();
228
+ }
229
+ }
230
+
231
+ removeDomain(domain: string): void {
232
+ if (this.config.advancedLimits?.domainControls?.domains) {
233
+ this.config.advancedLimits.domainControls.domains =
234
+ this.config.advancedLimits.domainControls.domains.filter((d: string) => d !== domain);
235
+ this.saveConfig();
236
+ }
237
+ }
238
+
239
+ // Advanced Limits - Geography Controls
240
+ getGeographyControls(): any {
241
+ return this.config.advancedLimits?.geographyControls || { enabled: false, mode: 'allow', countries: [] };
242
+ }
243
+
244
+ setGeographyControls(controls: any): void {
245
+ if (!this.config.advancedLimits) {
246
+ this.config.advancedLimits = this.getDefaultConfig().advancedLimits;
247
+ }
248
+ this.config.advancedLimits.geographyControls = controls;
249
+ this.saveConfig();
250
+ }
251
+
252
+ // Advanced Limits - Category Controls
253
+ getCategoryControls(): any {
254
+ return this.config.advancedLimits?.categoryControls || { blockedCategories: [], allowedCategories: [] };
255
+ }
256
+
257
+ setCategoryControls(controls: any): void {
258
+ if (!this.config.advancedLimits) {
259
+ this.config.advancedLimits = this.getDefaultConfig().advancedLimits;
260
+ }
261
+ this.config.advancedLimits.categoryControls = controls;
262
+ this.saveConfig();
176
263
  }
177
264
 
178
265
  addBlockedCategory(category: string): void {
179
- if (!this.config.blockedCategories.includes(category)) {
180
- this.config.blockedCategories.push(category);
266
+ if (!this.config.advancedLimits) {
267
+ this.config.advancedLimits = this.getDefaultConfig().advancedLimits;
268
+ }
269
+ if (!this.config.advancedLimits.categoryControls.blockedCategories.includes(category)) {
270
+ this.config.advancedLimits.categoryControls.blockedCategories.push(category);
181
271
  this.saveConfig();
182
272
  }
183
273
  }
184
274
 
185
275
  removeBlockedCategory(category: string): void {
186
- this.config.blockedCategories =
187
- this.config.blockedCategories.filter((c: string) => c !== category);
188
- this.saveConfig();
276
+ if (this.config.advancedLimits?.categoryControls?.blockedCategories) {
277
+ this.config.advancedLimits.categoryControls.blockedCategories =
278
+ this.config.advancedLimits.categoryControls.blockedCategories.filter((c: string) => c !== category);
279
+ this.saveConfig();
280
+ }
281
+ }
282
+
283
+ addAllowedCategory(category: string): void {
284
+ if (!this.config.advancedLimits) {
285
+ this.config.advancedLimits = this.getDefaultConfig().advancedLimits;
286
+ }
287
+ if (!this.config.advancedLimits.categoryControls.allowedCategories.includes(category)) {
288
+ this.config.advancedLimits.categoryControls.allowedCategories.push(category);
289
+ this.saveConfig();
290
+ }
291
+ }
292
+
293
+ removeAllowedCategory(category: string): void {
294
+ if (this.config.advancedLimits?.categoryControls?.allowedCategories) {
295
+ this.config.advancedLimits.categoryControls.allowedCategories =
296
+ this.config.advancedLimits.categoryControls.allowedCategories.filter((c: string) => c !== category);
297
+ this.saveConfig();
298
+ }
189
299
  }
190
300
 
191
301
  // Webhook URL
@@ -84,14 +84,124 @@ export class PaymentSkillServer {
84
84
  res.json({ success: true, message: 'Emergency stop deactivated' });
85
85
  });
86
86
 
87
- // Get limits
87
+ // Get all limits and controls
88
88
  this.app.get('/api/limits', (req, res) => {
89
89
  res.json({
90
90
  limits: configManager.getLimits(),
91
- timeWindow: configManager.getTimeWindow()
91
+ timeWindow: configManager.getTimeWindow(),
92
+ cumulativeBudgets: configManager.getCumulativeBudgets(),
93
+ domainControls: configManager.getDomainControls(),
94
+ geographyControls: configManager.getGeographyControls(),
95
+ categoryControls: configManager.getCategoryControls()
92
96
  });
93
97
  });
94
98
 
99
+ // Update basic limits
100
+ this.app.post('/api/limits', (req, res) => {
101
+ const { perTransaction, daily, weekly, monthly, maxTransactionsPerHour } = req.body;
102
+ configManager.setLimits({ perTransaction, daily, weekly, monthly, maxTransactionsPerHour });
103
+ res.json({ success: true, message: 'Limits updated' });
104
+ });
105
+
106
+ // Cumulative Budgets
107
+ this.app.get('/api/limits/budgets', (req, res) => {
108
+ res.json(configManager.getCumulativeBudgets());
109
+ });
110
+
111
+ this.app.post('/api/limits/budgets', (req, res) => {
112
+ configManager.addCumulativeBudget(req.body);
113
+ res.json({ success: true, message: 'Budget added' });
114
+ });
115
+
116
+ this.app.delete('/api/limits/budgets/:index', (req, res) => {
117
+ configManager.removeCumulativeBudget(parseInt(req.params.index));
118
+ res.json({ success: true, message: 'Budget removed' });
119
+ });
120
+
121
+ // Domain Controls
122
+ this.app.get('/api/limits/domains', (req, res) => {
123
+ res.json(configManager.getDomainControls());
124
+ });
125
+
126
+ this.app.post('/api/limits/domains', (req, res) => {
127
+ const { mode, domain } = req.body;
128
+ if (mode) {
129
+ const controls = configManager.getDomainControls();
130
+ controls.mode = mode;
131
+ configManager.setDomainControls(controls);
132
+ }
133
+ if (domain) {
134
+ configManager.addDomain(domain);
135
+ }
136
+ res.json({ success: true, message: 'Domain controls updated' });
137
+ });
138
+
139
+ this.app.delete('/api/limits/domains/:domain', (req, res) => {
140
+ configManager.removeDomain(req.params.domain);
141
+ res.json({ success: true, message: 'Domain removed' });
142
+ });
143
+
144
+ // Time Window
145
+ this.app.get('/api/limits/time-window', (req, res) => {
146
+ res.json(configManager.getTimeWindow());
147
+ });
148
+
149
+ this.app.post('/api/limits/time-window', (req, res) => {
150
+ configManager.setTimeWindow(req.body);
151
+ res.json({ success: true, message: 'Time window updated' });
152
+ });
153
+
154
+ // Geography Controls
155
+ this.app.get('/api/limits/geo', (req, res) => {
156
+ res.json(configManager.getGeographyControls());
157
+ });
158
+
159
+ this.app.post('/api/limits/geo', (req, res) => {
160
+ const { enabled, mode, country } = req.body;
161
+ const controls = configManager.getGeographyControls();
162
+ if (enabled !== undefined) controls.enabled = enabled;
163
+ if (mode) controls.mode = mode;
164
+ if (country) {
165
+ if (!controls.countries.includes(country)) {
166
+ controls.countries.push(country);
167
+ }
168
+ }
169
+ configManager.setGeographyControls(controls);
170
+ res.json({ success: true, message: 'Geography controls updated' });
171
+ });
172
+
173
+ this.app.delete('/api/limits/geo/:country', (req, res) => {
174
+ const controls = configManager.getGeographyControls();
175
+ controls.countries = controls.countries.filter((c: string) => c !== req.params.country);
176
+ configManager.setGeographyControls(controls);
177
+ res.json({ success: true, message: 'Country removed' });
178
+ });
179
+
180
+ // Category Controls
181
+ this.app.get('/api/limits/categories', (req, res) => {
182
+ res.json(configManager.getCategoryControls());
183
+ });
184
+
185
+ this.app.post('/api/limits/categories/block', (req, res) => {
186
+ configManager.addBlockedCategory(req.body.category);
187
+ res.json({ success: true, message: 'Category blocked' });
188
+ });
189
+
190
+ this.app.post('/api/limits/categories/unblock', (req, res) => {
191
+ configManager.removeBlockedCategory(req.body.category);
192
+ res.json({ success: true, message: 'Category unblocked' });
193
+ });
194
+
195
+ this.app.post('/api/limits/categories/allow', (req, res) => {
196
+ configManager.addAllowedCategory(req.body.category);
197
+ res.json({ success: true, message: 'Category added to allowed list' });
198
+ });
199
+
200
+ this.app.post('/api/limits/categories/disallow', (req, res) => {
201
+ configManager.removeAllowedCategory(req.body.category);
202
+ res.json({ success: true, message: 'Category removed from allowed list' });
203
+ });
204
+
95
205
  // Webhook endpoints
96
206
  this.app.post('/webhooks/wise', (req, res) => {
97
207
  console.log('Wise webhook received:', req.body);
@@ -135,6 +135,37 @@ export interface TimeWindowConfig {
135
135
  blockedDays?: string[];
136
136
  }
137
137
 
138
+ export interface CumulativeBudget {
139
+ enabled: boolean;
140
+ amount: number;
141
+ period: 'daily' | 'weekly' | 'monthly';
142
+ resetDay?: number; // For monthly: 1-31
143
+ resetDayOfWeek?: number; // For weekly: 0-6 (Sunday-Saturday)
144
+ }
145
+
146
+ export interface DomainControl {
147
+ mode: 'whitelist' | 'blacklist';
148
+ domains: string[];
149
+ }
150
+
151
+ export interface GeographyControl {
152
+ enabled: boolean;
153
+ mode: 'allow' | 'block';
154
+ countries: string[]; // ISO country codes
155
+ }
156
+
157
+ export interface CategoryControl {
158
+ blockedCategories: string[];
159
+ allowedCategories?: string[]; // If set, only these are allowed
160
+ }
161
+
162
+ export interface AdvancedLimits {
163
+ cumulativeBudgets: CumulativeBudget[];
164
+ domainControls: DomainControl;
165
+ geographyControls: GeographyControl;
166
+ categoryControls: CategoryControl;
167
+ }
168
+
138
169
  // Emergency Stop Types
139
170
  export interface EmergencyStopState {
140
171
  active: boolean;