payment-kit 1.13.239 → 1.13.240

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.
@@ -1,5 +1,5 @@
1
1
  import dayjs from 'dayjs';
2
- import { clone } from 'lodash';
2
+ import clone from 'lodash/clone';
3
3
  import pAll from 'p-all';
4
4
 
5
5
  import { notificationCronConcurrency } from '../libs/env';
@@ -27,19 +27,21 @@ export abstract class BaseSubscriptionScheduleNotification<Options extends any>
27
27
  abstract getSubscriptions(): Promise<Subscription[]>;
28
28
 
29
29
  async run() {
30
- const label: string = new Date().toISOString();
30
+ const { name } = this.constructor;
31
31
 
32
- logger.info(`${label}: ${this.constructor.name}.run start`);
32
+ logger.info(`${name}.run start`, { start: dayjs(this.start).toISOString(), end: dayjs(this.end).toISOString() });
33
33
 
34
34
  const subscriptions = await this.getSubscriptions();
35
+ logger.info(`${name}.run.${subscriptions.length}`, subscriptions.length);
36
+
35
37
  const subscriptionForWillRenew = this.getSubscriptionsForWillRenew(subscriptions);
36
38
 
37
39
  await this.addTaskToQueue(subscriptionForWillRenew);
38
40
 
39
- logger.info(`${label}: ${this.constructor.name}.run end`);
41
+ logger.info(`${name}.run end`);
40
42
  }
41
43
 
42
- static DIFFS: Diff[] = [
44
+ static readonly DIFFS: Diff[] = [
43
45
  {
44
46
  value: 1,
45
47
  unit: 'M',
@@ -164,6 +166,7 @@ export abstract class BaseSubscriptionScheduleNotification<Options extends any>
164
166
  return;
165
167
  }
166
168
 
169
+ logger.info(`BaseSubscriptionScheduleNotification.addTaskToQueue.${this.eventType}`, x);
167
170
  notificationQueue.push(x);
168
171
  };
169
172
  }),
@@ -18,6 +18,10 @@ export class SubscriptionWillCanceledSchedule extends BaseSubscriptionScheduleNo
18
18
  raw: true,
19
19
  });
20
20
 
21
+ subscriptions.forEach((subscription) => {
22
+ subscription.current_period_end = subscription.cancel_at!;
23
+ });
24
+
21
25
  return subscriptions;
22
26
  }
23
27
 
@@ -37,7 +41,7 @@ export class SubscriptionWillCanceledSchedule extends BaseSubscriptionScheduleNo
37
41
  subscriptionId: subscription.id,
38
42
  willCancelValue: diff.value,
39
43
  willCancelUnit: diff.unit,
40
- required: !!diff.required,
44
+ required: true,
41
45
  },
42
46
  },
43
47
  delay: dayjs(subscription.current_period_end * 1000)
@@ -19,7 +19,6 @@ export class SubscriptionWillRenewSchedule extends BaseSubscriptionScheduleNotif
19
19
  current_period_end: {
20
20
  [Op.lt]: this.end / 1000,
21
21
  },
22
- trial_start: 0,
23
22
  status: 'active',
24
23
  },
25
24
  attributes: ['id', 'current_period_start', 'current_period_end'],
@@ -9,6 +9,7 @@ export const stripeInvoiceCronTime: string = process.env.STRIPE_INVOICE_CRON_TIM
9
9
  export const stripePaymentCronTime: string = process.env.STRIPE_PAYMENT_CRON_TIME || '0 */20 * * * *'; // 默认每 20min 执行一次
10
10
  export const stripeSubscriptionCronTime: string = process.env.STRIPE_SUBSCRIPTION_CRON_TIME || '0 10 */8 * * *'; // 默认每 8小时 执行一次
11
11
  export const revokeStakeCronTime: string = process.env.REVOKE_STAKE_CRON_TIME || '0 */5 * * * *'; // 默认每 5 min 行一次
12
+ export const daysUntilCancel: string | undefined = process.env.DAYS_UNTIL_CANCEL;
12
13
 
13
14
  export default {
14
15
  ...env,
@@ -1,7 +1,6 @@
1
- import querystring from 'querystring';
2
-
3
1
  import { component } from '@blocklet/sdk';
4
2
  import type { LiteralUnion } from 'type-fest';
3
+ import { withQuery } from 'ufo';
5
4
 
6
5
  import { getConnectQueryParam } from './util';
7
6
 
@@ -17,8 +16,10 @@ export function getCustomerInvoicePageUrl({
17
16
  action?: LiteralUnion<'pay', string>;
18
17
  }) {
19
18
  return component.getUrl(
20
- `customer/invoice/${invoiceId}?locale=${locale}&action=${action}&${querystring.stringify(
21
- getConnectQueryParam({ userDid })
22
- )}`
19
+ withQuery(`customer/invoice/${invoiceId}`, {
20
+ locale,
21
+ action,
22
+ ...getConnectQueryParam({ userDid }),
23
+ })
23
24
  );
24
25
  }
@@ -104,7 +104,13 @@ export class OneTimePaymentSucceededEmailTemplate
104
104
 
105
105
  // @ts-expect-error
106
106
  const txHash: string | undefined = paymentIntent?.payment_details?.[paymentMethod.type]?.tx_hash;
107
- const viewTxHashLink: string | undefined = txHash && getExplorerLink(chainHost, txHash as string, 'tx');
107
+ const viewTxHashLink: string | undefined =
108
+ txHash &&
109
+ getExplorerLink({
110
+ type: 'tx',
111
+ did: txHash,
112
+ chainHost,
113
+ });
108
114
 
109
115
  return {
110
116
  locale,
@@ -223,17 +229,17 @@ export class OneTimePaymentSucceededEmailTemplate
223
229
  // @ts-ignore
224
230
  actions: [
225
231
  viewSubscriptionLink && {
226
- name: 'viewSubscription',
232
+ name: translate('notification.common.viewSubscription', locale),
227
233
  title: translate('notification.common.viewSubscription', locale),
228
234
  link: viewSubscriptionLink,
229
235
  },
230
236
  viewInvoiceLink && {
231
- name: 'viewSubscription',
237
+ name: translate('notification.common.viewInvoice', locale),
232
238
  title: translate('notification.common.viewInvoice', locale),
233
239
  link: viewInvoiceLink,
234
240
  },
235
241
  viewTxHashLink && {
236
- name: 'viewTxHash',
242
+ name: translate('notification.common.viewTxHash', locale),
237
243
  title: translate('notification.common.viewTxHash', locale),
238
244
  link: viewTxHashLink as string,
239
245
  },
@@ -49,13 +49,17 @@ export class SubscriptionCanceledEmailTemplate implements BaseEmailTemplate<Subs
49
49
  if (subscription.status !== 'canceled') {
50
50
  throw new Error(`Subscription(${this.options.subscriptionId}) status(${subscription.status}) must be canceled`);
51
51
  }
52
- if (subscription.cancelation_details?.reason !== 'payment_disputed') {
53
- // 非管理员取消的订阅不需要发送邮件
52
+ if (['payment_failed', 'payment_disputed'].includes(subscription.cancelation_details?.reason as string) === false) {
53
+ // 只有没钱导致订阅被取消了,或者管理员取消了,才会发送通知
54
54
  logger.error(
55
- `Subscription(${this.options.subscriptionId}) cancelation reason must be payment_disputed`,
56
- subscription.cancelation_details
55
+ `Subscription(${this.options.subscriptionId}) cancelation reason must be payment_disputed or payment_failed`,
56
+ {
57
+ cancelation_details: subscription.cancelation_details,
58
+ }
59
+ );
60
+ throw new Error(
61
+ `Subscription(${this.options.subscriptionId}) cancelation reason must be payment_disputed or payment_failed`
57
62
  );
58
- throw new Error(`Subscription(${this.options.subscriptionId}) cancelation reason must be payment_disputed`);
59
63
  }
60
64
 
61
65
  const customer = await Customer.findByPk(subscription.customer_id);
@@ -229,7 +233,7 @@ export class SubscriptionCanceledEmailTemplate implements BaseEmailTemplate<Subs
229
233
  // @ts-ignore
230
234
  actions: [
231
235
  viewSubscriptionLink && {
232
- name: 'viewSubscription',
236
+ name: translate('notification.common.viewSubscription', locale),
233
237
  title: translate('notification.common.viewSubscription', locale),
234
238
  link: viewSubscriptionLink,
235
239
  },
@@ -115,7 +115,13 @@ export class SubscriptionRefundSucceededEmailTemplate
115
115
 
116
116
  // @ts-expect-error
117
117
  const txHash: string | undefined = refund?.payment_details?.[paymentMethod.type]?.tx_hash;
118
- const viewTxHashLink: string | undefined = txHash && getExplorerLink(chainHost, txHash as string, 'tx');
118
+ const viewTxHashLink: string | undefined =
119
+ txHash &&
120
+ getExplorerLink({
121
+ type: 'tx',
122
+ did: txHash,
123
+ chainHost,
124
+ });
119
125
 
120
126
  return {
121
127
  locale,
@@ -269,12 +275,12 @@ export class SubscriptionRefundSucceededEmailTemplate
269
275
  // @ts-ignore
270
276
  actions: [
271
277
  {
272
- name: 'viewSubscription',
278
+ name: translate('notification.common.viewSubscription', locale),
273
279
  title: translate('notification.common.viewSubscription', locale),
274
280
  link: viewSubscriptionLink,
275
281
  },
276
282
  viewTxHashLink && {
277
- name: 'viewTxHash',
283
+ name: translate('notification.common.viewTxHash', locale),
278
284
  title: translate('notification.common.viewTxHash', locale),
279
285
  link: viewTxHashLink as string,
280
286
  },
@@ -136,7 +136,14 @@ export class SubscriptionRenewFailedEmailTemplate
136
136
  });
137
137
  const txHash: string | undefined =
138
138
  paymentIntent?.payment_details?.[checkoutSession?.nft_mint_details?.type as 'arcblock' | 'ethereum']?.tx_hash;
139
- const viewTxHashLink: string | undefined = hasNft && txHash ? getExplorerLink(chainHost, txHash, 'tx') : undefined;
139
+ const viewTxHashLink: string | undefined =
140
+ hasNft && txHash
141
+ ? getExplorerLink({
142
+ type: 'tx',
143
+ did: txHash,
144
+ chainHost,
145
+ })
146
+ : undefined;
140
147
 
141
148
  return {
142
149
  locale,
@@ -181,7 +188,7 @@ export class SubscriptionRenewFailedEmailTemplate
181
188
  body: `${translate('notification.subscriptionRenewFailed.body', locale, {
182
189
  at,
183
190
  productName,
184
- reason: `${reason}`,
191
+ reason: `<span style="color: red;">${reason}</span>`,
185
192
  })}`,
186
193
  // @ts-expect-error
187
194
  attachments: [
@@ -269,17 +276,17 @@ export class SubscriptionRenewFailedEmailTemplate
269
276
  // @ts-ignore
270
277
  actions: [
271
278
  {
272
- name: 'viewSubscription',
279
+ name: translate('notification.common.viewSubscription', locale),
273
280
  title: translate('notification.common.viewSubscription', locale),
274
281
  link: viewSubscriptionLink,
275
282
  },
276
283
  {
277
- name: 'viewInvoice',
278
- title: translate('notification.subscriptionRenewFailed.renewNow', locale),
284
+ name: translate('notification.common.renewNow', locale),
285
+ title: translate('notification.common.renewNow', locale),
279
286
  link: viewInvoiceLink,
280
287
  },
281
288
  viewTxHashLink && {
282
- name: 'viewTxHash',
289
+ name: translate('notification.common.viewTxHash', locale),
283
290
  title: translate('notification.common.viewTxHash', locale),
284
291
  link: viewTxHashLink as string,
285
292
  },
@@ -125,7 +125,14 @@ export class SubscriptionRenewedEmailTemplate implements BaseEmailTemplate<Subsc
125
125
  });
126
126
  const txHash: string | undefined =
127
127
  paymentIntent?.payment_details?.[checkoutSession?.nft_mint_details?.type as 'arcblock' | 'ethereum']?.tx_hash;
128
- const viewTxHashLink: string | undefined = hasNft && txHash ? getExplorerLink(chainHost, txHash, 'tx') : undefined;
128
+ const viewTxHashLink: string | undefined =
129
+ hasNft && txHash
130
+ ? getExplorerLink({
131
+ type: 'tx',
132
+ did: txHash,
133
+ chainHost,
134
+ })
135
+ : undefined;
129
136
 
130
137
  return {
131
138
  locale,
@@ -261,17 +268,17 @@ export class SubscriptionRenewedEmailTemplate implements BaseEmailTemplate<Subsc
261
268
  // @ts-ignore
262
269
  actions: [
263
270
  {
264
- name: 'viewSubscription',
271
+ name: translate('notification.common.viewSubscription', locale),
265
272
  title: translate('notification.common.viewSubscription', locale),
266
273
  link: viewSubscriptionLink,
267
274
  },
268
275
  {
269
- name: 'viewSubscription',
276
+ name: translate('notification.common.viewInvoice', locale),
270
277
  title: translate('notification.common.viewInvoice', locale),
271
278
  link: viewInvoiceLink,
272
279
  },
273
280
  viewTxHashLink && {
274
- name: 'viewTxHash',
281
+ name: translate('notification.common.viewTxHash', locale),
275
282
  title: translate('notification.common.viewTxHash', locale),
276
283
  link: viewTxHashLink as string,
277
284
  },
@@ -145,7 +145,13 @@ export class SubscriptionSucceededEmailTemplate
145
145
  const paymentIntent = await PaymentIntent.findByPk(invoice.payment_intent_id);
146
146
  const txHash: string | undefined =
147
147
  paymentIntent?.payment_details?.[checkoutSession?.nft_mint_details?.type as 'arcblock' | 'ethereum']?.tx_hash;
148
- const viewTxHashLink: string | undefined = txHash && getExplorerLink(chainHost, txHash as string, 'tx');
148
+ const viewTxHashLink: string | undefined =
149
+ txHash &&
150
+ getExplorerLink({
151
+ type: 'tx',
152
+ did: txHash,
153
+ chainHost,
154
+ });
149
155
 
150
156
  return {
151
157
  locale,
@@ -270,17 +276,17 @@ export class SubscriptionSucceededEmailTemplate
270
276
  // @ts-ignore
271
277
  actions: [
272
278
  {
273
- name: 'viewSubscription',
279
+ name: translate('notification.common.viewSubscription', locale),
274
280
  title: translate('notification.common.viewSubscription', locale),
275
281
  link: viewSubscriptionLink,
276
282
  },
277
283
  {
278
- name: 'viewSubscription',
284
+ name: translate('notification.common.viewInvoice', locale),
279
285
  title: translate('notification.common.viewInvoice', locale),
280
286
  link: viewInvoiceLink,
281
287
  },
282
288
  viewTxHashLink && {
283
- name: 'viewTxHash',
289
+ name: translate('notification.common.viewTxHash', locale),
284
290
  title: translate('notification.common.viewTxHash', locale),
285
291
  link: viewTxHashLink as string,
286
292
  },
@@ -262,12 +262,12 @@ export class SubscriptionTrialStartEmailTemplate
262
262
  // @ts-ignore
263
263
  actions: [
264
264
  {
265
- name: 'viewSubscription',
265
+ name: translate('notification.common.viewSubscription', locale),
266
266
  title: translate('notification.common.viewSubscription', locale),
267
267
  link: viewSubscriptionLink,
268
268
  },
269
269
  {
270
- name: 'viewSubscription',
270
+ name: translate('notification.common.viewInvoice', locale),
271
271
  title: translate('notification.common.viewInvoice', locale),
272
272
  link: viewInvoiceLink,
273
273
  },
@@ -248,7 +248,7 @@ export class SubscriptionTrialWilEndEmailTemplate
248
248
  // @ts-ignore
249
249
  actions: [
250
250
  {
251
- name: 'viewSubscription',
251
+ name: translate('notification.common.viewSubscription', locale),
252
252
  title: translate('notification.common.viewSubscription', locale),
253
253
  link: viewSubscriptionLink,
254
254
  },
@@ -114,7 +114,13 @@ export class SubscriptionUpgradedEmailTemplate implements BaseEmailTemplate<Subs
114
114
 
115
115
  // @ts-expect-error
116
116
  const txHash: string | undefined = paymentIntent?.payment_details?.[paymentMethod.type]?.tx_hash;
117
- const viewTxHashLink: string | undefined = txHash && getExplorerLink(chainHost, txHash, 'tx');
117
+ const viewTxHashLink: string | undefined =
118
+ txHash &&
119
+ getExplorerLink({
120
+ type: 'tx',
121
+ did: txHash,
122
+ chainHost,
123
+ });
118
124
 
119
125
  return {
120
126
  locale,
@@ -239,17 +245,17 @@ export class SubscriptionUpgradedEmailTemplate implements BaseEmailTemplate<Subs
239
245
  // @ts-ignore
240
246
  actions: [
241
247
  {
242
- name: 'viewSubscription',
248
+ name: translate('notification.common.viewSubscription', locale),
243
249
  title: translate('notification.common.viewSubscription', locale),
244
250
  link: viewSubscriptionLink,
245
251
  },
246
252
  {
247
- name: 'viewSubscription',
253
+ name: translate('notification.common.viewInvoice', locale),
248
254
  title: translate('notification.common.viewInvoice', locale),
249
255
  link: viewInvoiceLink,
250
256
  },
251
257
  viewTxHashLink && {
252
- name: 'viewTxHash',
258
+ name: translate('notification.common.viewTxHash', locale),
253
259
  title: translate('notification.common.viewTxHash', locale),
254
260
  link: viewTxHashLink,
255
261
  },
@@ -208,12 +208,12 @@ export class SubscriptionWillCanceledEmailTemplate
208
208
  // @ts-ignore
209
209
  actions: [
210
210
  viewSubscriptionLink && {
211
- name: 'viewSubscription',
211
+ name: translate('notification.common.viewSubscription', locale),
212
212
  title: translate('notification.common.viewSubscription', locale),
213
213
  link: viewSubscriptionLink,
214
214
  },
215
215
  viewInvoiceLink && {
216
- name: 'viewInvoice',
216
+ name: translate('notification.common.renewNow', locale),
217
217
  title: translate('notification.common.renewNow', locale),
218
218
  link: viewInvoiceLink,
219
219
  },
@@ -7,12 +7,13 @@ import prettyMsI18n from 'pretty-ms-i18n';
7
7
 
8
8
  import { getUserLocale } from '../../../integrations/blocklet/notification';
9
9
  import { translate } from '../../../locales';
10
- import { Customer, Invoice, Subscription } from '../../../store/models';
10
+ import { Customer, Invoice, PaymentMethod, Subscription } from '../../../store/models';
11
11
  import { PaymentCurrency } from '../../../store/models/payment-currency';
12
12
  import { PaymentDetail, getPaymentDetail } from '../../payment';
13
13
  import { getMainProductName } from '../../product';
14
14
  import { getCustomerSubscriptionPageUrl } from '../../subscription';
15
15
  import { formatTime, getPrettyMsI18nLocale } from '../../time';
16
+ import { getExplorerLink } from '../../util';
16
17
  import type { BaseEmailTemplate, BaseEmailTemplateType } from './base';
17
18
 
18
19
  export interface SubscriptionWillRenewEmailTemplateOptions {
@@ -36,6 +37,7 @@ interface SubscriptionWillRenewEmailTemplateContext {
36
37
  duration: string;
37
38
 
38
39
  viewSubscriptionLink: string;
40
+ immediateRechargeLink: string;
39
41
  }
40
42
 
41
43
  export class SubscriptionWillRenewEmailTemplate
@@ -97,6 +99,17 @@ export class SubscriptionWillRenewEmailTemplate
97
99
  locale,
98
100
  userDid,
99
101
  });
102
+ const paymentMethod: PaymentMethod | null = await PaymentMethod.findByPk(paymentCurrency.payment_method_id);
103
+ // @ts-ignore
104
+ const chainHost: string | undefined = paymentMethod?.settings?.[paymentMethod.type]?.api_host;
105
+ const immediateRechargeLink: string = getExplorerLink({
106
+ type: 'account',
107
+ did: userDid,
108
+ chainHost,
109
+ queryParams: {
110
+ action: 'recharge',
111
+ },
112
+ })!;
100
113
 
101
114
  return {
102
115
  locale,
@@ -112,6 +125,7 @@ export class SubscriptionWillRenewEmailTemplate
112
125
  duration,
113
126
 
114
127
  viewSubscriptionLink,
128
+ immediateRechargeLink,
115
129
  };
116
130
  }
117
131
 
@@ -171,6 +185,7 @@ export class SubscriptionWillRenewEmailTemplate
171
185
  paymentInfo,
172
186
 
173
187
  viewSubscriptionLink,
188
+ immediateRechargeLink,
174
189
  } = await this.getContext();
175
190
 
176
191
  const canPay: boolean = paymentDetail.balance >= paymentDetail.price;
@@ -189,6 +204,7 @@ export class SubscriptionWillRenewEmailTemplate
189
204
  at,
190
205
  productName,
191
206
  willRenewDuration,
207
+ balance: `${paymentDetail.balance} ${paymentDetail.symbol}`,
192
208
  })}`
193
209
  : `${translate('notification.subscriptionWillRenew.unableToPayBody', locale, {
194
210
  at,
@@ -252,8 +268,13 @@ export class SubscriptionWillRenewEmailTemplate
252
268
  ].filter(Boolean),
253
269
  // @ts-ignore
254
270
  actions: [
271
+ !canPay && {
272
+ name: translate('notification.common.immediateRecharge', locale),
273
+ title: translate('notification.common.immediateRecharge', locale),
274
+ link: immediateRechargeLink,
275
+ },
255
276
  {
256
- name: 'viewSubscription',
277
+ name: translate('notification.common.viewSubscription', locale),
257
278
  title: translate('notification.common.viewSubscription', locale),
258
279
  link: viewSubscriptionLink,
259
280
  },
@@ -181,6 +181,12 @@ export async function getPaymentDetail(userDid: string, invoice: Invoice): Promi
181
181
  symbol: '',
182
182
  };
183
183
 
184
+ const paymentCurrency = await PaymentCurrency.findByPk(invoice.currency_id);
185
+ if (!paymentCurrency) {
186
+ return defaultResult;
187
+ }
188
+ Object.assign(defaultResult, { symbol: paymentCurrency.symbol });
189
+
184
190
  const paymentIntent = await PaymentIntent.findByPk(invoice.payment_intent_id);
185
191
  if (!paymentIntent) {
186
192
  return defaultResult;
@@ -191,12 +197,7 @@ export async function getPaymentDetail(userDid: string, invoice: Invoice): Promi
191
197
  return defaultResult;
192
198
  }
193
199
 
194
- const paymentCurrency = await PaymentCurrency.findByPk(paymentIntent.currency_id);
195
- if (!paymentCurrency) {
196
- return defaultResult;
197
- }
198
-
199
- if (paymentMethod.type === 'arcblock') {
200
+ if (['arcblock', 'ethereum'].includes(paymentMethod.type)) {
200
201
  // balance enough token for payment?
201
202
  const result = await isDelegationSufficientForPayment({
202
203
  paymentMethod,
@@ -1,8 +1,7 @@
1
- import querystring from 'querystring';
2
-
3
1
  import component from '@blocklet/sdk/lib/component';
4
2
  import { BN } from '@ocap/util';
5
3
  import type { LiteralUnion } from 'type-fest';
4
+ import { withQuery } from 'ufo';
6
5
 
7
6
  import {
8
7
  Customer,
@@ -29,9 +28,10 @@ export function getCustomerSubscriptionPageUrl({
29
28
  userDid: string;
30
29
  }) {
31
30
  return component.getUrl(
32
- `customer/subscription/${subscriptionId}?locale=${locale}&${querystring.stringify(
33
- getConnectQueryParam({ userDid })
34
- )}`
31
+ withQuery(`customer/subscription/${subscriptionId}`, {
32
+ locale,
33
+ ...getConnectQueryParam({ userDid }),
34
+ })
35
35
  );
36
36
  }
37
37
 
@@ -4,6 +4,7 @@ import { getUrl } from '@blocklet/sdk/lib/component';
4
4
  import env from '@blocklet/sdk/lib/env';
5
5
  import { customAlphabet } from 'nanoid';
6
6
  import type { LiteralUnion } from 'type-fest';
7
+ import { withQuery } from 'ufo';
7
8
 
8
9
  import dayjs from './dayjs';
9
10
 
@@ -172,11 +173,17 @@ export function getDataObjectFromQuery(
172
173
  }
173
174
 
174
175
  // @FIXME: 这个应该封装在某个通用类库里面 @jianchao @wangshijun
175
- export function getExplorerLink(
176
- chainHost: string | undefined,
177
- did: string | undefined,
178
- type: LiteralUnion<'asset' | 'account' | 'tx' | 'token' | 'factory' | ' bridge', string>
179
- ) {
176
+ export function getExplorerLink({
177
+ type,
178
+ did,
179
+ chainHost = undefined,
180
+ queryParams = {},
181
+ }: {
182
+ chainHost: string | undefined;
183
+ did: string | undefined;
184
+ type: LiteralUnion<'asset' | 'account' | 'tx' | 'token' | 'factory' | ' bridge', string>;
185
+ queryParams?: Record<string, string>;
186
+ }) {
180
187
  if (!chainHost) return undefined;
181
188
  try {
182
189
  const chainUrl = new URL(chainHost);
@@ -203,7 +210,7 @@ export function getExplorerLink(
203
210
  chainUrl.pathname = '/';
204
211
  }
205
212
 
206
- return chainUrl.href;
213
+ return withQuery(chainUrl.href, queryParams);
207
214
  } catch {
208
215
  return undefined;
209
216
  }
@@ -24,7 +24,8 @@ export default flat({
24
24
  minute: 'minute',
25
25
  minutes: 'minutes',
26
26
  cancellationReason: 'Cancellation reason',
27
- renewNow: 'Renew now',
27
+ renewNow: 'Pay now',
28
+ immediateRecharge: 'Immediate recharge',
28
29
  },
29
30
 
30
31
  sendTo: 'Sent to',
@@ -40,9 +41,9 @@ export default flat({
40
41
 
41
42
  subscriptionTrialWillEnd: {
42
43
  title: 'The {productName} trial will end soon',
43
- body: 'Your {productName} trial subscription will end after {willRenewDuration}. Please make sure your account balance is sufficient to automatically renew your subscription at the end of the trial period. Thank you for your support and trust!',
44
+ body: 'Your trial for {productName} will end in {willRenewDuration}. Please ensure your account balance is sufficient for automatic billing after the trial ends. Thank you for your support and trust!',
44
45
  unableToPayBody:
45
- 'Your {productName} trial subscription will end after {willRenewDuration}.<span style="color: red;">Your current balance is {balance}, which is less than {price}</span>,please make sure your balance is sufficient for automatic renewal. Thank you for your support and trust!',
46
+ 'Your trial for {productName} will end in {willRenewDuration}. <span style="color: red;">Your current balance is {balance}, which is less than {price}</span>, Please ensure your balance is sufficient for automatic billing. Thank you for your support and trust!',
46
47
  },
47
48
 
48
49
  subscriptionSucceed: {
@@ -61,39 +62,35 @@ export default flat({
61
62
  },
62
63
 
63
64
  subscriptionWillRenew: {
64
- title: '{productName} will be auto-renewed soon',
65
- body: 'Your subscription to {productName} expires in {willRenewDuration}. Please make sure you have enough balance in your account to auto-renew your subscription when it expires ({at}). We wish you all the best!',
65
+ title: '{productName} will be deducted automatically',
66
+ body: 'Your {productName} subscription has {willRenewDuration} until the next deduction. Your current balance is {balance}, please ensure that your account balance is sufficient so that the deduction is automatically completed after the maturity ({at}). I wish you all the best! ',
66
67
  unableToPayBody:
67
- 'Your subscription to {productName} expires in {willRenewDuration}. <span style="color: red;">Your current balance is {balance}, which is less than {price}</span>, so please make sure you have enough balance in your account to automatically renew your subscription when it expires ({at}). We wish you all the best!',
68
- renewAmount: 'Renewal amount',
68
+ 'Your {productName} subscription has {willRenewDuration} until the next deduction. <span style="color: red;" > Your current balance is {balance}, less than {price}</span>, please ensure that your account balance is sufficient so that the deduction will be completed automatically after the expiration ({at}). I wish you all the best! ',
69
+ renewAmount: 'deduction amount ',
69
70
  },
70
71
 
71
72
  subscriptionRenewed: {
72
- title: '{productName} renewal successful',
73
- body: 'Your {productName} was successfully renewed on {at}. Thank you for your continued support and trust, have a great day!',
74
- noExpenseIncurred: 'No charges were incurred during the service period',
73
+ title: '{productName} payment successful',
74
+ body: 'Payment for your subscription {productName} is successfully collected on {at}. Thank you for your continued support and trust, I wish you a happy use! ',
75
+ noExpenseIncurred: 'No expenses incurred during the service ',
75
76
  },
76
77
 
77
78
  subscriptionRenewFailed: {
78
- title: 'Renewal of {productName} failed',
79
- body: "We're sorry to inform you that your {productName} renewal failed on {at}. The reason for the failure is <span style='color: red;'>{reason}</span>. If you have any questions, please do not hesitate to contact us. Thank you.",
80
- renewNow: 'Renew now',
79
+ title: '{productName} charge failed',
80
+ body: 'We are sorry to inform you that your {productName} failed to be charged on {at}. The reason for the failure is {reason}. If you have any questions, please contact us in time. Thank you!',
81
81
  reason: {
82
- noDidWallet:
83
- 'You have not yet bound the DID Wallet, please bind the DID Wallet, make sure the balance is sufficient and then renew it',
84
- noDelegation: 'No delegation found from your DID Wallet, please renew it after completing the authorization',
82
+ noDidWallet: 'You have not bound DID Wallet, please bind DID Wallet to ensure sufficient balance',
83
+ noDelegation: 'Your DID Wallet has not been authorized, please update authorization',
85
84
  noTransferPermission:
86
- 'Transfer permission not granted to app, please update the authorization and renew it again',
85
+ 'Your DID Wallet has not granted transfer permission to the application, please update authorization',
87
86
  noTokenPermission:
88
- 'Token transfer permission not granted to app, please update the authorization and renew it again',
89
- noTransferTo:
90
- 'App not in whitelist of the transfer permission, please update the authorization and renew it again',
91
- noEnoughAllowance: 'Transfer amount exceeds tx allowance, please update the authorization and renew it again',
92
- noToken: "You don't have any tokens in your account, please replenish your tokens and renew your account",
93
- noEnoughToken:
94
- 'Your account token balance is {balance}, not enough for {price}, please replenish your tokens and renew your account',
95
- noSupported: 'Token renewal is not supported, please check your subscription',
96
- txSendFailed: 'Failed to send transaction when try to collect payment.',
87
+ 'Your DID Wallet has not granted token transfer permission to the application, please update authorization',
88
+ noTransferTo: 'Your DID Wallet has not granted the application charge permission, please update authorization',
89
+ noEnoughAllowance: 'The deduction amount exceeds the single transfer limit, please update authorization',
90
+ noToken: 'Your account has no tokens, please recharge tokens',
91
+ noEnoughToken: 'Your account token balance is {balance}, insufficient for {price}, please recharge tokens',
92
+ noSupported: 'It is not supported to charge with tokens, please check your package',
93
+ txSendFailed: 'Failed to send charge transaction',
97
94
  },
98
95
  },
99
96
 
@@ -103,9 +100,9 @@ export default flat({
103
100
  },
104
101
 
105
102
  subscriptWillCanceled: {
106
- title: '{productName} subscription is about to be automatically canceled',
107
- body: 'Due to the long period of unsuccessful automatic renewal, your subscription to {productName} will be automatically canceled by the system on {at} ({willCancelDuration} later). Please handle the renewal issue manually in time to avoid any inconvenience. If you have any questions, please feel free to contact us.',
108
- renewAmount: 'Renewal Amount',
103
+ title: '{productName} subscription is about to be automatically cancelled ',
104
+ body: 'Your subscription {productName} will be automatically unsubscribed by the system after {at} (after {willCancelDuration}) due to a long period of failure to automatically complete the deduction. Please handle the problem of charge deduction manually in time, so as not to affect the use. If you have any questions, please feel free to contact us. ',
105
+ renewAmount: 'deduction amount ',
109
106
  },
110
107
 
111
108
  subscriptionCanceled: {
@@ -24,7 +24,8 @@ export default flat({
24
24
  minute: '分钟',
25
25
  minutes: '分钟',
26
26
  cancellationReason: '取消原因',
27
- renewNow: '立即续费',
27
+ renewNow: '立即付款',
28
+ immediateRecharge: '立即充值',
28
29
  },
29
30
 
30
31
  sendTo: '发送给',
@@ -40,9 +41,9 @@ export default flat({
40
41
 
41
42
  subscriptionTrialWillEnd: {
42
43
  title: '{productName} 试用期即将结束',
43
- body: '您订阅的 {productName} 试用资格将在 {willRenewDuration} 后结束。请确保您的账户余额充足,以便在试用期结束后自动续费。感谢您的支持与信任!',
44
+ body: '您订阅的 {productName} 试用资格将在 {willRenewDuration} 后结束。请确保您的账户余额充足,以便在试用期结束后自动完成扣费。感谢您的支持与信任!',
44
45
  unableToPayBody:
45
- '您订阅的 {productName} 试用资格将在 {willRenewDuration} 后结束。<span style="color: red;">您的当前余额为 {balance},不足 {price}</span>,请确保余额充足以便自动续费。感谢您的支持与信任!',
46
+ '您订阅的 {productName} 试用资格将在 {willRenewDuration} 后结束。<span style="color: red;">您的当前余额为 {balance},不足 {price}</span>,请确保余额充足以便自动完成扣费。感谢您的支持与信任!',
46
47
  },
47
48
 
48
49
  subscriptionSucceed: {
@@ -61,34 +62,33 @@ export default flat({
61
62
  },
62
63
 
63
64
  subscriptionWillRenew: {
64
- title: '{productName} 即将自动续费',
65
- body: '您订阅的 {productName} 还有 {willRenewDuration} 到期。请确保您的账户余额充足,以便在到期后({at})自动续费。祝您一切顺利!',
65
+ title: '{productName} 即将自动完成扣费',
66
+ body: '您订阅的 {productName} 距离下一次扣费还有 {willRenewDuration}。您的当前余额为 {balance},请确保您的账户余额充足,以便在到期后({at})自动完成扣费。祝您一切顺利!',
66
67
  unableToPayBody:
67
- '您订阅的 {productName} 还有 {willRenewDuration} 到期。<span style="color: red;">您的当前余额为 {balance},不足 {price}</span>,请确保您的账户余额充足,以便在到期后({at})自动续费。祝您一切顺利!',
68
- renewAmount: '扣款金额',
68
+ '您订阅的 {productName} 距离下一次扣费还有 {willRenewDuration}。<span style="color: red;">您的当前余额为 {balance},不足 {price}</span>,请确保您的账户余额充足,以便在到期后({at})自动完成扣费。祝您一切顺利!',
69
+ renewAmount: '扣费金额',
69
70
  },
70
71
 
71
72
  subscriptionRenewed: {
72
- title: '{productName} 续费成功',
73
- body: '您的 {productName} 已于 {at} 成功续费。感谢您的持续支持与信任,祝您使用愉快!',
73
+ title: '{productName} 扣费成功',
74
+ body: '您的 {productName} 已于 {at} 扣费成功。感谢您的持续支持与信任,祝您使用愉快!',
74
75
  noExpenseIncurred: '服务期间未产生费用',
75
76
  },
76
77
 
77
78
  subscriptionRenewFailed: {
78
- title: '{productName} 续费失败',
79
- body: '很抱歉地通知您,您的 {productName} 续费于 {at} 失败。失败原因为 <span style="color: red;">{reason}</span>。如有任何疑问,请及时联系我们。谢谢!',
80
- renewNow: '立即续费',
79
+ title: '{productName} 扣费失败',
80
+ body: '很抱歉地通知您,您的 {productName} {at} 扣费失败。失败原因为 {reason}。如有任何疑问,请及时联系我们。谢谢!',
81
81
  reason: {
82
- noDidWallet: '您尚未绑定 DID Wallet,请绑定 DID Wallet,确保余额充足后重新续费',
83
- noDelegation: '您的 DID Wallet 尚未授权,请完成授权后重新续费',
84
- noTransferPermission: '您的 DID Wallet 未授予应用转账权限,请更新授权后重新续费',
85
- noTokenPermission: '您的 DID Wallet 未授予应用对应通证的转账权限,请更新授权后重新续费',
86
- noTransferTo: '您的 DID Wallet 未授予应用扣款权限,请更新授权后重新续费',
87
- noEnoughAllowance: '扣款金额超出单笔转账限额,请更新授权后重新续费',
88
- noToken: '您的账户没有任何代币,请充值代币后重新续费',
89
- noEnoughToken: '您的账户代币余额为 {balance},不足 {price},请充值代币后重新续费',
90
- noSupported: '不支持使用代币续费,请检查您的套餐',
91
- txSendFailed: '扣款交易发送失败',
82
+ noDidWallet: '您尚未绑定 DID Wallet,请绑定 DID Wallet,确保余额充足',
83
+ noDelegation: '您的 DID Wallet 尚未授权,请更新授权',
84
+ noTransferPermission: '您的 DID Wallet 未授予应用转账权限,请更新授权',
85
+ noTokenPermission: '您的 DID Wallet 未授予应用对应通证的转账权限,请更新授权',
86
+ noTransferTo: '您的 DID Wallet 未授予应用扣费权限,请更新授权',
87
+ noEnoughAllowance: '扣款金额超出单笔转账限额,请更新授权',
88
+ noToken: '您的账户没有任何代币,请充值代币',
89
+ noEnoughToken: '您的账户代币余额为 {balance},不足 {price},请充值代币',
90
+ noSupported: '不支持使用代币扣费,请检查您的套餐',
91
+ txSendFailed: '扣费交易发送失败',
92
92
  },
93
93
  },
94
94
 
@@ -99,8 +99,8 @@ export default flat({
99
99
 
100
100
  subscriptWillCanceled: {
101
101
  title: '{productName} 订阅即将自动取消',
102
- body: '由于长时间未能自动完成续费,您订阅的 {productName} 将于 {at} ({willCancelDuration}后) 被系统自动取消订阅。请您及时手动处理续费问题,以免影响使用。如有任何疑问,请随时与我们联系。',
103
- renewAmount: '续费金额',
102
+ body: '由于长时间未能自动完成扣费,您订阅的 {productName} 将于 {at} ({willCancelDuration}后) 被系统自动取消订阅。请您及时手动处理扣费问题,以免影响使用。如有任何疑问,请随时与我们联系。',
103
+ renewAmount: '扣费金额',
104
104
  },
105
105
 
106
106
  subscriptionCanceled: {
@@ -105,6 +105,7 @@ async function handleNotificationJob(job: NotificationQueueJob): Promise<void> {
105
105
  try {
106
106
  const template = getNotificationTemplate(job);
107
107
  await new Notification(template).send();
108
+ logger.info('handleNotificationJob.success', { job });
108
109
  } catch (error) {
109
110
  logger.error('handleNotificationJob.error.$job', job);
110
111
  logger.error('handleNotificationJob.error', error);
@@ -133,6 +134,7 @@ export async function startNotificationQueue() {
133
134
  // 试用期开始
134
135
  events.on('customer.subscription.trial_start', (subscription: Subscription) => {
135
136
  notificationQueue.push({
137
+ id: `customer.subscription.trial_start.${subscription.id}`,
136
138
  job: {
137
139
  type: 'customer.subscription.trial_start',
138
140
  options: {
@@ -146,6 +148,7 @@ export async function startNotificationQueue() {
146
148
  if (!subscription.trial_start) {
147
149
  // 没有试用期的 subscription 通知
148
150
  notificationQueue.push({
151
+ id: `customer.subscription.started.${subscription.id}`,
149
152
  job: {
150
153
  type: 'customer.subscription.started',
151
154
  options: {
@@ -160,6 +163,7 @@ export async function startNotificationQueue() {
160
163
  events.on('checkout.session.completed', (checkoutSession: CheckoutSession) => {
161
164
  if (checkoutSession.mode === 'payment') {
162
165
  notificationQueue.push({
166
+ id: `checkout.session.completed.${checkoutSession.id}`,
163
167
  job: {
164
168
  type: 'checkout.session.completed',
165
169
  options: {
@@ -172,6 +176,7 @@ export async function startNotificationQueue() {
172
176
 
173
177
  events.on('customer.subscription.renewed', (subscription: Subscription) => {
174
178
  notificationQueue.push({
179
+ id: `customer.subscription.renewed.${subscription.id}.${subscription.latest_invoice_id}`,
175
180
  job: {
176
181
  type: 'customer.subscription.renewed',
177
182
  options: {
@@ -186,6 +191,7 @@ export async function startNotificationQueue() {
186
191
  const invoice = await Invoice.findByPk(subscription.latest_invoice_id);
187
192
  if (invoice && subscription.metadata.renew_failed_reason) {
188
193
  notificationQueue.push({
194
+ id: `customer.subscription.renew_failed.${subscription.id}.${invoice.id}`,
189
195
  job: {
190
196
  type: 'customer.subscription.renew_failed',
191
197
  options: {
@@ -199,6 +205,7 @@ export async function startNotificationQueue() {
199
205
 
200
206
  events.on('customer.subscription.upgraded', (subscription: Subscription) => {
201
207
  notificationQueue.push({
208
+ id: `customer.subscription.upgraded.${subscription.id}.${subscription.latest_invoice_id}`,
202
209
  job: {
203
210
  type: 'customer.subscription.upgraded',
204
211
  options: {
@@ -210,6 +217,7 @@ export async function startNotificationQueue() {
210
217
 
211
218
  events.on('refund.succeeded', (refund: Refund) => {
212
219
  notificationQueue.push({
220
+ id: `refund.succeeded.${refund.subscription_id}.${refund.id}`,
213
221
  job: {
214
222
  type: 'refund.succeeded',
215
223
  options: {
@@ -221,6 +229,7 @@ export async function startNotificationQueue() {
221
229
 
222
230
  events.on('customer.subscription.deleted', (subscription: Subscription) => {
223
231
  notificationQueue.push({
232
+ id: `customer.subscription.deleted.${subscription.id}`,
224
233
  job: {
225
234
  type: 'customer.subscription.deleted',
226
235
  options: {
@@ -554,9 +554,9 @@ export const handlePayment = async (job: PaymentJob) => {
554
554
  await paymentIntent.update(updates.payment);
555
555
  await invoice.update(updates.invoice);
556
556
 
557
- // 只有在重试次数超过阈值的时候才发送邮件,不然邮件频率太高了
557
+ // 只有在 第一次重试 或者 重试次数超过阈值 的时候才发送邮件,不然邮件频率太高了
558
558
  const minRetryMail = updates.minRetryMail || MIN_RETRY_MAIL;
559
- if (attemptCount >= minRetryMail && invoice.billing_reason === 'subscription_cycle') {
559
+ if ((attemptCount === 1 || attemptCount >= minRetryMail) && invoice.billing_reason === 'subscription_cycle') {
560
560
  const subscription = await Subscription.findByPk(invoice.subscription_id);
561
561
  if (subscription) {
562
562
  await subscription.update({
@@ -176,10 +176,12 @@ export class Subscription extends Model<InferAttributes<Subscription>, InferCrea
176
176
  type: DataTypes.ENUM('active', 'canceled', 'incomplete', 'incomplete_expired', 'past_due', 'trialing', 'paused'),
177
177
  allowNull: false,
178
178
  },
179
+ // 将来在什么时候这个订阅会被取消
179
180
  cancel_at: {
180
181
  type: DataTypes.INTEGER,
181
182
  allowNull: true,
182
183
  },
184
+ // 什么时候开始说要去取消订阅的
183
185
  canceled_at: {
184
186
  type: DataTypes.INTEGER,
185
187
  allowNull: true,
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.13.239
17
+ version: 1.13.240
18
18
  logo: logo.png
19
19
  files:
20
20
  - dist
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payment-kit",
3
- "version": "1.13.239",
3
+ "version": "1.13.240",
4
4
  "scripts": {
5
5
  "dev": "cross-env COMPONENT_STORE_URL=https://test.store.blocklet.dev blocklet dev --open",
6
6
  "eject": "vite eject",
@@ -43,30 +43,30 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@abtnode/cron": "1.16.26",
46
- "@arcblock/did": "^1.18.115",
46
+ "@arcblock/did": "^1.18.116",
47
47
  "@arcblock/did-auth-storage-nedb": "^1.7.1",
48
- "@arcblock/did-connect": "^2.9.75",
49
- "@arcblock/did-util": "^1.18.115",
50
- "@arcblock/jwt": "^1.18.115",
51
- "@arcblock/ux": "^2.9.75",
52
- "@arcblock/validator": "^1.18.115",
48
+ "@arcblock/did-connect": "^2.9.77",
49
+ "@arcblock/did-util": "^1.18.116",
50
+ "@arcblock/jwt": "^1.18.116",
51
+ "@arcblock/ux": "^2.9.77",
52
+ "@arcblock/validator": "^1.18.116",
53
53
  "@blocklet/logger": "1.16.26",
54
- "@blocklet/payment-react": "1.13.239",
54
+ "@blocklet/payment-react": "1.13.240",
55
55
  "@blocklet/sdk": "1.16.26",
56
- "@blocklet/ui-react": "^2.9.75",
56
+ "@blocklet/ui-react": "^2.9.77",
57
57
  "@blocklet/uploader": "^0.0.78",
58
- "@mui/icons-material": "^5.15.15",
58
+ "@mui/icons-material": "^5.15.16",
59
59
  "@mui/lab": "^5.0.0-alpha.170",
60
- "@mui/material": "^5.15.15",
61
- "@mui/styles": "^5.15.15",
60
+ "@mui/material": "^5.15.16",
61
+ "@mui/styles": "^5.15.16",
62
62
  "@mui/system": "^5.15.15",
63
- "@ocap/asset": "^1.18.115",
64
- "@ocap/client": "^1.18.115",
65
- "@ocap/mcrypto": "^1.18.115",
66
- "@ocap/util": "^1.18.115",
67
- "@ocap/wallet": "^1.18.115",
68
- "@react-pdf/renderer": "^3.4.2",
69
- "@stripe/react-stripe-js": "^2.7.0",
63
+ "@ocap/asset": "^1.18.116",
64
+ "@ocap/client": "^1.18.116",
65
+ "@ocap/mcrypto": "^1.18.116",
66
+ "@ocap/util": "^1.18.116",
67
+ "@ocap/wallet": "^1.18.116",
68
+ "@react-pdf/renderer": "^3.4.4",
69
+ "@stripe/react-stripe-js": "^2.7.1",
70
70
  "@stripe/stripe-js": "^2.4.0",
71
71
  "ahooks": "^3.7.11",
72
72
  "axios": "^0.27.2",
@@ -76,9 +76,9 @@
76
76
  "copy-to-clipboard": "^3.3.3",
77
77
  "cors": "^2.8.5",
78
78
  "date-fns": "^3.6.0",
79
- "dayjs": "^1.11.10",
79
+ "dayjs": "^1.11.11",
80
80
  "dotenv-flow": "^3.3.0",
81
- "ethers": "^6.12.0",
81
+ "ethers": "^6.12.1",
82
82
  "express": "^4.19.2",
83
83
  "express-async-errors": "^3.1.1",
84
84
  "express-history-api-fallback": "^2.2.1",
@@ -86,7 +86,7 @@
86
86
  "flat": "^5.0.2",
87
87
  "google-libphonenumber": "^3.2.34",
88
88
  "iframe-resizer-react": "^1.1.0",
89
- "joi": "^17.12.3",
89
+ "joi": "^17.13.1",
90
90
  "json-stable-stringify": "^1.1.1",
91
91
  "lodash": "^4.17.21",
92
92
  "morgan": "^1.10.0",
@@ -95,13 +95,13 @@
95
95
  "p-all": "3.0.0",
96
96
  "p-wait-for": "3",
97
97
  "pretty-ms-i18n": "^1.0.3",
98
- "react": "^18.2.0",
99
- "react-dom": "^18.2.0",
98
+ "react": "^18.3.1",
99
+ "react-dom": "^18.3.1",
100
100
  "react-error-boundary": "^4.0.13",
101
- "react-hook-form": "^7.51.3",
101
+ "react-hook-form": "^7.51.4",
102
102
  "react-international-phone": "^3.1.2",
103
- "react-router-dom": "^6.22.3",
104
- "recharts": "^2.12.5",
103
+ "react-router-dom": "^6.23.0",
104
+ "recharts": "^2.12.7",
105
105
  "rimraf": "^3.0.2",
106
106
  "sequelize": "^6.37.3",
107
107
  "sql-where-parser": "^2.2.1",
@@ -116,14 +116,14 @@
116
116
  "devDependencies": {
117
117
  "@abtnode/types": "1.16.26",
118
118
  "@arcblock/eslint-config-ts": "^0.3.0",
119
- "@blocklet/payment-types": "1.13.239",
119
+ "@blocklet/payment-types": "1.13.240",
120
120
  "@types/cookie-parser": "^1.4.7",
121
121
  "@types/cors": "^2.8.17",
122
122
  "@types/dotenv-flow": "^3.3.3",
123
123
  "@types/express": "^4.17.21",
124
- "@types/node": "^18.19.31",
125
- "@types/react": "^18.2.79",
126
- "@types/react-dom": "^18.2.25",
124
+ "@types/node": "^18.19.32",
125
+ "@types/react": "^18.3.1",
126
+ "@types/react-dom": "^18.3.0",
127
127
  "@vitejs/plugin-react": "^4.2.1",
128
128
  "bumpp": "^8.2.1",
129
129
  "cross-env": "^7.0.3",
@@ -137,9 +137,9 @@
137
137
  "prettier-plugin-import-sort": "^0.0.7",
138
138
  "ts-jest": "^29.1.2",
139
139
  "ts-node": "^10.9.2",
140
- "type-fest": "^4.15.0",
140
+ "type-fest": "^4.18.2",
141
141
  "typescript": "^4.9.5",
142
- "vite": "^5.2.9",
142
+ "vite": "^5.2.11",
143
143
  "vite-plugin-blocklet": "^0.7.9",
144
144
  "vite-plugin-node-polyfills": "^0.21.0",
145
145
  "vite-plugin-svgr": "^4.2.0",
@@ -155,5 +155,5 @@
155
155
  "parser": "typescript"
156
156
  }
157
157
  },
158
- "gitHead": "898fbcb595e77f6183aa0cac9fa69dbceb19d75f"
158
+ "gitHead": "02b0f1dc4e711c889dd88f7ace2b56062c5d2f0e"
159
159
  }