payment-kit 1.26.4 → 1.27.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.
Files changed (54) hide show
  1. package/api/src/libs/payment.ts +113 -22
  2. package/api/src/libs/queue/index.ts +20 -9
  3. package/api/src/libs/queue/store.ts +11 -7
  4. package/api/src/libs/reference-cache.ts +115 -0
  5. package/api/src/queues/auto-recharge.ts +68 -21
  6. package/api/src/queues/credit-consume.ts +835 -206
  7. package/api/src/routes/checkout-sessions.ts +78 -1
  8. package/api/src/routes/customers.ts +15 -3
  9. package/api/src/routes/donations.ts +4 -4
  10. package/api/src/routes/index.ts +37 -8
  11. package/api/src/routes/invoices.ts +14 -3
  12. package/api/src/routes/meter-events.ts +41 -15
  13. package/api/src/routes/payment-links.ts +2 -2
  14. package/api/src/routes/prices.ts +1 -1
  15. package/api/src/routes/pricing-table.ts +3 -2
  16. package/api/src/routes/products.ts +2 -2
  17. package/api/src/routes/subscription-items.ts +12 -3
  18. package/api/src/routes/subscriptions.ts +27 -9
  19. package/api/src/store/migrations/20260306-checkout-session-indexes.ts +23 -0
  20. package/api/src/store/models/checkout-session.ts +3 -2
  21. package/api/src/store/models/coupon.ts +9 -6
  22. package/api/src/store/models/credit-grant.ts +4 -1
  23. package/api/src/store/models/credit-transaction.ts +3 -2
  24. package/api/src/store/models/customer.ts +9 -6
  25. package/api/src/store/models/exchange-rate-provider.ts +9 -6
  26. package/api/src/store/models/invoice.ts +3 -2
  27. package/api/src/store/models/meter-event.ts +6 -4
  28. package/api/src/store/models/meter.ts +9 -6
  29. package/api/src/store/models/payment-intent.ts +9 -6
  30. package/api/src/store/models/payment-link.ts +9 -6
  31. package/api/src/store/models/payout.ts +3 -2
  32. package/api/src/store/models/price.ts +9 -6
  33. package/api/src/store/models/pricing-table.ts +9 -6
  34. package/api/src/store/models/product.ts +9 -6
  35. package/api/src/store/models/promotion-code.ts +9 -6
  36. package/api/src/store/models/refund.ts +9 -6
  37. package/api/src/store/models/setup-intent.ts +6 -4
  38. package/api/src/store/sequelize.ts +8 -3
  39. package/api/tests/queues/credit-consume-batch.spec.ts +438 -0
  40. package/api/tests/queues/credit-consume.spec.ts +505 -0
  41. package/api/third.d.ts +1 -1
  42. package/blocklet.yml +1 -1
  43. package/package.json +8 -7
  44. package/scripts/benchmark-seed.js +247 -0
  45. package/src/components/customer/credit-overview.tsx +31 -42
  46. package/src/components/invoice-pdf/template.tsx +5 -4
  47. package/src/components/payment-link/actions.tsx +45 -0
  48. package/src/components/payment-link/before-pay.tsx +24 -0
  49. package/src/components/subscription/payment-method-info.tsx +23 -6
  50. package/src/components/subscription/portal/actions.tsx +2 -0
  51. package/src/locales/en.tsx +11 -0
  52. package/src/locales/zh.tsx +10 -0
  53. package/src/pages/admin/products/links/detail.tsx +8 -0
  54. package/src/pages/customer/subscription/detail.tsx +21 -18
@@ -99,12 +99,15 @@ export class ExchangeRateProvider extends Model<
99
99
  createdAt: 'created_at',
100
100
  updatedAt: 'updated_at',
101
101
  hooks: {
102
- afterCreate: (model: ExchangeRateProvider, options) =>
103
- createEvent('ExchangeRateProvider', 'exchange_rate_provider.created', model, options).catch(console.error),
104
- afterUpdate: (model: ExchangeRateProvider, options) =>
105
- createEvent('ExchangeRateProvider', 'exchange_rate_provider.updated', model, options).catch(console.error),
106
- afterDestroy: (model: ExchangeRateProvider, options) =>
107
- createEvent('ExchangeRateProvider', 'exchange_rate_provider.deleted', model, options).catch(console.error),
102
+ afterCreate: (model: ExchangeRateProvider, options) => {
103
+ createEvent('ExchangeRateProvider', 'exchange_rate_provider.created', model, options).catch(console.error);
104
+ },
105
+ afterUpdate: (model: ExchangeRateProvider, options) => {
106
+ createEvent('ExchangeRateProvider', 'exchange_rate_provider.updated', model, options).catch(console.error);
107
+ },
108
+ afterDestroy: (model: ExchangeRateProvider, options) => {
109
+ createEvent('ExchangeRateProvider', 'exchange_rate_provider.deleted', model, options).catch(console.error);
110
+ },
108
111
  },
109
112
  }
110
113
  );
@@ -491,8 +491,9 @@ export class Invoice extends Model<InferAttributes<Invoice>, InferCreationAttrib
491
491
  options
492
492
  ).catch(console.error);
493
493
  },
494
- afterDestroy: (model: Invoice, options) =>
495
- createEvent('Invoice', 'invoice.deleted', model, options).catch(console.error),
494
+ afterDestroy: (model: Invoice, options) => {
495
+ createEvent('Invoice', 'invoice.deleted', model, options).catch(console.error);
496
+ },
496
497
  },
497
498
  }
498
499
  );
@@ -233,8 +233,9 @@ export class MeterEvent extends Model<InferAttributes<MeterEvent>, InferCreation
233
233
  updatedAt: 'updated_at',
234
234
  indexes: [{ fields: ['identifier'], unique: true }, { fields: ['status'] }, { fields: ['event_name'] }],
235
235
  hooks: {
236
- afterCreate: (model: MeterEvent, options) =>
237
- createEvent('MeterEvent', 'billing.meter_event.created', model, options).catch(console.error),
236
+ afterCreate: (model: MeterEvent, options) => {
237
+ createEvent('MeterEvent', 'billing.meter_event.created', model, options).catch(console.error);
238
+ },
238
239
  },
239
240
  }
240
241
  );
@@ -260,10 +261,11 @@ export class MeterEvent extends Model<InferAttributes<MeterEvent>, InferCreation
260
261
 
261
262
  // 检查事件是否已存在(防重复)
262
263
  public static async isEventExists(identifier: string): Promise<boolean> {
263
- const count = await this.count({
264
+ const event = await this.findOne({
264
265
  where: { identifier },
266
+ attributes: ['id'],
265
267
  });
266
- return count > 0;
268
+ return !!event;
267
269
  }
268
270
 
269
271
  // 获取事件统计
@@ -123,12 +123,15 @@ export class Meter extends Model<InferAttributes<Meter>, InferCreationAttributes
123
123
  updatedAt: 'updated_at',
124
124
  indexes: [{ fields: ['event_name'] }, { fields: ['currency_id'] }],
125
125
  hooks: {
126
- afterCreate: (model: Meter, options) =>
127
- createEvent('Meter', 'meter.created', model, options).catch(console.error),
128
- afterUpdate: (model: Meter, options) =>
129
- createEvent('Meter', 'meter.updated', model, options).catch(console.error),
130
- afterDestroy: (model: Meter, options) =>
131
- createEvent('Meter', 'meter.deleted', model, options).catch(console.error),
126
+ afterCreate: (model: Meter, options) => {
127
+ createEvent('Meter', 'meter.created', model, options).catch(console.error);
128
+ },
129
+ afterUpdate: (model: Meter, options) => {
130
+ createEvent('Meter', 'meter.updated', model, options).catch(console.error);
131
+ },
132
+ afterDestroy: (model: Meter, options) => {
133
+ createEvent('Meter', 'meter.deleted', model, options).catch(console.error);
134
+ },
132
135
  },
133
136
  });
134
137
  }
@@ -257,9 +257,10 @@ export class PaymentIntent extends Model<InferAttributes<PaymentIntent>, InferCr
257
257
  createdAt: 'created_at',
258
258
  updatedAt: 'updated_at',
259
259
  hooks: {
260
- afterCreate: (model: PaymentIntent, options) =>
261
- createEvent('PaymentIntent', 'payment_intent.created', model, options).catch(console.error),
262
- afterUpdate: (model: PaymentIntent, options) =>
260
+ afterCreate: (model: PaymentIntent, options) => {
261
+ createEvent('PaymentIntent', 'payment_intent.created', model, options).catch(console.error);
262
+ },
263
+ afterUpdate: (model: PaymentIntent, options) => {
263
264
  createStatusEvent(
264
265
  'PaymentIntent',
265
266
  'payment_intent',
@@ -271,9 +272,11 @@ export class PaymentIntent extends Model<InferAttributes<PaymentIntent>, InferCr
271
272
  },
272
273
  model,
273
274
  options
274
- ),
275
- afterDestroy: (model: PaymentIntent, options) =>
276
- createEvent('PaymentIntent', 'payment_intent.deleted', model, options).catch(console.error),
275
+ ).catch(console.error);
276
+ },
277
+ afterDestroy: (model: PaymentIntent, options) => {
278
+ createEvent('PaymentIntent', 'payment_intent.deleted', model, options).catch(console.error);
279
+ },
277
280
  },
278
281
  }
279
282
  );
@@ -239,12 +239,15 @@ export class PaymentLink extends Model<InferAttributes<PaymentLink>, InferCreati
239
239
  createdAt: 'created_at',
240
240
  updatedAt: 'updated_at',
241
241
  hooks: {
242
- afterCreate: (model: PaymentLink, options) =>
243
- createEvent('PaymentLink', 'payment_link.created', model, options).catch(console.error),
244
- afterUpdate: (model: PaymentLink, options) =>
245
- createEvent('PaymentLink', 'payment_link.updated', model, options).catch(console.error),
246
- afterDestroy: (model: PaymentLink, options) =>
247
- createEvent('PaymentLink', 'payment_link.deleted', model, options).catch(console.error),
242
+ afterCreate: (model: PaymentLink, options) => {
243
+ createEvent('PaymentLink', 'payment_link.created', model, options).catch(console.error);
244
+ },
245
+ afterUpdate: (model: PaymentLink, options) => {
246
+ createEvent('PaymentLink', 'payment_link.updated', model, options).catch(console.error);
247
+ },
248
+ afterDestroy: (model: PaymentLink, options) => {
249
+ createEvent('PaymentLink', 'payment_link.deleted', model, options).catch(console.error);
250
+ },
248
251
  },
249
252
  }
250
253
  );
@@ -196,14 +196,15 @@ export class Payout extends Model<InferAttributes<Payout>, InferCreationAttribut
196
196
  createEvent('Payout', 'payout.paid', model, options).catch(console.error);
197
197
  }
198
198
  },
199
- afterUpdate: (model: Payout, options) =>
199
+ afterUpdate: (model: Payout, options) => {
200
200
  createStatusEvent(
201
201
  'Payout',
202
202
  'payout',
203
203
  { canceled: 'canceled', failed: 'failed', paid: 'paid' },
204
204
  model,
205
205
  options
206
- ),
206
+ ).catch(console.error);
207
+ },
207
208
  },
208
209
  }
209
210
  );
@@ -249,12 +249,15 @@ export class Price extends Model<InferAttributes<Price>, InferCreationAttributes
249
249
  createdAt: 'created_at',
250
250
  updatedAt: 'updated_at',
251
251
  hooks: {
252
- afterCreate: (model: Price, options) =>
253
- createEvent('Price', 'price.created', model, options).catch(console.error),
254
- afterUpdate: (model: Price, options) =>
255
- createEvent('Price', 'price.updated', model, options).catch(console.error),
256
- afterDestroy: (model: Price, options) =>
257
- createEvent('Price', 'price.deleted', model, options).catch(console.error),
252
+ afterCreate: (model: Price, options) => {
253
+ createEvent('Price', 'price.created', model, options).catch(console.error);
254
+ },
255
+ afterUpdate: (model: Price, options) => {
256
+ createEvent('Price', 'price.updated', model, options).catch(console.error);
257
+ },
258
+ afterDestroy: (model: Price, options) => {
259
+ createEvent('Price', 'price.deleted', model, options).catch(console.error);
260
+ },
258
261
  },
259
262
  }
260
263
  );
@@ -91,12 +91,15 @@ export class PricingTable extends Model<InferAttributes<PricingTable>, InferCrea
91
91
  createdAt: 'created_at',
92
92
  updatedAt: 'updated_at',
93
93
  hooks: {
94
- afterCreate: (model: PricingTable, options) =>
95
- createEvent('PricingTable', 'pricing_table.created', model, options).catch(console.error),
96
- afterUpdate: (model: PricingTable, options) =>
97
- createEvent('PricingTable', 'pricing_table.updated', model, options).catch(console.error),
98
- afterDestroy: (model: PricingTable, options) =>
99
- createEvent('PricingTable', 'pricing_table.deleted', model, options).catch(console.error),
94
+ afterCreate: (model: PricingTable, options) => {
95
+ createEvent('PricingTable', 'pricing_table.created', model, options).catch(console.error);
96
+ },
97
+ afterUpdate: (model: PricingTable, options) => {
98
+ createEvent('PricingTable', 'pricing_table.updated', model, options).catch(console.error);
99
+ },
100
+ afterDestroy: (model: PricingTable, options) => {
101
+ createEvent('PricingTable', 'pricing_table.deleted', model, options).catch(console.error);
102
+ },
100
103
  },
101
104
  });
102
105
  }
@@ -170,12 +170,15 @@ export class Product extends Model<InferAttributes<Product>, InferCreationAttrib
170
170
  createdAt: 'created_at',
171
171
  updatedAt: 'updated_at',
172
172
  hooks: {
173
- afterCreate: (model: Product, options) =>
174
- createEvent('Product', 'product.created', model, options).catch(console.error),
175
- afterUpdate: (model: Product, options) =>
176
- createEvent('Product', 'product.updated', model, options).catch(console.error),
177
- afterDestroy: (model: Product, options) =>
178
- createEvent('Product', 'product.deleted', model, options).catch(console.error),
173
+ afterCreate: (model: Product, options) => {
174
+ createEvent('Product', 'product.created', model, options).catch(console.error);
175
+ },
176
+ afterUpdate: (model: Product, options) => {
177
+ createEvent('Product', 'product.updated', model, options).catch(console.error);
178
+ },
179
+ afterDestroy: (model: Product, options) => {
180
+ createEvent('Product', 'product.deleted', model, options).catch(console.error);
181
+ },
179
182
  },
180
183
  }
181
184
  );
@@ -156,12 +156,15 @@ export class PromotionCode extends Model<InferAttributes<PromotionCode>, InferCr
156
156
  createdAt: 'created_at',
157
157
  updatedAt: 'updated_at',
158
158
  hooks: {
159
- afterCreate: (model: PromotionCode, options) =>
160
- createEvent('PromotionCode', 'promotion_code.created', model, options).catch(console.error),
161
- afterUpdate: (model: PromotionCode, options) =>
162
- createEvent('PromotionCode', 'promotion_code.updated', model, options).catch(console.error),
163
- afterDestroy: (model: PromotionCode, options) =>
164
- createEvent('PromotionCode', 'promotion_code.deleted', model, options).catch(console.error),
159
+ afterCreate: (model: PromotionCode, options) => {
160
+ createEvent('PromotionCode', 'promotion_code.created', model, options).catch(console.error);
161
+ },
162
+ afterUpdate: (model: PromotionCode, options) => {
163
+ createEvent('PromotionCode', 'promotion_code.updated', model, options).catch(console.error);
164
+ },
165
+ afterDestroy: (model: PromotionCode, options) => {
166
+ createEvent('PromotionCode', 'promotion_code.deleted', model, options).catch(console.error);
167
+ },
165
168
  },
166
169
  }
167
170
  );
@@ -200,18 +200,21 @@ export class Refund extends Model<InferAttributes<Refund>, InferCreationAttribut
200
200
  createdAt: 'created_at',
201
201
  updatedAt: 'updated_at',
202
202
  hooks: {
203
- afterCreate: (model: Refund, options) =>
204
- createEvent('Refund', 'refund.created', model, options).catch(console.error),
205
- afterUpdate: (model: Refund, options) =>
203
+ afterCreate: (model: Refund, options) => {
204
+ createEvent('Refund', 'refund.created', model, options).catch(console.error);
205
+ },
206
+ afterUpdate: (model: Refund, options) => {
206
207
  createStatusEvent(
207
208
  'Refund',
208
209
  'refund',
209
210
  { canceled: 'canceled', processing: 'processing', succeeded: 'succeeded' },
210
211
  model,
211
212
  options
212
- ),
213
- afterDestroy: (model: Refund, options) =>
214
- createEvent('Refund', 'refund.deleted', model, options).catch(console.error),
213
+ ).catch(console.error);
214
+ },
215
+ afterDestroy: (model: Refund, options) => {
216
+ createEvent('Refund', 'refund.deleted', model, options).catch(console.error);
217
+ },
215
218
  },
216
219
  }
217
220
  );
@@ -163,9 +163,10 @@ export class SetupIntent extends Model<InferAttributes<SetupIntent>, InferCreati
163
163
  createdAt: 'created_at',
164
164
  updatedAt: 'updated_at',
165
165
  hooks: {
166
- afterCreate: (model: SetupIntent, options) =>
167
- createEvent('SetupIntent', 'setup_intent.created', model, options).catch(console.error),
168
- afterUpdate: (model: SetupIntent, options) =>
166
+ afterCreate: (model: SetupIntent, options) => {
167
+ createEvent('SetupIntent', 'setup_intent.created', model, options).catch(console.error);
168
+ },
169
+ afterUpdate: (model: SetupIntent, options) => {
169
170
  createStatusEvent(
170
171
  'SetupIntent',
171
172
  'setup_intent',
@@ -176,7 +177,8 @@ export class SetupIntent extends Model<InferAttributes<SetupIntent>, InferCreati
176
177
  },
177
178
  model,
178
179
  options
179
- ),
180
+ ).catch(console.error);
181
+ },
180
182
  },
181
183
  });
182
184
  }
@@ -26,6 +26,11 @@ export const sequelize = new Sequelize({
26
26
  },
27
27
  });
28
28
 
29
- sequelize.query('pragma journal_mode = WAL;');
30
- sequelize.query('pragma synchronous = normal;');
31
- sequelize.query('pragma journal_size_limit = 67108864;');
29
+ // SQLite PRAGMAs — run once at startup on the single reused connection.
30
+ // Note: SQLite in Sequelize reuses a cached connection (connection-manager.js:43-44),
31
+ // so these fire-and-forget calls reliably apply to all subsequent queries.
32
+ sequelize.query('PRAGMA journal_mode = WAL');
33
+ sequelize.query('PRAGMA synchronous = NORMAL');
34
+ sequelize.query('PRAGMA journal_size_limit = 67108864');
35
+ sequelize.query('PRAGMA busy_timeout = 5000');
36
+ sequelize.query('PRAGMA cache_size = -16000'); // 16MB page cache (default ~2MB)