@abtnode/core 1.17.6-beta-20251221-021146-1a145a92 → 1.17.7-beta-20251223-090654-55d57623
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 +36 -1
- package/lib/blocklet/manager/disk.js +64 -36
- package/lib/blocklet/manager/ensure-blocklet-running.js +1 -0
- package/lib/blocklet/manager/helper/install-application-from-backup.js +1 -0
- package/lib/blocklet/manager/helper/install-application-from-general.js +1 -0
- package/lib/blocklet/manager/helper/install-component-from-url.js +1 -0
- package/lib/blocklet/manager/helper/upgrade-components.js +1 -0
- package/lib/blocklet/migration-dist/migration.cjs +1 -1
- package/lib/blocklet/storage/backup/spaces.js +11 -0
- package/lib/blocklet/storage/utils/disk.js +3 -0
- package/lib/event/auto-backup-handler.js +15 -11
- package/lib/event/index.js +4 -2
- package/lib/states/job.js +55 -1
- package/lib/states/notification.js +25 -25
- package/lib/webhook/index.js +1 -0
- package/package.json +24 -24
package/lib/api/team.js
CHANGED
|
@@ -58,6 +58,7 @@ const { getEmailServiceProvider } = require('@abtnode/auth/lib/email');
|
|
|
58
58
|
const md5 = require('@abtnode/util/lib/md5');
|
|
59
59
|
const { sanitizeTag } = require('@abtnode/util/lib/sanitize');
|
|
60
60
|
const { Joi } = require('@arcblock/validator');
|
|
61
|
+
const { getBlockletAppIdList } = require('@blocklet/meta/lib/util');
|
|
61
62
|
|
|
62
63
|
const { validateTrustedPassportIssuers } = require('../validators/trusted-passport');
|
|
63
64
|
const { validateTrustedFactories } = require('../validators/trusted-factory');
|
|
@@ -3119,6 +3120,7 @@ class TeamAPI extends EventEmitter {
|
|
|
3119
3120
|
{
|
|
3120
3121
|
action: 'issueOrgOwnerPassport',
|
|
3121
3122
|
entity: 'blocklet',
|
|
3123
|
+
entityId: teamDid,
|
|
3122
3124
|
params: {
|
|
3123
3125
|
teamDid,
|
|
3124
3126
|
org: result,
|
|
@@ -3623,10 +3625,43 @@ class TeamAPI extends EventEmitter {
|
|
|
3623
3625
|
|
|
3624
3626
|
const pushState = getNotificationPushState(results, channelsAvailable, isServer);
|
|
3625
3627
|
|
|
3628
|
+
let teamDids = [teamDid];
|
|
3629
|
+
if (isServer) {
|
|
3630
|
+
const nodeInfo = await this.node.read();
|
|
3631
|
+
teamDids = [nodeInfo.did];
|
|
3632
|
+
} else {
|
|
3633
|
+
teamDids = getBlockletAppIdList(blocklet);
|
|
3634
|
+
}
|
|
3635
|
+
|
|
3636
|
+
const pendingResult = await this.states.job.getPendingNotifications({
|
|
3637
|
+
teamDids,
|
|
3638
|
+
isServer,
|
|
3639
|
+
channels: Object.keys(channelsAvailable),
|
|
3640
|
+
createdAt: startTime,
|
|
3641
|
+
});
|
|
3642
|
+
|
|
3643
|
+
// pushState 的 key 与 pendingResult 的 key 映射关系
|
|
3644
|
+
const channelKeyMap = {
|
|
3645
|
+
pushKit: NOTIFICATION_SEND_CHANNEL.PUSH,
|
|
3646
|
+
wallet: NOTIFICATION_SEND_CHANNEL.WALLET,
|
|
3647
|
+
email: NOTIFICATION_SEND_CHANNEL.EMAIL,
|
|
3648
|
+
webhook: NOTIFICATION_SEND_CHANNEL.WEBHOOK,
|
|
3649
|
+
};
|
|
3650
|
+
|
|
3651
|
+
// 合并 pending 数量到对应的 channel
|
|
3652
|
+
const channels = Object.entries(pushState).reduce((acc, [key, value]) => {
|
|
3653
|
+
const pendingKey = channelKeyMap[key] || key;
|
|
3654
|
+
acc[key] = {
|
|
3655
|
+
...value,
|
|
3656
|
+
pending: pendingResult[pendingKey] || 0,
|
|
3657
|
+
};
|
|
3658
|
+
return acc;
|
|
3659
|
+
}, {});
|
|
3660
|
+
|
|
3626
3661
|
return {
|
|
3627
3662
|
healthy: true,
|
|
3628
3663
|
since: startTime,
|
|
3629
|
-
channels
|
|
3664
|
+
channels,
|
|
3630
3665
|
};
|
|
3631
3666
|
} catch (err) {
|
|
3632
3667
|
logger.error('Get notification service health failed', err, { teamDid });
|
|
@@ -367,6 +367,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
367
367
|
*/
|
|
368
368
|
const handleBackupComplete = async ({ id: jobId, job }) => {
|
|
369
369
|
await this.backupQueue.delete(jobId);
|
|
370
|
+
SpacesBackup.abort(job.did);
|
|
370
371
|
|
|
371
372
|
const autoBackup = await this.getAutoBackup({ did: job.did });
|
|
372
373
|
if (autoBackup?.enabled) {
|
|
@@ -3009,17 +3010,19 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3009
3010
|
await spacesBackup.initialize();
|
|
3010
3011
|
await spacesBackup.verifySpace();
|
|
3011
3012
|
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3013
|
+
if (!SpacesBackup.isRunning(did)) {
|
|
3014
|
+
this.backupQueue.push(
|
|
3015
|
+
{
|
|
3016
|
+
entity: 'blocklet',
|
|
3017
|
+
action: 'backupToSpaces',
|
|
3018
|
+
did,
|
|
3019
|
+
context,
|
|
3020
|
+
},
|
|
3021
|
+
jobId,
|
|
3022
|
+
true,
|
|
3023
|
+
BACKUPS.JOB.INTERVAL
|
|
3024
|
+
);
|
|
3025
|
+
}
|
|
3023
3026
|
}
|
|
3024
3027
|
|
|
3025
3028
|
await states.blockletExtras.setSettings(did, { autoBackup: value });
|
|
@@ -3748,17 +3751,37 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3748
3751
|
strategy: BACKUPS.STRATEGY.AUTO,
|
|
3749
3752
|
},
|
|
3750
3753
|
}) {
|
|
3751
|
-
if (shouldJobBackoff()) {
|
|
3752
|
-
logger.warn('Backup to spaces is not available when blocklet server is starting.');
|
|
3753
|
-
return;
|
|
3754
|
-
}
|
|
3755
|
-
|
|
3756
3754
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
3757
3755
|
const {
|
|
3758
3756
|
appDid,
|
|
3759
3757
|
meta: { did: appPid },
|
|
3760
3758
|
} = blocklet;
|
|
3761
3759
|
|
|
3760
|
+
if (shouldJobBackoff()) {
|
|
3761
|
+
const backup = await states.backup.findOne({ appPid }, {}, { createdAt: -1 });
|
|
3762
|
+
const message = 'Backup to spaces is not available when blocklet server is starting.';
|
|
3763
|
+
|
|
3764
|
+
if (backup.status === BACKUPS.STATUS.PROGRESS) {
|
|
3765
|
+
await states.backup.fail(backup.id, {
|
|
3766
|
+
message,
|
|
3767
|
+
});
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3770
|
+
this.emit(BlockletEvents.backupProgress, {
|
|
3771
|
+
appDid,
|
|
3772
|
+
meta: { did: appPid },
|
|
3773
|
+
completed: true,
|
|
3774
|
+
progress: -1,
|
|
3775
|
+
message,
|
|
3776
|
+
backup,
|
|
3777
|
+
context,
|
|
3778
|
+
blocklet,
|
|
3779
|
+
});
|
|
3780
|
+
|
|
3781
|
+
logger.warn(message);
|
|
3782
|
+
return;
|
|
3783
|
+
}
|
|
3784
|
+
|
|
3762
3785
|
const spaceGateways = await this.getBlockletSpaceGateways({ did });
|
|
3763
3786
|
const backupEndpoint = getBackupEndpoint(blocklet.environments);
|
|
3764
3787
|
if (isEmpty(spaceGateways) || isEmpty(backupEndpoint)) {
|
|
@@ -5488,28 +5511,33 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
5488
5511
|
const { did } = blocklet.meta;
|
|
5489
5512
|
const jobId = getBackupJobId(did);
|
|
5490
5513
|
const { job, willRunAt } = (await this.backupQueue.get(jobId, { full: true })) ?? {};
|
|
5491
|
-
if (job) {
|
|
5492
|
-
if (job.backupState?.strategy === BACKUPS.STRATEGY.MANUAL || willRunAt <= Date.now()) {
|
|
5493
|
-
logger.warn(`This app(${did})'s manual backup is already running, skip it`, { job });
|
|
5494
|
-
await this.backupQueue.restoreCancelled(jobId);
|
|
5495
|
-
return blocklet;
|
|
5496
|
-
}
|
|
5497
|
-
await this.backupQueue.delete(jobId);
|
|
5498
|
-
logger.warn(`This app(${did})'s auto backup is already removed from backup queue`, { job });
|
|
5499
|
-
}
|
|
5500
5514
|
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5515
|
+
// 任务正在运行或者将要在 1s 内运行,或者任务可能已过期,都是表示任务可用
|
|
5516
|
+
const waitBackupDone = (job && willRunAt - Date.now() <= 1_000) || SpacesBackup.isRunning(did);
|
|
5517
|
+
|
|
5518
|
+
if (waitBackupDone) {
|
|
5519
|
+
logger.warn(`This app(${did})'s manual or auto backup is already running, skip manual backup`, {
|
|
5520
|
+
job,
|
|
5521
|
+
willRunAt,
|
|
5522
|
+
now: Date.now(),
|
|
5523
|
+
isRunning: SpacesBackup.isRunning(did),
|
|
5524
|
+
});
|
|
5525
|
+
await this.backupQueue.restoreCancelled(jobId);
|
|
5526
|
+
} else {
|
|
5527
|
+
await this.backupQueue.delete(jobId);
|
|
5528
|
+
this.backupQueue.push(
|
|
5529
|
+
{
|
|
5530
|
+
entity: 'blocklet',
|
|
5531
|
+
action: 'backupToSpaces',
|
|
5532
|
+
did,
|
|
5533
|
+
context,
|
|
5534
|
+
backupState: {
|
|
5535
|
+
strategy: BACKUPS.STRATEGY.MANUAL,
|
|
5536
|
+
},
|
|
5509
5537
|
},
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5538
|
+
jobId
|
|
5539
|
+
);
|
|
5540
|
+
}
|
|
5513
5541
|
|
|
5514
5542
|
return blocklet;
|
|
5515
5543
|
} catch (error) {
|
|
@@ -39044,7 +39044,7 @@ module.exports = require("zlib");
|
|
|
39044
39044
|
/***/ ((module) => {
|
|
39045
39045
|
|
|
39046
39046
|
"use strict";
|
|
39047
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.17.
|
|
39047
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.17.6","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.17.6","@abtnode/auth":"1.17.6","@abtnode/certificate-manager":"1.17.6","@abtnode/constant":"1.17.6","@abtnode/cron":"1.17.6","@abtnode/db-cache":"1.17.6","@abtnode/docker-utils":"1.17.6","@abtnode/logger":"1.17.6","@abtnode/models":"1.17.6","@abtnode/queue":"1.17.6","@abtnode/rbac":"1.17.6","@abtnode/router-provider":"1.17.6","@abtnode/static-server":"1.17.6","@abtnode/timemachine":"1.17.6","@abtnode/util":"1.17.6","@aigne/aigne-hub":"^0.10.15","@arcblock/did":"^1.27.15","@arcblock/did-connect-js":"^1.27.15","@arcblock/did-ext":"^1.27.15","@arcblock/did-motif":"^1.1.14","@arcblock/did-util":"^1.27.15","@arcblock/event-hub":"^1.27.15","@arcblock/jwt":"^1.27.15","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"^1.27.15","@arcblock/vc":"^1.27.15","@blocklet/constant":"1.17.6","@blocklet/did-space-js":"^1.2.11","@blocklet/env":"1.17.6","@blocklet/error":"^0.3.5","@blocklet/meta":"1.17.6","@blocklet/resolver":"1.17.6","@blocklet/sdk":"1.17.6","@blocklet/server-js":"1.17.6","@blocklet/store":"1.17.6","@blocklet/theme":"^3.2.19","@fidm/x509":"^1.2.1","@ocap/mcrypto":"^1.27.15","@ocap/util":"^1.27.15","@ocap/wallet":"^1.27.15","@slack/webhook":"^7.0.6","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","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","private-ip":"^2.3.4","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":"^11.1.0","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"axios-mock-adapter":"^2.1.0","expand-tilde":"^2.0.2","express":"^4.18.2","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
|
|
39048
39048
|
|
|
39049
39049
|
/***/ }),
|
|
39050
39050
|
|
|
@@ -406,6 +406,17 @@ class SpacesBackup extends BaseBackup {
|
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
+
/**
|
|
410
|
+
*
|
|
411
|
+
*
|
|
412
|
+
* @static
|
|
413
|
+
* @param {string} appPid
|
|
414
|
+
* @memberof SpacesBackup
|
|
415
|
+
*/
|
|
416
|
+
static isRunning(appPid) {
|
|
417
|
+
return SpacesBackup.instanceMap.has(appPid);
|
|
418
|
+
}
|
|
419
|
+
|
|
409
420
|
/**
|
|
410
421
|
*
|
|
411
422
|
*
|
|
@@ -104,6 +104,8 @@ function getFolderSize(folderPath) {
|
|
|
104
104
|
*/
|
|
105
105
|
// eslint-disable-next-line require-await
|
|
106
106
|
async function getFolderObjects(path, prefix = '') {
|
|
107
|
+
// @note: 我尝试动手解析 .gitignore 文件,但是发现 fast-glob 不支持解析它的规则,并找到了对应的 issue: https://github.com/mrmlnc/fast-glob/issues/265#issue-579211456
|
|
108
|
+
const ignore = ['**/node_modules/**', '**/.next/**', '**/.DS_Store'];
|
|
107
109
|
const stream = FastGlob.stream('**', {
|
|
108
110
|
cwd: path,
|
|
109
111
|
objectMode: true,
|
|
@@ -112,6 +114,7 @@ async function getFolderObjects(path, prefix = '') {
|
|
|
112
114
|
absolute: true,
|
|
113
115
|
dot: true,
|
|
114
116
|
concurrency: 2,
|
|
117
|
+
ignore,
|
|
115
118
|
});
|
|
116
119
|
|
|
117
120
|
const objects = [];
|
|
@@ -2,6 +2,7 @@ const debounce = require('lodash/debounce');
|
|
|
2
2
|
const logger = require('@abtnode/logger')('@abtnode/core:event:auto-backup-handler');
|
|
3
3
|
const { BACKUPS } = require('@abtnode/constant');
|
|
4
4
|
const { getBackupJobId } = require('../util/spaces');
|
|
5
|
+
const { SpacesBackup } = require('../blocklet/storage/backup/spaces');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @description
|
|
@@ -16,19 +17,22 @@ async function autoBackupHandler(_eventName, payload, blockletManager) {
|
|
|
16
17
|
if (autoBackup.enabled && payload.context) {
|
|
17
18
|
const jobId = getBackupJobId(did);
|
|
18
19
|
const { job, willRunAt } = (await blockletManager.backupQueue.get(jobId, { full: true })) ?? {};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
|
|
21
|
+
// 任务正在运行或者将要在 3s 内运行,或者任务可能已过期,都是表示任务可用
|
|
22
|
+
const waitBackupDone = (job && willRunAt - Date.now() <= 3_000) || SpacesBackup.isRunning(did);
|
|
23
|
+
|
|
24
|
+
if (waitBackupDone) {
|
|
25
|
+
logger.warn(`This app(${did})'s manual or auto backup is already running, skip auto backup`, {
|
|
26
|
+
job,
|
|
27
|
+
willRunAt,
|
|
28
|
+
now: Date.now(),
|
|
29
|
+
isRunning: SpacesBackup.isRunning(did),
|
|
30
|
+
});
|
|
31
|
+
await blockletManager.backupQueue.restoreCancelled(jobId);
|
|
32
|
+
return;
|
|
30
33
|
}
|
|
31
34
|
|
|
35
|
+
await blockletManager.backupQueue.delete(jobId);
|
|
32
36
|
blockletManager.backupQueue.push(
|
|
33
37
|
{
|
|
34
38
|
entity: 'blocklet',
|
package/lib/event/index.js
CHANGED
|
@@ -695,8 +695,10 @@ module.exports = ({
|
|
|
695
695
|
* @returns
|
|
696
696
|
*/
|
|
697
697
|
(_eventName, payload, ...args) => {
|
|
698
|
-
|
|
699
|
-
|
|
698
|
+
if (payload.context) {
|
|
699
|
+
const id = payload.meta.did;
|
|
700
|
+
autoBackupHandlerFactory(id, autoBackupHandler)(eventName, payload, blockletManager, ...args);
|
|
701
|
+
}
|
|
700
702
|
}
|
|
701
703
|
);
|
|
702
704
|
});
|
package/lib/states/job.js
CHANGED
|
@@ -1,8 +1,62 @@
|
|
|
1
|
+
const { NOTIFICATION_SEND_CHANNEL } = require('@abtnode/constant');
|
|
2
|
+
const dayjs = require('@abtnode/util/lib/dayjs');
|
|
3
|
+
const { Op, Sequelize } = require('sequelize');
|
|
4
|
+
const { CustomError } = require('@blocklet/error');
|
|
5
|
+
|
|
1
6
|
const BaseState = require('./base');
|
|
2
7
|
|
|
8
|
+
// 根据 channel 映射对于的查询类别
|
|
9
|
+
const CHANNEL_MAP = {
|
|
10
|
+
[NOTIFICATION_SEND_CHANNEL.WALLET]: 'send-notification-wallet',
|
|
11
|
+
[NOTIFICATION_SEND_CHANNEL.PUSH]: 'send-notification-push',
|
|
12
|
+
[NOTIFICATION_SEND_CHANNEL.EMAIL]: 'send-notification-email',
|
|
13
|
+
[NOTIFICATION_SEND_CHANNEL.WEBHOOK]: 'send-notification-webhook',
|
|
14
|
+
};
|
|
15
|
+
|
|
3
16
|
/**
|
|
4
17
|
* @extends BaseState<import('@abtnode/models').JobState>
|
|
5
18
|
*/
|
|
6
|
-
class Job extends BaseState {
|
|
19
|
+
class Job extends BaseState {
|
|
20
|
+
async getPendingNotifications({ teamDids = [], channels = [], createdAt = '', isServer = false }) {
|
|
21
|
+
if (!teamDids.length || !channels.length) {
|
|
22
|
+
throw new CustomError(400, 'teamDids and channels are required');
|
|
23
|
+
}
|
|
24
|
+
let startTime = createdAt;
|
|
25
|
+
if (!startTime) {
|
|
26
|
+
startTime = dayjs().subtract(1, 'hours').toDate();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 过滤有效 channel,获取对应的 queue 名称
|
|
30
|
+
const validChannels = channels.filter((channel) => CHANNEL_MAP[channel]);
|
|
31
|
+
const queueNames = validChannels.map((channel) => CHANNEL_MAP[channel]);
|
|
32
|
+
|
|
33
|
+
// 构建 entityId 查询条件
|
|
34
|
+
// isServer 为 true 时,使用 COALESCE 查询 entityId 在 teamDids 中或为空(null/'')的记录
|
|
35
|
+
// isServer 为 false 时,直接查询 entityId 在 teamDids 中的记录,索引利用率最高
|
|
36
|
+
const entityIdCondition = isServer
|
|
37
|
+
? Sequelize.where(Sequelize.fn('COALESCE', Sequelize.col('entityId'), ''), { [Op.in]: [...teamDids, ''] })
|
|
38
|
+
: { entityId: { [Op.in]: teamDids } };
|
|
39
|
+
|
|
40
|
+
// 单次查询,使用 GROUP BY 获取所有 channel 的统计
|
|
41
|
+
const results = await this.model.findAll({
|
|
42
|
+
attributes: ['queue', [Sequelize.fn('COUNT', Sequelize.col('id')), 'count']],
|
|
43
|
+
where: {
|
|
44
|
+
queue: { [Op.in]: queueNames },
|
|
45
|
+
...(isServer ? { [Op.and]: entityIdCondition } : entityIdCondition),
|
|
46
|
+
createdAt: { [Op.gte]: startTime },
|
|
47
|
+
},
|
|
48
|
+
group: ['queue'],
|
|
49
|
+
raw: true,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// 将结果映射回 channel 名称,确保所有请求的 channel 都有返回值
|
|
53
|
+
return validChannels.reduce((acc, channel) => {
|
|
54
|
+
const queueName = CHANNEL_MAP[channel];
|
|
55
|
+
const row = results.find((r) => r.queue === queueName);
|
|
56
|
+
acc[channel] = row ? Number(row.count) : 0;
|
|
57
|
+
return acc;
|
|
58
|
+
}, {});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
7
61
|
|
|
8
62
|
module.exports = Job;
|
|
@@ -1035,32 +1035,32 @@ class NotificationState extends BaseState {
|
|
|
1035
1035
|
// 计算时间范围
|
|
1036
1036
|
const startTime = dayjs().subtract(hours, 'hours').toDate();
|
|
1037
1037
|
|
|
1038
|
-
//
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
// 提取通知 ID 列表
|
|
1054
|
-
const notificationIds = notifications.map((n) => n.id);
|
|
1038
|
+
// 只查询统计所需字段,排除大的 JSON 字段 (walletSendRecord, pushKitSendRecord, emailSendRecord)
|
|
1039
|
+
// 这样可以大幅减少数据传输量
|
|
1040
|
+
const results = await this.model.sequelize.query(
|
|
1041
|
+
`SELECT
|
|
1042
|
+
"walletSendAt", "walletSendStatus", "walletSendFailedReason",
|
|
1043
|
+
"pushKitSendAt", "pushKitSendStatus", "pushKitSendFailedReason",
|
|
1044
|
+
"emailSendAt", "emailSendStatus", "emailSendFailedReason",
|
|
1045
|
+
"webhook", "createdAt"
|
|
1046
|
+
FROM notification_receivers
|
|
1047
|
+
WHERE "createdAt" >= :startTime`,
|
|
1048
|
+
{
|
|
1049
|
+
replacements: { startTime },
|
|
1050
|
+
type: Sequelize.QueryTypes.SELECT,
|
|
1051
|
+
}
|
|
1052
|
+
);
|
|
1055
1053
|
|
|
1056
|
-
//
|
|
1057
|
-
return
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1054
|
+
// 只需要解析 webhook JSON 字段
|
|
1055
|
+
return results.map((item) => {
|
|
1056
|
+
if (typeof item.webhook === 'string') {
|
|
1057
|
+
try {
|
|
1058
|
+
item.webhook = JSON.parse(item.webhook);
|
|
1059
|
+
} catch {
|
|
1060
|
+
item.webhook = {};
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
return item;
|
|
1064
1064
|
});
|
|
1065
1065
|
}
|
|
1066
1066
|
}
|
package/lib/webhook/index.js
CHANGED
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.17.
|
|
6
|
+
"version": "1.17.7-beta-20251223-090654-55d57623",
|
|
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.
|
|
21
|
-
"@abtnode/auth": "1.17.
|
|
22
|
-
"@abtnode/certificate-manager": "1.17.
|
|
23
|
-
"@abtnode/constant": "1.17.
|
|
24
|
-
"@abtnode/cron": "1.17.
|
|
25
|
-
"@abtnode/db-cache": "1.17.
|
|
26
|
-
"@abtnode/docker-utils": "1.17.
|
|
27
|
-
"@abtnode/logger": "1.17.
|
|
28
|
-
"@abtnode/models": "1.17.
|
|
29
|
-
"@abtnode/queue": "1.17.
|
|
30
|
-
"@abtnode/rbac": "1.17.
|
|
31
|
-
"@abtnode/router-provider": "1.17.
|
|
32
|
-
"@abtnode/static-server": "1.17.
|
|
33
|
-
"@abtnode/timemachine": "1.17.
|
|
34
|
-
"@abtnode/util": "1.17.
|
|
20
|
+
"@abtnode/analytics": "1.17.7-beta-20251223-090654-55d57623",
|
|
21
|
+
"@abtnode/auth": "1.17.7-beta-20251223-090654-55d57623",
|
|
22
|
+
"@abtnode/certificate-manager": "1.17.7-beta-20251223-090654-55d57623",
|
|
23
|
+
"@abtnode/constant": "1.17.7-beta-20251223-090654-55d57623",
|
|
24
|
+
"@abtnode/cron": "1.17.7-beta-20251223-090654-55d57623",
|
|
25
|
+
"@abtnode/db-cache": "1.17.7-beta-20251223-090654-55d57623",
|
|
26
|
+
"@abtnode/docker-utils": "1.17.7-beta-20251223-090654-55d57623",
|
|
27
|
+
"@abtnode/logger": "1.17.7-beta-20251223-090654-55d57623",
|
|
28
|
+
"@abtnode/models": "1.17.7-beta-20251223-090654-55d57623",
|
|
29
|
+
"@abtnode/queue": "1.17.7-beta-20251223-090654-55d57623",
|
|
30
|
+
"@abtnode/rbac": "1.17.7-beta-20251223-090654-55d57623",
|
|
31
|
+
"@abtnode/router-provider": "1.17.7-beta-20251223-090654-55d57623",
|
|
32
|
+
"@abtnode/static-server": "1.17.7-beta-20251223-090654-55d57623",
|
|
33
|
+
"@abtnode/timemachine": "1.17.7-beta-20251223-090654-55d57623",
|
|
34
|
+
"@abtnode/util": "1.17.7-beta-20251223-090654-55d57623",
|
|
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.
|
|
46
|
+
"@blocklet/constant": "1.17.7-beta-20251223-090654-55d57623",
|
|
47
47
|
"@blocklet/did-space-js": "^1.2.11",
|
|
48
|
-
"@blocklet/env": "1.17.
|
|
48
|
+
"@blocklet/env": "1.17.7-beta-20251223-090654-55d57623",
|
|
49
49
|
"@blocklet/error": "^0.3.5",
|
|
50
|
-
"@blocklet/meta": "1.17.
|
|
51
|
-
"@blocklet/resolver": "1.17.
|
|
52
|
-
"@blocklet/sdk": "1.17.
|
|
53
|
-
"@blocklet/server-js": "1.17.
|
|
54
|
-
"@blocklet/store": "1.17.
|
|
50
|
+
"@blocklet/meta": "1.17.7-beta-20251223-090654-55d57623",
|
|
51
|
+
"@blocklet/resolver": "1.17.7-beta-20251223-090654-55d57623",
|
|
52
|
+
"@blocklet/sdk": "1.17.7-beta-20251223-090654-55d57623",
|
|
53
|
+
"@blocklet/server-js": "1.17.7-beta-20251223-090654-55d57623",
|
|
54
|
+
"@blocklet/store": "1.17.7-beta-20251223-090654-55d57623",
|
|
55
55
|
"@blocklet/theme": "^3.2.19",
|
|
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": "
|
|
119
|
+
"gitHead": "00a82b6f4ef5818d6ec37d74be404031c693247c"
|
|
120
120
|
}
|