payment-kit 1.13.248 → 1.13.249

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.
@@ -0,0 +1,297 @@
1
+ /* eslint-disable @typescript-eslint/brace-style */
2
+ /* eslint-disable @typescript-eslint/indent */
3
+ import { fromUnitToToken } from '@ocap/util';
4
+ import isEmpty from 'lodash/isEmpty';
5
+ import pWaitFor from 'p-wait-for';
6
+ import type { LiteralUnion } from 'type-fest';
7
+
8
+ import { getUserLocale } from '../../../integrations/blocklet/notification';
9
+ import { translate } from '../../../locales';
10
+ import {
11
+ CheckoutSession,
12
+ Customer,
13
+ DonationSettings,
14
+ NftMintItem,
15
+ PaymentBeneficiary,
16
+ PaymentIntent,
17
+ PaymentLink,
18
+ PaymentMethod,
19
+ } from '../../../store/models';
20
+ import { PaymentCurrency } from '../../../store/models/payment-currency';
21
+ import { getCustomerInvoicePageUrl } from '../../invoice';
22
+ import logger from '../../logger';
23
+ import { formatTime } from '../../time';
24
+ import { getExplorerLink } from '../../util';
25
+ import type { BaseEmailTemplate, BaseEmailTemplateType } from './base';
26
+
27
+ export interface CustomerRewardSucceededEmailTemplateOptions {
28
+ checkoutSessionId: string;
29
+ }
30
+
31
+ interface CustomerRewardSucceededEmailTemplateContext {
32
+ locale: string;
33
+ at: string;
34
+
35
+ nftMintItem: NftMintItem | undefined;
36
+ chainHost: string | undefined;
37
+ userDid: string;
38
+ paymentInfo: string;
39
+ rewardDetail: string;
40
+ donationSettings: DonationSettings;
41
+
42
+ viewInvoiceLink: string;
43
+ viewTxHashLink: string;
44
+ }
45
+
46
+ /**
47
+ * @see https://github.com/blocklet/payment-kit/issues/236#issue-2007698930
48
+ * @description
49
+ * @export
50
+ * @class CustomerRewardSucceededEmailTemplate
51
+ * @implements {BaseEmailTemplate<CustomerRewardSucceededEmailTemplateContext>}
52
+ */
53
+ export class CustomerRewardSucceededEmailTemplate
54
+ implements BaseEmailTemplate<CustomerRewardSucceededEmailTemplateContext>
55
+ {
56
+ options: CustomerRewardSucceededEmailTemplateOptions;
57
+
58
+ constructor(options: CustomerRewardSucceededEmailTemplateOptions) {
59
+ this.options = options;
60
+ }
61
+
62
+ async getContext(): Promise<CustomerRewardSucceededEmailTemplateContext> {
63
+ const cs: CheckoutSession | null = await CheckoutSession.findByPk(this.options.checkoutSessionId);
64
+ if (!cs) {
65
+ throw new Error(`CheckoutSession(${this.options.checkoutSessionId}) not found`);
66
+ }
67
+ if (cs.mode !== 'payment') {
68
+ throw new Error(`CheckoutSession(${this.options.checkoutSessionId}) mode must be payment`);
69
+ }
70
+
71
+ const customer = await Customer.findByPk(cs.customer_id);
72
+ if (!customer) {
73
+ throw new Error(`Customer not found: ${cs.customer_id}`);
74
+ }
75
+
76
+ await pWaitFor(
77
+ async () => {
78
+ const checkoutSession = await CheckoutSession.findOne({
79
+ where: {
80
+ id: cs.id,
81
+ },
82
+ });
83
+
84
+ return Boolean(['disabled', 'minted', 'sent', 'error'].includes(checkoutSession?.nft_mint_status as string));
85
+ },
86
+ { timeout: 1000 * 10, interval: 1000 }
87
+ );
88
+
89
+ const checkoutSession = (await CheckoutSession.findByPk(cs.id)) as CheckoutSession;
90
+ if (!checkoutSession.payment_link_id) {
91
+ throw new Error(`Payment link cannot be found for checkoutSession: ${cs.id}`);
92
+ }
93
+
94
+ const paymentLink = await PaymentLink.findByPk(checkoutSession.payment_link_id);
95
+ if (!paymentLink) {
96
+ throw new Error(`Payment link cannot be found for payment_link_id(${checkoutSession.payment_link_id})`);
97
+ }
98
+ if (paymentLink.submit_type !== 'donate') {
99
+ throw new Error(`Payment link submit_type(${paymentLink.submit_type}) must be donate`);
100
+ }
101
+
102
+ const paymentCurrency = (await PaymentCurrency.findOne({
103
+ where: {
104
+ id: checkoutSession.currency_id,
105
+ },
106
+ })) as PaymentCurrency;
107
+
108
+ const userDid: string = customer.did;
109
+ const locale = await getUserLocale(userDid);
110
+ const at: string = formatTime(checkoutSession.created_at);
111
+
112
+ const paymentInfo: string = `${fromUnitToToken(checkoutSession?.amount_total, paymentCurrency.decimal)} ${
113
+ paymentCurrency.symbol
114
+ }`;
115
+ const paymentIntent = await PaymentIntent.findByPk(checkoutSession!.payment_intent_id);
116
+ if (!paymentIntent) {
117
+ throw new Error(
118
+ `Payment intent cannot be found for checkoutSession.payment_intent_id${checkoutSession!.payment_intent_id}`
119
+ );
120
+ }
121
+ const rewardDetail: string = this.getRewardDetail({
122
+ paymentIntent,
123
+ paymentCurrency,
124
+ locale,
125
+ });
126
+ const donationSettings: DonationSettings = paymentLink.donation_settings as DonationSettings;
127
+
128
+ const hasNft: boolean = checkoutSession?.nft_mint_status === 'minted';
129
+ const nftMintItem: NftMintItem | undefined = hasNft
130
+ ? // @ts-expect-error
131
+ checkoutSession?.nft_mint_details?.[paymentMethod.type]
132
+ : undefined;
133
+
134
+ const paymentMethod: PaymentMethod | null = await PaymentMethod.findByPk(paymentIntent!.payment_method_id);
135
+ // @ts-expect-error
136
+ const chainHost: string | undefined = paymentMethod?.settings?.[paymentMethod.type]?.api_host;
137
+ const viewInvoiceLink = getCustomerInvoicePageUrl({
138
+ invoiceId: checkoutSession.invoice_id!,
139
+ userDid,
140
+ locale,
141
+ });
142
+
143
+ // @ts-expect-error
144
+ const txHash: string | undefined = paymentIntent?.payment_details?.[paymentMethod.type]?.tx_hash;
145
+ const viewTxHashLink: string =
146
+ (txHash &&
147
+ getExplorerLink({
148
+ type: 'tx',
149
+ did: txHash,
150
+ chainHost,
151
+ })) ||
152
+ '';
153
+
154
+ return {
155
+ locale,
156
+ at,
157
+
158
+ userDid,
159
+ nftMintItem,
160
+ chainHost,
161
+ paymentInfo,
162
+ rewardDetail,
163
+ donationSettings,
164
+
165
+ viewInvoiceLink,
166
+ viewTxHashLink,
167
+ };
168
+ }
169
+ getRewardDetail({
170
+ paymentIntent,
171
+ paymentCurrency,
172
+ locale,
173
+ }: {
174
+ paymentIntent: PaymentIntent;
175
+ paymentCurrency: PaymentCurrency;
176
+ locale: LiteralUnion<'zh' | 'en', string>;
177
+ }): string {
178
+ if (isEmpty(paymentIntent.beneficiaries)) {
179
+ logger.warn('Payment intent not available', { paymentIntentId: paymentIntent.id });
180
+ return '';
181
+ }
182
+
183
+ const rewardDetail: string = paymentIntent
184
+ .beneficiaries!.map((x: PaymentBeneficiary) => {
185
+ return translate('notification.customerRewardSucceeded.received', locale, {
186
+ address: `${x.address}`,
187
+ amount: `${fromUnitToToken(x.share, paymentCurrency.decimal)} ${paymentCurrency.symbol}`,
188
+ });
189
+ })
190
+ .join('\r\n');
191
+
192
+ return rewardDetail;
193
+ }
194
+
195
+ async getTemplate(): Promise<BaseEmailTemplateType> {
196
+ const {
197
+ locale,
198
+ at,
199
+ nftMintItem,
200
+ chainHost,
201
+ userDid,
202
+ paymentInfo,
203
+ rewardDetail,
204
+ donationSettings,
205
+
206
+ viewInvoiceLink,
207
+ viewTxHashLink,
208
+ } = await this.getContext();
209
+
210
+ const template: BaseEmailTemplateType = {
211
+ title: `${translate('notification.customerRewardSucceeded.title', locale, {
212
+ amount: paymentInfo,
213
+ })}`,
214
+ body: `${translate('notification.customerRewardSucceeded.body', locale, {
215
+ at,
216
+ amount: paymentInfo,
217
+ subject: `<${donationSettings.title}(link:${donationSettings.reference})>`,
218
+ })}`,
219
+ // @ts-expect-error
220
+ attachments: [
221
+ nftMintItem &&
222
+ chainHost && {
223
+ type: 'asset',
224
+ data: {
225
+ chainHost,
226
+ did: nftMintItem.address,
227
+ },
228
+ },
229
+ {
230
+ type: 'section',
231
+ fields: [
232
+ {
233
+ type: 'text',
234
+ data: {
235
+ type: 'plain',
236
+ color: '#9397A1',
237
+ text: translate('notification.common.account', locale),
238
+ },
239
+ },
240
+ {
241
+ type: 'text',
242
+ data: {
243
+ type: 'plain',
244
+ text: userDid,
245
+ },
246
+ },
247
+ {
248
+ type: 'text',
249
+ data: {
250
+ type: 'plain',
251
+ color: '#9397A1',
252
+ text: translate('notification.common.rewardAmount', locale),
253
+ },
254
+ },
255
+ {
256
+ type: 'text',
257
+ data: {
258
+ type: 'plain',
259
+ text: `${paymentInfo}`,
260
+ },
261
+ },
262
+ {
263
+ type: 'text',
264
+ data: {
265
+ type: 'plain',
266
+ color: '#9397A1',
267
+ text: translate('notification.common.rewardDetail', locale),
268
+ },
269
+ },
270
+ {
271
+ type: 'text',
272
+ data: {
273
+ type: 'plain',
274
+ text: `${rewardDetail}`,
275
+ },
276
+ },
277
+ ].filter(Boolean),
278
+ },
279
+ ].filter(Boolean),
280
+ // @ts-ignore
281
+ actions: [
282
+ viewInvoiceLink && {
283
+ name: translate('notification.common.viewInvoice', locale),
284
+ title: translate('notification.common.viewInvoice', locale),
285
+ link: viewInvoiceLink,
286
+ },
287
+ viewTxHashLink && {
288
+ name: translate('notification.common.viewTxHash', locale),
289
+ title: translate('notification.common.viewTxHash', locale),
290
+ link: viewTxHashLink,
291
+ },
292
+ ].filter(Boolean),
293
+ };
294
+
295
+ return template;
296
+ }
297
+ }
@@ -5,7 +5,14 @@ import pWaitFor from 'p-wait-for';
5
5
 
6
6
  import { getUserLocale } from '../../../integrations/blocklet/notification';
7
7
  import { translate } from '../../../locales';
8
- import { CheckoutSession, Customer, NftMintItem, PaymentIntent, PaymentMethod } from '../../../store/models';
8
+ import {
9
+ CheckoutSession,
10
+ Customer,
11
+ NftMintItem,
12
+ PaymentIntent,
13
+ PaymentLink,
14
+ PaymentMethod,
15
+ } from '../../../store/models';
9
16
  import { PaymentCurrency } from '../../../store/models/payment-currency';
10
17
  import { getMainProductNameByCheckoutSession } from '../../product';
11
18
  import { formatTime } from '../../time';
@@ -75,6 +82,14 @@ export class OneTimePaymentSucceededEmailTemplate
75
82
  );
76
83
 
77
84
  const checkoutSession = (await CheckoutSession.findByPk(cs.id)) as CheckoutSession;
85
+ const paymentLink = await PaymentLink.findByPk(checkoutSession.payment_link_id);
86
+ if (!paymentLink) {
87
+ throw new Error(`Payment link cannot be found for payment_link_id(${checkoutSession.payment_link_id})`);
88
+ }
89
+ if (paymentLink.submit_type !== 'auto') {
90
+ throw new Error(`Payment link submit_type(${paymentLink.submit_type}) must be auto`);
91
+ }
92
+
78
93
  const paymentCurrency = (await PaymentCurrency.findOne({
79
94
  where: {
80
95
  id: checkoutSession.currency_id,
@@ -11,7 +11,7 @@ import { Customer, Invoice, PaymentMethod, Subscription } from '../../../store/m
11
11
  import { PaymentCurrency } from '../../../store/models/payment-currency';
12
12
  import { PaymentDetail, getPaymentDetail } from '../../payment';
13
13
  import { getMainProductName } from '../../product';
14
- import { getCustomerSubscriptionPageUrl } from '../../subscription';
14
+ import { getCustomerSubscriptionPageUrl, getUpcomingInvoiceAmount } from '../../subscription';
15
15
  import { formatTime, getPrettyMsI18nLocale } from '../../time';
16
16
  import { getExplorerLink } from '../../util';
17
17
  import type { BaseEmailTemplate, BaseEmailTemplateType } from './base';
@@ -84,7 +84,11 @@ export class SubscriptionWillRenewEmailTemplate
84
84
  locale === 'en' ? this.getWillRenewDuration(locale) : this.getWillRenewDuration(locale).split(' ').join('');
85
85
 
86
86
  const paymentDetail: PaymentDetail = await getPaymentDetail(userDid, invoice);
87
- const paymentInfo: string = `${fromUnitToToken(+invoice.total, paymentCurrency.decimal)} ${paymentCurrency.symbol}`;
87
+ const upcomingInvoiceAmount = await getUpcomingInvoiceAmount(subscription.id);
88
+ const paymentInfo: string = `${fromUnitToToken(
89
+ +upcomingInvoiceAmount.amount,
90
+ upcomingInvoiceAmount.currency?.decimal
91
+ )} ${paymentCurrency.symbol}`;
88
92
  const currentPeriodStart: string = formatTime(invoice.period_start * 1000);
89
93
  const currentPeriodEnd: string = formatTime(invoice.period_end * 1000);
90
94
  const duration: string = prettyMsI18n(
@@ -248,6 +252,21 @@ export class SubscriptionWillRenewEmailTemplate
248
252
  text: productName,
249
253
  },
250
254
  },
255
+ {
256
+ type: 'text',
257
+ data: {
258
+ type: 'plain',
259
+ color: '#9397A1',
260
+ text: translate('notification.common.currentBalance', locale),
261
+ },
262
+ },
263
+ {
264
+ type: 'text',
265
+ data: {
266
+ type: 'plain',
267
+ text: `${paymentDetail.balance} ${paymentDetail.symbol}`,
268
+ },
269
+ },
251
270
  {
252
271
  type: 'text',
253
272
  data: {
@@ -26,6 +26,10 @@ export default flat({
26
26
  cancellationReason: 'Cancellation reason',
27
27
  renewNow: 'Pay now',
28
28
  immediateRecharge: 'Immediate recharge',
29
+ amount: 'Amount',
30
+ rewardAmount: 'Reward amount',
31
+ rewardDetail: 'Reward detail',
32
+ currentBalance: 'Current balance',
29
33
  },
30
34
 
31
35
  sendTo: 'Sent to',
@@ -62,16 +66,16 @@ export default flat({
62
66
  },
63
67
 
64
68
  subscriptionWillRenew: {
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! ',
69
+ title: '{productName} automatic payment reminder',
70
+ body: 'Your subscription to {productName} is scheduled for automatic payment on {at}({willRenewDuration} later). If you have any questions or need assistance, please feel free to contact us.',
67
71
  unableToPayBody:
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 ',
72
+ 'Your subscription to {productName} is scheduled for automatic payment on {at}({willRenewDuration} later). <span style="color: red;">Your current balance is {balance}, which is less than {price}, please ensure that your account has enough balance to avoid payment failure.</span> If you have any questions or need assistance, please feel free to contact us.',
73
+ renewAmount: 'Payment Amount',
70
74
  },
71
75
 
72
76
  subscriptionRenewed: {
73
77
  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! ',
78
+ body: 'Payment for your subscription {productName} is successfully collected on {at}. Thanks for your continued support and trust, we wish you a pleasant journey when using this service!',
75
79
  noExpenseIncurred: 'No expenses incurred during the service ',
76
80
  },
77
81
 
@@ -99,6 +103,12 @@ export default flat({
99
103
  body: 'Your subscription to {productName} has been successfully refunded on {at}, with a refund amount of {refundInfo}. If you have any questions, please feel free to contact us.',
100
104
  },
101
105
 
106
+ customerRewardSucceeded: {
107
+ title: 'Thanks for your reward of {amount}',
108
+ body: 'Thanks for your reward on {at} for {subject}, the amount of reward is {amount}. Your support is our driving force, thanks for your generous support!',
109
+ received: '{address} has received {amount}',
110
+ },
111
+
102
112
  subscriptWillCanceled: {
103
113
  title: '{productName} subscription is about to be automatically cancelled ',
104
114
  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. ',
@@ -26,6 +26,10 @@ export default flat({
26
26
  cancellationReason: '取消原因',
27
27
  renewNow: '立即付款',
28
28
  immediateRecharge: '立即充值',
29
+ amount: '金额',
30
+ rewardAmount: '打赏金额',
31
+ rewardDetail: '打赏详情',
32
+ currentBalance: '当前余额',
29
33
  },
30
34
 
31
35
  sendTo: '发送给',
@@ -62,10 +66,10 @@ export default flat({
62
66
  },
63
67
 
64
68
  subscriptionWillRenew: {
65
- title: '{productName} 即将自动完成扣费',
66
- body: '您订阅的 {productName} 距离下一次扣费还有 {willRenewDuration}。您的当前余额为 {balance},请确保您的账户余额充足,以便在到期后({at})自动完成扣费。祝您一切顺利!',
69
+ title: '{productName} 自动扣费提醒',
70
+ body: '您订阅的 {productName} 将在 {at}({willRenewDuration}) 发起自动扣费。若有任何疑问或需要帮助,请随时与我们联系。',
67
71
  unableToPayBody:
68
- '您订阅的 {productName} 距离下一次扣费还有 {willRenewDuration}。<span style="color: red;">您的当前余额为 {balance},不足 {price}</span>,请确保您的账户余额充足,以便在到期后({at})自动完成扣费。祝您一切顺利!',
72
+ '您订阅的 {productName} 将在 {at}({willRenewDuration}后) 发起自动扣费。<span style="color: red;">您的当前余额为 {balance},不足 {price}</span>,请确保您的账户余额充足,避免扣费失败。若有任何疑问或需要帮助,请随时与我们联系。',
69
73
  renewAmount: '扣费金额',
70
74
  },
71
75
 
@@ -97,6 +101,12 @@ export default flat({
97
101
  body: '您订阅的 {productName} 在 {at} 已退款成功,退款金额为 {refundInfo}。如有任何疑问,请随时与我们联系。',
98
102
  },
99
103
 
104
+ customerRewardSucceeded: {
105
+ title: '感谢您打赏的 {amount}',
106
+ body: '感谢您于 {at} 在 {subject} 下的打赏,打赏金额为 {amount}。您的支持是我们前行的动力,谢谢您的大力支持!',
107
+ received: '{address} 收到了 {amount}',
108
+ },
109
+
100
110
  subscriptWillCanceled: {
101
111
  title: '{productName} 订阅即将自动取消',
102
112
  body: '由于长时间未能自动完成扣费,您订阅的 {productName} 将于 {at} ({willCancelDuration}后) 被系统自动取消订阅。请您及时手动处理扣费问题,以免影响使用。如有任何疑问,请随时与我们联系。',
@@ -3,6 +3,10 @@ import { events } from '../libs/event';
3
3
  import logger from '../libs/logger';
4
4
  import { Notification } from '../libs/notification';
5
5
  import type { BaseEmailTemplate } from '../libs/notification/template/base';
6
+ import {
7
+ CustomerRewardSucceededEmailTemplate,
8
+ CustomerRewardSucceededEmailTemplateOptions,
9
+ } from '../libs/notification/template/customer-reward-succeeded';
6
10
  import {
7
11
  OneTimePaymentSucceededEmailTemplate,
8
12
  OneTimePaymentSucceededEmailTemplateOptions,
@@ -48,7 +52,7 @@ import {
48
52
  SubscriptionWillRenewEmailTemplateOptions,
49
53
  } from '../libs/notification/template/subscription-will-renew';
50
54
  import createQueue from '../libs/queue';
51
- import { CheckoutSession, EventType, Invoice, Refund, Subscription } from '../store/models';
55
+ import { CheckoutSession, EventType, Invoice, PaymentLink, Refund, Subscription } from '../store/models';
52
56
 
53
57
  export type NotificationQueueJobOptions = any;
54
58
 
@@ -56,7 +60,8 @@ export type NotificationQueueJobType =
56
60
  | EventType
57
61
  | 'customer.subscription.will_renew'
58
62
  | 'customer.subscription.trial_will_end'
59
- | 'customer.subscription.will_canceled';
63
+ | 'customer.subscription.will_canceled'
64
+ | 'customer.reward.succeeded';
60
65
 
61
66
  export type NotificationQueueJob = {
62
67
  type: NotificationQueueJobType;
@@ -97,6 +102,9 @@ function getNotificationTemplate(job: NotificationQueueJob): BaseEmailTemplate {
97
102
  if (job.type === 'refund.succeeded') {
98
103
  return new SubscriptionRefundSucceededEmailTemplate(job.options as SubscriptionRefundSucceededEmailTemplateOptions);
99
104
  }
105
+ if (job.type === 'customer.reward.succeeded') {
106
+ return new CustomerRewardSucceededEmailTemplate(job.options as CustomerRewardSucceededEmailTemplateOptions);
107
+ }
100
108
 
101
109
  throw new Error(`Unknown job type: ${job.type}`);
102
110
  }
@@ -160,8 +168,22 @@ export async function startNotificationQueue() {
160
168
  });
161
169
 
162
170
  // 一次性购买成功
163
- events.on('checkout.session.completed', (checkoutSession: CheckoutSession) => {
171
+ events.on('checkout.session.completed', async (checkoutSession: CheckoutSession) => {
164
172
  if (checkoutSession.mode === 'payment') {
173
+ const paymentLink = await PaymentLink.findByPk(checkoutSession.payment_link_id);
174
+ if (paymentLink?.submit_type === 'donate') {
175
+ notificationQueue.push({
176
+ id: `customer.reward.succeeded.${checkoutSession.id}`,
177
+ job: {
178
+ type: 'customer.reward.succeeded',
179
+ options: {
180
+ checkoutSessionId: checkoutSession.id,
181
+ },
182
+ },
183
+ });
184
+ return;
185
+ }
186
+
165
187
  notificationQueue.push({
166
188
  id: `checkout.session.completed.${checkoutSession.id}`,
167
189
  job: {
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.247
17
+ version: 1.13.249
18
18
  logo: logo.png
19
19
  files:
20
20
  - dist
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "payment-kit",
3
- "version": "1.13.248",
3
+ "version": "1.13.249",
4
4
  "scripts": {
5
- "dev": "cross-env COMPONENT_STORE_URL=https://test.store.blocklet.dev blocklet dev --open",
5
+ "dev": "blocklet dev --open",
6
6
  "eject": "vite eject",
7
7
  "lint": "tsc --noEmit && eslint src api/src --ext .mjs,.js,.jsx,.ts,.tsx",
8
8
  "lint:fix": "npm run lint -- --fix",
@@ -51,7 +51,7 @@
51
51
  "@arcblock/ux": "^2.9.77",
52
52
  "@arcblock/validator": "^1.18.116",
53
53
  "@blocklet/logger": "1.16.26",
54
- "@blocklet/payment-react": "1.13.248",
54
+ "@blocklet/payment-react": "1.13.249",
55
55
  "@blocklet/sdk": "1.16.26",
56
56
  "@blocklet/ui-react": "^2.9.77",
57
57
  "@blocklet/uploader": "^0.1.6",
@@ -116,7 +116,7 @@
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.248",
119
+ "@blocklet/payment-types": "1.13.249",
120
120
  "@types/cookie-parser": "^1.4.7",
121
121
  "@types/cors": "^2.8.17",
122
122
  "@types/dotenv-flow": "^3.3.3",
@@ -155,5 +155,5 @@
155
155
  "parser": "typescript"
156
156
  }
157
157
  },
158
- "gitHead": "7d3aeec451e759eef8b676a11041ff9c5b7cd92d"
158
+ "gitHead": "8d7617c2a9cb318f4e161163f44de29abf99c150"
159
159
  }