@abtnode/core 1.16.35 → 1.16.37-beta-20241224-013714-a79db7d3

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.
package/lib/api/team.js CHANGED
@@ -1517,23 +1517,48 @@ class TeamAPI extends EventEmitter {
1517
1517
  return this.teamManager.updateStoreList(teamDid, storeList);
1518
1518
  }
1519
1519
 
1520
+ getNotificationReceivers(payload) {
1521
+ return this.teamManager.getNotificationReceivers(payload);
1522
+ }
1523
+
1520
1524
  createNotification = (payload) => {
1521
1525
  return this.teamManager.createNotification(payload);
1522
1526
  };
1523
1527
 
1524
- async getNotification({ teamDid, ...rest }) {
1528
+ async getNotification({ teamDid, ...rest }, context) {
1525
1529
  const notificationState = await this.getNotificationState(teamDid);
1526
- return notificationState.findPaginated({ teamDid, ...rest });
1530
+ return notificationState.findPaginated({ teamDid, ...rest }, context);
1527
1531
  }
1528
1532
 
1529
- async readNotifications({ teamDid, ...rest }) {
1533
+ async getNotificationById({ teamDid, id }) {
1530
1534
  const notificationState = await this.getNotificationState(teamDid);
1531
- return notificationState.read({ teamDid, ...rest });
1535
+ const notification = await notificationState.findNotification({ id });
1536
+ return notification;
1537
+ }
1538
+
1539
+ async getBlockletNotificationsUnreadCount({ teamDid, receiver }) {
1540
+ const notificationReceiverState = await this.getNotificationReceiverState(teamDid);
1541
+ return notificationReceiverState.getUnreadCount({ receiver });
1532
1542
  }
1533
1543
 
1534
- async unreadNotifications({ teamDid, ...rest }) {
1544
+ async markAllBlockletNotificationsAsRead({ teamDid, receiver }) {
1545
+ const notificationReceiverState = await this.getNotificationReceiverState(teamDid);
1546
+ return notificationReceiverState.makeAllAsRead({ receiver });
1547
+ }
1548
+
1549
+ async updateBlockletNotificationStatus({ teamDid, receivers, notificationId, updates }) {
1550
+ const notificationReceiverState = await this.getNotificationReceiverState(teamDid);
1551
+ return notificationReceiverState.updateStatus({ receivers, notificationId, updates });
1552
+ }
1553
+
1554
+ async readNotifications({ teamDid, ...rest }, context) {
1555
+ const notificationState = await this.getNotificationState(teamDid);
1556
+ return notificationState.read({ teamDid, ...rest }, context);
1557
+ }
1558
+
1559
+ async unreadNotifications({ teamDid, ...rest }, context) {
1535
1560
  const notificationState = await this.getNotificationState(teamDid);
1536
- return notificationState.unread({ teamDid, ...rest });
1561
+ return notificationState.unread({ teamDid, ...rest }, context);
1537
1562
  }
1538
1563
 
1539
1564
  // =======
@@ -1565,7 +1590,11 @@ class TeamAPI extends EventEmitter {
1565
1590
  }
1566
1591
 
1567
1592
  getNotificationState(did) {
1568
- return this.teamManager.getNotification(did);
1593
+ return this.teamManager.getNotificationState(did);
1594
+ }
1595
+
1596
+ getNotificationReceiverState(did) {
1597
+ return this.teamManager.getNotificationReceiverState(did);
1569
1598
  }
1570
1599
 
1571
1600
  // =============
@@ -36,6 +36,7 @@ const {
36
36
  FEDERATED,
37
37
  CHECK_UPDATE,
38
38
  SESSION_CACHE_TTL,
39
+ ROLES,
39
40
  } = require('@abtnode/constant');
40
41
 
41
42
  const { getBlockletEngine } = require('@blocklet/meta/lib/engine');
@@ -640,7 +641,7 @@ class DiskBlockletManager extends BaseBlockletManager {
640
641
  if (!blocklet.children) {
641
642
  return componentDids;
642
643
  }
643
- const targetDid = !inputComponentDids?.length ? componentDids[0] : inputComponentDids[0];
644
+ const targetDid = !inputComponentDids?.length ? componentDids?.[0] : inputComponentDids[0];
644
645
 
645
646
  const canStartStatus = {
646
647
  [BlockletStatus.installed]: true,
@@ -877,6 +878,7 @@ class DiskBlockletManager extends BaseBlockletManager {
877
878
  entityType: 'blocklet',
878
879
  entityId: did,
879
880
  severity: 'error',
881
+ componentDid: componentDids?.[0],
880
882
  });
881
883
 
882
884
  await this.deleteProcess({ did, componentDids });
@@ -984,6 +986,7 @@ class DiskBlockletManager extends BaseBlockletManager {
984
986
  entityType: 'blocklet',
985
987
  entityId: did,
986
988
  severity: 'success',
989
+ componentDid: componentDids?.[0],
987
990
  });
988
991
 
989
992
  return res;
@@ -1080,6 +1083,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1080
1083
  entityType: 'blocklet',
1081
1084
  entityId: did,
1082
1085
  severity: 'error',
1086
+ componentDid: componentDids?.[0],
1083
1087
  });
1084
1088
  });
1085
1089
 
@@ -1168,6 +1172,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1168
1172
  entityType: 'blocklet',
1169
1173
  entityId: doc.meta.did,
1170
1174
  severity: 'success',
1175
+ componentDid: did,
1171
1176
  });
1172
1177
  return doc;
1173
1178
  } catch (error) {
@@ -1181,6 +1186,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1181
1186
  entityType: 'blocklet',
1182
1187
  entityId: doc.meta.did,
1183
1188
  severity: 'success',
1189
+ componentDid: did,
1184
1190
  });
1185
1191
 
1186
1192
  return doc;
@@ -1371,6 +1377,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1371
1377
  severity: 'success',
1372
1378
  action: `/blocklets/${newBlocklet.meta.did}/components`,
1373
1379
  blockletDashboardAction: '/.well-known/service/admin/components',
1380
+ componentDid: child.meta.did,
1374
1381
  });
1375
1382
 
1376
1383
  this.emit(BlockletEvents.componentRemoved, {
@@ -2734,6 +2741,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2734
2741
  entityType: 'blocklet',
2735
2742
  entityId: did,
2736
2743
  severity: 'error',
2744
+ componentDid: childrenToDownload[0]?.meta.did,
2737
2745
  });
2738
2746
 
2739
2747
  // rollback on download failed
@@ -2916,6 +2924,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2916
2924
  entityType: 'blocklet',
2917
2925
  entityId: did,
2918
2926
  severity: 'success',
2927
+ componentDid: componentDids?.[0],
2919
2928
  });
2920
2929
 
2921
2930
  launcher.notifyBlockletUpdated(blocklet);
@@ -2946,6 +2955,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2946
2955
  entityType: 'blocklet',
2947
2956
  entityId: did,
2948
2957
  severity: 'error',
2958
+ componentDid: componentDids?.[0],
2949
2959
  });
2950
2960
 
2951
2961
  this.emit(BlockletEvents.startFailed, { ...doc, componentDids, error: { message: error.message } });
@@ -3164,6 +3174,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3164
3174
  if (!list || !list.updateList?.length) {
3165
3175
  return;
3166
3176
  }
3177
+ const componentDids = list.updateList.map((item) => item.meta.did);
3167
3178
  const updateList = list.updateList.map((item) => {
3168
3179
  return { title: item.meta.title, description: item.meta.description, version: item.meta.version };
3169
3180
  });
@@ -3240,6 +3251,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3240
3251
  appSk: wallet.secretKey,
3241
3252
  },
3242
3253
  users,
3254
+ componentDids,
3243
3255
  });
3244
3256
  await states.blockletExtras.setSettings(did, { checkUpdateMd5 });
3245
3257
  } catch (err) {
@@ -3280,20 +3292,10 @@ class DiskBlockletManager extends BaseBlockletManager {
3280
3292
  * blockletDashboardAction: string,
3281
3293
  * sender: { appDid: string, appSk: string },
3282
3294
  * users: Array<{ did: string, locale: string }>
3295
+ * componentDids: Array<string>
3283
3296
  * */
3284
- async _sendAllMessageToUser({
3285
- did,
3286
- blocklet,
3287
- title,
3288
- body,
3289
- button,
3290
- description,
3291
- attachments,
3292
- action,
3293
- blockletDashboardAction,
3294
- sender,
3295
- users,
3296
- }) {
3297
+ _sendAllMessageToUser({ did, title, description, action, blockletDashboardAction, componentDids }) {
3298
+ // 这个方法会向用户发送消息
3297
3299
  this._createNotification(did, {
3298
3300
  title: title.en,
3299
3301
  description: description.en,
@@ -3302,50 +3304,52 @@ class DiskBlockletManager extends BaseBlockletManager {
3302
3304
  severity: 'success',
3303
3305
  action,
3304
3306
  blockletDashboardAction,
3307
+ componentDid: componentDids?.[0],
3305
3308
  });
3306
3309
 
3307
- const zhUsers = users.filter((x) => x.locale === 'zh');
3308
- const enUsers = users.filter((x) => x.locale !== 'zh');
3309
- const url = `http://${getDidDomainForBlocklet({
3310
- did: blocklet.appPid,
3311
- })}`;
3312
- const link = `${url}${blockletDashboardAction}`;
3310
+ // _createNotification 会将消息通过 sendToUser 发送
3311
+ // const zhUsers = users.filter((x) => x.locale === 'zh');
3312
+ // const enUsers = users.filter((x) => x.locale !== 'zh');
3313
+ // const url = `http://${getDidDomainForBlocklet({
3314
+ // did: blocklet.appPid,
3315
+ // })}`;
3316
+ // const link = `${url}${blockletDashboardAction}`;
3313
3317
 
3314
3318
  // send in batches by language
3315
- if (zhUsers.length) {
3316
- await sendToUser(
3317
- zhUsers.map((x) => x.did),
3318
- {
3319
- title: title.zh,
3320
- body: body.zh,
3321
- attachments,
3322
- actions: [
3323
- {
3324
- name: button.zh,
3325
- link,
3326
- },
3327
- ],
3328
- },
3329
- sender
3330
- );
3331
- }
3332
- if (enUsers.length) {
3333
- await sendToUser(
3334
- enUsers.map((x) => x.did),
3335
- {
3336
- title: title.en,
3337
- body: body.en,
3338
- attachments,
3339
- actions: [
3340
- {
3341
- name: button.en,
3342
- link,
3343
- },
3344
- ],
3345
- },
3346
- sender
3347
- );
3348
- }
3319
+ // if (zhUsers.length) {
3320
+ // await sendToUser(
3321
+ // zhUsers.map((x) => x.did),
3322
+ // {
3323
+ // title: title.zh,
3324
+ // body: body.zh,
3325
+ // attachments,
3326
+ // actions: [
3327
+ // {
3328
+ // name: button.zh,
3329
+ // link,
3330
+ // },
3331
+ // ],
3332
+ // },
3333
+ // sender
3334
+ // );
3335
+ // }
3336
+ // if (enUsers.length) {
3337
+ // await sendToUser(
3338
+ // enUsers.map((x) => x.did),
3339
+ // {
3340
+ // title: title.en,
3341
+ // body: body.en,
3342
+ // attachments,
3343
+ // actions: [
3344
+ // {
3345
+ // name: button.en,
3346
+ // link,
3347
+ // },
3348
+ // ],
3349
+ // },
3350
+ // sender
3351
+ // );
3352
+ // }
3349
3353
  }
3350
3354
 
3351
3355
  async getBlockletEnvironments(did) {
@@ -3757,6 +3761,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3757
3761
  entityId: did,
3758
3762
  severity: 'success',
3759
3763
  extra: { wallet: walletExtra },
3764
+ componentDid: meta.did,
3760
3765
  });
3761
3766
  } catch (error) {
3762
3767
  logger.error('create installed notification failed', { error, did });
@@ -3784,6 +3789,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3784
3789
  entityType: 'blocklet',
3785
3790
  entityId: did,
3786
3791
  severity: 'error',
3792
+ componentDid: meta.did,
3787
3793
  });
3788
3794
  } catch (e) {
3789
3795
  logger.error('failed to remove blocklet on install error', { did: meta.did, error: e });
@@ -3997,6 +4003,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3997
4003
  entityType: 'blocklet',
3998
4004
  entityId: did,
3999
4005
  severity: 'success',
4006
+ componentDid: componentDids?.[0],
4000
4007
  });
4001
4008
  } catch (error) {
4002
4009
  logger.error('emit upgrade notification failed', { name, version, error });
@@ -4046,6 +4053,7 @@ class DiskBlockletManager extends BaseBlockletManager {
4046
4053
  entityType: 'blocklet',
4047
4054
  entityId: did,
4048
4055
  severity: 'error',
4056
+ componentDid: componentDids?.[0],
4049
4057
  });
4050
4058
  throw err;
4051
4059
  }
@@ -4342,15 +4350,26 @@ class DiskBlockletManager extends BaseBlockletManager {
4342
4350
  await forEachBlocklet(blocklet, hookFn, { parallel: true, concurrencyLimit: 4 });
4343
4351
  }
4344
4352
 
4353
+ async getReceiverDids(teamDid) {
4354
+ const receivers = await this.teamAPI.getNotificationReceivers({
4355
+ teamDid,
4356
+ roles: [ROLES.ADMIN, ROLES.OWNER],
4357
+ selection: { did: 1 },
4358
+ });
4359
+ return receivers.map((r) => r.did);
4360
+ }
4361
+
4362
+ // 目前:Blocklet 的安装消息都会聚合在这里。
4345
4363
  async _createNotification(did, notification) {
4346
4364
  if (isCLI()) {
4347
- return;
4365
+ return undefined;
4348
4366
  }
4349
4367
 
4350
4368
  try {
4351
4369
  let blockletUrl;
4370
+ let blocklet;
4352
4371
  try {
4353
- const blocklet = await this.getBlocklet(did);
4372
+ blocklet = await this.getBlocklet(did);
4354
4373
  if (blocklet) {
4355
4374
  const urls = blocklet.site?.domainAliases || [];
4356
4375
  const customUrl = urls.find((x) => !x.isProtected)?.value;
@@ -4367,16 +4386,34 @@ class DiskBlockletManager extends BaseBlockletManager {
4367
4386
  const isExternal = !!extra?.controller;
4368
4387
 
4369
4388
  if (!isExternal) {
4370
- await states.notification.create({ ...notification, blockletUrl });
4389
+ // notification 信息保存在 server 中
4390
+ const serverReceivers = await this.getReceiverDids(this.teamManager.nodeDid);
4391
+ await states.notification.create({
4392
+ ...notification,
4393
+ blockletUrl,
4394
+ receiver: serverReceivers,
4395
+ sender: did,
4396
+ source: 'system',
4397
+ });
4371
4398
  }
4372
- await this.teamManager.createNotification({
4373
- teamDid: did,
4374
- ...notification,
4375
- action: notification.blockletDashboardAction || notification.action,
4376
- blockletUrl,
4377
- });
4399
+
4400
+ if (blocklet) {
4401
+ const blockletReceivers = await this.getReceiverDids(did);
4402
+ const doc = await this.teamManager.createNotification({
4403
+ teamDid: did,
4404
+ ...notification,
4405
+ action: notification.blockletDashboardAction || notification.action,
4406
+ blockletUrl,
4407
+ sender: did,
4408
+ source: 'system',
4409
+ receiver: blockletReceivers,
4410
+ });
4411
+ return doc;
4412
+ }
4413
+ return undefined;
4378
4414
  } catch (error) {
4379
4415
  logger.error('create notification failed', { did, error });
4416
+ return undefined;
4380
4417
  }
4381
4418
  }
4382
4419
 
@@ -272,6 +272,7 @@ const installApplicationFromBackup = async ({
272
272
  entityType: 'blocklet',
273
273
  entityId: did,
274
274
  severity: 'error',
275
+ componentDid: blockletState?.meta?.did,
275
276
  });
276
277
  });
277
278
 
@@ -132,6 +132,7 @@ const installApplicationFromGeneral = async ({
132
132
  entityType: 'blocklet',
133
133
  entityId: did,
134
134
  severity: 'error',
135
+ componentDid,
135
136
  });
136
137
 
137
138
  throw err;
@@ -187,6 +188,7 @@ const installApplicationFromGeneral = async ({
187
188
  entityType: 'blocklet',
188
189
  entityId: did,
189
190
  severity: 'error',
191
+ componentDid,
190
192
  });
191
193
  });
192
194
  }, delay || 0);
@@ -206,6 +206,7 @@ const installComponentFromUrl = async ({
206
206
  entityType: 'blocklet',
207
207
  entityId: rootDid,
208
208
  severity: 'error',
209
+ componentDid: componentDids[0],
209
210
  });
210
211
  });
211
212
  return newBlocklet;
@@ -167,6 +167,7 @@ const upgrade = async ({ updateId, componentDids, context, states, manager }) =>
167
167
  entityType: 'blocklet',
168
168
  entityId: did,
169
169
  severity: 'error',
170
+ componentDid: componentDids[0],
170
171
  });
171
172
  });
172
173
 
@@ -610,6 +610,8 @@ module.exports = Object.freeze({
610
610
  STORE_DETAIL_PAGE_PATH_PREFIX: '/blocklets',
611
611
 
612
612
  MAX_USER_PAGE_SIZE: 100,
613
+ // 默认最大 page size
614
+ MAX_PAGE_SIZE: 100,
613
615
 
614
616
  SERVER_STATUS: {
615
617
  RUNNING: 1,
@@ -38551,7 +38553,7 @@ module.exports = require("zlib");
38551
38553
  /***/ ((module) => {
38552
38554
 
38553
38555
  "use strict";
38554
- module.exports = JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.33","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.33","@abtnode/auth":"1.16.33","@abtnode/certificate-manager":"1.16.33","@abtnode/constant":"1.16.33","@abtnode/cron":"1.16.33","@abtnode/logger":"1.16.33","@abtnode/models":"1.16.33","@abtnode/queue":"1.16.33","@abtnode/rbac":"1.16.33","@abtnode/router-provider":"1.16.33","@abtnode/static-server":"1.16.33","@abtnode/timemachine":"1.16.33","@abtnode/util":"1.16.33","@arcblock/did":"1.18.162","@arcblock/did-auth":"1.18.162","@arcblock/did-ext":"^1.18.162","@arcblock/did-motif":"^1.1.13","@arcblock/did-util":"1.18.162","@arcblock/event-hub":"1.18.162","@arcblock/jwt":"^1.18.162","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"^1.18.162","@arcblock/vc":"1.18.162","@blocklet/constant":"1.16.33","@blocklet/did-space-js":"^0.5.82","@blocklet/env":"1.16.33","@blocklet/meta":"1.16.33","@blocklet/resolver":"1.16.33","@blocklet/sdk":"1.16.33","@blocklet/store":"1.16.33","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.18.162","@ocap/util":"1.18.162","@ocap/wallet":"1.18.162","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.5","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","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-url":"^1.2.4","is-ip":"3","is-cidr":"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","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","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"}');
38556
+ module.exports = JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.36","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.36","@abtnode/auth":"1.16.36","@abtnode/certificate-manager":"1.16.36","@abtnode/constant":"1.16.36","@abtnode/cron":"1.16.36","@abtnode/logger":"1.16.36","@abtnode/models":"1.16.36","@abtnode/queue":"1.16.36","@abtnode/rbac":"1.16.36","@abtnode/router-provider":"1.16.36","@abtnode/static-server":"1.16.36","@abtnode/timemachine":"1.16.36","@abtnode/util":"1.16.36","@arcblock/did":"1.18.162","@arcblock/did-auth":"1.18.162","@arcblock/did-ext":"^1.18.162","@arcblock/did-motif":"^1.1.13","@arcblock/did-util":"1.18.162","@arcblock/event-hub":"1.18.162","@arcblock/jwt":"^1.18.162","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"^1.18.162","@arcblock/vc":"1.18.162","@blocklet/constant":"1.16.36","@blocklet/did-space-js":"^0.6.0","@blocklet/env":"1.16.36","@blocklet/meta":"1.16.36","@blocklet/resolver":"1.16.36","@blocklet/sdk":"1.16.36","@blocklet/store":"1.16.36","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.18.162","@ocap/util":"1.18.162","@ocap/wallet":"1.18.162","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.5","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","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","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","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"}');
38555
38557
 
38556
38558
  /***/ }),
38557
38559
 
package/lib/index.js CHANGED
@@ -537,17 +537,27 @@ function ABTNode(options) {
537
537
  addBlockletStore: teamAPI.addStore.bind(teamAPI),
538
538
  deleteBlockletStore: teamAPI.deleteStore.bind(teamAPI),
539
539
 
540
+ getNotificationReceivers: teamAPI.getNotificationReceivers.bind(teamAPI),
541
+
540
542
  // Notifications
541
543
  createNotification: states.notification.create.bind(states.notification),
542
544
  getNotifications: states.notification.findPaginated.bind(states.notification),
543
545
  readNotifications: states.notification.read.bind(states.notification),
544
546
  unreadNotifications: states.notification.unread.bind(states.notification),
547
+ getNotificationById: states.notification.findNotification.bind(states.notification),
548
+ getNotificationsUnreadCount: states.notificationReceiver.getUnreadCount.bind(states.notificationReceiver),
549
+ makeAllAsRead: states.notificationReceiver.makeAllAsRead.bind(states.notificationReceiver),
550
+ updateNotificationStatus: states.notificationReceiver.updateStatus.bind(states.notificationReceiver),
545
551
 
546
552
  // Blocklet Notifications
547
553
  createBlockletNotification: teamAPI.createNotification.bind(teamAPI),
548
554
  getBlockletNotifications: teamAPI.getNotification.bind(teamAPI),
549
555
  readBlockletNotifications: teamAPI.readNotifications.bind(teamAPI),
550
556
  unreadBlockletNotifications: teamAPI.unreadNotifications.bind(teamAPI),
557
+ getBlockletNotificationById: teamAPI.getNotificationById.bind(teamAPI),
558
+ getBlockletNotificationsUnreadCount: teamAPI.getBlockletNotificationsUnreadCount.bind(teamAPI),
559
+ makeAllBlockletNotificationsAsRead: teamAPI.markAllBlockletNotificationsAsRead.bind(teamAPI),
560
+ updateBlockletNotificationStatus: teamAPI.updateBlockletNotificationStatus.bind(teamAPI),
551
561
 
552
562
  // AuditLog
553
563
  createAuditLog: (params) => states.auditLog.create(params, instance),
@@ -5,6 +5,7 @@ const logger = require('@abtnode/logger')('@abtnode/core:states');
5
5
  const NodeState = require('./node');
6
6
  const BlockletState = require('./blocklet');
7
7
  const NotificationState = require('./notification');
8
+ const NotificationReceiverState = require('./notification-receiver');
8
9
  const SiteState = require('./site');
9
10
  const AccessKeyState = require('./access-key');
10
11
  const WebhookState = require('./webhook');
@@ -29,6 +30,12 @@ const init = (dataDirs, config = {}) => {
29
30
  logger.info(`Init server states in ${dbPath}`);
30
31
 
31
32
  const notificationState = new NotificationState(models.Notification, config);
33
+ const notificationReceiverState = new NotificationReceiverState(models.NotificationReceivers, config);
34
+
35
+ // bind notification model
36
+ notificationState.setNotificationReceiversState(notificationReceiverState);
37
+ notificationReceiverState.setNotificationState(notificationState);
38
+
32
39
  const nodeState = new NodeState(models.Server, config, dataDirs, notificationState);
33
40
  const blockletState = new BlockletState(models.Blocklet, config);
34
41
  const siteState = new SiteState(models.Site, config);
@@ -48,6 +55,7 @@ const init = (dataDirs, config = {}) => {
48
55
  node: nodeState,
49
56
  blocklet: blockletState,
50
57
  notification: notificationState,
58
+ notificationReceiver: notificationReceiverState,
51
59
  site: siteState,
52
60
  accessKey: accessKeyState,
53
61
  webhook: webhookState,
@@ -68,6 +76,7 @@ const init = (dataDirs, config = {}) => {
68
76
  * blocklet: import('./blocklet'),
69
77
  * blockletExtras: import('./blocklet-extras'),
70
78
  * notification: import('./notification'),
79
+ * notificationReceiver: import('./notification-receiver'),
71
80
  * job: import('./job'),
72
81
  * node: import('./node'),
73
82
  * [key: string]: any
@@ -0,0 +1,59 @@
1
+ const logger = require('@abtnode/logger')('@abtnode/core:states:notification');
2
+ const BaseState = require('./base');
3
+
4
+ /**
5
+ * @extends BaseState<import('@abtnode/models').NotificationReceiverState>
6
+ */
7
+ class NotificationReceiverState extends BaseState {
8
+ constructor(baseDir, config = {}) {
9
+ super(baseDir, { ...config });
10
+
11
+ this.defaultReceiver = config.defaultReceiver || '';
12
+ this.notificationState = config.notificationState;
13
+ }
14
+
15
+ setNotificationState(state) {
16
+ this.notificationState = state;
17
+ }
18
+
19
+ getNotificationState() {
20
+ return this.notificationState;
21
+ }
22
+
23
+ // 更新消息状态
24
+ async updateStatus({ notificationId, receivers, updates }) {
25
+ if (!notificationId || !receivers.length) {
26
+ logger.error('notification is not exist', notificationId, receivers);
27
+ }
28
+ const [numAffected] = await this.update({ receiver: { $in: receivers }, notificationId }, { $set: { ...updates } });
29
+ return numAffected;
30
+ }
31
+
32
+ /**
33
+ * 获取当前用户未读消息数量
34
+ */
35
+ async getUnreadCount({ receiver }) {
36
+ if (!receiver) {
37
+ logger.error('receiver is not as empty');
38
+ }
39
+
40
+ const count = await this.count({
41
+ receiver,
42
+ read: false,
43
+ });
44
+ return count;
45
+ }
46
+
47
+ /**
48
+ * 将当前用户所有消息标记为已读
49
+ */
50
+ async makeAllAsRead({ receiver }) {
51
+ if (!receiver) {
52
+ logger.error('receiver is not as empty');
53
+ }
54
+ const [numAffected] = await this.update({ receiver }, { $set: { read: true } });
55
+ return numAffected;
56
+ }
57
+ }
58
+
59
+ module.exports = NotificationReceiverState;
@@ -1,8 +1,29 @@
1
1
  const logger = require('@abtnode/logger')('@abtnode/core:states:notification');
2
2
  const { EVENTS } = require('@abtnode/constant');
3
+ const { MAX_PAGE_SIZE } = require('@abtnode/constant');
4
+ const { Sequelize, Op } = require('sequelize');
5
+ const { isValid } = require('@arcblock/did');
3
6
 
4
7
  const BaseState = require('./base');
5
8
 
9
+ const receiverDidValidation = (receiver, context) => {
10
+ const { did } = context?.user ?? {};
11
+ if (!receiver || did !== receiver) {
12
+ return "You are not allowed to mark other user's notification as read";
13
+ }
14
+ if (!isValid(receiver)) {
15
+ return 'Please provide a valid receiver DID.';
16
+ }
17
+ return '';
18
+ };
19
+
20
+ const readUnreadInputValidation = ({ notificationIds, receiver }, context) => {
21
+ if (!notificationIds.length) {
22
+ return 'Please provide the notificationId(s) to mark as read.';
23
+ }
24
+ return receiverDidValidation(receiver, context);
25
+ };
26
+
6
27
  /**
7
28
  * @extends BaseState<import('@abtnode/models').NotificationState>
8
29
  */
@@ -12,6 +33,7 @@ class NotificationState extends BaseState {
12
33
 
13
34
  this.defaultSender = config.defaultSender || '';
14
35
  this.defaultReceiver = config.defaultReceiver || '';
36
+ this.notificationReceiverState = config.notificationReceiverState;
15
37
  }
16
38
 
17
39
  setDefaultSender(sender) {
@@ -22,58 +44,165 @@ class NotificationState extends BaseState {
22
44
  this.defaultReceiver = receiver;
23
45
  }
24
46
 
47
+ setNotificationReceiversState(state) {
48
+ this.notificationReceiverState = state;
49
+ }
50
+
51
+ getNotificationReceiversState() {
52
+ return this.notificationReceiverState;
53
+ }
54
+
25
55
  async create(payload) {
26
- ['description'].forEach((x) => {
27
- if (!payload[x]) {
28
- throw new Error(`Invalid notification payload: ${x} is required`);
29
- }
30
- });
31
-
32
- const doc = await this.insert({
33
- sender: payload.sender || this.defaultSender,
34
- receiver: payload.receiver || this.defaultReceiver,
35
- title: payload.title,
36
- description: payload.description,
37
- action: payload.action || '',
56
+ if (!this.notificationReceiverState) {
57
+ throw new Error('Invalid database: missing notification_receivers tables');
58
+ }
59
+
60
+ const title = payload.title || '';
61
+ const description = payload.description || payload.body;
62
+
63
+ // 校验必填字段
64
+ if (!title) {
65
+ throw new Error('Invalid notification payload: title is required');
66
+ }
67
+
68
+ if (!description) {
69
+ throw new Error('Invalid notification payload: description is required');
70
+ }
71
+
72
+ const sender = payload?.sender?.did || this.defaultSender;
73
+ const receiverRaws = payload.receiver || this.defaultReceiver;
74
+
75
+ const actions = payload.actions ?? [];
76
+ if (payload.action) {
77
+ actions.push({
78
+ name: 'Visit',
79
+ link: payload.action,
80
+ });
81
+ }
82
+
83
+ let { severity } = payload;
84
+ if (severity === 'normal') {
85
+ severity = 'info';
86
+ }
87
+
88
+ const notificationData = {
89
+ sender,
90
+ receiver: '',
38
91
  entityType: payload.entityType || '',
39
92
  entityId: payload.entityId || '',
40
- severity: payload.severity || 'info',
93
+ action: payload.action || '',
94
+ title,
41
95
  read: false,
42
- });
96
+ description,
97
+ severity: severity || 'info',
98
+ attachments: payload.attachments ? payload.attachments : [],
99
+ actions,
100
+ blocks: payload.blocks ? payload.blocks : [],
101
+ type: payload.type || 'notification',
102
+ source: payload.source || (sender === payload.teamDid ? 'system' : 'component'),
103
+ componentDid: payload.componentDid || sender,
104
+ };
105
+ const receivers = Array.isArray(receiverRaws) ? receiverRaws : [receiverRaws];
106
+ const doc = await this.insert(notificationData);
107
+
108
+ const receiverEntries = receivers.map((receiverId) => ({
109
+ receiver: receiverId,
110
+ notificationId: doc.id,
111
+ }));
43
112
 
113
+ const receiverDoc = await this.notificationReceiverState.insertMany(receiverEntries);
114
+ if (receiverDoc) {
115
+ doc.receivers = receiverDoc;
116
+ }
44
117
  if (!payload.teamDid) {
45
118
  this.emit(EVENTS.NOTIFICATION_CREATE, {
46
119
  ...payload,
47
120
  ...doc,
121
+ receiver: receiverDoc.map((item) => item.receiver),
48
122
  });
49
123
  }
50
-
51
124
  return doc;
52
125
  }
53
126
 
54
- findPaginated({ read, paging, teamDid } = {}) {
55
- const conditions = {};
127
+ findPaginated({ read, paging, receiver, severity, componentDid, entityId, pageSize = 10 } = {}, context) {
128
+ const errorMsg = receiverDidValidation(receiver, context);
129
+ if (errorMsg) {
130
+ throw new Error(errorMsg);
131
+ }
132
+
133
+ const where = {};
134
+ const includeConditions = {};
56
135
  if (typeof read === 'boolean') {
57
- conditions.read = read;
136
+ includeConditions.read = read;
137
+ }
138
+ if (receiver) {
139
+ includeConditions.receiver = receiver;
58
140
  }
59
- if (teamDid) {
60
- conditions.entityId = teamDid;
141
+ where.id = {
142
+ [Op.in]: Sequelize.literal(`
143
+ (SELECT DISTINCT notificationId FROM notification_receivers WHERE receiver = '${receiver}')
144
+ `),
145
+ };
146
+
147
+ if (componentDid) {
148
+ where.componentDid = componentDid;
149
+ }
150
+
151
+ if (severity) {
152
+ where.severity = severity;
61
153
  }
62
- return this.paginate(conditions, { createdAt: -1 }, { ...paging, pageSize: 10 });
154
+ if (entityId) {
155
+ where.entityId = entityId;
156
+ }
157
+
158
+ const include = [
159
+ {
160
+ model: this.notificationReceiverState.model,
161
+ as: 'receivers', // 关联的别名
162
+ where: includeConditions,
163
+ required: true,
164
+ separate: true, // 会对主查询和关联查询分开执行,而不是通过单个 SQL 查询一次性完成
165
+ },
166
+ ];
167
+
168
+ const curPageSize = pageSize > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : pageSize;
169
+
170
+ return this.paginate({ where, include }, { createdAt: -1 }, { ...paging, pageSize: curPageSize });
171
+ }
172
+
173
+ async findNotification({ id }) {
174
+ if (!id) {
175
+ throw new Error('notification id is not allow empty');
176
+ }
177
+ const doc = await this.findOne({ id });
178
+ return doc;
63
179
  }
64
180
 
65
- // eslint-disable-next-line no-unused-vars
66
- async read({ id }, context) {
67
- const idList = id.split(',').map((x) => x.trim());
68
- logger.info('mark notification as read', { idList });
69
- const [numAffected] = await this.update({ id: { $in: idList } }, { $set: { read: true } });
181
+ async read({ notificationIds, receiver }, context) {
182
+ const errorMsg = readUnreadInputValidation({ notificationIds, receiver }, context);
183
+ if (errorMsg) {
184
+ throw new Error(errorMsg);
185
+ }
186
+ logger.info('mark notification as read', { notificationIds });
187
+ const conditions = {
188
+ notificationId: { $in: notificationIds },
189
+ receiver,
190
+ };
191
+ const [numAffected] = await this.notificationReceiverState.update(conditions, { $set: { read: true } });
70
192
  return numAffected;
71
193
  }
72
194
 
73
- // eslint-disable-next-line no-unused-vars
74
- async unread({ id }, context) {
75
- const idList = Array.isArray(id) ? id : [id];
76
- const [numAffected] = await this.update({ id: { $in: idList } }, { $set: { read: false } });
195
+ async unread({ notificationIds, receiver }, context) {
196
+ const errorMsg = readUnreadInputValidation({ notificationIds, receiver }, context);
197
+ if (errorMsg) {
198
+ throw new Error(errorMsg);
199
+ }
200
+ logger.info('mark notification as unread', { notificationIds });
201
+ const conditions = {
202
+ notificationId: { $in: notificationIds },
203
+ receiver,
204
+ };
205
+ const [numAffected] = await this.notificationReceiverState.update(conditions, { $set: { read: false } });
77
206
  return numAffected;
78
207
  }
79
208
  }
@@ -367,7 +367,14 @@ SELECT did,inviter,generation FROM UserTree`.trim();
367
367
 
368
368
  // eslint-disable-next-line require-await
369
369
  async getUsersByDids({ dids, query }) {
370
- const { approved, includeTags, includePassports, includeUserSessions } = query || {};
370
+ const {
371
+ approved,
372
+ includeTags,
373
+ includePassports,
374
+ includeUserSessions,
375
+ enableConnectedAccounts = false,
376
+ selection = {},
377
+ } = query || {};
371
378
  const condition = { did: dids };
372
379
  if (isNullOrUndefined(approved) === false) {
373
380
  condition.approved = !!approved;
@@ -392,8 +399,12 @@ SELECT did,inviter,generation FROM UserTree`.trim();
392
399
  required: false,
393
400
  });
394
401
  }
402
+ if (enableConnectedAccounts) {
403
+ include.push(this.getConnectedInclude());
404
+ }
395
405
 
396
- return this.find({ where: condition, include });
406
+ const result = await this.find({ where: condition, include }, selection);
407
+ return result;
397
408
  }
398
409
 
399
410
  // eslint-disable-next-line require-await
@@ -681,6 +692,14 @@ SELECT did,inviter,generation FROM UserTree`.trim();
681
692
  return result;
682
693
  }
683
694
 
695
+ getConnectedInclude() {
696
+ return {
697
+ model: this.models.ConnectedAccount,
698
+ as: 'connectedAccounts',
699
+ required: false,
700
+ };
701
+ }
702
+
684
703
  async getPassports(did) {
685
704
  const passports = await this.passport.find({ userDid: did });
686
705
  return passports;
@@ -726,6 +745,34 @@ SELECT did,inviter,generation FROM UserTree`.trim();
726
745
  }
727
746
  return user;
728
747
  }
748
+
749
+ /**
750
+ * 查询一个 Role 下的所有用户
751
+ * @returns
752
+ */
753
+ async getUsersByRoles({ roles = [], enableConnectedAccounts = false, selection = {} }) {
754
+ if (!roles.length) {
755
+ return [];
756
+ }
757
+ const replacements = {
758
+ status: PASSPORT_STATUS.VALID,
759
+ roles,
760
+ };
761
+ const condition = {
762
+ approved: true,
763
+ did: {
764
+ [Op.in]: Sequelize.literal(
765
+ '(SELECT DISTINCT userDid FROM passports WHERE name IN (:roles) AND status = :status)'
766
+ ),
767
+ },
768
+ };
769
+ const include = [];
770
+ if (enableConnectedAccounts) {
771
+ include.push(this.getConnectedInclude());
772
+ }
773
+ const result = await this.find({ where: condition, replacements, include }, selection);
774
+ return result;
775
+ }
729
776
  }
730
777
 
731
778
  module.exports = User;
@@ -38,6 +38,7 @@ const States = {
38
38
  Project: require('../states/project'),
39
39
  Release: require('../states/release'),
40
40
  Notification: require('../states/notification'),
41
+ NotificationReceivers: require('../states/notification-receiver'),
41
42
  VerifyCode: require('../states/verify-code'),
42
43
  SecurityRule: SecurityRuleState,
43
44
  AccessPolicy: AccessPolicyState,
@@ -54,6 +55,7 @@ const getDefaultTeamState = () => ({
54
55
  project: null,
55
56
  release: null,
56
57
  notification: null,
58
+ notificationReceivers: null,
57
59
  verifyCode: null,
58
60
  securityRule: null,
59
61
  accessPolicy: null,
@@ -115,6 +117,7 @@ class TeamManager extends EventEmitter {
115
117
  connectedAccount: await this.createState(this.nodeDid, 'ConnectedAccount'),
116
118
  session: await this.createState(this.nodeDid, 'Session'),
117
119
  notification: await this.createState(this.nodeDid, 'Notification'),
120
+ NotificationReceivers: await this.createState(this.nodeDid, 'NotificationReceivers'),
118
121
  verifyCode: await this.createState(this.nodeDid, 'VerifyCode'),
119
122
  securityRule: await this.createState(this.nodeDid, 'SecurityRule'),
120
123
  accessPolicy: await this.createState(this.nodeDid, 'AccessPolicy'),
@@ -146,19 +149,77 @@ class TeamManager extends EventEmitter {
146
149
  return this.getState(teamDid, 'session');
147
150
  }
148
151
 
149
- getNotification(teamDid) {
150
- return this.getState(teamDid, 'notification');
152
+ async getNotificationState(teamDid) {
153
+ const state = await this.getState(teamDid, 'notification');
154
+ const receiverState = await this.getState(teamDid, 'notificationReceivers');
155
+ state.setNotificationReceiversState(receiverState);
156
+ return state;
157
+ }
158
+
159
+ async getNotificationReceiverState(teamDid) {
160
+ const state = await this.getState(teamDid, 'notificationReceivers');
161
+ const notificationState = await this.getState(teamDid, 'notification');
162
+ state.setNotificationState(notificationState);
163
+ return state;
151
164
  }
152
165
 
153
166
  getVerifyCodeState(teamDid) {
154
167
  return this.getState(teamDid, 'verifyCode');
155
168
  }
156
169
 
170
+ async getNotificationReceivers(payload) {
171
+ const { teamDid, userDids = [], roles = [], selection = {}, enableConnectedAccounts = false } = payload;
172
+ // 会根据 teamDid 返回对应 state
173
+ const userState = await this.getUserState(teamDid);
174
+ if (!userDids.length && !roles.length) {
175
+ return [];
176
+ }
177
+ try {
178
+ // 这些用户信息已经是 approved 的用户,不需要再次确认
179
+ let users = [];
180
+ if (roles.length > 0) {
181
+ const roleUsers = await userState.getUsersByRoles({ roles, selection, enableConnectedAccounts });
182
+ users = users.concat(roleUsers);
183
+ }
184
+ if (userDids.length > 0) {
185
+ const queryUsers = await userState.getUsersByDids({
186
+ dids: userDids,
187
+ query: {
188
+ approved: true,
189
+ selection,
190
+ enableConnectedAccounts,
191
+ },
192
+ });
193
+ users = users.concat(queryUsers);
194
+ }
195
+
196
+ return users;
197
+ } catch (error) {
198
+ logger.error('get receivers failed: ', error);
199
+ return [];
200
+ }
201
+ }
202
+
157
203
  async createNotification({ teamDid, receiver, ...payload }) {
158
- const notification = await this.getState(teamDid, 'notification');
159
- const doc = await notification.create({ ...payload, teamDid });
204
+ // const notification = await this.getState(teamDid, 'notification');
205
+ const notification = await this.getNotificationState(teamDid);
206
+ const doc = await notification.create({ ...payload, receiver, teamDid });
160
207
  const metaDid = await this.states.blocklet.getBlockletMetaDid(teamDid);
161
- this.emit(EVENTS.NOTIFICATION_BLOCKLET_CREATE, { meta: { did: metaDid }, ...payload, ...doc, teamDid, receiver });
208
+ if (!payload.ignoreBroadcast) {
209
+ // 是否需要广播到页面
210
+ this.emit(EVENTS.NOTIFICATION_BLOCKLET_CREATE, {
211
+ meta: { did: metaDid },
212
+ ...payload,
213
+ ...doc,
214
+ teamDid,
215
+ appInfo: {
216
+ did: teamDid,
217
+ },
218
+ receiver: doc?.receivers?.map((item) => item.receiver),
219
+ });
220
+ }
221
+
222
+ return doc;
162
223
  }
163
224
 
164
225
  async getProjectState(teamDid) {
@@ -4,6 +4,8 @@ const checkURLAccessible = require('@abtnode/util/lib/url-evaluation/check-acces
4
4
  const { EVENTS } = require('@abtnode/constant');
5
5
  const isEmpty = require('lodash/isEmpty');
6
6
 
7
+ const { joinURL } = require('ufo');
8
+ const isUrl = require('is-url');
7
9
  const WebHookSender = require('./sender');
8
10
  const WalletSender = require('./sender/wallet');
9
11
  const createQueue = require('../util/queue');
@@ -108,6 +110,24 @@ module.exports = ({ events, dataDirs, instance }) => {
108
110
  serverUrls: baseUrls,
109
111
  });
110
112
  } else if (item.type === WalletSender.type && !isEmpty(extra?.wallet)) {
113
+ // 要将 logo 的 URL 拼接为完整的地址
114
+ const { attachments } = extra.wallet ?? {};
115
+ if (Array.isArray(attachments)) {
116
+ const newAttachments = attachments.map((attachment) => {
117
+ if (attachment.data.url && attachment.data.logo && !isUrl(attachment.data.log)) {
118
+ attachment.data.logo = joinURL(attachment.data.url, attachment.data.logo);
119
+ return attachment;
120
+ }
121
+ return attachment;
122
+ });
123
+ options = {
124
+ ...options,
125
+ ...{
126
+ ...extra.wallet,
127
+ attachments: newAttachments,
128
+ },
129
+ };
130
+ }
111
131
  options = { ...options, ...extra.wallet };
112
132
  }
113
133
 
@@ -139,9 +159,22 @@ module.exports = ({ events, dataDirs, instance }) => {
139
159
 
140
160
  [EVENTS.NOTIFICATION_CREATE, EVENTS.NOTIFICATION_BLOCKLET_CREATE].forEach((event) => {
141
161
  events.on(event, (data) => {
142
- const { title, description, severity, action, entityType, blockletUrl, entityId, extra, receiver } = data;
143
- if (!reduceQueue({ title, description, entityType, entityId, severity, extra })) {
144
- queue.push({ title, description, status: severity, action, entityType, blockletUrl, extra, receiver });
162
+ const { id, title, description, severity, action, entityType, blockletUrl, entityId, extra, receiver, appInfo } =
163
+ data;
164
+ if (!reduceQueue({ id, title, description, entityType, entityId, severity, extra })) {
165
+ queue.push({
166
+ title,
167
+ description,
168
+ status: severity,
169
+ action,
170
+ entityType,
171
+ blockletUrl,
172
+ extra,
173
+ receiver,
174
+ id,
175
+ appInfo,
176
+ teamDid: data.teamDid,
177
+ });
145
178
  }
146
179
  });
147
180
  });
@@ -5,7 +5,7 @@ const BaseSender = require('../base');
5
5
 
6
6
  class WalletSender extends BaseSender {
7
7
  async send(params, data = {}) {
8
- const { title, description, nodeInfo, node, receiver, actions, attachments } = data;
8
+ const { id, title, description, nodeInfo, node, receiver, actions, attachments, appInfo } = data;
9
9
 
10
10
  try {
11
11
  const sender = {
@@ -15,10 +15,12 @@ class WalletSender extends BaseSender {
15
15
  };
16
16
 
17
17
  const message = {
18
+ id,
18
19
  title,
19
20
  body: description,
20
21
  actions,
21
22
  attachments,
23
+ appInfo,
22
24
  };
23
25
 
24
26
  let to = [];
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.35",
6
+ "version": "1.16.37-beta-20241224-013714-a79db7d3",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,19 +19,19 @@
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.35",
23
- "@abtnode/auth": "1.16.35",
24
- "@abtnode/certificate-manager": "1.16.35",
25
- "@abtnode/constant": "1.16.35",
26
- "@abtnode/cron": "1.16.35",
27
- "@abtnode/logger": "1.16.35",
28
- "@abtnode/models": "1.16.35",
29
- "@abtnode/queue": "1.16.35",
30
- "@abtnode/rbac": "1.16.35",
31
- "@abtnode/router-provider": "1.16.35",
32
- "@abtnode/static-server": "1.16.35",
33
- "@abtnode/timemachine": "1.16.35",
34
- "@abtnode/util": "1.16.35",
22
+ "@abtnode/analytics": "1.16.37-beta-20241224-013714-a79db7d3",
23
+ "@abtnode/auth": "1.16.37-beta-20241224-013714-a79db7d3",
24
+ "@abtnode/certificate-manager": "1.16.37-beta-20241224-013714-a79db7d3",
25
+ "@abtnode/constant": "1.16.37-beta-20241224-013714-a79db7d3",
26
+ "@abtnode/cron": "1.16.37-beta-20241224-013714-a79db7d3",
27
+ "@abtnode/logger": "1.16.37-beta-20241224-013714-a79db7d3",
28
+ "@abtnode/models": "1.16.37-beta-20241224-013714-a79db7d3",
29
+ "@abtnode/queue": "1.16.37-beta-20241224-013714-a79db7d3",
30
+ "@abtnode/rbac": "1.16.37-beta-20241224-013714-a79db7d3",
31
+ "@abtnode/router-provider": "1.16.37-beta-20241224-013714-a79db7d3",
32
+ "@abtnode/static-server": "1.16.37-beta-20241224-013714-a79db7d3",
33
+ "@abtnode/timemachine": "1.16.37-beta-20241224-013714-a79db7d3",
34
+ "@abtnode/util": "1.16.37-beta-20241224-013714-a79db7d3",
35
35
  "@arcblock/did": "1.18.162",
36
36
  "@arcblock/did-auth": "1.18.162",
37
37
  "@arcblock/did-ext": "^1.18.162",
@@ -42,13 +42,13 @@
42
42
  "@arcblock/pm2-events": "^0.0.5",
43
43
  "@arcblock/validator": "^1.18.162",
44
44
  "@arcblock/vc": "1.18.162",
45
- "@blocklet/constant": "1.16.35",
46
- "@blocklet/did-space-js": "^0.5.82",
47
- "@blocklet/env": "1.16.35",
48
- "@blocklet/meta": "1.16.35",
49
- "@blocklet/resolver": "1.16.35",
50
- "@blocklet/sdk": "1.16.35",
51
- "@blocklet/store": "1.16.35",
45
+ "@blocklet/constant": "1.16.37-beta-20241224-013714-a79db7d3",
46
+ "@blocklet/did-space-js": "^0.6.0",
47
+ "@blocklet/env": "1.16.37-beta-20241224-013714-a79db7d3",
48
+ "@blocklet/meta": "1.16.37-beta-20241224-013714-a79db7d3",
49
+ "@blocklet/resolver": "1.16.37-beta-20241224-013714-a79db7d3",
50
+ "@blocklet/sdk": "1.16.37-beta-20241224-013714-a79db7d3",
51
+ "@blocklet/store": "1.16.37-beta-20241224-013714-a79db7d3",
52
52
  "@fidm/x509": "^1.2.1",
53
53
  "@ocap/mcrypto": "1.18.162",
54
54
  "@ocap/util": "1.18.162",
@@ -108,5 +108,5 @@
108
108
  "jest": "^29.7.0",
109
109
  "unzipper": "^0.10.11"
110
110
  },
111
- "gitHead": "a1888a5814c97a1cf6adfcee4e4d0721eabba7c3"
111
+ "gitHead": "040363d1ac077f7d4b4ee29e6c3bfc3e61c3ce3f"
112
112
  }