payment-kit 1.25.8 → 1.26.0
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.
- package/api/src/crons/index.ts +24 -0
- package/api/src/libs/archive/config.ts +254 -0
- package/api/src/libs/archive/executor.ts +729 -0
- package/api/src/libs/archive/index.ts +7 -0
- package/api/src/libs/archive/lock.ts +50 -0
- package/api/src/libs/archive/policy.ts +55 -0
- package/api/src/libs/archive/query.ts +136 -0
- package/api/src/libs/archive/snapshot.ts +291 -0
- package/api/src/libs/archive/store.ts +200 -0
- package/api/src/libs/session.ts +43 -25
- package/api/src/queues/archive.ts +32 -0
- package/api/src/queues/subscription.ts +3 -1
- package/api/src/routes/archive.ts +176 -0
- package/api/src/routes/checkout-sessions.ts +50 -34
- package/api/src/routes/index.ts +2 -0
- package/api/src/routes/meters.ts +28 -0
- package/api/src/routes/payment-stats.ts +167 -20
- package/api/src/store/migrations/20260203-archive.ts +12 -0
- package/api/src/store/migrations/20260204-revenue-snapshot.ts +19 -0
- package/api/src/store/models/archive-lock.ts +55 -0
- package/api/src/store/models/archive-metadata.ts +132 -0
- package/api/src/store/models/index.ts +9 -0
- package/api/src/store/models/revenue-snapshot.ts +110 -0
- package/api/tests/libs/archive-config.spec.ts +185 -0
- package/api/tests/libs/archive-executor.spec.ts +678 -0
- package/api/tests/libs/archive-lock.spec.ts +130 -0
- package/api/tests/libs/archive-policy.spec.ts +255 -0
- package/api/tests/libs/archive-query.spec.ts +267 -0
- package/api/tests/libs/archive-store.spec.ts +159 -0
- package/blocklet.prefs.json +187 -0
- package/blocklet.yml +2 -1
- package/package.json +10 -10
- package/src/components/customer/actions.tsx +1 -1
- package/src/components/customer/credit-overview.tsx +3 -1
- package/src/components/customer/overdraft-protection.tsx +1 -1
- package/src/components/event/list.tsx +1 -1
- package/src/components/filter-toolbar.tsx +2 -2
- package/src/components/invoice/action.tsx +3 -3
- package/src/components/invoice/list.tsx +1 -1
- package/src/components/invoice/recharge.tsx +2 -2
- package/src/components/meter/add-usage-dialog.tsx +1 -1
- package/src/components/passport/actions.tsx +1 -1
- package/src/components/passport/assign.tsx +1 -1
- package/src/components/payment-currency/add.tsx +1 -1
- package/src/components/payment-currency/edit.tsx +1 -1
- package/src/components/payment-intent/actions.tsx +4 -4
- package/src/components/payment-intent/list.tsx +1 -1
- package/src/components/payment-link/actions.tsx +4 -4
- package/src/components/payment-link/item.tsx +1 -1
- package/src/components/payouts/list.tsx +1 -1
- package/src/components/payouts/portal/list.tsx +1 -1
- package/src/components/price/upsell-select.tsx +1 -1
- package/src/components/price/upsell.tsx +2 -2
- package/src/components/pricing-table/actions.tsx +3 -3
- package/src/components/pricing-table/product-item.tsx +1 -1
- package/src/components/product/actions.tsx +3 -3
- package/src/components/product/create.tsx +1 -1
- package/src/components/product/cross-sell.tsx +2 -2
- package/src/components/promotion/active-redemptions.tsx +1 -1
- package/src/components/refund/list.tsx +1 -1
- package/src/components/subscription/actions/index.tsx +1 -1
- package/src/components/subscription/items/usage-records.tsx +4 -2
- package/src/components/subscription/list.tsx +1 -1
- package/src/components/subscription/metrics.tsx +3 -3
- package/src/components/subscription/portal/actions.tsx +15 -12
- package/src/components/subscription/portal/list.tsx +1 -1
- package/src/components/webhook/attempts.tsx +4 -4
- package/src/hooks/subscription.ts +2 -2
- package/src/locales/en.tsx +4 -0
- package/src/locales/zh.tsx +4 -0
- package/src/pages/admin/billing/meter-events/index.tsx +3 -3
- package/src/pages/admin/billing/meters/index.tsx +1 -1
- package/src/pages/admin/billing/overdue/index.tsx +2 -2
- package/src/pages/admin/billing/subscriptions/detail.tsx +2 -2
- package/src/pages/admin/customers/customers/credit-grant/detail.tsx +1 -1
- package/src/pages/admin/customers/customers/credit-transaction/detail.tsx +1 -1
- package/src/pages/admin/customers/customers/detail.tsx +4 -4
- package/src/pages/admin/developers/events/detail.tsx +1 -1
- package/src/pages/admin/developers/webhooks/detail.tsx +1 -1
- package/src/pages/admin/developers/webhooks/index.tsx +1 -1
- package/src/pages/admin/overview.tsx +2 -0
- package/src/pages/admin/payments/intents/detail.tsx +2 -2
- package/src/pages/admin/payments/payouts/detail.tsx +2 -2
- package/src/pages/admin/payments/refunds/detail.tsx +2 -2
- package/src/pages/admin/products/coupons/detail.tsx +1 -1
- package/src/pages/admin/products/coupons/index.tsx +1 -1
- package/src/pages/admin/products/exchange-rate-providers/index.tsx +1 -1
- package/src/pages/admin/products/links/create.tsx +1 -1
- package/src/pages/admin/products/links/detail.tsx +2 -2
- package/src/pages/admin/products/links/index.tsx +1 -1
- package/src/pages/admin/products/passports/index.tsx +1 -1
- package/src/pages/admin/products/prices/actions.tsx +4 -4
- package/src/pages/admin/products/prices/detail.tsx +2 -2
- package/src/pages/admin/products/pricing-tables/create.tsx +1 -1
- package/src/pages/admin/products/pricing-tables/detail.tsx +2 -2
- package/src/pages/admin/products/pricing-tables/index.tsx +1 -1
- package/src/pages/admin/products/products/index.tsx +1 -1
- package/src/pages/admin/products/promotion-codes/actions.tsx +2 -2
- package/src/pages/admin/products/promotion-codes/detail.tsx +2 -2
- package/src/pages/admin/products/promotion-codes/list.tsx +1 -1
- package/src/pages/admin/settings/payment-methods/create.tsx +1 -1
- package/src/pages/admin/settings/payment-methods/edit.tsx +1 -1
- package/src/pages/admin/settings/payment-methods/index.tsx +2 -2
- package/src/pages/admin/tax/detail.tsx +2 -2
- package/src/pages/admin/tax/list.tsx +1 -1
- package/src/pages/checkout/pay.tsx +2 -2
- package/src/pages/customer/index.tsx +1 -1
- package/src/pages/customer/invoice/past-due.tsx +1 -1
- package/src/pages/customer/payout/detail.tsx +1 -1
- package/src/pages/customer/refund/list.tsx +1 -1
- package/src/pages/customer/subscription/change-payment.tsx +2 -2
- package/src/pages/customer/subscription/change-plan.tsx +3 -3
- package/src/pages/customer/subscription/detail.tsx +3 -3
- package/src/pages/integrations/donations/index.tsx +1 -1
- package/vite.config.ts +3 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getArchiveDir,
|
|
5
|
+
getArchiveFilePath,
|
|
6
|
+
listArchiveFiles,
|
|
7
|
+
getFileSize,
|
|
8
|
+
cleanupOldArchiveFiles,
|
|
9
|
+
} from '../../src/libs/archive/store';
|
|
10
|
+
|
|
11
|
+
jest.mock('@blocklet/sdk/lib/config', () => ({
|
|
12
|
+
__esModule: true,
|
|
13
|
+
default: {
|
|
14
|
+
env: {
|
|
15
|
+
dataDir: '/tmp/test-payment-kit',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
jest.mock('fs');
|
|
21
|
+
jest.mock('../../src/libs/logger', () => ({
|
|
22
|
+
__esModule: true,
|
|
23
|
+
default: {
|
|
24
|
+
info: jest.fn(),
|
|
25
|
+
warn: jest.fn(),
|
|
26
|
+
error: jest.fn(),
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
describe('archive/store', () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
jest.clearAllMocks();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('getArchiveDir', () => {
|
|
36
|
+
it('should create archive directory if it does not exist', () => {
|
|
37
|
+
(fs.existsSync as jest.Mock).mockReturnValue(false);
|
|
38
|
+
(fs.mkdirSync as jest.Mock).mockReturnValue(undefined);
|
|
39
|
+
|
|
40
|
+
const result = getArchiveDir();
|
|
41
|
+
|
|
42
|
+
expect(result).toContain('archive');
|
|
43
|
+
expect(fs.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('archive'), { recursive: true });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should not create directory if it already exists', () => {
|
|
47
|
+
(fs.existsSync as jest.Mock).mockReturnValue(true);
|
|
48
|
+
|
|
49
|
+
getArchiveDir();
|
|
50
|
+
|
|
51
|
+
expect(fs.mkdirSync).not.toHaveBeenCalled();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('getArchiveFilePath', () => {
|
|
56
|
+
it('should return full path for archive file', () => {
|
|
57
|
+
(fs.existsSync as jest.Mock).mockReturnValue(true);
|
|
58
|
+
|
|
59
|
+
const result = getArchiveFilePath('archive-2024.db');
|
|
60
|
+
|
|
61
|
+
expect(result).toContain('archive-2024.db');
|
|
62
|
+
expect(result).toContain('archive');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('listArchiveFiles', () => {
|
|
67
|
+
it('should return sorted list of .db files', () => {
|
|
68
|
+
(fs.existsSync as jest.Mock).mockReturnValue(true);
|
|
69
|
+
(fs.readdirSync as jest.Mock).mockReturnValue([
|
|
70
|
+
'archive-2025.db',
|
|
71
|
+
'archive-2023.db',
|
|
72
|
+
'archive-2024.db',
|
|
73
|
+
'some-other-file.txt',
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
const result = listArchiveFiles();
|
|
77
|
+
|
|
78
|
+
expect(result).toHaveLength(3);
|
|
79
|
+
expect(result[0]).toContain('archive-2023.db');
|
|
80
|
+
expect(result[1]).toContain('archive-2024.db');
|
|
81
|
+
expect(result[2]).toContain('archive-2025.db');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should return empty array when no .db files', () => {
|
|
85
|
+
(fs.existsSync as jest.Mock).mockReturnValue(true);
|
|
86
|
+
(fs.readdirSync as jest.Mock).mockReturnValue(['readme.txt', 'config.json']);
|
|
87
|
+
|
|
88
|
+
const result = listArchiveFiles();
|
|
89
|
+
|
|
90
|
+
expect(result).toHaveLength(0);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('getFileSize', () => {
|
|
95
|
+
it('should return file size in bytes', () => {
|
|
96
|
+
(fs.statSync as jest.Mock).mockReturnValue({ size: 1024 });
|
|
97
|
+
|
|
98
|
+
const result = getFileSize('/tmp/archive.db');
|
|
99
|
+
|
|
100
|
+
expect(result).toBe(1024);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should return 0 when file does not exist', () => {
|
|
104
|
+
(fs.statSync as jest.Mock).mockImplementation(() => {
|
|
105
|
+
throw new Error('ENOENT');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const result = getFileSize('/tmp/nonexistent.db');
|
|
109
|
+
|
|
110
|
+
expect(result).toBe(0);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('cleanupOldArchiveFiles', () => {
|
|
115
|
+
it('should not remove files when under max limit', () => {
|
|
116
|
+
(fs.existsSync as jest.Mock).mockReturnValue(true);
|
|
117
|
+
(fs.readdirSync as jest.Mock).mockReturnValue(['archive-2023.db', 'archive-2024.db']);
|
|
118
|
+
|
|
119
|
+
const result = cleanupOldArchiveFiles(10);
|
|
120
|
+
|
|
121
|
+
expect(result).toHaveLength(0);
|
|
122
|
+
expect(fs.unlinkSync).not.toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should remove oldest files when exceeding max limit', () => {
|
|
126
|
+
(fs.existsSync as jest.Mock).mockReturnValue(true);
|
|
127
|
+
(fs.readdirSync as jest.Mock).mockReturnValue([
|
|
128
|
+
'archive-2021.db',
|
|
129
|
+
'archive-2022.db',
|
|
130
|
+
'archive-2023.db',
|
|
131
|
+
'archive-2024.db',
|
|
132
|
+
]);
|
|
133
|
+
(fs.unlinkSync as jest.Mock).mockReturnValue(undefined);
|
|
134
|
+
|
|
135
|
+
const result = cleanupOldArchiveFiles(2);
|
|
136
|
+
|
|
137
|
+
expect(result).toHaveLength(2);
|
|
138
|
+
expect(result).toContain('archive-2021.db');
|
|
139
|
+
expect(result).toContain('archive-2022.db');
|
|
140
|
+
expect(fs.unlinkSync).toHaveBeenCalledTimes(2);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should continue cleanup even if one file fails to delete', () => {
|
|
144
|
+
(fs.existsSync as jest.Mock).mockReturnValue(true);
|
|
145
|
+
(fs.readdirSync as jest.Mock).mockReturnValue(['archive-2022.db', 'archive-2023.db', 'archive-2024.db']);
|
|
146
|
+
(fs.unlinkSync as jest.Mock)
|
|
147
|
+
.mockImplementationOnce(() => {
|
|
148
|
+
throw new Error('Permission denied');
|
|
149
|
+
})
|
|
150
|
+
.mockReturnValue(undefined);
|
|
151
|
+
|
|
152
|
+
const result = cleanupOldArchiveFiles(1);
|
|
153
|
+
|
|
154
|
+
expect(fs.unlinkSync).toHaveBeenCalledTimes(2);
|
|
155
|
+
expect(result).toHaveLength(1);
|
|
156
|
+
expect(result).toContain('archive-2023.db');
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
});
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
{
|
|
2
|
+
"form": {
|
|
3
|
+
"labelCol": 6,
|
|
4
|
+
"wrapperCol": 12
|
|
5
|
+
},
|
|
6
|
+
"schema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"8ezxt923qyy": {
|
|
10
|
+
"type": "void",
|
|
11
|
+
"x-component": "Card",
|
|
12
|
+
"x-component-props": {
|
|
13
|
+
"title": "Config"
|
|
14
|
+
},
|
|
15
|
+
"x-designable-id": "8ezxt923qyy",
|
|
16
|
+
"properties": {
|
|
17
|
+
"wvny47lybcc": {
|
|
18
|
+
"type": "void",
|
|
19
|
+
"x-component": "FormCollapse",
|
|
20
|
+
"x-component-props": {},
|
|
21
|
+
"name": "Data Retention",
|
|
22
|
+
"x-designable-id": "wvny47lybcc",
|
|
23
|
+
"properties": {
|
|
24
|
+
"5tiydb79qp2": {
|
|
25
|
+
"type": "void",
|
|
26
|
+
"x-component": "FormCollapse.CollapsePanel",
|
|
27
|
+
"x-component-props": {
|
|
28
|
+
"header": "Data Retention"
|
|
29
|
+
},
|
|
30
|
+
"x-designable-id": "5tiydb79qp2",
|
|
31
|
+
"properties": {
|
|
32
|
+
"retentionEnabled": {
|
|
33
|
+
"type": "boolean",
|
|
34
|
+
"title": "Enable Data Retention ",
|
|
35
|
+
"x-decorator": "FormItem",
|
|
36
|
+
"x-component": "Switch",
|
|
37
|
+
"x-validator": [],
|
|
38
|
+
"x-component-props": {},
|
|
39
|
+
"x-decorator-props": {},
|
|
40
|
+
"name": "retentionEnabled",
|
|
41
|
+
"default": false,
|
|
42
|
+
"description": "Archive expired data to reduce database size",
|
|
43
|
+
"x-designable-id": "886b4pe1o1y",
|
|
44
|
+
"x-index": 0
|
|
45
|
+
},
|
|
46
|
+
"scheduleEnabled": {
|
|
47
|
+
"type": "boolean",
|
|
48
|
+
"title": "Enable Scheduled Archive",
|
|
49
|
+
"x-decorator": "FormItem",
|
|
50
|
+
"x-component": "Switch",
|
|
51
|
+
"x-validator": [],
|
|
52
|
+
"x-component-props": {},
|
|
53
|
+
"x-decorator-props": {},
|
|
54
|
+
"description": "Run archive job automatically every day",
|
|
55
|
+
"name": "scheduleEnabled",
|
|
56
|
+
"default": true,
|
|
57
|
+
"x-reactions": {
|
|
58
|
+
"dependencies": [
|
|
59
|
+
{
|
|
60
|
+
"property": "value",
|
|
61
|
+
"type": "boolean",
|
|
62
|
+
"source": "8ezxt923qyy.wvny47lybcc.5tiydb79qp2.retentionEnabled",
|
|
63
|
+
"name": "retentionEnabled"
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"fulfill": {
|
|
67
|
+
"state": {
|
|
68
|
+
"visible": "{{$deps.retentionEnabled}}"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"x-designable-id": "53cmu3qg9j3",
|
|
73
|
+
"x-index": 1
|
|
74
|
+
},
|
|
75
|
+
"scheduleHour": {
|
|
76
|
+
"type": "number",
|
|
77
|
+
"title": " Archive Hour (0-23) ",
|
|
78
|
+
"x-decorator": "FormItem",
|
|
79
|
+
"x-component": "NumberPicker",
|
|
80
|
+
"x-validator": "number",
|
|
81
|
+
"x-component-props": {
|
|
82
|
+
"min": 0,
|
|
83
|
+
"max": 23
|
|
84
|
+
},
|
|
85
|
+
"x-decorator-props": {},
|
|
86
|
+
"name": "scheduleHour",
|
|
87
|
+
"default": 2,
|
|
88
|
+
"description": "Hour of day to\nrun the archive job (server Local\ntime)",
|
|
89
|
+
"x-reactions": {
|
|
90
|
+
"dependencies": [
|
|
91
|
+
{
|
|
92
|
+
"property": "value",
|
|
93
|
+
"type": "boolean",
|
|
94
|
+
"source": "8ezxt923qyy.wvny47lybcc.5tiydb79qp2.retentionEnabled",
|
|
95
|
+
"name": "retentionEnabled"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"property": "value",
|
|
99
|
+
"type": "boolean",
|
|
100
|
+
"source": "8ezxt923qyy.wvny47lybcc.5tiydb79qp2.scheduleEnabled",
|
|
101
|
+
"name": "scheduleEnabled"
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
"fulfill": {
|
|
105
|
+
"state": {
|
|
106
|
+
"visible": "{{$deps.retentionEnabled === true && $deps.scheduleEnabled === true}}"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"x-designable-id": "dvdqp2aaszw",
|
|
111
|
+
"x-index": 2
|
|
112
|
+
},
|
|
113
|
+
"batchSize": {
|
|
114
|
+
"type": "number",
|
|
115
|
+
"title": "Batch Size ",
|
|
116
|
+
"x-decorator": "FormItem",
|
|
117
|
+
"x-component": "NumberPicker",
|
|
118
|
+
"x-validator": [],
|
|
119
|
+
"x-component-props": {
|
|
120
|
+
"min": 100
|
|
121
|
+
},
|
|
122
|
+
"x-decorator-props": {},
|
|
123
|
+
"name": "batchSize",
|
|
124
|
+
"default": 500,
|
|
125
|
+
"description": "Number of records to archive per batch. Smaller\nvalues reduce database load",
|
|
126
|
+
"x-reactions": {
|
|
127
|
+
"dependencies": [
|
|
128
|
+
{
|
|
129
|
+
"property": "value",
|
|
130
|
+
"type": "boolean",
|
|
131
|
+
"source": "8ezxt923qyy.wvny47lybcc.5tiydb79qp2.retentionEnabled",
|
|
132
|
+
"name": "retentionEnabled"
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
"fulfill": {
|
|
136
|
+
"state": {
|
|
137
|
+
"visible": "{{$deps.retentionEnabled}}"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"x-designable-id": "5mdfl84f6xw",
|
|
142
|
+
"x-index": 3
|
|
143
|
+
},
|
|
144
|
+
"minFreeDiskMB": {
|
|
145
|
+
"type": "number",
|
|
146
|
+
"title": "Min Free Disk Space (MB)",
|
|
147
|
+
"x-decorator": "FormItem",
|
|
148
|
+
"x-component": "NumberPicker",
|
|
149
|
+
"x-validator": [],
|
|
150
|
+
"x-component-props": {
|
|
151
|
+
"min": 100
|
|
152
|
+
},
|
|
153
|
+
"x-decorator-props": {},
|
|
154
|
+
"name": "minFreeDiskMB",
|
|
155
|
+
"default": 1000,
|
|
156
|
+
"description": "Stop archiving when free disk space falls below this threshold (default 1GB)",
|
|
157
|
+
"x-reactions": {
|
|
158
|
+
"dependencies": [
|
|
159
|
+
{
|
|
160
|
+
"property": "value",
|
|
161
|
+
"type": "boolean",
|
|
162
|
+
"source": "8ezxt923qyy.wvny47lybcc.5tiydb79qp2.retentionEnabled",
|
|
163
|
+
"name": "retentionEnabled"
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
"fulfill": {
|
|
167
|
+
"state": {
|
|
168
|
+
"visible": "{{$deps.retentionEnabled}}"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"x-designable-id": "ud3govolh1e",
|
|
173
|
+
"x-index": 4
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"x-index": 0
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"x-index": 0
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
"x-index": 0
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
"x-designable-id": "yfw4ta3wi0l"
|
|
186
|
+
}
|
|
187
|
+
}
|
package/blocklet.yml
CHANGED
|
@@ -14,7 +14,7 @@ repository:
|
|
|
14
14
|
type: git
|
|
15
15
|
url: git+https://github.com/blocklet/payment-kit.git
|
|
16
16
|
specVersion: 1.2.8
|
|
17
|
-
version: 1.
|
|
17
|
+
version: 1.26.0
|
|
18
18
|
logo: logo.png
|
|
19
19
|
files:
|
|
20
20
|
- dist
|
|
@@ -47,6 +47,7 @@ interfaces:
|
|
|
47
47
|
- /api/products/**
|
|
48
48
|
- /methods/**
|
|
49
49
|
- /currencies/**
|
|
50
|
+
- /meters/public/**
|
|
50
51
|
blockUnauthorized: false
|
|
51
52
|
proxyBehavior: service
|
|
52
53
|
community: ''
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"prelint": "npm run types",
|
|
@@ -47,23 +47,23 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@abtnode/cron": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
49
49
|
"@arcblock/did": "^1.28.5",
|
|
50
|
-
"@arcblock/did-connect-react": "^3.
|
|
50
|
+
"@arcblock/did-connect-react": "^3.5.1",
|
|
51
51
|
"@arcblock/did-connect-storage-nedb": "^1.8.0",
|
|
52
52
|
"@arcblock/did-util": "^1.28.5",
|
|
53
53
|
"@arcblock/jwt": "^1.28.5",
|
|
54
|
-
"@arcblock/react-hooks": "^3.
|
|
55
|
-
"@arcblock/ux": "^3.
|
|
54
|
+
"@arcblock/react-hooks": "^3.5.1",
|
|
55
|
+
"@arcblock/ux": "^3.5.1",
|
|
56
56
|
"@arcblock/validator": "^1.28.5",
|
|
57
57
|
"@arcblock/vc": "^1.28.5",
|
|
58
58
|
"@blocklet/did-space-js": "^1.2.15",
|
|
59
59
|
"@blocklet/error": "^0.3.5",
|
|
60
60
|
"@blocklet/js-sdk": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
61
61
|
"@blocklet/logger": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
62
|
-
"@blocklet/payment-broker-client": "1.
|
|
63
|
-
"@blocklet/payment-react": "1.
|
|
64
|
-
"@blocklet/payment-vendor": "1.
|
|
62
|
+
"@blocklet/payment-broker-client": "1.26.0",
|
|
63
|
+
"@blocklet/payment-react": "1.26.0",
|
|
64
|
+
"@blocklet/payment-vendor": "1.26.0",
|
|
65
65
|
"@blocklet/sdk": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
66
|
-
"@blocklet/ui-react": "^3.
|
|
66
|
+
"@blocklet/ui-react": "^3.5.1",
|
|
67
67
|
"@blocklet/uploader": "^0.3.19",
|
|
68
68
|
"@blocklet/xss": "^0.3.16",
|
|
69
69
|
"@mui/icons-material": "^7.1.2",
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"devDependencies": {
|
|
133
133
|
"@abtnode/types": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
134
134
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
135
|
-
"@blocklet/payment-types": "1.
|
|
135
|
+
"@blocklet/payment-types": "1.26.0",
|
|
136
136
|
"@types/cookie-parser": "^1.4.9",
|
|
137
137
|
"@types/cors": "^2.8.19",
|
|
138
138
|
"@types/debug": "^4.1.12",
|
|
@@ -179,5 +179,5 @@
|
|
|
179
179
|
"parser": "typescript"
|
|
180
180
|
}
|
|
181
181
|
},
|
|
182
|
-
"gitHead": "
|
|
182
|
+
"gitHead": "9585ec8bc077fc5f8a8c5946d05436b10576e145"
|
|
183
183
|
}
|
|
@@ -25,7 +25,7 @@ export default function CustomerActions({ data, onChange, variant = 'compact' }:
|
|
|
25
25
|
const onUpdateInfo = async (updates: TCustomerExpanded) => {
|
|
26
26
|
try {
|
|
27
27
|
setState({ loading: true });
|
|
28
|
-
await api.put(`/api/customers/${data.id}`, updates).then((res) => res.data);
|
|
28
|
+
await api.put(`/api/customers/${data.id}`, updates).then((res: any) => res.data);
|
|
29
29
|
Toast.success(t('common.saved'));
|
|
30
30
|
onChange('update');
|
|
31
31
|
} catch (err) {
|
|
@@ -117,7 +117,9 @@ export default function CreditOverview({ customerId, settings, mode = 'portal' }
|
|
|
117
117
|
|
|
118
118
|
const handleRecharge = async (currency: TPaymentCurrency) => {
|
|
119
119
|
try {
|
|
120
|
-
const response = await api
|
|
120
|
+
const response = await api
|
|
121
|
+
.get(`/api/payment-currencies/${currency.id}/recharge-config`)
|
|
122
|
+
.then((res: any) => res.data);
|
|
121
123
|
if (response.recharge_config && response.recharge_config.payment_url) {
|
|
122
124
|
const url = new URL(response.recharge_config.payment_url);
|
|
123
125
|
url.searchParams.set('redirect', window.location.href);
|
|
@@ -35,7 +35,7 @@ const fetchCycleAmount = (
|
|
|
35
35
|
subscriptionId: string,
|
|
36
36
|
params: { overdraftProtection: boolean }
|
|
37
37
|
): Promise<{ amount: string; gas: string; currency: TPaymentCurrency }> => {
|
|
38
|
-
return api.get(`/api/subscriptions/${subscriptionId}/cycle-amount`, { params }).then((res) => res.data);
|
|
38
|
+
return api.get(`/api/subscriptions/${subscriptionId}/cycle-amount`, { params }).then((res: any) => res.data);
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
function safeAdd(currency: { decimal: number }, ...numbers: string[]) {
|
|
@@ -16,7 +16,7 @@ const fetchData = (params: Record<string, any> = {}): Promise<{ list: TEventExpa
|
|
|
16
16
|
Object.keys(params).forEach((key) => {
|
|
17
17
|
search.set(key, String(params[key]));
|
|
18
18
|
});
|
|
19
|
-
return api.get(`/api/events?${search.toString()}`).then((res) => res.data);
|
|
19
|
+
return api.get(`/api/events?${search.toString()}`).then((res: any) => res.data);
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
type SearchProps = {
|
|
@@ -30,7 +30,7 @@ const fetchUserData = (params: Record<string, any> = {}): Promise<{ list: TCusto
|
|
|
30
30
|
}
|
|
31
31
|
search.set(key, String(v));
|
|
32
32
|
});
|
|
33
|
-
return api.get(`api/customers?${search.toString()}`).then((res) => res.data);
|
|
33
|
+
return api.get(`api/customers?${search.toString()}`).then((res: any) => res.data);
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
const fetchSubscriptionItems = (params: Record<string, any> = {}): Promise<{ list: TCustomer[]; count: number }> => {
|
|
@@ -39,7 +39,7 @@ const fetchSubscriptionItems = (params: Record<string, any> = {}): Promise<{ lis
|
|
|
39
39
|
const v = params[key];
|
|
40
40
|
search.set(key, String(v));
|
|
41
41
|
});
|
|
42
|
-
return api.get(`api/subscription-items?${search.toString()}`).then((res) => res.data);
|
|
42
|
+
return api.get(`api/subscription-items?${search.toString()}`).then((res: any) => res.data);
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
type Props = {
|
|
@@ -55,7 +55,7 @@ export default function InvoiceActions({ data, variant = 'compact', onChange, mo
|
|
|
55
55
|
try {
|
|
56
56
|
setState({ loading: true });
|
|
57
57
|
if (state.action === 'return-stake') {
|
|
58
|
-
const result = await api.post(`/api/invoices/${data.id}/return-stake`).then((res) => res.data);
|
|
58
|
+
const result = await api.post(`/api/invoices/${data.id}/return-stake`).then((res: any) => res.data);
|
|
59
59
|
if (result.success) {
|
|
60
60
|
Toast.success(t('admin.invoice.returnStake.success'));
|
|
61
61
|
} else {
|
|
@@ -69,11 +69,11 @@ export default function InvoiceActions({ data, variant = 'compact', onChange, mo
|
|
|
69
69
|
invoiceId: data.id,
|
|
70
70
|
},
|
|
71
71
|
})
|
|
72
|
-
.then((res) => res.data);
|
|
72
|
+
.then((res: any) => res.data);
|
|
73
73
|
Toast.success(t('admin.invoice.retryUncollectible.success'));
|
|
74
74
|
}
|
|
75
75
|
if (state.action === 'void') {
|
|
76
|
-
await api.post(`/api/invoices/${data.id}/void`).then((res) => res.data);
|
|
76
|
+
await api.post(`/api/invoices/${data.id}/void`).then((res: any) => res.data);
|
|
77
77
|
Toast.success(t('admin.invoice.void.success'));
|
|
78
78
|
}
|
|
79
79
|
onChange(state.action);
|
|
@@ -52,7 +52,7 @@ const fetchData = (params: Record<string, any> = {}): Promise<{ list: TInvoiceEx
|
|
|
52
52
|
search.set(key, String(v));
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
return api.get(`/api/invoices?${search.toString()}`).then((res) => res.data);
|
|
55
|
+
return api.get(`/api/invoices?${search.toString()}`).then((res: any) => res.data);
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
type SearchProps = {
|
|
@@ -35,12 +35,12 @@ const fetchData = (
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
if (subscriptionId) {
|
|
38
|
-
return api.get(`/api/subscriptions/${subscriptionId}/recharge?${search.toString()}`).then((res) => res.data);
|
|
38
|
+
return api.get(`/api/subscriptions/${subscriptionId}/recharge?${search.toString()}`).then((res: any) => res.data);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
if (currencyId) {
|
|
42
42
|
search.set('currency_id', currencyId);
|
|
43
|
-
return api.get(`/api/invoices/recharge?${search.toString()}`).then((res) => res.data);
|
|
43
|
+
return api.get(`/api/invoices/recharge?${search.toString()}`).then((res: any) => res.data);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
return Promise.resolve({ list: [], count: 0 });
|
|
@@ -30,7 +30,7 @@ export default function PassportActions(rawProps: Props) {
|
|
|
30
30
|
try {
|
|
31
31
|
setState({ loading: true });
|
|
32
32
|
// eslint-disable-next-line react/prop-types
|
|
33
|
-
await api.delete(`/api/passports/assign/${props.data.name}`).then((res) => res.data);
|
|
33
|
+
await api.delete(`/api/passports/assign/${props.data.name}`).then((res: any) => res.data);
|
|
34
34
|
Toast.success(t('common.saved'));
|
|
35
35
|
} catch (err) {
|
|
36
36
|
console.error(err);
|
|
@@ -6,7 +6,7 @@ import { useRequest } from 'ahooks';
|
|
|
6
6
|
import { useEffect, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
const fetchData = (): Promise<any[]> => {
|
|
9
|
-
return api.get('/api/passports').then((res) => res.data);
|
|
9
|
+
return api.get('/api/passports').then((res: any) => res.data);
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export default function AssignPassportDialog(props: { id: string; onCancel: any }) {
|
|
@@ -116,7 +116,7 @@ export default function PaymentCurrencyAdd({
|
|
|
116
116
|
dispatch('drawer.submitted');
|
|
117
117
|
dispatch('paymentCurrency.added');
|
|
118
118
|
})
|
|
119
|
-
.catch((err) => {
|
|
119
|
+
.catch((err: any) => {
|
|
120
120
|
setState({ loading: false });
|
|
121
121
|
console.error(err);
|
|
122
122
|
Toast.error(formatError(err));
|
|
@@ -132,7 +132,7 @@ export default function PaymentCurrencyEdit({
|
|
|
132
132
|
dispatch('drawer.submitted');
|
|
133
133
|
dispatch('paymentCurrency.updated');
|
|
134
134
|
})
|
|
135
|
-
.catch((err) => {
|
|
135
|
+
.catch((err: any) => {
|
|
136
136
|
setState({ loading: false });
|
|
137
137
|
console.error(err);
|
|
138
138
|
Toast.error(formatError(err));
|
|
@@ -28,7 +28,7 @@ type Props = {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
const fetchRefundData = (id: string) => {
|
|
31
|
-
return api.get(`/api/payment-intents/${id}/refundable-amount`).then((res) => res.data);
|
|
31
|
+
return api.get(`/api/payment-intents/${id}/refundable-amount`).then((res: any) => res.data);
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
function RefundForm({ data, refundMaxAmount }: { data: TPaymentIntentExpanded; refundMaxAmount: string }) {
|
|
@@ -176,7 +176,7 @@ export function PaymentIntentActionsInner({ data, variant = 'compact', onChange
|
|
|
176
176
|
});
|
|
177
177
|
const [refundMaxAmount, setRefundMaxAmount] = useState('0');
|
|
178
178
|
const isSlash = data.payment_details?.arcblock?.type === 'slash' && data.paymentMethod?.type === 'arcblock';
|
|
179
|
-
const { runAsync: runRefundAmountAsync } = useRequest(
|
|
179
|
+
const { runAsync: runRefundAmountAsync } = useRequest<any, any[]>(
|
|
180
180
|
() => {
|
|
181
181
|
if (isSlash) {
|
|
182
182
|
return Promise.resolve({ amount: '0' });
|
|
@@ -184,7 +184,7 @@ export function PaymentIntentActionsInner({ data, variant = 'compact', onChange
|
|
|
184
184
|
return fetchRefundData(data.id);
|
|
185
185
|
},
|
|
186
186
|
{
|
|
187
|
-
onSuccess: (res) => {
|
|
187
|
+
onSuccess: (res: any) => {
|
|
188
188
|
const amount = formatBNStr(res?.amount, data.paymentCurrency.decimal);
|
|
189
189
|
setRefundMaxAmount(amount);
|
|
190
190
|
},
|
|
@@ -200,7 +200,7 @@ export function PaymentIntentActionsInner({ data, variant = 'compact', onChange
|
|
|
200
200
|
}
|
|
201
201
|
try {
|
|
202
202
|
setState({ loading: true });
|
|
203
|
-
await api.put(`/api/payment-intents/${data.id}/refund`, refund).then((res) => res.data);
|
|
203
|
+
await api.put(`/api/payment-intents/${data.id}/refund`, refund).then((res: any) => res.data);
|
|
204
204
|
Toast.success(t('admin.paymentIntent.refundSuccess'));
|
|
205
205
|
onChange('refund');
|
|
206
206
|
runRefundAmountAsync();
|
|
@@ -31,7 +31,7 @@ const fetchData = (params: Record<string, any> = {}): Promise<{ list: TPaymentIn
|
|
|
31
31
|
}
|
|
32
32
|
search.set(key, String(v));
|
|
33
33
|
});
|
|
34
|
-
return api.get(`/api/payment-intents?${search.toString()}`).then((res) => res.data);
|
|
34
|
+
return api.get(`/api/payment-intents?${search.toString()}`).then((res: any) => res.data);
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
type SearchProps = {
|
|
@@ -28,7 +28,7 @@ export default function PaymentLinkActions({ data, variant = 'compact', onChange
|
|
|
28
28
|
const onUpdate = async (updates: TPaymentLinkExpanded) => {
|
|
29
29
|
try {
|
|
30
30
|
setState({ loading: true });
|
|
31
|
-
await api.put(`/api/payment-links/${data.id}`, updates).then((res) => res.data);
|
|
31
|
+
await api.put(`/api/payment-links/${data.id}`, updates).then((res: any) => res.data);
|
|
32
32
|
Toast.success(t('common.saved'));
|
|
33
33
|
onChange(state.action);
|
|
34
34
|
} catch (err) {
|
|
@@ -41,7 +41,7 @@ export default function PaymentLinkActions({ data, variant = 'compact', onChange
|
|
|
41
41
|
const onArchive = async () => {
|
|
42
42
|
try {
|
|
43
43
|
setState({ loading: true });
|
|
44
|
-
await api.put(`/api/payment-links/${data.id}/archive`).then((res) => res.data);
|
|
44
|
+
await api.put(`/api/payment-links/${data.id}/archive`).then((res: any) => res.data);
|
|
45
45
|
Toast.success(t('common.saved'));
|
|
46
46
|
onChange(state.action);
|
|
47
47
|
} catch (err) {
|
|
@@ -54,7 +54,7 @@ export default function PaymentLinkActions({ data, variant = 'compact', onChange
|
|
|
54
54
|
const onRemove = async () => {
|
|
55
55
|
try {
|
|
56
56
|
setState({ loading: true });
|
|
57
|
-
await api.delete(`/api/payment-links/${data.id}`).then((res) => res.data);
|
|
57
|
+
await api.delete(`/api/payment-links/${data.id}`).then((res: any) => res.data);
|
|
58
58
|
Toast.success(t('common.removed'));
|
|
59
59
|
onChange(state.action);
|
|
60
60
|
} catch (err) {
|
|
@@ -72,7 +72,7 @@ export default function PaymentLinkActions({ data, variant = 'compact', onChange
|
|
|
72
72
|
.put(`/api/payment-links/${data.id}`, {
|
|
73
73
|
allow_promotion_codes: !data.allow_promotion_codes,
|
|
74
74
|
})
|
|
75
|
-
.then((res) => res.data);
|
|
75
|
+
.then((res: any) => res.data);
|
|
76
76
|
Toast.success(t('common.saved'));
|
|
77
77
|
onChange(state.action);
|
|
78
78
|
} catch (err) {
|