@abtnode/core 1.16.44-beta-20250601-083116-288e5ea5 → 1.16.44-beta-20250605-131649-6eaf56d9

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.
@@ -169,7 +169,9 @@ const {
169
169
  getAppConfigsFromComponent,
170
170
  removeAppConfigsFromComponent,
171
171
  getConfigsFromInput,
172
+ getPackComponent,
172
173
  getPackConfig,
174
+ copyPackImages,
173
175
  filterRequiredComponents,
174
176
  } = require('../../util/blocklet');
175
177
  const states = require('../../states');
@@ -445,7 +447,7 @@ class DiskBlockletManager extends BaseBlockletManager {
445
447
  title,
446
448
  description,
447
449
  action: `/blocklets/${did}/overview`,
448
- blockletDashboardAction: '/.well-known/service/admin/blocklets',
450
+ blockletDashboardAction: `${WELLKNOWN_SERVICE_PATH_PREFIX}/admin/blocklets`,
449
451
  entityType: 'blocklet',
450
452
  entityId: did,
451
453
  severity,
@@ -1484,7 +1486,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1484
1486
  entityId: newBlocklet.meta.did,
1485
1487
  severity: 'success',
1486
1488
  action: `/blocklets/${newBlocklet.meta.did}/components`,
1487
- blockletDashboardAction: '/.well-known/service/admin/components',
1489
+ blockletDashboardAction: `${WELLKNOWN_SERVICE_PATH_PREFIX}/admin/components`,
1488
1490
  });
1489
1491
 
1490
1492
  this.emit(BlockletEvents.componentRemoved, {
@@ -3080,6 +3082,8 @@ class DiskBlockletManager extends BaseBlockletManager {
3080
3082
  // install blocklet
3081
3083
  if (postAction === INSTALL_ACTIONS.INSTALL) {
3082
3084
  await this._onInstall({ blocklet, componentDids, context, oldBlocklet });
3085
+ await this.getBlocklet(did);
3086
+
3083
3087
  return;
3084
3088
  }
3085
3089
 
@@ -3103,6 +3107,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3103
3107
  });
3104
3108
 
3105
3109
  const newBlocklet = await this.getBlocklet(did);
3110
+
3106
3111
  if (newBlocklet.controller) {
3107
3112
  const eventType = 'install';
3108
3113
 
@@ -3527,7 +3532,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3527
3532
  };
3528
3533
 
3529
3534
  const action = `/blocklets/${did}/components?checkUpdate=1`;
3530
- const blockletDashboardAction = '/.well-known/service/admin/components?checkUpdate=1';
3535
+ const blockletDashboardAction = `${WELLKNOWN_SERVICE_PATH_PREFIX}/admin/components?checkUpdate=1`;
3531
3536
  const users = await this.teamManager.getOwnerAndAdminUsers(did, 1);
3532
3537
  const nodeInfo = await states.node.read();
3533
3538
  const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
@@ -4022,8 +4027,34 @@ class DiskBlockletManager extends BaseBlockletManager {
4022
4027
  // Inject pack configs
4023
4028
  const packConfig = await getPackConfig(blocklet);
4024
4029
  if (packConfig) {
4030
+ const packComponent = getPackComponent(blocklet);
4031
+
4032
+ // 同步图片资源
4033
+ await copyPackImages({
4034
+ appDataDir: path.join(this.dataDirs.data, blocklet.meta.name),
4035
+ packDir: packComponent.env.appDir,
4036
+ packConfig,
4037
+ });
4038
+
4039
+ // 同步 App 导航配置
4025
4040
  await this.configNavigations({ did, navigations: packConfig.navigations });
4026
4041
 
4042
+ // 同步 App 品牌相关图片配置
4043
+ const configObj = packConfig.configObj || {};
4044
+ for (const key of util.APP_CONFIG_IMAGE_KEYS) {
4045
+ const value = configObj[key];
4046
+ if (value) {
4047
+ await this.config({
4048
+ did: [blocklet.meta.did],
4049
+ configs: [{ key, value }],
4050
+ skipHook: true,
4051
+ skipDidDocument: true,
4052
+ skipEmitEvents: true,
4053
+ });
4054
+ }
4055
+ }
4056
+
4057
+ // 同步各子组件配置
4027
4058
  for (const { did: componentDid, configs } of packConfig.components || []) {
4028
4059
  if (blocklet.children.some((x) => x.meta.did === componentDid)) {
4029
4060
  await this.config({
@@ -4081,7 +4112,7 @@ class DiskBlockletManager extends BaseBlockletManager {
4081
4112
  deployedFrom || fromBlockletSource(source)
4082
4113
  })`,
4083
4114
  action: `/blocklets/${did}/overview`,
4084
- blockletDashboardAction: '/.well-known/service/admin/blocklets',
4115
+ blockletDashboardAction: `${WELLKNOWN_SERVICE_PATH_PREFIX}/admin/blocklets`,
4085
4116
  entityType: 'blocklet',
4086
4117
  entityId: did,
4087
4118
  severity: 'success',
@@ -4322,7 +4353,7 @@ class DiskBlockletManager extends BaseBlockletManager {
4322
4353
  componentDids
4323
4354
  )} is ${actionName} successfully for ${title}`,
4324
4355
  action: `/blocklets/${did}/overview`,
4325
- blockletDashboardAction: '/.well-known/service/admin/blocklets',
4356
+ blockletDashboardAction: `${WELLKNOWN_SERVICE_PATH_PREFIX}/admin/blocklets`,
4326
4357
  entityType: 'blocklet',
4327
4358
  entityId: did,
4328
4359
  severity: 'success',
@@ -287,6 +287,8 @@ const EVENTS = {
287
287
  RELOAD_GATEWAY: 'gateway.reload',
288
288
  NOTIFICATION_CREATE_QUEUED: 'notification.create.queued',
289
289
  UPDATE_DOMAIN_ALIAS: 'router.domain.alias.updated',
290
+
291
+ WEBHOOK_ATTEMPT: 'webhook.attempt',
290
292
  };
291
293
 
292
294
  const WHO_CAN_ACCESS = Object.freeze({
@@ -752,6 +754,7 @@ module.exports = Object.freeze({
752
754
  // FIXME: 梁柱, 下面两个 get 接口, 可以不开放但是前端需要根据情况取消获取这两个接口的调用
753
755
  getBlockletRuntimeHistory: true,
754
756
  checkDomains: true,
757
+ isDidDomain: true,
755
758
  },
756
759
  // 这些接口可以跳过 ACCESS VERIFY
757
760
  SKIP_ACCESS_VERIFY_METHODS: {
@@ -38885,7 +38888,7 @@ module.exports = require("zlib");
38885
38888
  /***/ ((module) => {
38886
38889
 
38887
38890
  "use strict";
38888
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.43","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.43","@abtnode/auth":"1.16.43","@abtnode/certificate-manager":"1.16.43","@abtnode/client":"1.16.43","@abtnode/constant":"1.16.43","@abtnode/cron":"1.16.43","@abtnode/docker-utils":"1.16.43","@abtnode/logger":"1.16.43","@abtnode/models":"1.16.43","@abtnode/queue":"1.16.43","@abtnode/rbac":"1.16.43","@abtnode/router-provider":"1.16.43","@abtnode/static-server":"1.16.43","@abtnode/timemachine":"1.16.43","@abtnode/util":"1.16.43","@arcblock/did":"1.20.11","@arcblock/did-auth":"1.20.11","@arcblock/did-ext":"1.20.11","@arcblock/did-motif":"^1.1.13","@arcblock/did-util":"1.20.11","@arcblock/event-hub":"1.20.11","@arcblock/jwt":"1.20.11","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"1.20.11","@arcblock/vc":"1.20.11","@blocklet/constant":"1.16.43","@blocklet/did-space-js":"^1.0.56","@blocklet/env":"1.16.43","@blocklet/error":"^0.2.5","@blocklet/meta":"1.16.43","@blocklet/resolver":"1.16.43","@blocklet/sdk":"1.16.43","@blocklet/store":"1.16.43","@blocklet/theme":"^2.13.57","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.20.11","@ocap/util":"1.20.11","@ocap/wallet":"1.20.11","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","dayjs":"^1.11.13","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","lru-cache":"^11.0.2","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","p-wait-for":"^3.2.0","rate-limiter-flexible":"^5.0.5","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","slugify":"^1.6.6","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^9.0.1","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
38891
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.43","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.43","@abtnode/auth":"1.16.43","@abtnode/certificate-manager":"1.16.43","@abtnode/client":"1.16.43","@abtnode/constant":"1.16.43","@abtnode/cron":"1.16.43","@abtnode/docker-utils":"1.16.43","@abtnode/logger":"1.16.43","@abtnode/models":"1.16.43","@abtnode/queue":"1.16.43","@abtnode/rbac":"1.16.43","@abtnode/router-provider":"1.16.43","@abtnode/static-server":"1.16.43","@abtnode/timemachine":"1.16.43","@abtnode/util":"1.16.43","@arcblock/did":"1.20.13","@arcblock/did-auth":"1.20.13","@arcblock/did-ext":"1.20.13","@arcblock/did-motif":"^1.1.13","@arcblock/did-util":"1.20.13","@arcblock/event-hub":"1.20.13","@arcblock/jwt":"1.20.13","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"1.20.13","@arcblock/vc":"1.20.13","@blocklet/constant":"1.16.43","@blocklet/did-space-js":"^1.0.57","@blocklet/env":"1.16.43","@blocklet/error":"^0.2.5","@blocklet/meta":"1.16.43","@blocklet/resolver":"1.16.43","@blocklet/sdk":"1.16.43","@blocklet/store":"1.16.43","@blocklet/theme":"^2.13.61","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.20.13","@ocap/util":"1.20.13","@ocap/wallet":"1.20.13","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","dayjs":"^1.11.13","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","lru-cache":"^11.0.2","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","p-wait-for":"^3.2.0","rate-limiter-flexible":"^5.0.5","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","slugify":"^1.6.6","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^9.0.1","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
38889
38892
 
38890
38893
  /***/ }),
38891
38894
 
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
3
3
  const fg = require('fast-glob');
4
4
  const { isValid: isValidDid } = require('@arcblock/did');
5
5
  const { PROJECT, BLOCKLET_RESOURCE_DIR, BLOCKLET_META_FILE } = require('@blocklet/constant');
6
- const { expandBundle } = require('../../util');
6
+ const { expandBundle, APP_CONFIG_IMAGE_KEYS } = require('../../util');
7
7
 
8
8
  const COMPONENT_CONFIG_MAP_DIR = '.component_config';
9
9
 
@@ -46,6 +46,42 @@ const exportBlockletResources = async ({
46
46
  await fs.remove(path.join(resourceDir, COMPONENT_CONFIG_MAP_DIR));
47
47
 
48
48
  if (isPack) {
49
+ const navigations = app.settings.navigations || [];
50
+ const imagesDir = path.join(exportDir, 'images');
51
+
52
+ // 将 tabbar icons 复制到 images 目录
53
+ const bottomNavItems = navigations.filter((item) => item.section === 'bottomNavigation' && item.icon);
54
+ if (bottomNavItems.length > 0) {
55
+ const mediaDir = path.join(app.env.dataDir, 'media', 'blocklet-service');
56
+ if (fs.existsSync(mediaDir)) {
57
+ await fs.ensureDir(imagesDir);
58
+
59
+ await Promise.all(
60
+ bottomNavItems.map(async (item) => {
61
+ const iconFileName = path.basename(item.icon);
62
+ const iconFile = path.join(mediaDir, iconFileName);
63
+ if (fs.existsSync(iconFile)) {
64
+ await fs.copy(iconFile, path.join(imagesDir, iconFileName));
65
+ }
66
+ })
67
+ );
68
+ }
69
+ }
70
+
71
+ // 将 branding images 复制到 images 目录
72
+ const configObj = app.configObj || {};
73
+ await Promise.all(
74
+ APP_CONFIG_IMAGE_KEYS.map(async (key) => {
75
+ const value = configObj[key];
76
+ if (value && !value.startsWith('http')) {
77
+ const imgFile = path.join(app.env.dataDir, value);
78
+ if (fs.existsSync(imgFile)) {
79
+ await fs.copy(imgFile, path.join(imagesDir, value));
80
+ }
81
+ }
82
+ })
83
+ );
84
+
49
85
  // create pack resource
50
86
  const packResourceDir = path.join(resourceDir, blockletDid, 'config');
51
87
  await fs.ensureDir(packResourceDir);
@@ -58,7 +94,6 @@ const exportBlockletResources = async ({
58
94
  }))
59
95
  .filter(Boolean),
60
96
  };
61
- const navigations = app.settings.navigations || [];
62
97
  const componentsConfigs = app.children
63
98
  .filter((x) => {
64
99
  if (selectedComponentDids.length) {
@@ -72,6 +107,7 @@ const exportBlockletResources = async ({
72
107
  }));
73
108
  await fs.outputJSON(path.join(packResourceDir, 'config.json'), {
74
109
  site,
110
+ configObj,
75
111
  navigations,
76
112
  components: componentsConfigs,
77
113
  });
@@ -2,7 +2,9 @@ const pick = require('lodash/pick');
2
2
  const pickBy = require('lodash/pickBy');
3
3
  const get = require('lodash/get');
4
4
  const { EventEmitter } = require('events');
5
- const { API_VERSION } = require('./util');
5
+ const { EVENTS } = require('@abtnode/constant');
6
+ const { API_VERSION, STATUS } = require('./util');
7
+ const endpointQueueInit = require('./queues');
6
8
 
7
9
  const DEFAULT_PAGE = 1;
8
10
  const DEFAULT_PAGE_SIZE = 10;
@@ -25,6 +27,9 @@ class WebhooksAPI extends EventEmitter {
25
27
 
26
28
  this.cache = new Map();
27
29
  this.TTL = 5 * 60 * 1000;
30
+
31
+ const { webhookEndpointQueue } = endpointQueueInit.init({ states, teamManager });
32
+ this.webhookEndpointQueue = webhookEndpointQueue;
28
33
  }
29
34
 
30
35
  async getUserInfo(userDid, teamDid, serverDid) {
@@ -161,6 +166,46 @@ class WebhooksAPI extends EventEmitter {
161
166
  const list = await webhookAttemptState.list(page, pageSize, where);
162
167
  return list;
163
168
  }
169
+
170
+ async retryWebhookAttempt({ eventId, webhookId, attemptId, teamDid }, context) {
171
+ const { webhookAttemptState } = await this.teamManager.getWebhookState(teamDid);
172
+
173
+ const result = await webhookAttemptState.insert({
174
+ eventId,
175
+ webhookId,
176
+ status: STATUS.PENDING,
177
+ retryCount: 1,
178
+ responseStatus: 200,
179
+ responseBody: {},
180
+ triggeredBy: getUserDid(context),
181
+ triggeredFrom: attemptId,
182
+ });
183
+
184
+ const emitResult = async () => {
185
+ return {
186
+ teamDid,
187
+ ...(await webhookAttemptState.findOne({ eventId, webhookId, id: result.id })),
188
+ };
189
+ };
190
+
191
+ this.webhookEndpointQueue.push({
192
+ eventId,
193
+ webhookId,
194
+ appDid: teamDid,
195
+ attemptId: result.id,
196
+ triggeredBy: getUserDid(context),
197
+ triggeredFrom: attemptId,
198
+ });
199
+
200
+ this.webhookEndpointQueue.on('finished', async () => {
201
+ this.emit(EVENTS.WEBHOOK_ATTEMPT, { ...(await emitResult()) });
202
+ });
203
+ this.webhookEndpointQueue.on('failed', async () => {
204
+ this.emit(EVENTS.WEBHOOK_ATTEMPT, { ...(await emitResult()) });
205
+ });
206
+
207
+ return result;
208
+ }
164
209
  }
165
210
 
166
211
  module.exports = WebhooksAPI;
@@ -3,13 +3,19 @@ const axios = require('@abtnode/util/lib/axios');
3
3
  const { Op } = require('sequelize');
4
4
 
5
5
  const createQueue = require('../../util/queue');
6
- const { getWebhookJobId } = require('./util');
6
+ const { getWebhookJobId, STATUS } = require('./util');
7
7
 
8
8
  const MAX_RETRY_COUNT = 2; // 重试一次
9
9
  const AXIOS_TIMEOUT = 1000 * 60 * 3;
10
10
 
11
11
  const createWebhookEndpointQueue = ({ states, teamManager }) => {
12
12
  // https://stripe.com/docs/webhooks
13
+ /**
14
+ *
15
+ * @param {*} job eventId: event.id, webhookId: webhook.id, appDid: job.appDid, attemptId?:string
16
+ *
17
+ * @returns
18
+ */
13
19
  const handleWebhookEndpoint = async (job) => {
14
20
  logger.info('handle webhook endpoint', job);
15
21
 
@@ -48,14 +54,31 @@ const createWebhookEndpointQueue = ({ states, teamManager }) => {
48
54
  // verify similar to component call, but supports external urls
49
55
  const response = await axios.post(webhook.url, event.request, { timeout: AXIOS_TIMEOUT });
50
56
 
51
- await webhookAttemptState.insert({
52
- eventId: event.id,
53
- webhookId: webhook.id,
54
- status: 'succeeded',
55
- responseStatus: response.status,
56
- responseBody: response.data || {},
57
- retryCount,
58
- });
57
+ if (job.attemptId) {
58
+ await webhookAttemptState.update(
59
+ { id: job.attemptId },
60
+ {
61
+ status: STATUS.SUCCEEDED,
62
+ responseStatus: response.status,
63
+ responseBody: response.data || {},
64
+ retryCount,
65
+ triggeredBy: job.triggeredBy,
66
+ triggeredFrom: job.triggeredFrom,
67
+ }
68
+ );
69
+ } else {
70
+ await webhookAttemptState.insert({
71
+ eventId: event.id,
72
+ webhookId: webhook.id,
73
+ status: STATUS.SUCCEEDED,
74
+ responseStatus: response.status,
75
+ responseBody: response.data || {},
76
+ retryCount,
77
+ triggeredBy: job.triggeredBy,
78
+ triggeredFrom: job.triggeredFrom,
79
+ });
80
+ }
81
+
59
82
  logger.info('WebhookAttempt created successfully', { eventId: event.id, webhookId: webhook.id });
60
83
 
61
84
  const newPendingCount = Math.max(0, event.pendingWebhooks - 1);
@@ -66,14 +89,31 @@ const createWebhookEndpointQueue = ({ states, teamManager }) => {
66
89
  } catch (err) {
67
90
  logger.warn('webhook attempt error', { ...job, retryCount, message: err.message });
68
91
 
69
- await webhookAttemptState.insert({
70
- eventId: event.id,
71
- webhookId: webhook.id,
72
- status: 'failed',
73
- responseStatus: err.response?.status || 500,
74
- responseBody: err.response?.data || {},
75
- retryCount,
76
- });
92
+ if (job.attemptId) {
93
+ await webhookAttemptState.update(
94
+ { id: job.attemptId },
95
+ {
96
+ status: STATUS.FAILED,
97
+ responseStatus: err.response?.status || 500,
98
+ responseBody: err.response?.data || {},
99
+ retryCount,
100
+ triggeredBy: job.triggeredBy,
101
+ triggeredFrom: job.triggeredFrom,
102
+ }
103
+ );
104
+ } else {
105
+ await webhookAttemptState.insert({
106
+ eventId: event.id,
107
+ webhookId: webhook.id,
108
+ status: STATUS.FAILED,
109
+ responseStatus: err.response?.status || 500,
110
+ responseBody: err.response?.data || {},
111
+ retryCount,
112
+ triggeredBy: job.triggeredBy,
113
+ triggeredFrom: job.triggeredFrom,
114
+ });
115
+ }
116
+
77
117
  logger.info('Failed WebhookAttempt created', { eventId: event.id, webhookId: webhook.id });
78
118
 
79
119
  // reschedule next attempt
@@ -6,7 +6,14 @@ const getWebhookJobId = (eventId, webhookId) => {
6
6
  return md5([eventId, webhookId].join('-'));
7
7
  };
8
8
 
9
+ const STATUS = {
10
+ SUCCEEDED: 'succeeded',
11
+ FAILED: 'failed',
12
+ PENDING: 'pending',
13
+ };
14
+
9
15
  module.exports = {
10
16
  API_VERSION,
17
+ STATUS,
11
18
  getWebhookJobId,
12
19
  };
@@ -19,6 +19,7 @@ const {
19
19
  DEFAULT_DID_DOMAIN,
20
20
  WELLKNOWN_BLOCKLET_ADMIN_PATH,
21
21
  TEST_STORE_URL,
22
+ WELLKNOWN_SERVICE_PATH_PREFIX,
22
23
  } = require('@abtnode/constant');
23
24
  const { joinURL } = require('ufo');
24
25
  const { encode } = require('@abtnode/util/lib/base32');
@@ -65,6 +66,7 @@ module.exports = ({
65
66
  node,
66
67
  nodeRuntimeMonitor,
67
68
  daemon,
69
+ webhookManager,
68
70
  }) => {
69
71
  const nodeState = states.node;
70
72
  const nodeMonitSender = new NodeMonitSender({ node });
@@ -561,6 +563,10 @@ module.exports = ({
561
563
  eventHub.broadcast(name, data);
562
564
  });
563
565
 
566
+ listen(webhookManager, EVENTS.WEBHOOK_ATTEMPT, (name, data) => {
567
+ onEvent(name, data, true);
568
+ });
569
+
564
570
  listen(nodeState, BlockletEvents.purchaseChange, onEvent);
565
571
  nodeState.on(EVENTS.ROUTING_UPDATED, (nodeInfo) => onEvent(EVENTS.ROUTING_UPDATED, { routing: nodeInfo.routing }));
566
572
  nodeState.once(EVENTS.NODE_ADDED_OWNER, () => downloadAddedBlocklet());
@@ -706,7 +712,7 @@ module.exports = ({
706
712
  actions: [
707
713
  {
708
714
  name: translation.viewYourAccount,
709
- link: joinURL(origin, '/.well-known/service/user/settings'),
715
+ link: joinURL(origin, `${WELLKNOWN_SERVICE_PATH_PREFIX}/user/settings`),
710
716
  },
711
717
  ],
712
718
  };
package/lib/index.js CHANGED
@@ -753,6 +753,7 @@ function ABTNode(options) {
753
753
  getWebhookEndpoints: webhookAPI.getWebhookEndpoints.bind(webhookAPI),
754
754
  getWebhookEndpoint: webhookAPI.getWebhookEndpoint.bind(webhookAPI),
755
755
  getWebhookAttempts: webhookAPI.getWebhookAttempts.bind(webhookAPI),
756
+ retryWebhookAttempt: webhookAPI.retryWebhookAttempt.bind(webhookAPI),
756
757
 
757
758
  // passport
758
759
  createPassportLog: passportAPI.createPassportLog.bind(passportAPI),
@@ -799,6 +800,7 @@ function ABTNode(options) {
799
800
  nodeRuntimeMonitor: nodeAPI.runtimeMonitor,
800
801
  daemon: options.daemon,
801
802
  handleBlockletWafChange,
803
+ webhookManager: webhookAPI,
802
804
  });
803
805
 
804
806
  const webhook = WebHook({ events, dataDirs, instance, teamManager });
@@ -1,3 +1,4 @@
1
+ const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
1
2
  const { createLogWatcher } = require('./watcher');
2
3
 
3
4
  // Function to parse the log entry and extract relevant information
@@ -36,7 +37,7 @@ function parseLogEntry(line, check = true) {
36
37
  logEntry.status <= 599 &&
37
38
  logEntry.request.includes('/.well-known/did.json') === false &&
38
39
  logEntry.request.includes('/websocket') === false &&
39
- logEntry.request.includes('/.well-known/service/health') === false
40
+ logEntry.request.includes(`${WELLKNOWN_SERVICE_PATH_PREFIX}/health`) === false
40
41
  ) {
41
42
  console.warn(`5xx request detected: ${logEntry.host}`, line);
42
43
  return logEntry;
@@ -515,6 +515,8 @@ const getLogContent = async (action, args, context, result, info, node) => {
515
515
  return `Delete Blocklet Webhook(${result.id})`;
516
516
  case 'ensureBlockletRunning':
517
517
  return `${result.title}:\n* ${result.description}`;
518
+ case 'retryWebhookAttempt':
519
+ return `Retry Webhook Attempt(${args.attemptId})`;
518
520
 
519
521
  case 'addUploadEndpoint':
520
522
  return `Create Upload Endpoint(${args.url})`;
@@ -657,6 +659,7 @@ const getLogCategory = (action) => {
657
659
  case 'createWebhookEndpoint':
658
660
  case 'updateWebhookEndpoint':
659
661
  case 'deleteWebhookEndpoint':
662
+ case 'retryWebhookAttempt':
660
663
  return 'integrations';
661
664
 
662
665
  // server
@@ -117,7 +117,14 @@ const FileLock = require('@abtnode/util/lib/lock-with-file');
117
117
  const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
118
118
 
119
119
  const isRequirementsSatisfied = require('./requirement');
120
- const { expandBundle, findInterfacePortByName, prettyURL, templateReplace, getServerDidDomain } = require('./index');
120
+ const {
121
+ expandBundle,
122
+ findInterfacePortByName,
123
+ prettyURL,
124
+ templateReplace,
125
+ getServerDidDomain,
126
+ APP_CONFIG_IMAGE_KEYS,
127
+ } = require('./index');
121
128
  const { installExternalDependencies } = require('./install-external-dependencies');
122
129
  const parseDockerOptionsFromPm2 = require('./docker/parse-docker-options-from-pm2');
123
130
  const dockerRemoveByName = require('./docker/docker-remove-by-name');
@@ -1676,7 +1683,8 @@ const fromProperty2Config = (properties = {}, result) => {
1676
1683
  name: `${BLOCKLET_PREFERENCE_PREFIX}${key}`,
1677
1684
  required: prop.required || false,
1678
1685
  secure,
1679
- shared: secure ? false : prop.shared,
1686
+ // eslint-disable-next-line no-nested-ternary
1687
+ shared: secure ? false : typeof prop.shared === 'undefined' ? true : prop.shared,
1680
1688
  });
1681
1689
  }
1682
1690
  });
@@ -2351,8 +2359,12 @@ const removeAppConfigsFromComponent = async (componentConfigs, app, blockletExtr
2351
2359
  }
2352
2360
  };
2353
2361
 
2362
+ const getPackComponent = (app) => {
2363
+ return (app?.children || []).find((x) => x.meta.group === BlockletGroup.pack);
2364
+ };
2365
+
2354
2366
  const getPackConfig = (app) => {
2355
- const packComponent = (app?.children || []).find((x) => x.meta.group === BlockletGroup.pack);
2367
+ const packComponent = getPackComponent(app);
2356
2368
  if (!packComponent) {
2357
2369
  return null;
2358
2370
  }
@@ -2374,6 +2386,52 @@ const getPackConfig = (app) => {
2374
2386
 
2375
2387
  return fs.readJSON(configFile);
2376
2388
  };
2389
+
2390
+ /** 复制打包文件中的图片
2391
+ * @param {string} appDataDir
2392
+ * @param {string} packDir
2393
+ * @param {{ navigations: Array<{ section: string | string[], icon: string }>, configObj: Record<string, string> }} packConfig
2394
+ */
2395
+ const copyPackImages = async ({ appDataDir, packDir, packConfig = {} }) => {
2396
+ const mediaDir = path.join(appDataDir, 'media', 'blocklet-service');
2397
+ const { navigations = [], configObj = {} } = packConfig;
2398
+ await fs.ensureDir(mediaDir);
2399
+
2400
+ // 过滤出 bottomNavigation 的图标
2401
+ const bottomNavItems = navigations.filter((item) => {
2402
+ // 处理 section 字段为数组的情况
2403
+ const sections = Array.isArray(item.section) ? item.section : [item.section];
2404
+ return sections.includes('bottomNavigation') && item.icon;
2405
+ });
2406
+
2407
+ // 复制 tabbar 导航图标
2408
+ if (bottomNavItems.length > 0) {
2409
+ await Promise.all(
2410
+ bottomNavItems.map(async (item) => {
2411
+ const iconFileName = path.basename(item.icon);
2412
+ const iconInImages = path.join(packDir, 'images', iconFileName);
2413
+
2414
+ if (fs.existsSync(iconInImages)) {
2415
+ await fs.copy(iconInImages, path.join(mediaDir, iconFileName));
2416
+ }
2417
+ })
2418
+ );
2419
+ }
2420
+
2421
+ // 复制品牌相关图片
2422
+ await Promise.all(
2423
+ APP_CONFIG_IMAGE_KEYS.map(async (key) => {
2424
+ const value = configObj[key];
2425
+ if (value) {
2426
+ const imgFile = path.join(packDir, 'images', value);
2427
+ if (fs.existsSync(imgFile)) {
2428
+ await fs.copy(imgFile, path.join(appDataDir, value));
2429
+ }
2430
+ }
2431
+ })
2432
+ );
2433
+ };
2434
+
2377
2435
  /**
2378
2436
  * @param {import('@abtnode/client').BlockletState} blocklet
2379
2437
  * @returns {boolean}
@@ -2449,7 +2507,9 @@ module.exports = {
2449
2507
  getAppConfigsFromComponent,
2450
2508
  removeAppConfigsFromComponent,
2451
2509
  getConfigsFromInput,
2510
+ getPackComponent,
2452
2511
  getPackConfig,
2512
+ copyPackImages,
2453
2513
  getBlockletConfigObj,
2454
2514
  isDevelopmentMode,
2455
2515
  resolveMountPointConflict,
package/lib/util/index.js CHANGED
@@ -30,8 +30,15 @@ const {
30
30
  SLOT_FOR_IP_DNS_SITE,
31
31
  BLOCKLET_SITE_GROUP_SUFFIX,
32
32
  } = require('@abtnode/constant');
33
+ const { BLOCKLET_CONFIGURABLE_KEY } = require('@blocklet/constant');
33
34
 
34
35
  const DEFAULT_WELLKNOWN_PORT = 8088;
36
+ const APP_CONFIG_IMAGE_KEYS = [
37
+ BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_FAVICON,
38
+ BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SPLASH_PORTRAIT,
39
+ BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SPLASH_LANDSCAPE,
40
+ BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_OG_IMAGE,
41
+ ];
35
42
 
36
43
  const logger = require('@abtnode/logger')('@abtnode/core:util');
37
44
  const getSafeEnv = require('./get-safe-env');
@@ -487,6 +494,7 @@ const toCamelCase = (obj) => {
487
494
  };
488
495
 
489
496
  const lib = {
497
+ APP_CONFIG_IMAGE_KEYS,
490
498
  validateOwner,
491
499
  getProviderFromNodeInfo,
492
500
  toStatus,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.44-beta-20250601-083116-288e5ea5",
6
+ "version": "1.16.44-beta-20250605-131649-6eaf56d9",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,44 +19,44 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@abtnode/analytics": "1.16.44-beta-20250601-083116-288e5ea5",
23
- "@abtnode/auth": "1.16.44-beta-20250601-083116-288e5ea5",
24
- "@abtnode/certificate-manager": "1.16.44-beta-20250601-083116-288e5ea5",
25
- "@abtnode/client": "1.16.44-beta-20250601-083116-288e5ea5",
26
- "@abtnode/constant": "1.16.44-beta-20250601-083116-288e5ea5",
27
- "@abtnode/cron": "1.16.44-beta-20250601-083116-288e5ea5",
28
- "@abtnode/docker-utils": "1.16.44-beta-20250601-083116-288e5ea5",
29
- "@abtnode/logger": "1.16.44-beta-20250601-083116-288e5ea5",
30
- "@abtnode/models": "1.16.44-beta-20250601-083116-288e5ea5",
31
- "@abtnode/queue": "1.16.44-beta-20250601-083116-288e5ea5",
32
- "@abtnode/rbac": "1.16.44-beta-20250601-083116-288e5ea5",
33
- "@abtnode/router-provider": "1.16.44-beta-20250601-083116-288e5ea5",
34
- "@abtnode/static-server": "1.16.44-beta-20250601-083116-288e5ea5",
35
- "@abtnode/timemachine": "1.16.44-beta-20250601-083116-288e5ea5",
36
- "@abtnode/util": "1.16.44-beta-20250601-083116-288e5ea5",
37
- "@arcblock/did": "1.20.11",
38
- "@arcblock/did-auth": "1.20.11",
39
- "@arcblock/did-ext": "1.20.11",
22
+ "@abtnode/analytics": "1.16.44-beta-20250605-131649-6eaf56d9",
23
+ "@abtnode/auth": "1.16.44-beta-20250605-131649-6eaf56d9",
24
+ "@abtnode/certificate-manager": "1.16.44-beta-20250605-131649-6eaf56d9",
25
+ "@abtnode/client": "1.16.44-beta-20250605-131649-6eaf56d9",
26
+ "@abtnode/constant": "1.16.44-beta-20250605-131649-6eaf56d9",
27
+ "@abtnode/cron": "1.16.44-beta-20250605-131649-6eaf56d9",
28
+ "@abtnode/docker-utils": "1.16.44-beta-20250605-131649-6eaf56d9",
29
+ "@abtnode/logger": "1.16.44-beta-20250605-131649-6eaf56d9",
30
+ "@abtnode/models": "1.16.44-beta-20250605-131649-6eaf56d9",
31
+ "@abtnode/queue": "1.16.44-beta-20250605-131649-6eaf56d9",
32
+ "@abtnode/rbac": "1.16.44-beta-20250605-131649-6eaf56d9",
33
+ "@abtnode/router-provider": "1.16.44-beta-20250605-131649-6eaf56d9",
34
+ "@abtnode/static-server": "1.16.44-beta-20250605-131649-6eaf56d9",
35
+ "@abtnode/timemachine": "1.16.44-beta-20250605-131649-6eaf56d9",
36
+ "@abtnode/util": "1.16.44-beta-20250605-131649-6eaf56d9",
37
+ "@arcblock/did": "1.20.13",
38
+ "@arcblock/did-auth": "1.20.13",
39
+ "@arcblock/did-ext": "1.20.13",
40
40
  "@arcblock/did-motif": "^1.1.13",
41
- "@arcblock/did-util": "1.20.11",
42
- "@arcblock/event-hub": "1.20.11",
43
- "@arcblock/jwt": "1.20.11",
41
+ "@arcblock/did-util": "1.20.13",
42
+ "@arcblock/event-hub": "1.20.13",
43
+ "@arcblock/jwt": "1.20.13",
44
44
  "@arcblock/pm2-events": "^0.0.5",
45
- "@arcblock/validator": "1.20.11",
46
- "@arcblock/vc": "1.20.11",
47
- "@blocklet/constant": "1.16.44-beta-20250601-083116-288e5ea5",
48
- "@blocklet/did-space-js": "^1.0.56",
49
- "@blocklet/env": "1.16.44-beta-20250601-083116-288e5ea5",
45
+ "@arcblock/validator": "1.20.13",
46
+ "@arcblock/vc": "1.20.13",
47
+ "@blocklet/constant": "1.16.44-beta-20250605-131649-6eaf56d9",
48
+ "@blocklet/did-space-js": "^1.0.57",
49
+ "@blocklet/env": "1.16.44-beta-20250605-131649-6eaf56d9",
50
50
  "@blocklet/error": "^0.2.5",
51
- "@blocklet/meta": "1.16.44-beta-20250601-083116-288e5ea5",
52
- "@blocklet/resolver": "1.16.44-beta-20250601-083116-288e5ea5",
53
- "@blocklet/sdk": "1.16.44-beta-20250601-083116-288e5ea5",
54
- "@blocklet/store": "1.16.44-beta-20250601-083116-288e5ea5",
55
- "@blocklet/theme": "^2.13.57",
51
+ "@blocklet/meta": "1.16.44-beta-20250605-131649-6eaf56d9",
52
+ "@blocklet/resolver": "1.16.44-beta-20250605-131649-6eaf56d9",
53
+ "@blocklet/sdk": "1.16.44-beta-20250605-131649-6eaf56d9",
54
+ "@blocklet/store": "1.16.44-beta-20250605-131649-6eaf56d9",
55
+ "@blocklet/theme": "^2.13.61",
56
56
  "@fidm/x509": "^1.2.1",
57
- "@ocap/mcrypto": "1.20.11",
58
- "@ocap/util": "1.20.11",
59
- "@ocap/wallet": "1.20.11",
57
+ "@ocap/mcrypto": "1.20.13",
58
+ "@ocap/util": "1.20.13",
59
+ "@ocap/wallet": "1.20.13",
60
60
  "@slack/webhook": "^5.0.4",
61
61
  "archiver": "^7.0.1",
62
62
  "axios": "^1.7.9",
@@ -116,5 +116,5 @@
116
116
  "jest": "^29.7.0",
117
117
  "unzipper": "^0.10.11"
118
118
  },
119
- "gitHead": "5d978739f099374dcc9d4ce9572eb343fd0c39b4"
119
+ "gitHead": "667899e10781e9fcc21c40c2a2f60f3fa2fecc88"
120
120
  }