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,185 @@
|
|
|
1
|
+
import { getRetentionConfig, getArchiveCronExpression } from '../../src/libs/archive/config';
|
|
2
|
+
|
|
3
|
+
jest.mock('@blocklet/sdk/lib/config', () => ({
|
|
4
|
+
__esModule: true,
|
|
5
|
+
default: {
|
|
6
|
+
env: {
|
|
7
|
+
preferences: {},
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
describe('archive/config', () => {
|
|
13
|
+
describe('getArchiveCronExpression', () => {
|
|
14
|
+
it('should generate weekly cron expression for hour 0', () => {
|
|
15
|
+
expect(getArchiveCronExpression(0)).toBe('0 0 0 * * 3');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should generate weekly cron expression for hour 2', () => {
|
|
19
|
+
expect(getArchiveCronExpression(2)).toBe('0 0 2 * * 3');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should generate weekly cron expression for hour 23', () => {
|
|
23
|
+
expect(getArchiveCronExpression(23)).toBe('0 0 23 * * 3');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should generate weekly cron expression for hour 12', () => {
|
|
27
|
+
expect(getArchiveCronExpression(12)).toBe('0 0 12 * * 3');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('getRetentionConfig', () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
jest.resetModules();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should return default config when no preferences set', () => {
|
|
37
|
+
const config = getRetentionConfig();
|
|
38
|
+
|
|
39
|
+
expect(config.enabled).toBe(false);
|
|
40
|
+
expect(config.defaults.retentionDays).toBe(365);
|
|
41
|
+
expect(config.defaults.batchSize).toBe(500);
|
|
42
|
+
expect(config.schedule.enabled).toBe(true);
|
|
43
|
+
expect(config.schedule.hour).toBe(2);
|
|
44
|
+
expect(config.storage.minFreeDiskMB).toBe(1000);
|
|
45
|
+
expect(config.storage.maxArchiveFiles).toBe(10);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should have tables configured', () => {
|
|
49
|
+
const config = getRetentionConfig();
|
|
50
|
+
|
|
51
|
+
expect(config.tables).toBeDefined();
|
|
52
|
+
expect(Object.keys(config.tables).length).toBeGreaterThan(0);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should include expected table policies', () => {
|
|
56
|
+
const config = getRetentionConfig();
|
|
57
|
+
const expectedTables = [
|
|
58
|
+
'meter_events',
|
|
59
|
+
'credit_transactions',
|
|
60
|
+
'events',
|
|
61
|
+
'webhook_attempts',
|
|
62
|
+
'jobs',
|
|
63
|
+
'payment_intents',
|
|
64
|
+
'invoices',
|
|
65
|
+
'refunds',
|
|
66
|
+
'payouts',
|
|
67
|
+
'subscriptions',
|
|
68
|
+
'credit_grants',
|
|
69
|
+
'products',
|
|
70
|
+
'prices',
|
|
71
|
+
'coupons',
|
|
72
|
+
'customers',
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
for (const table of expectedTables) {
|
|
76
|
+
expect(config.tables[table]).toBeDefined();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should have retention days set for each enabled table', () => {
|
|
81
|
+
const config = getRetentionConfig();
|
|
82
|
+
|
|
83
|
+
for (const policy of Object.values(config.tables)) {
|
|
84
|
+
if (policy.enabled) {
|
|
85
|
+
expect(policy.retentionDays).toBeGreaterThan(0);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should have customers table disabled', () => {
|
|
91
|
+
const config = getRetentionConfig();
|
|
92
|
+
expect(config.tables.customers!.enabled).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should have different retention periods for different table types', () => {
|
|
96
|
+
const config = getRetentionConfig();
|
|
97
|
+
|
|
98
|
+
expect(config.tables.meter_events!.retentionDays).toBe(90);
|
|
99
|
+
expect(config.tables.credit_transactions!.retentionDays).toBe(90);
|
|
100
|
+
|
|
101
|
+
expect(config.tables.payment_intents!.retentionDays).toBe(730);
|
|
102
|
+
expect(config.tables.invoices!.retentionDays).toBe(730);
|
|
103
|
+
|
|
104
|
+
expect(config.tables.products!.enabled).toBe(false);
|
|
105
|
+
expect(config.tables.prices!.enabled).toBe(false);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should have archivable statuses defined for transaction tables', () => {
|
|
109
|
+
const config = getRetentionConfig();
|
|
110
|
+
|
|
111
|
+
expect(config.tables.meter_events!.archivableStatuses).toContain('completed');
|
|
112
|
+
expect(config.tables.payment_intents!.archivableStatuses).toContain('succeeded');
|
|
113
|
+
expect(config.tables.invoices!.archivableStatuses).toContain('paid');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should have exclude conditions for financial tables', () => {
|
|
117
|
+
const config = getRetentionConfig();
|
|
118
|
+
|
|
119
|
+
expect(config.tables.payment_intents!.excludeConditions?.statuses).toContain('processing');
|
|
120
|
+
expect(config.tables.invoices!.excludeConditions?.statuses).toContain('draft');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should have hasActiveSubscription exclusion for relevant tables', () => {
|
|
124
|
+
const config = getRetentionConfig();
|
|
125
|
+
|
|
126
|
+
expect(config.tables.meter_events!.excludeConditions?.hasActiveSubscription).toBe(true);
|
|
127
|
+
expect(config.tables.credit_transactions!.excludeConditions?.hasActiveSubscription).toBe(true);
|
|
128
|
+
expect(config.tables.payment_intents!.excludeConditions?.hasActiveSubscription).toBe(true);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should generate correct cron expression in schedule', () => {
|
|
132
|
+
const config = getRetentionConfig();
|
|
133
|
+
expect(config.schedule.cron).toBe('0 0 2 * * 3');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('getRetentionConfig with custom preferences', () => {
|
|
138
|
+
it('should apply custom preferences when set', async () => {
|
|
139
|
+
jest.resetModules();
|
|
140
|
+
jest.doMock('@blocklet/sdk/lib/config', () => ({
|
|
141
|
+
__esModule: true,
|
|
142
|
+
default: {
|
|
143
|
+
env: {
|
|
144
|
+
preferences: {
|
|
145
|
+
retentionEnabled: true,
|
|
146
|
+
scheduleEnabled: false,
|
|
147
|
+
scheduleHour: 5,
|
|
148
|
+
batchSize: 300,
|
|
149
|
+
minFreeDiskMB: 1000,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
}));
|
|
154
|
+
|
|
155
|
+
const { getRetentionConfig: getConfigWithPrefs } = await import('../../src/libs/archive/config');
|
|
156
|
+
const config = getConfigWithPrefs();
|
|
157
|
+
|
|
158
|
+
expect(config.enabled).toBe(true);
|
|
159
|
+
expect(config.schedule.enabled).toBe(false);
|
|
160
|
+
expect(config.schedule.hour).toBe(5);
|
|
161
|
+
expect(config.defaults.batchSize).toBe(300);
|
|
162
|
+
expect(config.storage.minFreeDiskMB).toBe(1000);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should fall back to defaults when batchSize exceeds max', async () => {
|
|
166
|
+
jest.resetModules();
|
|
167
|
+
jest.doMock('@blocklet/sdk/lib/config', () => ({
|
|
168
|
+
__esModule: true,
|
|
169
|
+
default: {
|
|
170
|
+
env: {
|
|
171
|
+
preferences: {
|
|
172
|
+
batchSize: 1000,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
}));
|
|
177
|
+
|
|
178
|
+
const { getRetentionConfig: getConfigWithPrefs } = await import('../../src/libs/archive/config');
|
|
179
|
+
const config = getConfigWithPrefs();
|
|
180
|
+
|
|
181
|
+
// batchSize: 1000 exceeds max(500) → validation fails → fall back to default 500
|
|
182
|
+
expect(config.defaults.batchSize).toBe(500);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|