@abtnode/core 1.17.6-beta-20251216-223535-283b9ffe → 1.17.6-beta-20251217-144034-62fafb94

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.
@@ -2832,7 +2832,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2832
2832
  {
2833
2833
  name: 'send-serverless-heartbeat',
2834
2834
  time: process.env.ABT_NODE_SERVERLESS_HEARTBEAT_INTERVAL || '*/5 * * * *', // default every 5 minutes
2835
- options: { runOnInit: false },
2835
+ options: { runOnInit: true },
2836
2836
  fn: () => launcher.sendServerlessHeartbeat(),
2837
2837
  },
2838
2838
  ];
@@ -5433,8 +5433,10 @@ class DiskBlockletManager extends BaseBlockletManager {
5433
5433
  this.emit(BlockletEvents.appDidChanged, blocklet);
5434
5434
 
5435
5435
  await updateBlockletDocument({
5436
- blocklet,
5436
+ did: blocklet.appPid,
5437
5437
  nodeInfo,
5438
+ states,
5439
+ teamManager: this.teamManager,
5438
5440
  })
5439
5441
  .then(() => {
5440
5442
  logger.info('updated blocklet dns document', { appPid: blocklet.appPid, appDid: blocklet.appDid });
@@ -37,7 +37,12 @@ const { getBackupEndpoint, getBackupFilesUrlFromEndpoint, getDIDSpacesUrlFromEnd
37
37
  const { autoBackupHandlerFactory, autoBackupHandler } = require('./auto-backup-handler');
38
38
 
39
39
  const eventBusHandler = require('../blocklet/webhook/event-bus');
40
- const { isDevelopmentMode, deleteBlockletCache } = require('../util/blocklet');
40
+ const {
41
+ isDevelopmentMode,
42
+ deleteBlockletCache,
43
+ updateDidDocument,
44
+ updateDidDocumentStateOnly,
45
+ } = require('../util/blocklet');
41
46
  const {
42
47
  backupBlockletSites,
43
48
  cleanBlockletSitesBackup,
@@ -229,6 +234,14 @@ module.exports = ({
229
234
 
230
235
  await teamAPI.refreshBlockletInterfacePermissions(blocklet.meta);
231
236
  logger.info('refreshed blocklet interface permissions after installed', { did: blocklet.meta.did });
237
+
238
+ try {
239
+ const nodeInfo = await node.getNodeInfo();
240
+ await updateDidDocument({ did: blocklet.appPid, nodeInfo, teamManager, states });
241
+ logger.info('updated blocklet DID document after install', { did: blocklet.meta.did });
242
+ } catch (error) {
243
+ logger.error('update blocklet DID document failed after install', { did: blocklet.meta.did, error });
244
+ }
232
245
  } catch (error) {
233
246
  logger.error('create.url.mapping.error', { event: name, error });
234
247
  teamManager.createNotification({
@@ -261,6 +274,19 @@ module.exports = ({
261
274
  logger.error('remove blocklet routing rules error', { event: name, error });
262
275
  }
263
276
 
277
+ try {
278
+ const nodeInfo = await node.getNodeInfo();
279
+ await updateDidDocumentStateOnly({
280
+ did: blocklet.appPid,
281
+ blocklet,
282
+ state: 'deleted',
283
+ nodeInfo,
284
+ });
285
+ logger.info('updated blocklet DID document state to deleted', { did: blocklet.meta.did });
286
+ } catch (error) {
287
+ logger.error('update blocklet DID document failed after remove', { did: blocklet.meta.did, error });
288
+ }
289
+
264
290
  try {
265
291
  await blockletManager.prune();
266
292
  } catch (error) {
@@ -503,6 +529,23 @@ module.exports = ({
503
529
  } catch (error) {
504
530
  logger.error('monit runtime info failed', { eventName, error });
505
531
  }
532
+
533
+ if ([BlockletEvents.started, BlockletEvents.stopped].includes(eventName)) {
534
+ try {
535
+ const nodeInfo = await node.getNodeInfo();
536
+ await updateDidDocument({ did: blocklet.appPid, nodeInfo, teamManager, states });
537
+ logger.info('updated blocklet DID document after state change', {
538
+ did: blocklet.meta.did,
539
+ event: eventName,
540
+ });
541
+ } catch (error) {
542
+ logger.error('update blocklet DID document failed after state change', {
543
+ did: blocklet.meta.did,
544
+ event: eventName,
545
+ error,
546
+ });
547
+ }
548
+ }
506
549
  }
507
550
 
508
551
  if ([BlockletEvents.statusChange].includes(eventName) && isDevelopmentMode(blocklet)) {
@@ -704,8 +747,17 @@ module.exports = ({
704
747
  });
705
748
  });
706
749
 
707
- routerManager.on(EVENTS.UPDATE_DOMAIN_ALIAS, (did) => {
750
+ routerManager.on(EVENTS.UPDATE_DOMAIN_ALIAS, async (did) => {
708
751
  if (did) {
752
+ const nodeInfo = await node.getNodeInfo();
753
+ updateDidDocument({ did, nodeInfo, teamManager, states })
754
+ .then(() => {
755
+ logger.info('Update did document successfully on update domain alias', { did });
756
+ })
757
+ .catch((err) => {
758
+ logger.error('Update did document failed on update domain alias', { did, error: err });
759
+ });
760
+
709
761
  blockletManager
710
762
  .detail({ did })
711
763
  .then((blocklet) => {
@@ -29,6 +29,7 @@ const axios = require('@abtnode/util/lib/axios');
29
29
  const { getIpDnsDomainForBlocklet } = require('@abtnode/util/lib/get-domain-for-blocklet');
30
30
  const { forEachBlockletSync } = require('@blocklet/meta/lib/util');
31
31
  const { processLogByDate } = require('@abtnode/analytics');
32
+ const { DBCache, getAbtNodeRedisAndSQLiteUrl } = require('@abtnode/db-cache');
32
33
  const pRetry = require('p-retry');
33
34
  const { buildLauncherUrl, buildRequestHeaders } = require('@abtnode/auth/lib/launcher');
34
35
  const {
@@ -105,6 +106,13 @@ const { get: getIp } = require('../util/ip');
105
106
 
106
107
  const isServiceFeDevelopment = process.env.ABT_NODE_SERVICE_FE_PORT;
107
108
 
109
+ // 使用 DBCache 实现分布式锁,防止同一个 blocklet 的路由操作并发执行
110
+ const ensureBlockletRoutingLock = new DBCache(() => ({
111
+ prefix: 'ensure-blocklet-routing-lock',
112
+ ttl: 1000 * 60, // 60 seconds timeout
113
+ ...getAbtNodeRedisAndSQLiteUrl(),
114
+ }));
115
+
108
116
  const hasRuleByPrefix = (site, value) => site.rules.find((x) => x.isProtected && get(x, 'from.pathPrefix') === value);
109
117
 
110
118
  const pingWellknownRule = {
@@ -1311,19 +1319,22 @@ module.exports = function getRouterHelpers({
1311
1319
 
1312
1320
  const existSite = await states.site.findOne({ domain: domainGroup });
1313
1321
  updateBlockletDocument({
1314
- blocklet,
1322
+ did: blocklet.appPid,
1315
1323
  nodeInfo,
1324
+ teamManager,
1325
+ states,
1316
1326
  })
1317
1327
  .then(() => {
1318
- logger.info(`updated blocklet ${blocklet.appDid} dns`);
1328
+ logger.info('updated blocklet dns document', {
1329
+ did: blocklet.appPid,
1330
+ });
1319
1331
  })
1320
1332
  .catch((err) => {
1321
- logger.error(`update blocklet ${blocklet.appDid} dns failed`, { error: err });
1333
+ logger.error('update blocklet dns document failed', { did: blocklet.meta.did, error: err });
1322
1334
  });
1323
1335
 
1324
1336
  if (!existSite) {
1325
1337
  const domainAliases = getBlockletDidDomainList(blocklet, nodeInfo);
1326
-
1327
1338
  // let didDomain in front of ipEchoDnsDomain
1328
1339
  domainAliases.push({ value: getIpDnsDomainForBlocklet(blocklet), isProtected: true });
1329
1340
 
@@ -1496,13 +1507,21 @@ module.exports = function getRouterHelpers({
1496
1507
  * @returns {Promise<boolean>} if routing changed
1497
1508
  */
1498
1509
  const ensureBlockletRouting = async (blocklet, context = {}) => {
1499
- const nodeInfo = await nodeState.read();
1500
- const hasWebInterface = (blocklet.meta.interfaces || []).some((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
1501
- if (!hasWebInterface) {
1502
- return false;
1503
- }
1510
+ const lockName = `ensure-blocklet-routing-${blocklet.meta.did}`;
1511
+
1512
+ await ensureBlockletRoutingLock.acquire(lockName);
1504
1513
 
1505
- return _ensureBlockletSites(blocklet, nodeInfo, context);
1514
+ try {
1515
+ const nodeInfo = await nodeState.read();
1516
+ const hasWebInterface = (blocklet.meta.interfaces || []).some((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
1517
+ if (!hasWebInterface) {
1518
+ return false;
1519
+ }
1520
+
1521
+ return await _ensureBlockletSites(blocklet, nodeInfo, context);
1522
+ } finally {
1523
+ await ensureBlockletRoutingLock.releaseLock(lockName);
1524
+ }
1506
1525
  };
1507
1526
 
1508
1527
  /**
@@ -56,6 +56,32 @@ class BlockletChildState extends BaseState {
56
56
  return (children || []).map(ensureDeployedFrom);
57
57
  }
58
58
 
59
+ /**
60
+ * Get children by multiple parent blocklet IDs (batch query)
61
+ * @param {string[]} parentBlockletIds - Array of parent blocklet IDs
62
+ * @returns {Promise<Map<string, Array>>} - Map of parentBlockletId -> children array
63
+ */
64
+ async getChildrenByParentIds(parentBlockletIds) {
65
+ if (!Array.isArray(parentBlockletIds) || parentBlockletIds.length === 0) {
66
+ return new Map();
67
+ }
68
+
69
+ const children = await this.find({ parentBlockletId: { $in: parentBlockletIds } }, {}, { createdAt: 1 });
70
+
71
+ // Group children by parentBlockletId
72
+ const childrenMap = new Map();
73
+ parentBlockletIds.forEach((id) => childrenMap.set(id, []));
74
+
75
+ (children || []).forEach((child) => {
76
+ const processedChild = ensureDeployedFrom(child);
77
+ if (childrenMap.has(child.parentBlockletId)) {
78
+ childrenMap.get(child.parentBlockletId).push(processedChild);
79
+ }
80
+ });
81
+
82
+ return childrenMap;
83
+ }
84
+
59
85
  /**
60
86
  * Delete children by parent blocklet ID
61
87
  * @param {string} parentBlockletId - The parent blocklet ID
@@ -265,13 +265,13 @@ class BlockletState extends BaseState {
265
265
  * @param {string} blockletId - The blocklet ID
266
266
  * @returns {Promise<Array>} - Array of children
267
267
  */
268
- async loadChildren(blockletId) {
269
- if (!this.BlockletChildState || !blockletId) {
270
- return [];
271
- }
272
-
273
- const children = await this.BlockletChildState.getChildrenByParentId(blockletId);
274
- // Ensure children is always an array
268
+ /**
269
+ * Process raw children records into structured format
270
+ * @param {Array} children - Raw children records from database
271
+ * @param {string} parentBlockletId - The parent blocklet ID (for logging)
272
+ * @returns {Array} - Processed children array
273
+ */
274
+ _processLoadedChildren(children, parentBlockletId) {
275
275
  if (!Array.isArray(children)) {
276
276
  return [];
277
277
  }
@@ -280,17 +280,17 @@ class BlockletState extends BaseState {
280
280
  // Ensure meta is an object and has required fields
281
281
  const meta = child.meta || {};
282
282
  if (!meta.did) {
283
- logger.warn('loadChildren: child missing meta.did', { childId: child.id, parentBlockletId: blockletId });
283
+ logger.warn('loadChildren: child missing meta.did', { childId: child.id, parentBlockletId });
284
284
  }
285
285
  if (!meta.name && !meta.bundleName) {
286
286
  logger.warn('loadChildren: child missing meta.name and meta.bundleName', {
287
287
  childId: child.id,
288
288
  childDid: meta.did,
289
- parentBlockletId: blockletId,
289
+ parentBlockletId,
290
290
  });
291
291
  }
292
292
 
293
- const childObj = {
293
+ return {
294
294
  id: child.id,
295
295
  mountPoint: child.mountPoint,
296
296
  meta,
@@ -312,15 +312,16 @@ class BlockletState extends BaseState {
312
312
  greenStatus: child.greenStatus,
313
313
  greenPorts: child.greenPorts,
314
314
  };
315
+ });
316
+ }
315
317
 
316
- // Recursively load children for this child
317
- if (child.children && child.children.length > 0) {
318
- // Note: children array now contains IDs, need to load them
319
- // This will be handled by forEachComponentV2 or similar methods
320
- }
318
+ async loadChildren(blockletId) {
319
+ if (!this.BlockletChildState || !blockletId) {
320
+ return [];
321
+ }
321
322
 
322
- return childObj;
323
- });
323
+ const children = await this.BlockletChildState.getChildrenByParentId(blockletId);
324
+ return this._processLoadedChildren(children, blockletId);
324
325
  }
325
326
 
326
327
  /**
@@ -525,16 +526,23 @@ class BlockletState extends BaseState {
525
526
 
526
527
  async getBlocklets(query = {}, projection = {}, sort = { createdAt: -1 }) {
527
528
  const docs = await this.find(query, projection, sort);
528
- const result = [];
529
+ const validDocs = docs.filter(Boolean);
529
530
 
530
- for (const doc of docs.filter(Boolean)) {
531
- // Load children for each blocklet
532
- const children = await this.loadChildren(doc.id);
533
- doc.children = children;
534
- result.push(formatBlocklet(doc, 'onRead', this.config.dek));
531
+ if (validDocs.length === 0) {
532
+ return [];
535
533
  }
536
534
 
537
- return result;
535
+ // Batch load all children in a single query (instead of N+1 queries)
536
+ let childrenMap = new Map();
537
+ if (this.BlockletChildState) {
538
+ const blockletIds = validDocs.map((doc) => doc.id);
539
+ childrenMap = await this.BlockletChildState.getChildrenByParentIds(blockletIds);
540
+ }
541
+
542
+ return validDocs.map((doc) => {
543
+ doc.children = this._processLoadedChildren(childrenMap.get(doc.id) || [], doc.id);
544
+ return formatBlocklet(doc, 'onRead', this.config.dek);
545
+ });
538
546
  }
539
547
 
540
548
  async deleteBlocklet(did) {
@@ -903,12 +911,22 @@ class BlockletState extends BaseState {
903
911
  }
904
912
 
905
913
  async getServices() {
906
- const blocklets = await this.getBlocklets({}, { meta: 1, ports: 1 });
914
+ const blocklets = await this.getBlocklets({}, { id: 1, meta: 1, ports: 1 });
907
915
  const services = [];
908
916
 
909
917
  blocklets.forEach((blocklet) => {
910
918
  const list = getBlockletServices(blocklet);
911
919
  list.forEach((x) => {
920
+ // 如果本地 53 端口被系统占用,调试可以配置: export ABT_NODE_REDIRECTION_SERVICE_PORTS="53:10053,553:101553" 等多个 Service 端口重定向
921
+ if (process.env.ABT_NODE_REDIRECTION_SERVICE_PORTS) {
922
+ const redirectionPorts = process.env.ABT_NODE_REDIRECTION_SERVICE_PORTS.split(',');
923
+ redirectionPorts.forEach((portString) => {
924
+ const [portA, portB] = portString.split(':');
925
+ if (x.port === +portA) {
926
+ x.port = +portB;
927
+ }
928
+ });
929
+ }
912
930
  if (!x.port) {
913
931
  logger.error('Missing service port', { appId: blocklet.meta.did, x });
914
932
  return;
@@ -941,7 +959,7 @@ class BlockletState extends BaseState {
941
959
  * @return {Object} { <did> : { interfaceName } }
942
960
  */
943
961
  async groupAllInterfaces() {
944
- const blocklets = await this.getBlocklets({}, { meta: 1 });
962
+ const blocklets = await this.getBlocklets({}, { id: 1, meta: 1 });
945
963
  const result = {};
946
964
  const fillResult = (component, { id }) => {
947
965
  const { interfaces } = component.meta;
@@ -1201,7 +1219,7 @@ class BlockletState extends BaseState {
1201
1219
  }
1202
1220
 
1203
1221
  async _getOccupiedPorts() {
1204
- const blocklets = await this.getBlocklets({}, { port: 1, ports: 1, meta: 1 });
1222
+ const blocklets = await this.getBlocklets({}, { id: 1, port: 1, ports: 1, meta: 1 });
1205
1223
 
1206
1224
  const occupiedExternalPorts = new Map();
1207
1225
  const occupiedInternalPorts = new Map();
@@ -31,6 +31,7 @@ const { isValid: isValidDid, isEthereumDid } = require('@arcblock/did');
31
31
  const logger = require('@abtnode/logger')('@abtnode/core:util:blocklet');
32
32
  const pm2 = require('@abtnode/util/lib/pm2/async-pm2');
33
33
  const sleep = require('@abtnode/util/lib/sleep');
34
+ const { isCustomDomain } = require('@abtnode/util/lib/url-evaluation');
34
35
  const getPm2ProcessInfo = require('@abtnode/util/lib/get-pm2-process-info');
35
36
  const { formatEnv, getSecurityNodeOptions, decrypt } = require('@abtnode/util/lib/security');
36
37
  const ensureEndpointHealthy = require('@abtnode/util/lib/ensure-endpoint-healthy');
@@ -45,6 +46,7 @@ const {
45
46
  APP_STRUCT_VERSION,
46
47
  BLOCKLET_CACHE_TTL,
47
48
  AIGNE_CONFIG_ENCRYPT_SALT,
49
+ SLOT_FOR_IP_DNS_SITE,
48
50
  } = require('@abtnode/constant');
49
51
  const { BLOCKLET_THEME_LIGHT, BLOCKLET_THEME_DARK } = require('@blocklet/theme');
50
52
  const {
@@ -127,6 +129,7 @@ const {
127
129
  templateReplace,
128
130
  getServerDidDomain,
129
131
  APP_CONFIG_IMAGE_KEYS,
132
+ replaceDomainSlot,
130
133
  } = require('./index');
131
134
  const { installExternalDependencies } = require('./install-external-dependencies');
132
135
  const parseDockerOptionsFromPm2 = require('./docker/parse-docker-options-from-pm2');
@@ -135,6 +138,7 @@ const getDockerRuntimeInfo = require('./docker/get-docker-runtime-info');
135
138
  const parseDockerName = require('./docker/parse-docker-name');
136
139
  const { createDockerNetwork } = require('./docker/docker-network');
137
140
  const { ensureBun } = require('./ensure-bun');
141
+ const { getFromCache: getAccessibleExternalNodeIp } = require('./get-accessible-external-node-ip');
138
142
 
139
143
  /**
140
144
  * Get actual listening port from Docker container or process
@@ -2402,9 +2406,16 @@ const validateStore = (nodeInfo, storeUrl) => {
2402
2406
  return;
2403
2407
  }
2404
2408
 
2409
+ const storeUrlObj = new URL(storeUrl);
2410
+ const registerUrlObj = new URL(nodeInfo.registerUrl);
2411
+
2412
+ // 信任 Launcher 打包的应用
2413
+ if (registerUrlObj.host === storeUrlObj.host) {
2414
+ return;
2415
+ }
2416
+
2405
2417
  const inStoreList = nodeInfo.blockletRegistryList.find((item) => {
2406
2418
  const itemURLObj = new URL(item.url);
2407
- const storeUrlObj = new URL(storeUrl);
2408
2419
 
2409
2420
  return itemURLObj.host === storeUrlObj.host;
2410
2421
  });
@@ -2736,8 +2747,10 @@ const getSlpDid = (serverDid, appPid) => {
2736
2747
  };
2737
2748
 
2738
2749
  // eslint-disable-next-line require-await
2739
- const updateDidDocument = async ({ blocklet, nodeInfo }) => {
2750
+ const publishDidDocument = async ({ blocklet, ownerInfo, nodeInfo }) => {
2740
2751
  const alsoKnownAs = getBlockletKnownAs(blocklet);
2752
+ logger.debug('updateDidDocument blocklet info', { blocklet });
2753
+
2741
2754
  const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
2742
2755
  const { mode, did: serverDid } = nodeInfo;
2743
2756
 
@@ -2761,6 +2774,58 @@ const updateDidDocument = async ({ blocklet, nodeInfo }) => {
2761
2774
  slpDomain: nodeInfo.slpDomain,
2762
2775
  });
2763
2776
 
2777
+ const name = blocklet.meta?.title || blocklet.meta?.name;
2778
+ const state = fromBlockletStatus(blocklet.status || BlockletStatus.stopped);
2779
+
2780
+ let launcher = null;
2781
+ if (!isEmpty(blocklet.controller)) {
2782
+ launcher = {
2783
+ did: toDid(blocklet.controller.did || nodeInfo.registerInfo.appPid), // 目前 controller 没有 launcher 的元信息, 默认在 nodeInfo 中存储
2784
+ name: blocklet.controller.launcherName || nodeInfo.registerInfo.appName || '',
2785
+ url: blocklet.controller.launcherUrl || nodeInfo.registerInfo.appUrl || '',
2786
+ userDid: toDid(blocklet.controller.nftOwner),
2787
+ };
2788
+ }
2789
+
2790
+ const isPrimaryDomain = (d) => {
2791
+ const appUrl = blocklet.environments.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_URL)?.value;
2792
+ try {
2793
+ const url = new URL(appUrl);
2794
+ return url.hostname === d;
2795
+ } catch (error) {
2796
+ logger.error('failed to get primary domain', { error, domain: d, appUrl });
2797
+ return false;
2798
+ }
2799
+ };
2800
+
2801
+ const domains = await Promise.all(
2802
+ blocklet.site.domainAliases.map(async (item) => {
2803
+ let type = isCustomDomain(item.value) ? 'custom' : 'internal';
2804
+ // 如果域名是 appUrl,则设置为 primary
2805
+ if (isPrimaryDomain(item.value)) {
2806
+ type = 'primary';
2807
+ }
2808
+
2809
+ if (item.value.includes(SLOT_FOR_IP_DNS_SITE)) {
2810
+ const nodeIp = await getAccessibleExternalNodeIp();
2811
+ item.value = replaceDomainSlot({ domain: item.value, nodeIp });
2812
+ }
2813
+
2814
+ return {
2815
+ type,
2816
+ host: item.value,
2817
+ url: `https://${item.value}`,
2818
+ source: 'dnsRecords', // 固定为 dnsRecords
2819
+ };
2820
+ })
2821
+ );
2822
+
2823
+ const owner = {
2824
+ did: toDid(ownerInfo.did),
2825
+ name: ownerInfo.fullName,
2826
+ avatar: ownerInfo.avatar,
2827
+ };
2828
+
2764
2829
  return didDocument.updateBlockletDocument({
2765
2830
  blocklet,
2766
2831
  wallet,
@@ -2772,6 +2837,56 @@ const updateDidDocument = async ({ blocklet, nodeInfo }) => {
2772
2837
  slpDomain: nodeInfo.slpDomain,
2773
2838
  serverDid,
2774
2839
  blockletServerVersion: nodeInfo.version,
2840
+ name,
2841
+ state,
2842
+ owner,
2843
+ launcher,
2844
+ domains,
2845
+ });
2846
+ };
2847
+
2848
+ const updateDidDocument = async ({ did, status, nodeInfo, teamManager, states }) => {
2849
+ const blocklet = await states.blocklet.getBlocklet(did);
2850
+ const blockletExtra = await states.blockletExtras.findOne({ did });
2851
+
2852
+ blocklet.site = await states.site.findOneByBlocklet(did);
2853
+ blocklet.settings = await states.blockletExtras.getSettings(did);
2854
+ blocklet.controller = blockletExtra.controller;
2855
+
2856
+ logger.debug('update did document', { blocklet });
2857
+
2858
+ if (isEmpty(blocklet.status)) {
2859
+ blocklet.status = status;
2860
+ }
2861
+
2862
+ const ownerDid = blocklet.settings.owner.did;
2863
+ logger.info('get owner info', { ownerDid, teamDid: blocklet.appPid });
2864
+ const userState = await teamManager.getUserState(blocklet.appPid);
2865
+ const ownerInfo = await userState.getUser(ownerDid);
2866
+
2867
+ logger.info('got user info', {
2868
+ owner: ownerInfo,
2869
+ blockletDid: blocklet.meta.did,
2870
+ ownerDid,
2871
+ teamDid: blocklet.appPid,
2872
+ });
2873
+
2874
+ return publishDidDocument({ blocklet, ownerInfo, nodeInfo });
2875
+ };
2876
+
2877
+ // Update DID document state only (e.g., to 'deleted') without fetching from database
2878
+ // Used when blocklet is being removed and database data may not be available
2879
+ const updateDidDocumentStateOnly = ({ did, blocklet, state, nodeInfo }) => {
2880
+ logger.debug('update did document state only', { did, state });
2881
+
2882
+ const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
2883
+
2884
+ return didDocument.updateBlockletStateOnly({
2885
+ did,
2886
+ state,
2887
+ didRegistryUrl: nodeInfo.didRegistry,
2888
+ wallet,
2889
+ blockletServerVersion: nodeInfo.version,
2775
2890
  });
2776
2891
  };
2777
2892
 
@@ -2983,7 +3098,9 @@ module.exports = {
2983
3098
  getBlockletURLForLauncher,
2984
3099
  ensureAppPortsNotOccupied,
2985
3100
  getComponentNamesWithVersion,
3101
+ publishDidDocument,
2986
3102
  updateDidDocument,
3103
+ updateDidDocumentStateOnly,
2987
3104
  getSlpDid,
2988
3105
  shouldEnableSlpDomain,
2989
3106
  getAppConfigsFromComponent,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.17.6-beta-20251216-223535-283b9ffe",
6
+ "version": "1.17.6-beta-20251217-144034-62fafb94",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -17,21 +17,21 @@
17
17
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
18
18
  "license": "Apache-2.0",
19
19
  "dependencies": {
20
- "@abtnode/analytics": "1.17.6-beta-20251216-223535-283b9ffe",
21
- "@abtnode/auth": "1.17.6-beta-20251216-223535-283b9ffe",
22
- "@abtnode/certificate-manager": "1.17.6-beta-20251216-223535-283b9ffe",
23
- "@abtnode/constant": "1.17.6-beta-20251216-223535-283b9ffe",
24
- "@abtnode/cron": "1.17.6-beta-20251216-223535-283b9ffe",
25
- "@abtnode/db-cache": "1.17.6-beta-20251216-223535-283b9ffe",
26
- "@abtnode/docker-utils": "1.17.6-beta-20251216-223535-283b9ffe",
27
- "@abtnode/logger": "1.17.6-beta-20251216-223535-283b9ffe",
28
- "@abtnode/models": "1.17.6-beta-20251216-223535-283b9ffe",
29
- "@abtnode/queue": "1.17.6-beta-20251216-223535-283b9ffe",
30
- "@abtnode/rbac": "1.17.6-beta-20251216-223535-283b9ffe",
31
- "@abtnode/router-provider": "1.17.6-beta-20251216-223535-283b9ffe",
32
- "@abtnode/static-server": "1.17.6-beta-20251216-223535-283b9ffe",
33
- "@abtnode/timemachine": "1.17.6-beta-20251216-223535-283b9ffe",
34
- "@abtnode/util": "1.17.6-beta-20251216-223535-283b9ffe",
20
+ "@abtnode/analytics": "1.17.6-beta-20251217-144034-62fafb94",
21
+ "@abtnode/auth": "1.17.6-beta-20251217-144034-62fafb94",
22
+ "@abtnode/certificate-manager": "1.17.6-beta-20251217-144034-62fafb94",
23
+ "@abtnode/constant": "1.17.6-beta-20251217-144034-62fafb94",
24
+ "@abtnode/cron": "1.17.6-beta-20251217-144034-62fafb94",
25
+ "@abtnode/db-cache": "1.17.6-beta-20251217-144034-62fafb94",
26
+ "@abtnode/docker-utils": "1.17.6-beta-20251217-144034-62fafb94",
27
+ "@abtnode/logger": "1.17.6-beta-20251217-144034-62fafb94",
28
+ "@abtnode/models": "1.17.6-beta-20251217-144034-62fafb94",
29
+ "@abtnode/queue": "1.17.6-beta-20251217-144034-62fafb94",
30
+ "@abtnode/rbac": "1.17.6-beta-20251217-144034-62fafb94",
31
+ "@abtnode/router-provider": "1.17.6-beta-20251217-144034-62fafb94",
32
+ "@abtnode/static-server": "1.17.6-beta-20251217-144034-62fafb94",
33
+ "@abtnode/timemachine": "1.17.6-beta-20251217-144034-62fafb94",
34
+ "@abtnode/util": "1.17.6-beta-20251217-144034-62fafb94",
35
35
  "@aigne/aigne-hub": "^0.10.15",
36
36
  "@arcblock/did": "^1.27.15",
37
37
  "@arcblock/did-connect-js": "^1.27.15",
@@ -43,15 +43,15 @@
43
43
  "@arcblock/pm2-events": "^0.0.5",
44
44
  "@arcblock/validator": "^1.27.15",
45
45
  "@arcblock/vc": "^1.27.15",
46
- "@blocklet/constant": "1.17.6-beta-20251216-223535-283b9ffe",
46
+ "@blocklet/constant": "1.17.6-beta-20251217-144034-62fafb94",
47
47
  "@blocklet/did-space-js": "^1.2.10",
48
- "@blocklet/env": "1.17.6-beta-20251216-223535-283b9ffe",
48
+ "@blocklet/env": "1.17.6-beta-20251217-144034-62fafb94",
49
49
  "@blocklet/error": "^0.3.5",
50
- "@blocklet/meta": "1.17.6-beta-20251216-223535-283b9ffe",
51
- "@blocklet/resolver": "1.17.6-beta-20251216-223535-283b9ffe",
52
- "@blocklet/sdk": "1.17.6-beta-20251216-223535-283b9ffe",
53
- "@blocklet/server-js": "1.17.6-beta-20251216-223535-283b9ffe",
54
- "@blocklet/store": "1.17.6-beta-20251216-223535-283b9ffe",
50
+ "@blocklet/meta": "1.17.6-beta-20251217-144034-62fafb94",
51
+ "@blocklet/resolver": "1.17.6-beta-20251217-144034-62fafb94",
52
+ "@blocklet/sdk": "1.17.6-beta-20251217-144034-62fafb94",
53
+ "@blocklet/server-js": "1.17.6-beta-20251217-144034-62fafb94",
54
+ "@blocklet/store": "1.17.6-beta-20251217-144034-62fafb94",
55
55
  "@blocklet/theme": "^3.2.14",
56
56
  "@fidm/x509": "^1.2.1",
57
57
  "@ocap/mcrypto": "^1.27.15",
@@ -116,5 +116,5 @@
116
116
  "express": "^4.18.2",
117
117
  "unzipper": "^0.10.11"
118
118
  },
119
- "gitHead": "00f2aa2d19ce17e3e15b8ab7a200830f633e9030"
119
+ "gitHead": "9f47bf4e66af87c562f846e5470f45491506ab36"
120
120
  }