payment-kit 1.21.15 → 1.21.16

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.
@@ -4,6 +4,8 @@ import { VendorFulfillmentService } from '../../libs/vendor-util/fulfillment';
4
4
  import { CheckoutSession } from '../../store/models';
5
5
  import { VendorInfo } from './fulfillment-coordinator';
6
6
 
7
+ export const MAX_RETURN_RETRY = 3;
8
+
7
9
  type ReturnProcessorJob = {
8
10
  checkoutSessionId: string;
9
11
  };
@@ -39,13 +41,14 @@ async function handleReturnProcessorJob(job: ReturnProcessorJob): Promise<void>
39
41
  let i = -1;
40
42
  for (const vendor of vendorInfoList) {
41
43
  i++;
42
- // Only process vendors with 'completed' status
43
- if (vendor.status !== 'completed') {
44
- logger.info('Skipping vendor return because status is not completed', {
44
+ const returnRetry = vendor.returnRetry ? vendor.returnRetry + 1 : 1;
45
+ if (vendor.status === 'returned') {
46
+ logger.info('Skipping vendor return because status is returned', {
45
47
  checkoutSessionId,
46
48
  vendorId: vendor.vendor_id,
47
49
  orderId: vendor.order_id,
48
50
  status: vendor.status,
51
+ returnRetry,
49
52
  });
50
53
  // eslint-disable-next-line no-continue
51
54
  continue;
@@ -56,53 +59,51 @@ async function handleReturnProcessorJob(job: ReturnProcessorJob): Promise<void>
56
59
  checkoutSessionId,
57
60
  vendorId: vendor.vendor_id,
58
61
  orderId: vendor.order_id,
62
+ returnRetry,
59
63
  });
60
64
 
61
65
  // 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
- }
66
+ await callVendorReturn(vendor, checkoutSession);
67
+
68
+ // Return successful, update status to 'returned'
69
+ vendorInfoList[i] = {
70
+ ...vendor,
71
+ status: 'returned',
72
+ lastAttemptAt: new Date().toISOString(),
73
+ };
74
+ hasChanges = true;
75
+
76
+ logger.info('Vendor return successful', {
77
+ checkoutSessionId,
78
+ vendorId: vendor.vendor_id,
79
+ orderId: vendor.order_id,
80
+ returnRetry,
81
+ });
93
82
  } catch (error: any) {
94
83
  logger.error('Error processing vendor return', {
95
84
  checkoutSessionId,
96
85
  vendorId: vendor.vendor_id,
97
86
  orderId: vendor.order_id,
98
- error: error.message,
87
+ error,
88
+ returnRetry,
99
89
  });
100
90
 
91
+ if (returnRetry >= MAX_RETURN_RETRY) {
92
+ logger.warn('Skipping vendor return because return retry is greater than 5', {
93
+ checkoutSessionId,
94
+ vendorId: vendor.vendor_id,
95
+ orderId: vendor.order_id,
96
+ returnRetry,
97
+ });
98
+ }
99
+
101
100
  // Record error but keep status unchanged for retry
102
101
  vendorInfoList[i] = {
103
102
  ...vendor,
103
+ status: returnRetry >= MAX_RETURN_RETRY ? 'returned' : vendor.status,
104
104
  lastAttemptAt: new Date().toISOString(),
105
105
  error_message: error.message,
106
+ returnRetry,
106
107
  };
107
108
  hasChanges = true;
108
109
  }
@@ -110,14 +111,14 @@ async function handleReturnProcessorJob(job: ReturnProcessorJob): Promise<void>
110
111
 
111
112
  // Update vendor_info if there are changes
112
113
  if (hasChanges) {
113
- await checkoutSession.update({ vendor_info: vendorInfoList });
114
+ await CheckoutSession.update({ vendor_info: vendorInfoList }, { where: { id: checkoutSessionId } });
114
115
  }
115
116
 
116
117
  // Check if all vendors have been returned
117
118
  const allReturned = vendorInfoList.every((vendor) => vendor.status === 'returned');
118
119
 
119
120
  if (allReturned && checkoutSession.fulfillment_status !== 'returned') {
120
- await checkoutSession.update({ fulfillment_status: 'returned' });
121
+ await CheckoutSession.update({ fulfillment_status: 'returned' }, { where: { id: checkoutSessionId } });
121
122
 
122
123
  logger.info('All vendors returned, updated fulfillment status to returned', {
123
124
  checkoutSessionId,
@@ -140,44 +141,20 @@ async function handleReturnProcessorJob(job: ReturnProcessorJob): Promise<void>
140
141
  }
141
142
  }
142
143
 
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
- }
144
+ async function callVendorReturn(vendor: VendorInfo, checkoutSession: CheckoutSession) {
145
+ const vendorAdapter = await VendorFulfillmentService.getVendorAdapter(vendor.vendor_key);
156
146
 
157
- const returnResult = await vendorAdapter.requestReturn({
158
- orderId: vendor.order_id,
159
- reason: 'Subscription canceled',
160
- customParams: {
161
- checkoutSessionId: checkoutSession.id,
162
- subscriptionId: checkoutSession.subscription_id,
163
- vendorKey: vendor.vendor_key,
164
- },
165
- });
166
-
167
- return {
168
- success: returnResult.success || false,
169
- message: returnResult.message,
170
- };
171
- } catch (error: any) {
172
- logger.error('Failed to call vendor return API', {
173
- vendorId: vendor.vendor_id,
174
- orderId: vendor.order_id,
175
- error: error.message,
176
- });
177
-
178
- return {
179
- success: false,
180
- message: error.message,
181
- };
147
+ if (!vendorAdapter) {
148
+ throw new Error(`No adapter found for vendor: ${vendor.vendor_id}`);
182
149
  }
150
+
151
+ return vendorAdapter.requestReturn({
152
+ orderId: vendor.order_id,
153
+ reason: 'Subscription canceled',
154
+ customParams: {
155
+ checkoutSessionId: checkoutSession.id,
156
+ subscriptionId: checkoutSession.subscription_id,
157
+ vendorKey: vendor.vendor_key,
158
+ },
159
+ });
183
160
  }
@@ -1,9 +1,11 @@
1
1
  import { Op } from 'sequelize';
2
+ import dayjs from 'dayjs';
2
3
  import logger from '../../libs/logger';
3
4
  import createQueue from '../../libs/queue';
4
5
  import { CheckoutSession, Subscription } from '../../store/models';
5
6
  import { vendorReturnProcessorQueue } from './return-processor';
6
7
  import { VendorInfo } from './fulfillment-coordinator';
8
+ import { events } from '../../libs/event';
7
9
 
8
10
  export const vendorReturnScannerQueue = createQueue({
9
11
  name: 'vendor-return-scanner',
@@ -52,8 +54,10 @@ async function handleReturnScannerJob(): Promise<void> {
52
54
  async function findSessionsNeedingVendorReturn(): Promise<CheckoutSession[]> {
53
55
  try {
54
56
  // First, find canceled subscriptions
57
+ const oneWeekAgo = dayjs().subtract(7, 'day').unix();
58
+
55
59
  const canceledSubscriptions = await Subscription.findAll({
56
- where: { status: 'canceled' },
60
+ where: { status: 'canceled', canceled_at: { [Op.gt]: oneWeekAgo } },
57
61
  attributes: ['id'],
58
62
  });
59
63
 
@@ -62,7 +66,7 @@ async function findSessionsNeedingVendorReturn(): Promise<CheckoutSession[]> {
62
66
  // Find checkout sessions with completed fulfillment and canceled subscriptions
63
67
  const readyToReturnSessions = await CheckoutSession.findAll({
64
68
  where: {
65
- fulfillment_status: 'completed',
69
+ fulfillment_status: { [Op.notIn]: ['returning', 'returned', 'failed'] },
66
70
  subscription_id: { [Op.in]: canceledSubscriptionIds },
67
71
  },
68
72
  order: [['updated_at', 'DESC']],
@@ -102,7 +106,10 @@ async function findSessionsNeedingVendorReturn(): Promise<CheckoutSession[]> {
102
106
  if (!vendorInfoList || vendorInfoList.length === 0) {
103
107
  return false;
104
108
  }
105
- const hasVendorNeedingReturn = vendorInfoList.some((vendor) => vendor.status === 'completed');
109
+
110
+ const hasVendorNeedingReturn = vendorInfoList.some(
111
+ (vendor) => !['cancelled', 'return_requested', 'returned'].includes(vendor.status)
112
+ );
106
113
  return hasVendorNeedingReturn;
107
114
  });
108
115
 
@@ -117,3 +124,31 @@ export function scheduleVendorReturnScan(): void {
117
124
  const scanId = `scan-${Date.now()}`;
118
125
  vendorReturnScannerQueue.push({ id: scanId, job: {} });
119
126
  }
127
+
128
+ events.on('customer.subscription.deleted', async (subscription: Subscription) => {
129
+ logger.info('Customer subscription deleted', { subscription });
130
+ if (subscription.status !== 'canceled') {
131
+ logger.info('Subscription is not canceled, skipping vendor return process[customer.subscription.deleted]', {
132
+ subscriptionId: subscription.id,
133
+ });
134
+ return;
135
+ }
136
+
137
+ const session = await CheckoutSession.findOne({
138
+ where: { subscription_id: subscription.id },
139
+ });
140
+
141
+ if (session) {
142
+ const id = `vendor-return-process-${session.id}`;
143
+ // eslint-disable-next-line no-await-in-loop
144
+ const exists = await vendorReturnProcessorQueue.get(id);
145
+ if (!exists) {
146
+ vendorReturnProcessorQueue.push({
147
+ id,
148
+ job: {
149
+ checkoutSessionId: session.id,
150
+ },
151
+ });
152
+ }
153
+ }
154
+ });
@@ -5,6 +5,7 @@ import Joi from 'joi';
5
5
 
6
6
  // eslint-disable-next-line import/no-extraneous-dependencies
7
7
  import { gte } from 'semver';
8
+ import { Op } from 'sequelize';
8
9
  import { MetadataSchema } from '../libs/api';
9
10
  import { wallet } from '../libs/auth';
10
11
  import dayjs from '../libs/dayjs';
@@ -31,19 +32,15 @@ const createVendorSchema = Joi.object({
31
32
  name: Joi.string().max(255).required(),
32
33
  description: Joi.string().max(1000).allow('').optional(),
33
34
  app_url: Joi.string().uri().max(512).required(),
34
- app_pid: Joi.string().max(255).allow('').optional(),
35
- app_logo: Joi.string().max(512).allow('').optional(),
36
35
  status: Joi.string().valid('active', 'inactive').default('active'),
37
36
  metadata: MetadataSchema,
38
- }).unknown(false);
37
+ }).unknown(true);
39
38
 
40
39
  const updateVendorSchema = Joi.object({
41
40
  vendor_type: Joi.string().valid('launcher', 'didnames').optional(),
42
41
  name: Joi.string().max(255).optional(),
43
42
  description: Joi.string().max(1000).allow('').optional(),
44
43
  app_url: Joi.string().uri().max(512).optional(),
45
- app_pid: Joi.string().max(255).allow('').optional(),
46
- app_logo: Joi.string().max(512).allow('').optional(),
47
44
  status: Joi.string().valid('active', 'inactive').optional(),
48
45
  metadata: MetadataSchema,
49
46
  }).unknown(true);
@@ -56,6 +53,10 @@ const sessionIdParamSchema = Joi.object({
56
53
  sessionId: Joi.string().max(100).required(),
57
54
  });
58
55
 
56
+ const sessionIdsParamSchema = Joi.object({
57
+ sessionIds: Joi.array().items(Joi.string().max(100)).required(),
58
+ });
59
+
59
60
  const subscriptionIdParamSchema = Joi.object({
60
61
  subscriptionId: Joi.string().max(100).required(),
61
62
  });
@@ -134,6 +135,51 @@ async function getVendorInfo(req: any, res: any) {
134
135
  }
135
136
  }
136
137
 
138
+ async function prepareVendorData(appUrlInput: string, vendorType: 'launcher' | 'didnames', metadata: any = {}) {
139
+ let appUrl = '';
140
+ let blockletJson = null;
141
+ try {
142
+ appUrl = new URL(appUrlInput).origin;
143
+ blockletJson = await getBlockletJson(appUrl);
144
+ } catch (error) {
145
+ logger.error('Failed to get blocklet json', {
146
+ appUrlInput,
147
+ error,
148
+ });
149
+ return { error: `Invalid app URL: ${appUrlInput}, get blocklet json failed` as const };
150
+ }
151
+
152
+ if (!blockletJson?.appId || !blockletJson?.appPk) {
153
+ return { error: `Invalid app URL: ${appUrl}, the appId or appPk is required in the target app` as const };
154
+ }
155
+
156
+ const vendorDid = VENDOR_DID[vendorType];
157
+ const component = blockletJson?.componentMountPoints?.find((item: any) => item.did === vendorDid);
158
+
159
+ if (!component) {
160
+ return { error: `Invalid app URL: ${appUrl}, the ${vendorType} did is not found in the target server` as const };
161
+ }
162
+
163
+ const mountPoint = component.mountPoint || '/';
164
+ return {
165
+ vendor_did: vendorDid,
166
+ app_url: appUrl,
167
+ // Both appPid and appId can be used here for transfer purposes, with did being recommended.
168
+ // Keeping appPid for now due to extensive changes required
169
+ app_pid: blockletJson.appId,
170
+ app_logo: blockletJson.appLogo,
171
+ metadata: {
172
+ ...metadata,
173
+ mountPoint,
174
+ },
175
+ extends: {
176
+ mountPoint,
177
+ appId: blockletJson.appId,
178
+ appPk: blockletJson.appPk,
179
+ },
180
+ };
181
+ }
182
+
137
183
  async function createVendor(req: any, res: any) {
138
184
  try {
139
185
  const { error, value } = createVendorSchema.validate(req.body);
@@ -144,26 +190,9 @@ async function createVendor(req: any, res: any) {
144
190
  });
145
191
  }
146
192
 
147
- const {
148
- vendor_key: vendorKey,
149
- vendor_type: type,
150
- name,
151
- description,
152
- metadata,
153
- app_pid: appPid,
154
- app_logo: appLogo,
155
- status,
156
- } = value;
157
-
158
- let appUrl = '';
159
- try {
160
- appUrl = new URL(value.app_url).origin;
161
- } catch {
162
- return res.status(400).json({ error: 'Invalid app URL' });
163
- }
193
+ const { vendor_key: vendorKey, vendor_type: type, name, description, metadata, status } = value;
164
194
 
165
195
  const vendorType = (type || 'launcher') as 'launcher' | 'didnames';
166
- const vendorDid = VENDOR_DID[vendorType];
167
196
 
168
197
  const existingVendor = await ProductVendor.findOne({
169
198
  where: { vendor_key: vendorKey },
@@ -172,30 +201,18 @@ async function createVendor(req: any, res: any) {
172
201
  return res.status(400).json({ error: 'Vendor key already exists' });
173
202
  }
174
203
 
175
- const blockletJson = await getBlockletJson(appUrl);
176
-
177
- const mountPoint =
178
- blockletJson?.componentMountPoints?.find((item: any) => item.did === vendorDid)?.mountPoint || '/';
204
+ const preparedData = await prepareVendorData(value.app_url, vendorType, metadata);
205
+ if ('error' in preparedData) {
206
+ return res.status(400).json({ error: preparedData.error });
207
+ }
179
208
 
180
209
  const vendor = await ProductVendor.create({
210
+ ...preparedData,
181
211
  vendor_key: vendorKey,
182
212
  vendor_type: vendorType,
183
213
  name,
184
214
  description,
185
- app_url: appUrl,
186
- vendor_did: vendorDid,
187
215
  status: status || 'active',
188
- app_pid: appPid,
189
- app_logo: appLogo,
190
- metadata: {
191
- ...metadata,
192
- mountPoint,
193
- },
194
- extends: {
195
- mountPoint,
196
- appId: blockletJson?.appId,
197
- appPk: blockletJson?.appPk,
198
- },
199
216
  created_by: req.user?.did || 'admin',
200
217
  });
201
218
 
@@ -224,50 +241,30 @@ async function updateVendor(req: any, res: any) {
224
241
  });
225
242
  }
226
243
 
227
- const { vendor_type: type, name, description, status, metadata, app_pid: appPid, app_logo: appLogo } = value;
228
-
229
- let appUrl = '';
230
- try {
231
- appUrl = new URL(value.app_url).origin;
232
- } catch {
233
- return res.status(400).json({ error: 'Invalid app URL' });
234
- }
235
-
236
- const vendorType = (type || 'launcher') as 'launcher' | 'didnames';
237
- const vendorDid = VENDOR_DID[vendorType];
238
-
239
- const blockletJson = await getBlockletJson(appUrl);
240
-
241
- const mountPoint =
242
- blockletJson?.componentMountPoints?.find((item: any) => item.did === vendorDid)?.mountPoint || '/';
244
+ const { vendor_type: type, vendor_key: vendorKey, name, description, status, metadata } = value;
243
245
 
244
- if (req.body.vendorKey && req.body.vendorKey !== vendor.vendor_key) {
246
+ if (vendorKey && vendorKey !== vendor.vendor_key) {
245
247
  const existingVendor = await ProductVendor.findOne({
246
- where: { vendor_key: req.body.vendorKey },
248
+ where: { vendor_key: vendorKey },
247
249
  });
248
250
  if (existingVendor) {
249
251
  return res.status(400).json({ error: 'Vendor key already exists' });
250
252
  }
251
253
  }
254
+
255
+ const vendorType = (type || 'launcher') as 'launcher' | 'didnames';
256
+ const preparedData = await prepareVendorData(value.app_url, vendorType, metadata);
257
+ if ('error' in preparedData) {
258
+ return res.status(400).json({ error: preparedData.error });
259
+ }
260
+
252
261
  const updates = {
262
+ ...preparedData,
253
263
  vendor_type: vendorType,
264
+ vendor_key: vendorKey,
254
265
  name,
255
266
  description,
256
- app_url: appUrl,
257
- vendor_did: vendorDid,
258
267
  status,
259
- metadata: {
260
- ...metadata,
261
- mountPoint,
262
- },
263
- app_pid: appPid,
264
- app_logo: appLogo,
265
- vendor_key: req.body.vendor_key,
266
- extends: {
267
- mountPoint,
268
- appId: blockletJson?.appId,
269
- appPk: blockletJson?.appPk,
270
- },
271
268
  };
272
269
 
273
270
  await vendor.update(Object.fromEntries(Object.entries(updates).filter(([, v]) => v !== undefined)));
@@ -561,6 +558,36 @@ async function redirectToVendor(req: any, res: any) {
561
558
  }
562
559
  }
563
560
 
561
+ async function getCancelledSessions(req: any, res: any) {
562
+ const { error } = sessionIdsParamSchema.validate(req.body);
563
+ if (error) {
564
+ return res.status(400).json({ error: error.message });
565
+ }
566
+
567
+ const { sessionIds = [] } = req.body;
568
+
569
+ const allCheckoutSessions = await CheckoutSession.findAll({
570
+ where: { id: { [Op.in]: sessionIds } },
571
+ attributes: ['id', 'subscription_id', 'fulfillment_status', 'vendor_info'],
572
+ });
573
+
574
+ const subscriptionIds = allCheckoutSessions.map((item) => item.subscription_id!).filter((item) => !!item);
575
+
576
+ const cancelledSubscriptions = await Subscription.findAll({
577
+ where: {
578
+ id: { [Op.in]: subscriptionIds },
579
+ status: 'canceled',
580
+ },
581
+ attributes: ['id'],
582
+ });
583
+
584
+ const cancelledSubIds = cancelledSubscriptions.map((item) => item.id);
585
+ const cancelledSessions = allCheckoutSessions.filter(
586
+ (item) => item.subscription_id && cancelledSubIds.includes(item.subscription_id)
587
+ );
588
+ return res.json({ cancelledSessions });
589
+ }
590
+
564
591
  async function getVendorSubscription(req: any, res: any) {
565
592
  const { sessionId } = req.params;
566
593
 
@@ -636,6 +663,7 @@ router.get('/order/:sessionId/detail', loginAuth, validateParams(sessionIdParamS
636
663
 
637
664
  // Those for Vendor Call
638
665
  router.get('/connectTest', ensureVendorAuth, getVendorConnectTest);
666
+ router.post('/subscription/cancelled', ensureVendorAuth, getCancelledSessions);
639
667
  router.get('/subscription/:sessionId/redirect', handleSubscriptionRedirect);
640
668
  router.get('/subscription/:sessionId', ensureVendorAuth, getVendorSubscription);
641
669
 
@@ -239,6 +239,7 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
239
239
 
240
240
  attempts?: number;
241
241
  lastAttemptAt?: string;
242
+ returnRetry?: number;
242
243
  completedAt?: string;
243
244
  commissionAmount?: string;
244
245
 
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.21.15
17
+ version: 1.21.16
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.21.15",
3
+ "version": "1.21.16",
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,9 +56,9 @@
56
56
  "@blocklet/error": "^0.2.5",
57
57
  "@blocklet/js-sdk": "^1.16.53-beta-20251011-054719-4ed2f6b7",
58
58
  "@blocklet/logger": "^1.16.53-beta-20251011-054719-4ed2f6b7",
59
- "@blocklet/payment-broker-client": "1.21.15",
60
- "@blocklet/payment-react": "1.21.15",
61
- "@blocklet/payment-vendor": "1.21.15",
59
+ "@blocklet/payment-broker-client": "1.21.16",
60
+ "@blocklet/payment-react": "1.21.16",
61
+ "@blocklet/payment-vendor": "1.21.16",
62
62
  "@blocklet/sdk": "^1.16.53-beta-20251011-054719-4ed2f6b7",
63
63
  "@blocklet/ui-react": "^3.1.46",
64
64
  "@blocklet/uploader": "^0.2.15",
@@ -128,7 +128,7 @@
128
128
  "devDependencies": {
129
129
  "@abtnode/types": "^1.16.53-beta-20251011-054719-4ed2f6b7",
130
130
  "@arcblock/eslint-config-ts": "^0.3.3",
131
- "@blocklet/payment-types": "1.21.15",
131
+ "@blocklet/payment-types": "1.21.16",
132
132
  "@types/cookie-parser": "^1.4.9",
133
133
  "@types/cors": "^2.8.19",
134
134
  "@types/debug": "^4.1.12",
@@ -175,5 +175,5 @@
175
175
  "parser": "typescript"
176
176
  }
177
177
  },
178
- "gitHead": "fd48f9233f19514b537e30b013e09a7d9f7a9f48"
178
+ "gitHead": "16509d9abd2da2f52587972c863c79ba9e4cd49d"
179
179
  }
@@ -5,23 +5,21 @@ import { AddOutlined } from '@mui/icons-material';
5
5
  import {
6
6
  Button,
7
7
  CircularProgress,
8
- Stack,
9
- TextField,
10
- FormControlLabel,
11
- Switch,
12
8
  FormControl,
9
+ FormControlLabel,
13
10
  InputLabel,
14
- Select,
15
11
  MenuItem,
12
+ Select,
13
+ Stack,
14
+ Switch,
15
+ TextField,
16
16
  } from '@mui/material';
17
17
  import { useState } from 'react';
18
- import { useForm, Controller, FormProvider } from 'react-hook-form';
18
+ import { Controller, FormProvider, useForm } from 'react-hook-form';
19
19
  import { dispatch } from 'use-bus';
20
20
 
21
- import { joinURL, withQuery } from 'ufo';
22
21
  import DrawerForm from '../../../../components/drawer-form';
23
22
  import MetadataForm from '../../../../components/metadata/form';
24
- import { formatProxyUrl } from '../../../../libs/util';
25
23
 
26
24
  interface Vendor {
27
25
  id: string;
@@ -84,8 +82,6 @@ export default function VendorCreate({
84
82
  app_url: '',
85
83
  status: 'inactive' as const,
86
84
  metadata: [{ key: 'blockletMetaUrl', value: '' }],
87
- app_pid: '',
88
- app_logo: '',
89
85
  };
90
86
 
91
87
  const methods = useForm<VendorFormData>({
@@ -147,36 +143,6 @@ export default function VendorCreate({
147
143
  metadata: metadataObj,
148
144
  };
149
145
 
150
- // 如果状态为启用,则检测应用地址可用性
151
- if (submitData.status === 'active') {
152
- try {
153
- const response = await fetch(
154
- formatProxyUrl(withQuery(joinURL(submitData.app_url, '__blocklet__.js'), { type: 'json' })),
155
- {
156
- method: 'GET',
157
- headers: { 'Content-Type': 'application/json' },
158
- }
159
- );
160
-
161
- if (!response.ok) {
162
- Toast.error(t('admin.vendor.addressCheckFailed'));
163
- setLoading(false);
164
- return;
165
- }
166
-
167
- // 从响应中获取appPid和appLogo
168
- const blockletInfo = await response.json();
169
- if (blockletInfo) {
170
- submitData.app_pid = blockletInfo.pid || blockletInfo.appPid;
171
- submitData.app_logo = blockletInfo.logo || blockletInfo.appLogo;
172
- }
173
- } catch (error) {
174
- Toast.error(t('admin.vendor.addressCheckFailed'));
175
- setLoading(false);
176
- return;
177
- }
178
- }
179
-
180
146
  if (isEditMode && vendorData) {
181
147
  // 编辑模式:更新供应商
182
148
  await api.put(`/api/vendors/${vendorData.id}`, submitData);
@@ -6,6 +6,7 @@ import { ContentCopy } from '@mui/icons-material';
6
6
  import { Box, Chip, CircularProgress, IconButton, Tooltip, Typography } from '@mui/material';
7
7
  import { useEffect, useState } from 'react';
8
8
  import useBus from 'use-bus';
9
+ import omit from 'lodash/omit';
9
10
 
10
11
  import { useLocalStorageState } from 'ahooks';
11
12
  import FilterToolbar from '../../../../components/filter-toolbar';
@@ -320,7 +321,10 @@ export default function VendorsList() {
320
321
  setSelectedVendor(null);
321
322
  refresh();
322
323
  }}
323
- vendorData={selectedVendor}
324
+ vendorData={{
325
+ ...selectedVendor,
326
+ metadata: omit(selectedVendor?.metadata || {}, 'mountPoint'),
327
+ }}
324
328
  />
325
329
  )}
326
330
  </>