payment-kit 1.20.12 → 1.20.13

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.
@@ -19,6 +19,7 @@ import {
19
19
  stripeSubscriptionCronTime,
20
20
  subscriptionCronTime,
21
21
  vendorStatusCheckCronTime,
22
+ vendorReturnScanCronTime,
22
23
  } from '../libs/env';
23
24
  import logger from '../libs/logger';
24
25
  import { startCreditConsumeQueue } from '../queues/credit-consume';
@@ -31,6 +32,7 @@ import { createPaymentStat } from './payment-stat';
31
32
  import { SubscriptionTrialWillEndSchedule } from './subscription-trial-will-end';
32
33
  import { SubscriptionWillCanceledSchedule } from './subscription-will-canceled';
33
34
  import { SubscriptionWillRenewSchedule } from './subscription-will-renew';
35
+ import { scheduleVendorReturnScan } from '../queues/vendors/return-scanner';
34
36
 
35
37
  function init() {
36
38
  Cron.init({
@@ -123,6 +125,12 @@ function init() {
123
125
  fn: () => startVendorStatusCheckSchedule(),
124
126
  options: { runOnInit: false },
125
127
  },
128
+ {
129
+ name: 'vendor.return.scan',
130
+ time: vendorReturnScanCronTime,
131
+ fn: () => scheduleVendorReturnScan(),
132
+ options: { runOnInit: false },
133
+ },
126
134
  ],
127
135
  onError: (error: Error, name: string) => {
128
136
  logger.error('run job failed', { name, error });
@@ -15,6 +15,7 @@ export const meteringSubscriptionDetectionCronTime: string =
15
15
  export const depositVaultCronTime: string = process.env.DEPOSIT_VAULT_CRON_TIME || '0 */5 * * * *'; // 默认每 5 min 执行一次
16
16
  export const creditConsumptionCronTime: string = process.env.CREDIT_CONSUMPTION_CRON_TIME || '0 */10 * * * *'; // 默认每 10 min 执行一次
17
17
  export const vendorStatusCheckCronTime: string = process.env.VENDOR_STATUS_CHECK_CRON_TIME || '0 */10 * * * *'; // 默认每 10 min 执行一次
18
+ export const vendorReturnScanCronTime: string = process.env.VENDOR_RETURN_SCAN_CRON_TIME || '0 */10 * * * *'; // 默认每 10 min 执行一次
18
19
  export const vendorTimeoutMinutes: number = process.env.VENDOR_TIMEOUT_MINUTES
19
20
  ? +process.env.VENDOR_TIMEOUT_MINUTES
20
21
  : 10; // 默认 10 分钟超时
@@ -1,4 +1,4 @@
1
- import { VendorAuth } from '@blocklet/payment-vendor';
1
+ import { Auth as VendorAuth } from '@blocklet/payment-vendor';
2
2
 
3
3
  import { joinURL } from 'ufo';
4
4
  import { ProductVendor } from '../../../store/models';
@@ -73,6 +73,7 @@ export interface ReturnRequestParams {
73
73
  export interface ReturnRequestResult {
74
74
  status: 'requested' | 'accepted' | 'rejected' | 'failed';
75
75
  message?: string;
76
+ success?: boolean;
76
77
  }
77
78
 
78
79
  export interface CheckOrderStatusParams extends Record<string, any> {}
@@ -206,7 +206,7 @@ export class VendorFulfillmentService {
206
206
  } catch (error: any) {
207
207
  logger.error('Failed to get vendor adapter', {
208
208
  vendorKey,
209
- error: error.message,
209
+ error,
210
210
  });
211
211
  throw error;
212
212
  }
@@ -13,35 +13,7 @@ import { Refund } from '../../store/models/refund';
13
13
  import { sequelize } from '../../store/sequelize';
14
14
  import { depositVaultQueue } from '../payment';
15
15
 
16
- type VendorInfo = {
17
- vendor_id: string;
18
- vendor_key: string;
19
- order_id: string;
20
- status:
21
- | 'pending'
22
- | 'processing'
23
- | 'completed'
24
- | 'failed'
25
- | 'cancelled'
26
- | 'max_retries_exceeded'
27
- | 'return_requested'
28
- | 'sent';
29
- service_url?: string;
30
- error_message?: string;
31
- amount: string;
32
-
33
- attempts?: number;
34
- lastAttemptAt?: string;
35
- completedAt?: string;
36
- commissionAmount?: string;
37
-
38
- returnRequest?: {
39
- reason: string;
40
- requestedAt: string;
41
- status: 'pending' | 'accepted' | 'rejected';
42
- returnDetails?: string;
43
- };
44
- };
16
+ export type VendorInfo = NonNullable<CheckoutSession['vendor_info']>[number];
45
17
 
46
18
  interface CoordinatorJob {
47
19
  checkoutSessionId: string;
@@ -0,0 +1,184 @@
1
+ import logger from '../../libs/logger';
2
+ import createQueue from '../../libs/queue';
3
+ import { VendorFulfillmentService } from '../../libs/vendor-util/fulfillment';
4
+ import { CheckoutSession } from '../../store/models';
5
+ import { VendorInfo } from './fulfillment-coordinator';
6
+
7
+ type ReturnProcessorJob = {
8
+ checkoutSessionId: string;
9
+ };
10
+
11
+ export const vendorReturnProcessorQueue = createQueue<ReturnProcessorJob>({
12
+ name: 'vendor-return-processor',
13
+ onJob: handleReturnProcessorJob,
14
+ options: {
15
+ concurrency: 1,
16
+ maxRetries: 2,
17
+ retryDelay: 30 * 1000,
18
+ },
19
+ });
20
+
21
+ async function handleReturnProcessorJob(job: ReturnProcessorJob): Promise<void> {
22
+ const { checkoutSessionId } = job;
23
+
24
+ logger.info('Starting vendor return processor job', {
25
+ checkoutSessionId,
26
+ });
27
+
28
+ try {
29
+ const checkoutSession = await CheckoutSession.findByPk(checkoutSessionId);
30
+
31
+ if (!checkoutSession) {
32
+ logger.warn('CheckoutSession not found', { checkoutSessionId });
33
+ return;
34
+ }
35
+
36
+ const vendorInfoList = checkoutSession.vendor_info as VendorInfo[];
37
+ let hasChanges = false;
38
+
39
+ let i = -1;
40
+ for (const vendor of vendorInfoList) {
41
+ i++;
42
+ // Only process vendors with 'completed' status
43
+ if (vendor.status !== 'completed') {
44
+ logger.info('Skipping vendor return because status is not completed', {
45
+ checkoutSessionId,
46
+ vendorId: vendor.vendor_id,
47
+ orderId: vendor.order_id,
48
+ status: vendor.status,
49
+ });
50
+ // eslint-disable-next-line no-continue
51
+ continue;
52
+ }
53
+
54
+ try {
55
+ logger.info('Processing vendor return', {
56
+ checkoutSessionId,
57
+ vendorId: vendor.vendor_id,
58
+ orderId: vendor.order_id,
59
+ });
60
+
61
+ // eslint-disable-next-line no-await-in-loop
62
+ const returnResult = await callVendorReturn(vendor, checkoutSession);
63
+
64
+ if (returnResult.success) {
65
+ // Return successful, update status to 'returned'
66
+ vendorInfoList[i] = {
67
+ ...vendor,
68
+ status: 'returned',
69
+ lastAttemptAt: new Date().toISOString(),
70
+ };
71
+ hasChanges = true;
72
+
73
+ logger.info('Vendor return successful', {
74
+ checkoutSessionId,
75
+ vendorId: vendor.vendor_id,
76
+ orderId: vendor.order_id,
77
+ });
78
+ } else {
79
+ // Return failed, keep 'completed' status for next scan retry
80
+ vendorInfoList[i] = {
81
+ ...vendor,
82
+ lastAttemptAt: new Date().toISOString(),
83
+ error_message: returnResult.message || 'Return request failed',
84
+ };
85
+
86
+ logger.warn('Vendor return failed', {
87
+ checkoutSessionId,
88
+ vendorId: vendor.vendor_id,
89
+ orderId: vendor.order_id,
90
+ error: returnResult.message,
91
+ });
92
+ }
93
+ } catch (error: any) {
94
+ logger.error('Error processing vendor return', {
95
+ checkoutSessionId,
96
+ vendorId: vendor.vendor_id,
97
+ orderId: vendor.order_id,
98
+ error: error.message,
99
+ });
100
+
101
+ // Record error but keep status unchanged for retry
102
+ vendorInfoList[i] = {
103
+ ...vendor,
104
+ lastAttemptAt: new Date().toISOString(),
105
+ error_message: error.message,
106
+ };
107
+ hasChanges = true;
108
+ }
109
+ }
110
+
111
+ // Update vendor_info if there are changes
112
+ if (hasChanges) {
113
+ await checkoutSession.update({ vendor_info: vendorInfoList });
114
+ }
115
+
116
+ // Check if all vendors have been returned
117
+ const allReturned = vendorInfoList.every((vendor) => vendor.status === 'returned');
118
+
119
+ if (allReturned && checkoutSession.fulfillment_status !== 'returned') {
120
+ await checkoutSession.update({ fulfillment_status: 'returned' });
121
+
122
+ logger.info('All vendors returned, updated fulfillment status to returned', {
123
+ checkoutSessionId,
124
+ totalVendors: vendorInfoList.length,
125
+ });
126
+ }
127
+
128
+ logger.info('Vendor return processor job completed', {
129
+ checkoutSessionId,
130
+ totalVendors: vendorInfoList.length,
131
+ allReturned,
132
+ hasChanges,
133
+ });
134
+ } catch (error: any) {
135
+ logger.error('Vendor return processor job failed', {
136
+ checkoutSessionId,
137
+ error,
138
+ });
139
+ throw error;
140
+ }
141
+ }
142
+
143
+ async function callVendorReturn(
144
+ vendor: VendorInfo,
145
+ checkoutSession: CheckoutSession
146
+ ): Promise<{ success: boolean; message?: string }> {
147
+ try {
148
+ const vendorAdapter = await VendorFulfillmentService.getVendorAdapter(vendor.vendor_key);
149
+
150
+ if (!vendorAdapter) {
151
+ return {
152
+ success: false,
153
+ message: `No adapter found for vendor: ${vendor.vendor_id}`,
154
+ };
155
+ }
156
+
157
+ const returnResult = await vendorAdapter.requestReturn({
158
+ orderId: vendor.order_id,
159
+ reason: 'Subscription canceled',
160
+ paymentIntentId: checkoutSession.payment_intent_id || '',
161
+ customParams: {
162
+ checkoutSessionId: checkoutSession.id,
163
+ subscriptionId: checkoutSession.subscription_id,
164
+ vendorKey: vendor.vendor_key,
165
+ },
166
+ });
167
+
168
+ return {
169
+ success: returnResult.success || false,
170
+ message: returnResult.message,
171
+ };
172
+ } catch (error: any) {
173
+ logger.error('Failed to call vendor return API', {
174
+ vendorId: vendor.vendor_id,
175
+ orderId: vendor.order_id,
176
+ error: error.message,
177
+ });
178
+
179
+ return {
180
+ success: false,
181
+ message: error.message,
182
+ };
183
+ }
184
+ }
@@ -0,0 +1,119 @@
1
+ import { Op } from 'sequelize';
2
+ import logger from '../../libs/logger';
3
+ import createQueue from '../../libs/queue';
4
+ import { CheckoutSession, Subscription } from '../../store/models';
5
+ import { vendorReturnProcessorQueue } from './return-processor';
6
+ import { VendorInfo } from './fulfillment-coordinator';
7
+
8
+ export const vendorReturnScannerQueue = createQueue({
9
+ name: 'vendor-return-scanner',
10
+ onJob: handleReturnScannerJob,
11
+ options: {
12
+ concurrency: 1,
13
+ maxRetries: 3,
14
+ retryDelay: 60 * 1000,
15
+ },
16
+ });
17
+
18
+ async function handleReturnScannerJob(): Promise<void> {
19
+ try {
20
+ const sessionsNeedingReturn = await findSessionsNeedingVendorReturn();
21
+ if (sessionsNeedingReturn.length === 0) {
22
+ logger.info('No checkout sessions needing vendor return');
23
+ return;
24
+ }
25
+
26
+ logger.info('Found checkout sessions needing vendor return', {
27
+ count: sessionsNeedingReturn.length,
28
+ sessionIds: sessionsNeedingReturn.map((s) => s.id),
29
+ });
30
+
31
+ for (const session of sessionsNeedingReturn) {
32
+ const id = `vendor-return-process-${session.id}`;
33
+ // eslint-disable-next-line no-await-in-loop
34
+ const exists = await vendorReturnProcessorQueue.get(id);
35
+ if (!exists) {
36
+ vendorReturnProcessorQueue.push({
37
+ id,
38
+ job: {
39
+ checkoutSessionId: session.id,
40
+ },
41
+ });
42
+ }
43
+ }
44
+ } catch (error: any) {
45
+ logger.error('Vendor return scanner job failed', {
46
+ error,
47
+ });
48
+ throw error;
49
+ }
50
+ }
51
+
52
+ async function findSessionsNeedingVendorReturn(): Promise<CheckoutSession[]> {
53
+ try {
54
+ // First, find canceled subscriptions
55
+ const canceledSubscriptions = await Subscription.findAll({
56
+ where: { status: 'canceled' },
57
+ attributes: ['id'],
58
+ });
59
+
60
+ const canceledSubscriptionIds = canceledSubscriptions.map((sub) => sub.id);
61
+
62
+ // Find checkout sessions with completed fulfillment and canceled subscriptions
63
+ const readyToReturnSessions = await CheckoutSession.findAll({
64
+ where: {
65
+ fulfillment_status: 'completed',
66
+ subscription_id: { [Op.in]: canceledSubscriptionIds },
67
+ },
68
+ order: [['updated_at', 'DESC']],
69
+ limit: 100,
70
+ });
71
+
72
+ // Find checkout sessions already in returning status
73
+ const returningSessions = await CheckoutSession.findAll({
74
+ where: {
75
+ fulfillment_status: 'returning',
76
+ subscription_id: { [Op.ne]: null as any },
77
+ },
78
+ order: [['updated_at', 'DESC']],
79
+ limit: 100,
80
+ });
81
+
82
+ // Update canceled sessions to returning status
83
+ if (readyToReturnSessions.length > 0) {
84
+ await CheckoutSession.update(
85
+ {
86
+ fulfillment_status: 'returning',
87
+ },
88
+ {
89
+ where: {
90
+ id: { [Op.in]: readyToReturnSessions.map((s) => s.id) },
91
+ },
92
+ }
93
+ );
94
+ }
95
+
96
+ const sessions = [...readyToReturnSessions, ...returningSessions];
97
+
98
+ // Filter sessions that have vendors needing return
99
+ const filteredSessions = sessions.filter((session) => {
100
+ const vendorInfoList = session.vendor_info as VendorInfo[];
101
+
102
+ if (!vendorInfoList || vendorInfoList.length === 0) {
103
+ return false;
104
+ }
105
+ const hasVendorNeedingReturn = vendorInfoList.some((vendor) => vendor.status === 'completed');
106
+ return hasVendorNeedingReturn;
107
+ });
108
+
109
+ return filteredSessions;
110
+ } catch (error: any) {
111
+ logger.error('Failed to find sessions needing vendor return', { error });
112
+ throw error;
113
+ }
114
+ }
115
+
116
+ export function scheduleVendorReturnScan(): void {
117
+ const scanId = `scan-${Date.now()}`;
118
+ vendorReturnScannerQueue.push({ id: scanId, job: {} });
119
+ }
@@ -1,5 +1,5 @@
1
1
  import { joinURL } from 'ufo';
2
- import { VendorAuth } from '@blocklet/payment-vendor';
2
+ import { Auth as VendorAuth } from '@blocklet/payment-vendor';
3
3
  import createQueue from '../../libs/queue';
4
4
  import { CheckoutSession } from '../../store/models/checkout-session';
5
5
  import { ProductVendor } from '../../store/models';
@@ -1,7 +1,8 @@
1
+ import { getUrl } from '@blocklet/sdk/lib/component';
1
2
  import { Router } from 'express';
2
3
  import Joi from 'joi';
3
4
 
4
- import { VendorAuth } from '@blocklet/payment-vendor';
5
+ import { Auth as VendorAuth, middleware } from '@blocklet/payment-vendor';
5
6
  import { joinURL } from 'ufo';
6
7
  import { MetadataSchema } from '../libs/api';
7
8
  import { wallet } from '../libs/auth';
@@ -9,7 +10,8 @@ import dayjs from '../libs/dayjs';
9
10
  import logger from '../libs/logger';
10
11
  import { authenticate } from '../libs/security';
11
12
  import { formatToShortUrl } from '../libs/url';
12
- import { CheckoutSession } from '../store/models';
13
+ import { getBlockletJson } from '../libs/util';
14
+ import { CheckoutSession, Invoice, Subscription } from '../store/models';
13
15
  import { ProductVendor } from '../store/models/product-vendor';
14
16
 
15
17
  const authAdmin = authenticate<CheckoutSession>({ component: true, roles: ['owner', 'admin'] });
@@ -159,6 +161,8 @@ async function createVendor(req: any, res: any) {
159
161
  return res.status(400).json({ error: 'Vendor key already exists' });
160
162
  }
161
163
 
164
+ const blockletJson = await getBlockletJson(appUrl);
165
+
162
166
  const vendor = await ProductVendor.create({
163
167
  vendor_key: vendorKey,
164
168
  vendor_type: vendorType || 'launcher',
@@ -170,6 +174,10 @@ async function createVendor(req: any, res: any) {
170
174
  app_pid: appPid,
171
175
  app_logo: appLogo,
172
176
  metadata: metadata || {},
177
+ extends: {
178
+ appId: blockletJson?.appId,
179
+ appPk: blockletJson?.appPk,
180
+ },
173
181
  created_by: req.user?.did || 'admin',
174
182
  });
175
183
 
@@ -210,6 +218,8 @@ async function updateVendor(req: any, res: any) {
210
218
  app_logo: appLogo,
211
219
  } = value;
212
220
 
221
+ const blockletJson = await getBlockletJson(appUrl);
222
+
213
223
  if (req.body.vendorKey && req.body.vendorKey !== vendor.vendor_key) {
214
224
  const existingVendor = await ProductVendor.findOne({
215
225
  where: { vendor_key: req.body.vendorKey },
@@ -229,6 +239,10 @@ async function updateVendor(req: any, res: any) {
229
239
  app_pid: appPid,
230
240
  app_logo: appLogo,
231
241
  vendor_key: req.body.vendor_key,
242
+ extends: {
243
+ appId: blockletJson?.appId,
244
+ appPk: blockletJson?.appPk,
245
+ },
232
246
  };
233
247
 
234
248
  await vendor.update(Object.fromEntries(Object.entries(updates).filter(([, v]) => v !== undefined)));
@@ -362,9 +376,23 @@ async function getVendorStatus(sessionId: string, isDetail = false) {
362
376
  return getVendorStatusByVendorId(item.vendor_id, item.order_id, isDetail);
363
377
  });
364
378
 
379
+ const subscriptionId = doc.subscription_id;
380
+ let shortSubscriptionUrl = '';
381
+
382
+ if (isDetail && subscriptionId) {
383
+ const subscriptionUrl = getUrl(`/customer/subscription/${subscriptionId}`);
384
+
385
+ shortSubscriptionUrl = await formatToShortUrl({
386
+ url: subscriptionUrl,
387
+ maxVisits: 5,
388
+ validUntil: dayjs().add(20, 'minutes').format('YYYY-MM-DDTHH:mm:ss+00:00'),
389
+ });
390
+ }
391
+
365
392
  return {
366
393
  payment_status: doc.payment_status,
367
394
  session_status: doc.status,
395
+ subscriptionUrl: shortSubscriptionUrl,
368
396
  vendors: await Promise.all(vendors),
369
397
  error: null,
370
398
  };
@@ -443,12 +471,71 @@ async function redirectToVendor(req: any, res: any) {
443
471
  }
444
472
  }
445
473
 
474
+ async function getVendorSubscription(req: any, res: any) {
475
+ const { sessionId } = req.params;
476
+
477
+ const checkoutSession = await CheckoutSession.findByPk(sessionId);
478
+
479
+ if (!checkoutSession) {
480
+ return res.status(404).json({ error: 'Checkout session not found' });
481
+ }
482
+
483
+ const subscription = await Subscription.findByPk(checkoutSession.subscription_id);
484
+
485
+ if (!subscription) {
486
+ return res.status(404).json({ error: 'Subscription not found' });
487
+ }
488
+
489
+ const invoices = await Invoice.findAll({
490
+ where: { subscription_id: subscription.id },
491
+ order: [['created_at', 'DESC']],
492
+ attributes: [
493
+ 'id',
494
+ 'amount_due',
495
+ 'amount_paid',
496
+ 'amount_remaining',
497
+ 'status',
498
+ 'currency_id',
499
+ 'period_start',
500
+ 'period_end',
501
+ 'created_at',
502
+ 'due_date',
503
+ 'description',
504
+ 'invoice_pdf',
505
+ ],
506
+ limit: 20,
507
+ });
508
+
509
+ return res.json({
510
+ subscription: subscription.toJSON(),
511
+ billing_history: invoices,
512
+ });
513
+ }
514
+
515
+ async function handleSubscriptionRedirect(req: any, res: any) {
516
+ const { sessionId } = req.params;
517
+
518
+ const checkoutSession = await CheckoutSession.findByPk(sessionId);
519
+ if (!checkoutSession) {
520
+ return res.status(404).json({ error: 'Checkout session not found' });
521
+ }
522
+
523
+ return res.redirect(getUrl(`/customer/subscription/${checkoutSession.subscription_id}`));
524
+ }
525
+
446
526
  const router = Router();
447
527
 
528
+ const ensureVendorAuth = middleware.ensureVendorAuth((vendorPk: string) =>
529
+ ProductVendor.findOne({ where: { 'extends.appPk': vendorPk } }).then((v) => v as any)
530
+ );
531
+
448
532
  // FIXME: Authentication not yet added, awaiting implementation @Pengfei
449
533
  router.get('/order/:sessionId/status', validateParams(sessionIdParamSchema), getVendorFulfillmentStatus);
450
534
  router.get('/order/:sessionId/detail', validateParams(sessionIdParamSchema), getVendorFulfillmentDetail);
451
535
 
536
+ router.get('/subscription/:sessionId/redirect', handleSubscriptionRedirect);
537
+ router.get('/subscription/:sessionId', ensureVendorAuth, getVendorSubscription);
538
+
452
539
  router.get(
453
540
  '/open/:subscriptionId',
454
541
  authAdmin,
@@ -0,0 +1,20 @@
1
+ import { safeApplyColumnChanges, type Migration } from '../migrate';
2
+
3
+ export const up: Migration = async ({ context }) => {
4
+ // Add extends column to product_vendors table
5
+ await safeApplyColumnChanges(context, {
6
+ product_vendors: [
7
+ {
8
+ name: 'extends',
9
+ field: {
10
+ type: 'JSON',
11
+ allowNull: true,
12
+ },
13
+ },
14
+ ],
15
+ });
16
+ };
17
+
18
+ export const down: Migration = async ({ context }) => {
19
+ await context.removeColumn('product_vendors', 'extends');
20
+ };
@@ -212,7 +212,9 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
212
212
  | 'cancelled'
213
213
  | 'max_retries_exceeded'
214
214
  | 'return_requested'
215
- | 'sent',
215
+ | 'sent'
216
+ | 'returning'
217
+ | 'returned',
216
218
  string
217
219
  >;
218
220
  declare vendor_info?: Array<{
@@ -227,7 +229,8 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
227
229
  | 'cancelled'
228
230
  | 'max_retries_exceeded'
229
231
  | 'return_requested'
230
- | 'sent';
232
+ | 'sent'
233
+ | 'returned';
231
234
  service_url?: string;
232
235
  app_url?: string;
233
236
  error_message?: string;
@@ -19,6 +19,7 @@ export class ProductVendor extends Model<InferAttributes<ProductVendor>, InferCr
19
19
 
20
20
  declare status: 'active' | 'inactive';
21
21
  declare metadata: Record<string, any>;
22
+ declare extends: Record<string, any>;
22
23
 
23
24
  declare created_by: string;
24
25
  declare created_at: CreationOptional<Date>;
@@ -75,6 +76,11 @@ export class ProductVendor extends Model<InferAttributes<ProductVendor>, InferCr
75
76
  allowNull: true,
76
77
  defaultValue: {},
77
78
  },
79
+ extends: {
80
+ type: DataTypes.JSON,
81
+ allowNull: true,
82
+ defaultValue: {},
83
+ },
78
84
  created_by: {
79
85
  type: DataTypes.STRING(30),
80
86
  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.20.12
17
+ version: 1.20.13
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.20.12",
3
+ "version": "1.20.13",
4
4
  "scripts": {
5
5
  "dev": "blocklet dev --open",
6
6
  "lint": "tsc --noEmit && eslint src api/src --ext .mjs,.js,.jsx,.ts,.tsx",
@@ -56,8 +56,8 @@
56
56
  "@blocklet/error": "^0.2.5",
57
57
  "@blocklet/js-sdk": "^1.16.52-beta-20250912-112002-e3499e9c",
58
58
  "@blocklet/logger": "^1.16.52-beta-20250912-112002-e3499e9c",
59
- "@blocklet/payment-react": "1.20.12",
60
- "@blocklet/payment-vendor": "1.20.12",
59
+ "@blocklet/payment-react": "1.20.13",
60
+ "@blocklet/payment-vendor": "1.20.13",
61
61
  "@blocklet/sdk": "^1.16.52-beta-20250912-112002-e3499e9c",
62
62
  "@blocklet/ui-react": "^3.1.41",
63
63
  "@blocklet/uploader": "^0.2.11",
@@ -126,7 +126,7 @@
126
126
  "devDependencies": {
127
127
  "@abtnode/types": "^1.16.52-beta-20250912-112002-e3499e9c",
128
128
  "@arcblock/eslint-config-ts": "^0.3.3",
129
- "@blocklet/payment-types": "1.20.12",
129
+ "@blocklet/payment-types": "1.20.13",
130
130
  "@types/cookie-parser": "^1.4.9",
131
131
  "@types/cors": "^2.8.19",
132
132
  "@types/debug": "^4.1.12",
@@ -173,5 +173,5 @@
173
173
  "parser": "typescript"
174
174
  }
175
175
  },
176
- "gitHead": "e6c432f89c2bf305efc903c0809f4a0557c07774"
176
+ "gitHead": "0cbe918549f7d06561b5307fb947bfbbd2250984"
177
177
  }