@abtnode/core 1.16.42 → 1.16.43-beta-20250419-231352-c78ac93d
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 +45 -6
- package/lib/blocklet/manager/disk.js +42 -7
- package/lib/blocklet/manager/ensure-blocklet-running.js +112 -50
- package/lib/blocklet/migration-dist/migration.cjs +1 -3
- package/lib/event/index.js +77 -0
- package/lib/index.js +2 -0
- package/lib/monitor/node-runtime-monitor.js +57 -0
- package/lib/states/audit-log.js +4 -2
- package/lib/states/user.js +7 -0
- package/lib/util/blocklet.js +9 -15
- package/lib/util/env.js +10 -4
- package/lib/util/launcher.js +2 -0
- package/lib/util/user.js +73 -0
- package/package.json +34 -34
package/lib/api/team.js
CHANGED
|
@@ -2022,7 +2022,10 @@ class TeamAPI extends EventEmitter {
|
|
|
2022
2022
|
* @returns
|
|
2023
2023
|
*/
|
|
2024
2024
|
|
|
2025
|
-
async upsertUserSession(
|
|
2025
|
+
async upsertUserSession(
|
|
2026
|
+
{ teamDid, appPid, userDid, visitorId, ua, lastLoginIp, passportId, status, extra, locale, origin },
|
|
2027
|
+
{ skipNotification = false } = {}
|
|
2028
|
+
) {
|
|
2026
2029
|
if (!userDid) {
|
|
2027
2030
|
throw new Error('userDid is required');
|
|
2028
2031
|
}
|
|
@@ -2039,6 +2042,17 @@ class TeamAPI extends EventEmitter {
|
|
|
2039
2042
|
extra,
|
|
2040
2043
|
});
|
|
2041
2044
|
logger.info('insert userSession successfully', { userDid, ua, lastLoginIp, appPid, passportId, extra });
|
|
2045
|
+
// HACK: 某些地方,首次新增 userSession 时不会,携带 ua 信息,这个时候不能发通知
|
|
2046
|
+
if (ua) {
|
|
2047
|
+
this.emit(BlockletEvents.addUserSession, {
|
|
2048
|
+
userSession: data,
|
|
2049
|
+
teamDid,
|
|
2050
|
+
userDid,
|
|
2051
|
+
locale,
|
|
2052
|
+
skipNotification,
|
|
2053
|
+
origin,
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2042
2056
|
} else {
|
|
2043
2057
|
const exist = await state.findOne({ userDid, visitorId, appPid });
|
|
2044
2058
|
if (exist) {
|
|
@@ -2052,6 +2066,25 @@ class TeamAPI extends EventEmitter {
|
|
|
2052
2066
|
extra: mergeExtra,
|
|
2053
2067
|
});
|
|
2054
2068
|
logger.info('update userSession successfully', { id: exist.id, ua, lastLoginIp, passportId, status, extra });
|
|
2069
|
+
if (Date.now() - new Date(exist.createdAt).getTime() < 1000 * 10) {
|
|
2070
|
+
// HACK: 此处是为了矫正首次创建 userSession 没有 ua 的情况,会通过 /api/did/session 接口来更新 ua 信息,这个时候才能当成新增 userSession 来发送通知
|
|
2071
|
+
this.emit(BlockletEvents.addUserSession, {
|
|
2072
|
+
userSession: data,
|
|
2073
|
+
teamDid,
|
|
2074
|
+
userDid,
|
|
2075
|
+
locale,
|
|
2076
|
+
skipNotification,
|
|
2077
|
+
origin,
|
|
2078
|
+
});
|
|
2079
|
+
} else {
|
|
2080
|
+
this.emit(BlockletEvents.updateUserSession, {
|
|
2081
|
+
userSession: data,
|
|
2082
|
+
teamDid,
|
|
2083
|
+
userDid,
|
|
2084
|
+
skipNotification,
|
|
2085
|
+
origin,
|
|
2086
|
+
});
|
|
2087
|
+
}
|
|
2055
2088
|
} else {
|
|
2056
2089
|
data = await state.insert({
|
|
2057
2090
|
visitorId,
|
|
@@ -2071,6 +2104,16 @@ class TeamAPI extends EventEmitter {
|
|
|
2071
2104
|
passportId,
|
|
2072
2105
|
extra,
|
|
2073
2106
|
});
|
|
2107
|
+
if (ua) {
|
|
2108
|
+
this.emit(BlockletEvents.addUserSession, {
|
|
2109
|
+
userSession: data,
|
|
2110
|
+
teamDid,
|
|
2111
|
+
userDid,
|
|
2112
|
+
locale,
|
|
2113
|
+
skipNotification,
|
|
2114
|
+
origin,
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2074
2117
|
}
|
|
2075
2118
|
}
|
|
2076
2119
|
|
|
@@ -2185,11 +2228,7 @@ class TeamAPI extends EventEmitter {
|
|
|
2185
2228
|
// HACK: 使用 state.remove 并不能按预期工作,先改为使用 state.model.destroy 来实现
|
|
2186
2229
|
const result = await state.model.destroy({ where });
|
|
2187
2230
|
const { permanentWallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
2188
|
-
const
|
|
2189
|
-
config: {},
|
|
2190
|
-
sites: [],
|
|
2191
|
-
});
|
|
2192
|
-
const masterSite = federated.sites[0];
|
|
2231
|
+
const masterSite = getFederatedMaster(blocklet);
|
|
2193
2232
|
if (masterSite && masterSite.isMaster !== false && masterSite.appPid !== teamDid) {
|
|
2194
2233
|
callFederated({
|
|
2195
2234
|
action: 'sync',
|
|
@@ -123,7 +123,7 @@ const {
|
|
|
123
123
|
} = require('@abtnode/auth/lib/util/federated');
|
|
124
124
|
const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
125
125
|
|
|
126
|
-
const
|
|
126
|
+
const groupBy = require('lodash/groupBy');
|
|
127
127
|
const launcher = require('../../util/launcher');
|
|
128
128
|
const util = require('../../util');
|
|
129
129
|
const {
|
|
@@ -229,10 +229,11 @@ const { dockerExec } = require('../../util/docker/docker-exec');
|
|
|
229
229
|
const { installExternalDependencies } = require('../../util/install-external-dependencies');
|
|
230
230
|
const { dockerExecChown } = require('../../util/docker/docker-exec-chown');
|
|
231
231
|
const checkDockerRunHistory = require('../../util/docker/check-docker-run-history');
|
|
232
|
-
const {
|
|
232
|
+
const { shouldJobBackoff } = require('../../util/env');
|
|
233
233
|
const ensureBlockletRunning = require('./ensure-blocklet-running');
|
|
234
234
|
|
|
235
235
|
const { transformNotification } = require('../../util/notification');
|
|
236
|
+
const { generateUserUpdateData } = require('../../util/user');
|
|
236
237
|
|
|
237
238
|
const { formatEnvironments, getBlockletMeta, validateOwner, isCLI } = util;
|
|
238
239
|
|
|
@@ -433,6 +434,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
433
434
|
stop: async (params) => {
|
|
434
435
|
await this.stop(params);
|
|
435
436
|
},
|
|
437
|
+
createAuditLog: (params) => this.createAuditLog(params),
|
|
436
438
|
notification: (did, title, description, severity) => {
|
|
437
439
|
try {
|
|
438
440
|
this._createNotification(did, {
|
|
@@ -448,6 +450,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
448
450
|
logger.error('create notification failed', { err });
|
|
449
451
|
}
|
|
450
452
|
},
|
|
453
|
+
checkSystemHighLoad: (...args) => this.nodeAPI.runtimeMonitor.checkSystemHighLoad(...args),
|
|
451
454
|
});
|
|
452
455
|
}
|
|
453
456
|
}
|
|
@@ -515,6 +518,11 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
515
518
|
});
|
|
516
519
|
}
|
|
517
520
|
|
|
521
|
+
// This property will be injected after the node instance is instantiated.
|
|
522
|
+
createAuditLog = (params) => {
|
|
523
|
+
console.warn('createAuditLog not initialized', params);
|
|
524
|
+
};
|
|
525
|
+
|
|
518
526
|
// ============================================================================================
|
|
519
527
|
// Public API for Installing/Upgrading Application or Components
|
|
520
528
|
// ============================================================================================
|
|
@@ -3160,6 +3168,11 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3160
3168
|
strategy: BACKUPS.STRATEGY.AUTO,
|
|
3161
3169
|
},
|
|
3162
3170
|
}) {
|
|
3171
|
+
if (shouldJobBackoff()) {
|
|
3172
|
+
logger.warn('Backup to spaces is not available when blocklet server is starting.');
|
|
3173
|
+
return;
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3163
3176
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
3164
3177
|
const {
|
|
3165
3178
|
appDid,
|
|
@@ -3206,10 +3219,9 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3206
3219
|
return message;
|
|
3207
3220
|
}
|
|
3208
3221
|
|
|
3209
|
-
|
|
3210
|
-
if (backupState?.strategy === BACKUPS.STRATEGY.AUTO && uptime < abtNodeStartBackupDelaySeconds) {
|
|
3222
|
+
if (backupState?.strategy === BACKUPS.STRATEGY.AUTO && shouldJobBackoff()) {
|
|
3211
3223
|
const message = 'Automatic backup is not available when blocklet server is starting.';
|
|
3212
|
-
logger.error(message, { appPid
|
|
3224
|
+
logger.error(message, { appPid });
|
|
3213
3225
|
|
|
3214
3226
|
return message;
|
|
3215
3227
|
}
|
|
@@ -3379,6 +3391,17 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3379
3391
|
}
|
|
3380
3392
|
|
|
3381
3393
|
async _onCheckForComponentUpdate({ did }) {
|
|
3394
|
+
if (shouldJobBackoff()) {
|
|
3395
|
+
logger.warn('Check for component update is not available when blocklet server is starting.');
|
|
3396
|
+
return;
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
const blocklet = await this.getBlocklet(did);
|
|
3400
|
+
if (blocklet.status === BlockletStatus.stopped) {
|
|
3401
|
+
logger.warn('Check for component update is not available when blocklet is stopped.');
|
|
3402
|
+
return;
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3382
3405
|
const list = await UpgradeComponents.check({ did, states });
|
|
3383
3406
|
if (!list || !list.updateList?.length) {
|
|
3384
3407
|
return;
|
|
@@ -3394,7 +3417,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3394
3417
|
if (checkUpdateMd5 === oldMd5) {
|
|
3395
3418
|
return;
|
|
3396
3419
|
}
|
|
3397
|
-
|
|
3420
|
+
|
|
3398
3421
|
const firstComponent = updateList[0];
|
|
3399
3422
|
const blockletTitle = getDisplayName(blocklet);
|
|
3400
3423
|
|
|
@@ -5358,9 +5381,21 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
5358
5381
|
return newState;
|
|
5359
5382
|
}
|
|
5360
5383
|
|
|
5384
|
+
/**
|
|
5385
|
+
* 调用来源有两种
|
|
5386
|
+
* 1. js-sdk: 调用时,会处理好 user.phone 与 user.metadata.phone 的同步,已经 user.metadata.location 与 user.address.city 的同步
|
|
5387
|
+
* 2. node-sdk: 需要处理 node-sdk 的调用时的数据同步
|
|
5388
|
+
* @param {*} param0
|
|
5389
|
+
* @returns
|
|
5390
|
+
*/
|
|
5361
5391
|
async updateUserInfoAndSync({ teamDid, user }) {
|
|
5362
5392
|
try {
|
|
5363
|
-
const
|
|
5393
|
+
const existingUser = await this.teamAPI.getUser({ teamDid, user: { did: user.did } });
|
|
5394
|
+
if (!existingUser) {
|
|
5395
|
+
throw new Error('User not found');
|
|
5396
|
+
}
|
|
5397
|
+
const updateData = generateUserUpdateData(user, existingUser);
|
|
5398
|
+
const updated = await this.teamAPI.updateUser({ teamDid, user: updateData });
|
|
5364
5399
|
const { sourceAppPid } = updated;
|
|
5365
5400
|
|
|
5366
5401
|
const blocklet = await this.getBlocklet(teamDid);
|
|
@@ -4,34 +4,36 @@ const { BlockletStatus } = require('@blocklet/constant');
|
|
|
4
4
|
const sleep = require('@abtnode/util/lib/sleep');
|
|
5
5
|
const { getDisplayName } = require('@blocklet/meta/lib/util');
|
|
6
6
|
|
|
7
|
-
const inProgressStatuses = [BlockletStatus.stopping, BlockletStatus.restarting, BlockletStatus.waiting];
|
|
8
|
-
|
|
9
7
|
const states = require('../../states');
|
|
10
8
|
const { isBlockletPortHealthy, shouldCheckHealthy } = require('../../util/blocklet');
|
|
9
|
+
const { shouldJobBackoff } = require('../../util/env');
|
|
10
|
+
|
|
11
|
+
const inProgressStatuses = [BlockletStatus.stopping, BlockletStatus.restarting, BlockletStatus.waiting];
|
|
11
12
|
|
|
12
13
|
class EnsureBlockletRunning {
|
|
13
14
|
initialized = false;
|
|
14
15
|
|
|
15
16
|
// 每次任务的最小间隔时间
|
|
16
|
-
checkInterval = process.env.ABT_NODE_ENSURE_RUNNING_CHECK_INTERVAL
|
|
17
|
-
? Number(process.env.ABT_NODE_ENSURE_RUNNING_CHECK_INTERVAL)
|
|
18
|
-
: 60 * 1000;
|
|
17
|
+
checkInterval = +process.env.ABT_NODE_ENSURE_RUNNING_CHECK_INTERVAL || 60 * 1000;
|
|
19
18
|
|
|
20
19
|
// 首次任务的延迟时间
|
|
21
|
-
deferredTime = process.env.ABT_NODE_ENSURE_RUNNING_DEFERRED_TIME
|
|
22
|
-
? Number(process.env.ABT_NODE_ENSURE_RUNNING_DEFERRED_TIME)
|
|
23
|
-
: 30 * 1000;
|
|
20
|
+
deferredTime = +process.env.ABT_NODE_ENSURE_RUNNING_DEFERRED_TIME || 30 * 1000;
|
|
24
21
|
|
|
25
22
|
// 每个重启任务(did + componentDids)的重启间隔为 2 min,如果 2 min 内重启过,就不会再重启
|
|
26
23
|
restartInterval = 1000 * 60 * 2;
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
maxLongtimeDoing = 1000 * 60 * 5;
|
|
25
|
+
everyBlockletCheckInterval = 2000;
|
|
30
26
|
|
|
31
|
-
|
|
27
|
+
everyBlockletDoingInterval = 5000;
|
|
32
28
|
|
|
33
29
|
fakeRunningToWaitingOnce = false;
|
|
34
30
|
|
|
31
|
+
highLoadCpu = +process.env.ABT_NODE_ENSURE_RUNNING_HIGH_LOAD_CPU || 0.7;
|
|
32
|
+
|
|
33
|
+
highLoadMemory = +process.env.ABT_NODE_ENSURE_RUNNING_HIGH_LOAD_MEMORY || 0.8;
|
|
34
|
+
|
|
35
|
+
highLoadDisk = +process.env.ABT_NODE_ENSURE_RUNNING_HIGH_LOAD_DISK || 0.8;
|
|
36
|
+
|
|
35
37
|
runningBlocklets = {};
|
|
36
38
|
|
|
37
39
|
runningRootBlocklets = {};
|
|
@@ -49,17 +51,26 @@ class EnsureBlockletRunning {
|
|
|
49
51
|
// Ease to mock
|
|
50
52
|
isBlockletPortHealthy = isBlockletPortHealthy;
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
// Ease to mock
|
|
55
|
+
shouldJobBackoff = shouldJobBackoff;
|
|
56
|
+
|
|
57
|
+
isBlockletPortHealthyWithRetries = async (blocklet, isDoing = false) => {
|
|
58
|
+
let error;
|
|
53
59
|
for (let attempt = 0; attempt < 10; attempt++) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
try {
|
|
61
|
+
// eslint-disable-next-line no-await-in-loop
|
|
62
|
+
await this.isBlockletPortHealthy(blocklet, {
|
|
63
|
+
minConsecutiveTime: 3000,
|
|
64
|
+
timeout: 6000,
|
|
65
|
+
});
|
|
66
|
+
return true;
|
|
67
|
+
} catch (e) {
|
|
68
|
+
error = e;
|
|
69
|
+
// eslint-disable-next-line no-await-in-loop
|
|
70
|
+
await sleep(isDoing ? this.everyBlockletDoingInterval : this.everyBlockletCheckInterval);
|
|
71
|
+
}
|
|
62
72
|
}
|
|
73
|
+
logger.error('blocklet port is not healthy', error);
|
|
63
74
|
return false;
|
|
64
75
|
};
|
|
65
76
|
|
|
@@ -67,7 +78,7 @@ class EnsureBlockletRunning {
|
|
|
67
78
|
this.states = states;
|
|
68
79
|
}
|
|
69
80
|
|
|
70
|
-
initialize = ({ restart, stop, notification }) => {
|
|
81
|
+
initialize = ({ restart, stop, notification, checkSystemHighLoad, createAuditLog }) => {
|
|
71
82
|
if (this.initialized) {
|
|
72
83
|
return;
|
|
73
84
|
}
|
|
@@ -75,13 +86,13 @@ class EnsureBlockletRunning {
|
|
|
75
86
|
this.restart = restart;
|
|
76
87
|
this.stop = stop;
|
|
77
88
|
this.notification = notification;
|
|
78
|
-
|
|
89
|
+
this.createAuditLog = createAuditLog;
|
|
90
|
+
this.checkSystemHighLoad = checkSystemHighLoad;
|
|
79
91
|
const task = async () => {
|
|
80
92
|
if (this.stopped) {
|
|
81
93
|
return;
|
|
82
94
|
}
|
|
83
95
|
await this.checkAndFix();
|
|
84
|
-
|
|
85
96
|
await sleep(this.checkInterval);
|
|
86
97
|
task();
|
|
87
98
|
};
|
|
@@ -104,6 +115,21 @@ class EnsureBlockletRunning {
|
|
|
104
115
|
if (process.env.ABT_NODE_RESTART_RUNNING_COMPONENT === '1') {
|
|
105
116
|
return;
|
|
106
117
|
}
|
|
118
|
+
|
|
119
|
+
if (!this.shouldJobBackoff()) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const systemHighLoad = this.checkSystemHighLoad({
|
|
123
|
+
maxCpus: this.highLoadCpu,
|
|
124
|
+
maxMem: this.highLoadMemory,
|
|
125
|
+
maxDisk: this.highLoadDisk,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
logger.info('Check ensure blocklet running', systemHighLoad);
|
|
129
|
+
if (systemHighLoad.isHighLoad) {
|
|
130
|
+
logger.warn('Skip once ensure blocklet running because system high load', systemHighLoad);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
107
133
|
this.runningBlocklets = {};
|
|
108
134
|
this.fakeRunningBlocklets = {};
|
|
109
135
|
this.fakeRunningBlockletsTimes = {};
|
|
@@ -186,24 +212,23 @@ class EnsureBlockletRunning {
|
|
|
186
212
|
}
|
|
187
213
|
return;
|
|
188
214
|
}
|
|
189
|
-
|
|
215
|
+
|
|
216
|
+
const health = await this.isBlockletPortHealthyWithRetries(
|
|
217
|
+
blocklet,
|
|
218
|
+
inProgressStatuses.includes(blocklet.status)
|
|
219
|
+
);
|
|
190
220
|
|
|
191
221
|
if (health) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
} else {
|
|
199
|
-
if (!this.fakeRunningBlocklets[did]) {
|
|
200
|
-
this.fakeRunningBlocklets[did] = [];
|
|
201
|
-
}
|
|
202
|
-
if (this.fakeRunningBlocklets[did].find((b) => b.meta.did === blocklet.meta.did)) {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
this.fakeRunningBlocklets[did].push(blocklet);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!this.fakeRunningBlocklets[did]) {
|
|
226
|
+
this.fakeRunningBlocklets[did] = [];
|
|
206
227
|
}
|
|
228
|
+
if (this.fakeRunningBlocklets[did].find((b) => b.meta.did === blocklet.meta.did)) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
this.fakeRunningBlocklets[did].push(blocklet);
|
|
207
232
|
};
|
|
208
233
|
}),
|
|
209
234
|
{ concurrency: 10 }
|
|
@@ -255,15 +280,34 @@ class EnsureBlockletRunning {
|
|
|
255
280
|
}
|
|
256
281
|
this.restartingBlocklets[key] = Date.now();
|
|
257
282
|
|
|
258
|
-
this.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
);
|
|
283
|
+
const blockletDisplayName = this.getDisplayNameByRootDid(did);
|
|
284
|
+
const restartTitle = 'Blocklet health check failed';
|
|
285
|
+
const restartDescription = `Blocklet ${blockletDisplayName} with components ${componentDids.map((v) => this.getDisplayName(blocklets.find((b) => b.meta.did === v))).join(', ')} health check failed, restarting...`;
|
|
286
|
+
this.notification(did, restartTitle, restartDescription, 'warning');
|
|
287
|
+
|
|
264
288
|
try {
|
|
265
289
|
logger.info('restart blocklet:', did, componentDids);
|
|
266
290
|
await this.restart({ did, componentDids, checkHealthImmediately: true });
|
|
291
|
+
this.createAuditLog({
|
|
292
|
+
action: 'ensureBlockletRunning',
|
|
293
|
+
args: {
|
|
294
|
+
teamDid: did,
|
|
295
|
+
componentDids,
|
|
296
|
+
},
|
|
297
|
+
context: {
|
|
298
|
+
user: {
|
|
299
|
+
did,
|
|
300
|
+
role: 'daemon',
|
|
301
|
+
blockletDid: did,
|
|
302
|
+
fullName: blockletDisplayName,
|
|
303
|
+
elevated: false,
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
result: {
|
|
307
|
+
title: restartTitle,
|
|
308
|
+
description: restartDescription,
|
|
309
|
+
},
|
|
310
|
+
});
|
|
267
311
|
delete this.restartingBlocklets[key];
|
|
268
312
|
} catch (e) {
|
|
269
313
|
logger.error('restart blocklet failed', did, componentDids, e);
|
|
@@ -274,16 +318,34 @@ class EnsureBlockletRunning {
|
|
|
274
318
|
|
|
275
319
|
// 如果重启失败次数超过 3 次,则设置为 stopped
|
|
276
320
|
if (this.errorStartBlocklets[key] >= 3) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
`Restart blocklet ${this.getDisplayNameByRootDid(did)} with components ${componentDids.map((v) => this.getDisplayName(blocklets.find((b) => b.meta.did === v))).join(', ')} failed`,
|
|
281
|
-
'error'
|
|
282
|
-
);
|
|
321
|
+
const title = 'Restart blocklet failed when health check failed';
|
|
322
|
+
const description = `Restart blocklet ${blockletDisplayName} with components ${componentDids.map((v) => this.getDisplayName(blocklets.find((b) => b.meta.did === v))).join(', ')} failed`;
|
|
323
|
+
this.notification(did, title, description, 'error');
|
|
283
324
|
delete this.errorStartBlocklets[key];
|
|
284
325
|
logger.error('restart many times blocklet failed, set stopped', did, componentDids, e);
|
|
285
326
|
try {
|
|
286
327
|
await this.stop({ did, componentDids });
|
|
328
|
+
this.createAuditLog({
|
|
329
|
+
action: 'ensureBlockletRunning',
|
|
330
|
+
args: {
|
|
331
|
+
blockletDisplayName,
|
|
332
|
+
teamDid: did,
|
|
333
|
+
componentDids,
|
|
334
|
+
},
|
|
335
|
+
context: {
|
|
336
|
+
user: {
|
|
337
|
+
did,
|
|
338
|
+
role: 'daemon',
|
|
339
|
+
blockletDid: did,
|
|
340
|
+
fullName: blockletDisplayName,
|
|
341
|
+
elevated: false,
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
result: {
|
|
345
|
+
title,
|
|
346
|
+
description,
|
|
347
|
+
},
|
|
348
|
+
});
|
|
287
349
|
} catch (err) {
|
|
288
350
|
logger.error('set blocklet stopped failed', did, componentDids, err);
|
|
289
351
|
}
|
|
@@ -100,7 +100,6 @@ const RBAC_CONFIG = {
|
|
|
100
100
|
name: SERVER_ROLES.CERTIFICATE,
|
|
101
101
|
title: 'Certificate',
|
|
102
102
|
description: 'Manage https certificates for blocklets on the Blocklet Server',
|
|
103
|
-
passport: true,
|
|
104
103
|
noHuman: true,
|
|
105
104
|
},
|
|
106
105
|
{
|
|
@@ -127,7 +126,6 @@ const RBAC_CONFIG = {
|
|
|
127
126
|
name: SERVER_ROLES.EXTERNAL_BLOCKLETS_MANAGER,
|
|
128
127
|
title: 'External Blocklets Manager',
|
|
129
128
|
description: 'Manage external blocklets in the Blocklet Server',
|
|
130
|
-
passport: true,
|
|
131
129
|
noHuman: true,
|
|
132
130
|
},
|
|
133
131
|
]),
|
|
@@ -38737,7 +38735,7 @@ module.exports = require("zlib");
|
|
|
38737
38735
|
/***/ ((module) => {
|
|
38738
38736
|
|
|
38739
38737
|
"use strict";
|
|
38740
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.
|
|
38738
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.42","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.42","@abtnode/auth":"1.16.42","@abtnode/certificate-manager":"1.16.42","@abtnode/constant":"1.16.42","@abtnode/cron":"1.16.42","@abtnode/docker-utils":"1.16.42","@abtnode/logger":"1.16.42","@abtnode/models":"1.16.42","@abtnode/queue":"1.16.42","@abtnode/rbac":"1.16.42","@abtnode/router-provider":"1.16.42","@abtnode/static-server":"1.16.42","@abtnode/timemachine":"1.16.42","@abtnode/util":"1.16.42","@arcblock/did":"1.20.1","@arcblock/did-auth":"1.20.1","@arcblock/did-ext":"^1.20.1","@arcblock/did-motif":"^1.1.13","@arcblock/did-util":"1.20.1","@arcblock/event-hub":"1.20.1","@arcblock/jwt":"^1.20.1","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"^1.20.1","@arcblock/vc":"1.20.1","@blocklet/constant":"1.16.42","@blocklet/did-space-js":"^1.0.48","@blocklet/env":"1.16.42","@blocklet/meta":"1.16.42","@blocklet/resolver":"1.16.42","@blocklet/sdk":"1.16.42","@blocklet/store":"1.16.42","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.20.1","@ocap/util":"1.20.1","@ocap/wallet":"1.20.1","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","dayjs":"^1.11.13","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","lru-cache":"^11.0.2","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","rate-limiter-flexible":"^5.0.5","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"}');
|
|
38741
38739
|
|
|
38742
38740
|
/***/ }),
|
|
38743
38741
|
|
package/lib/event/index.js
CHANGED
|
@@ -22,6 +22,7 @@ const {
|
|
|
22
22
|
} = require('@abtnode/constant');
|
|
23
23
|
const { joinURL } = require('ufo');
|
|
24
24
|
const { encode } = require('@abtnode/util/lib/base32');
|
|
25
|
+
|
|
25
26
|
const { NodeMonitSender } = require('../monitor/node-monit-sender');
|
|
26
27
|
const { isCLI } = require('../util');
|
|
27
28
|
|
|
@@ -626,5 +627,81 @@ module.exports = ({
|
|
|
626
627
|
eventHub.on(EVENT_BUS_EVENT, (data) => handleEventBusEvent(data));
|
|
627
628
|
}
|
|
628
629
|
|
|
630
|
+
// 更新会话时,暂不做任何操作
|
|
631
|
+
// listen(teamAPI, BlockletEvents.updateUserSession, noop);
|
|
632
|
+
listen(teamAPI, BlockletEvents.addUserSession, (eventName, eventData) => {
|
|
633
|
+
const { teamDid, userDid, userSession, locale = 'en', skipNotification = false, origin } = eventData;
|
|
634
|
+
if (skipNotification) {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const translations = {
|
|
638
|
+
en: {
|
|
639
|
+
title: 'You are logged in a new device',
|
|
640
|
+
body: `You are logged in a new device: ${userSession.ua}. \n\nIf this is not you, please click "View Your Account" button to view details`,
|
|
641
|
+
loginIp: 'Login IP',
|
|
642
|
+
loginAt: 'Login At',
|
|
643
|
+
viewYourAccount: 'View Your Account',
|
|
644
|
+
},
|
|
645
|
+
zh: {
|
|
646
|
+
title: '你在一个新的设备上登录了',
|
|
647
|
+
loginIp: '登录 IP',
|
|
648
|
+
loginAt: '登录时间',
|
|
649
|
+
body: `你在一个新的设备上登录了: ${userSession.ua}。\n\n如果这不是你本人在登录,请点击“查看您的账户”按钮查看详情`,
|
|
650
|
+
viewYourAccount: '查看您的账户',
|
|
651
|
+
},
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
const translation = translations[locale] || translations.en;
|
|
655
|
+
const localeMap = {
|
|
656
|
+
en: 'en-US',
|
|
657
|
+
zh: 'zh-CN',
|
|
658
|
+
};
|
|
659
|
+
const targetLocale = localeMap[locale] || localeMap.en;
|
|
660
|
+
const notification = {
|
|
661
|
+
title: translation.title,
|
|
662
|
+
body: translation.body,
|
|
663
|
+
severity: 'warning',
|
|
664
|
+
attachments: [
|
|
665
|
+
{
|
|
666
|
+
type: 'section',
|
|
667
|
+
fields: [
|
|
668
|
+
{
|
|
669
|
+
type: 'text',
|
|
670
|
+
data: { type: 'plain', color: '#9397A1', text: translation.loginIp },
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
type: 'text',
|
|
674
|
+
data: { type: 'plain', text: userSession.lastLoginIp },
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
type: 'text',
|
|
678
|
+
data: { type: 'plain', color: '#9397A1', text: translation.loginAt },
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
type: 'text',
|
|
682
|
+
data: { type: 'plain', text: userSession.updatedAt.toLocaleString(targetLocale) },
|
|
683
|
+
},
|
|
684
|
+
],
|
|
685
|
+
},
|
|
686
|
+
],
|
|
687
|
+
actions: [
|
|
688
|
+
{
|
|
689
|
+
name: translation.viewYourAccount,
|
|
690
|
+
link: `${origin}/.well-known/service/user/settings`,
|
|
691
|
+
},
|
|
692
|
+
],
|
|
693
|
+
};
|
|
694
|
+
logger.info(`create notification on ${eventName}`, { teamDid, receiver: userDid, notification });
|
|
695
|
+
teamManager.createNotification({
|
|
696
|
+
teamDid,
|
|
697
|
+
receiver: userDid,
|
|
698
|
+
// NOTICE: createNotification 如果传递 notification 对象,就必须加上 pushOnly 选项,否则会调用失败
|
|
699
|
+
// 目前先改为使用 payload 的形式传递通知内容
|
|
700
|
+
// notification,
|
|
701
|
+
...notification,
|
|
702
|
+
source: 'component',
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
|
|
629
706
|
return events;
|
|
630
707
|
};
|
package/lib/index.js
CHANGED
|
@@ -755,6 +755,8 @@ function ABTNode(options) {
|
|
|
755
755
|
getBlockletBaseInfo: teamAPI.getBlockletBaseInfo.bind(teamAPI),
|
|
756
756
|
};
|
|
757
757
|
|
|
758
|
+
blockletManager.createAuditLog = (params) => states.auditLog.create(params, instance);
|
|
759
|
+
|
|
758
760
|
const events = createEvents({
|
|
759
761
|
blockletManager,
|
|
760
762
|
ensureBlockletRouting,
|
|
@@ -193,6 +193,63 @@ class NodeRuntimeMonitor extends EventEmitter {
|
|
|
193
193
|
});
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
calculateUtilization() {
|
|
197
|
+
if (!this.data.realtime || !this.data.realtime.cpu || !this.data.realtime.mem || !this.data.realtime.disks) {
|
|
198
|
+
return {
|
|
199
|
+
cpus: [0],
|
|
200
|
+
disks: [0],
|
|
201
|
+
memory: 0,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
const { cpu, mem, disks } = this.data.realtime;
|
|
206
|
+
// 计算每个 CPU 的占用率:load字段为百分比,除以 100 得到 0 到 1 的值
|
|
207
|
+
const cpuUtilizations = cpu.cpus.filter((v) => v.load > 0).map((v) => v.load / 100);
|
|
208
|
+
|
|
209
|
+
// 计算内存占用率:used / total
|
|
210
|
+
const memoryUtilization = mem.total > 0 && mem.available > 0 ? (mem.total - mem.available) / mem.total : 0;
|
|
211
|
+
|
|
212
|
+
// 计算每个硬盘占用率:used / total
|
|
213
|
+
const diskUtilizations = disks.filter((v) => v.used > 0).map((v) => v.used / v.total);
|
|
214
|
+
|
|
215
|
+
// 返回包含所需值的对象
|
|
216
|
+
return {
|
|
217
|
+
cpus: cpuUtilizations,
|
|
218
|
+
disks: diskUtilizations,
|
|
219
|
+
memory: memoryUtilization,
|
|
220
|
+
};
|
|
221
|
+
} catch (error) {
|
|
222
|
+
this.logger.error('failed to calculate utilization', error);
|
|
223
|
+
return {
|
|
224
|
+
cpus: [0],
|
|
225
|
+
disks: [0],
|
|
226
|
+
memory: 0,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
checkSystemHighLoad({ maxCpus, maxMem, maxDisk }) {
|
|
232
|
+
const { cpus, memory, disks } = this.calculateUtilization();
|
|
233
|
+
let highType = '';
|
|
234
|
+
if (cpus.some((v) => v > maxCpus)) {
|
|
235
|
+
highType = 'cpu';
|
|
236
|
+
} else if (memory > maxMem) {
|
|
237
|
+
highType = 'memory';
|
|
238
|
+
} else if (disks.some((v) => v > maxDisk)) {
|
|
239
|
+
highType = 'disk';
|
|
240
|
+
}
|
|
241
|
+
if (highType) {
|
|
242
|
+
this.logger.info('system high load', { cpus, memory, disks });
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
isHighLoad: !!highType,
|
|
246
|
+
highType,
|
|
247
|
+
cpus,
|
|
248
|
+
memory,
|
|
249
|
+
disks,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
196
253
|
cleanup() {
|
|
197
254
|
return this.state.remove({ date: { $lt: Date.now() - 1000 * 60 * 60 * 24 } });
|
|
198
255
|
}
|
package/lib/states/audit-log.js
CHANGED
|
@@ -513,6 +513,8 @@ const getLogContent = async (action, args, context, result, info, node) => {
|
|
|
513
513
|
return `Update Blocklet Webhook(${result.id})`;
|
|
514
514
|
case 'deleteWebhookEndpoint':
|
|
515
515
|
return `Delete Blocklet Webhook(${result.id})`;
|
|
516
|
+
case 'ensureBlockletRunning':
|
|
517
|
+
return `${result.title}:\n* ${result.description}`;
|
|
516
518
|
|
|
517
519
|
default:
|
|
518
520
|
return action;
|
|
@@ -557,6 +559,7 @@ const getLogCategory = (action) => {
|
|
|
557
559
|
case 'auditFederated':
|
|
558
560
|
case 'syncMasterAuthorization':
|
|
559
561
|
case 'syncFederatedConfig':
|
|
562
|
+
case 'ensureBlockletRunning':
|
|
560
563
|
return 'blocklet';
|
|
561
564
|
|
|
562
565
|
// store,此处应该返回 server
|
|
@@ -732,11 +735,9 @@ class AuditLogState extends BaseState {
|
|
|
732
735
|
const [info, uaInfo] = await Promise.all([node.states.node.read(), parse(ua)]);
|
|
733
736
|
|
|
734
737
|
fixActor(user);
|
|
735
|
-
|
|
736
738
|
const content = (await getLogContent(action, args, context, result, info, node)).trim();
|
|
737
739
|
const actor = pick(user.actual || user, ['did', 'fullName', 'role']);
|
|
738
740
|
actor.source = '';
|
|
739
|
-
|
|
740
741
|
const teamDid =
|
|
741
742
|
user.blockletDid || args.teamDid || (typeof args?.did === 'string' ? args.did : get(args, 'did.0'));
|
|
742
743
|
const userDid = user.did || args.userDid || get(args, 'user.did') || args.ownerDid;
|
|
@@ -770,6 +771,7 @@ class AuditLogState extends BaseState {
|
|
|
770
771
|
}
|
|
771
772
|
} else {
|
|
772
773
|
actor.avatar = '';
|
|
774
|
+
// actor.did = teamDid || info.did;
|
|
773
775
|
}
|
|
774
776
|
|
|
775
777
|
const data = await this.insert({
|
package/lib/states/user.js
CHANGED
|
@@ -757,6 +757,13 @@ SELECT did,inviter,generation FROM UserTree`.trim();
|
|
|
757
757
|
if (user.phone) {
|
|
758
758
|
user.phone = String(user.phone).trim().toLowerCase().replace(/\s+/g, '').replace(/[()-]/g, '');
|
|
759
759
|
}
|
|
760
|
+
if (user.metadata?.phone?.phoneNumber) {
|
|
761
|
+
user.metadata.phone.phoneNumber = String(user.metadata.phone.phoneNumber)
|
|
762
|
+
.trim()
|
|
763
|
+
.toLowerCase()
|
|
764
|
+
.replace(/\s+/g, '')
|
|
765
|
+
.replace(/[()-]/g, '');
|
|
766
|
+
}
|
|
760
767
|
return user;
|
|
761
768
|
}
|
|
762
769
|
|
package/lib/util/blocklet.js
CHANGED
|
@@ -1028,7 +1028,7 @@ const shouldCheckHealthy = (blocklet) => {
|
|
|
1028
1028
|
|
|
1029
1029
|
const isBlockletPortHealthy = async (blocklet, { minConsecutiveTime = 3000, timeout = 10 * 1000 } = {}) => {
|
|
1030
1030
|
if (!blocklet) {
|
|
1031
|
-
return
|
|
1031
|
+
return;
|
|
1032
1032
|
}
|
|
1033
1033
|
const { environments } = blocklet;
|
|
1034
1034
|
const webInterface = (blocklet.meta?.interfaces || []).find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
@@ -1042,22 +1042,16 @@ const isBlockletPortHealthy = async (blocklet, { minConsecutiveTime = 3000, time
|
|
|
1042
1042
|
}
|
|
1043
1043
|
|
|
1044
1044
|
if (!port) {
|
|
1045
|
-
return
|
|
1045
|
+
return;
|
|
1046
1046
|
}
|
|
1047
1047
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
});
|
|
1056
|
-
return true;
|
|
1057
|
-
} catch (error) {
|
|
1058
|
-
logger.error('blocklet port is not healthy', error);
|
|
1059
|
-
return false;
|
|
1060
|
-
}
|
|
1048
|
+
await ensureEndpointHealthy({
|
|
1049
|
+
port,
|
|
1050
|
+
protocol: webInterface ? 'http' : 'tcp',
|
|
1051
|
+
minConsecutiveTime,
|
|
1052
|
+
timeout,
|
|
1053
|
+
doConsecutiveCheck: false,
|
|
1054
|
+
});
|
|
1061
1055
|
};
|
|
1062
1056
|
|
|
1063
1057
|
const expandTarball = async ({ source, dest, strip = 1 }) => {
|
package/lib/util/env.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
const
|
|
2
|
-
? +process.env.
|
|
3
|
-
:
|
|
1
|
+
const serverJobBackoffSeconds = process.env.ABT_NODE_JOB_BACKOFF_SECONDS
|
|
2
|
+
? +process.env.ABT_NODE_JOB_BACKOFF_SECONDS
|
|
3
|
+
: 600;
|
|
4
|
+
|
|
5
|
+
const shouldJobBackoff = () => {
|
|
6
|
+
const uptime = process.uptime();
|
|
7
|
+
return uptime <= serverJobBackoffSeconds;
|
|
8
|
+
};
|
|
4
9
|
|
|
5
10
|
module.exports = {
|
|
6
|
-
|
|
11
|
+
serverJobBackoffSeconds,
|
|
12
|
+
shouldJobBackoff,
|
|
7
13
|
};
|
package/lib/util/launcher.js
CHANGED
|
@@ -367,6 +367,8 @@ const setupAppOwner = async ({ node, sessionId, justCreate = false, context, pro
|
|
|
367
367
|
clientName: context?.device?.clientName,
|
|
368
368
|
},
|
|
369
369
|
},
|
|
370
|
+
locale,
|
|
371
|
+
origin: context?.origin,
|
|
370
372
|
})
|
|
371
373
|
.catch((error) => {
|
|
372
374
|
logger.error('upsertUserSession failed', { error, appDid, ownerDid, context });
|
package/lib/util/user.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const omitBy = require('lodash/omitBy');
|
|
2
|
+
const omit = require('lodash/omit');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 生成用户要更新的数据
|
|
6
|
+
* @param {*} user 要更新的用户对象
|
|
7
|
+
* @param {*} existingUser 已存在的用户对象
|
|
8
|
+
*/
|
|
9
|
+
const generateUserUpdateData = (user, existingUser) => {
|
|
10
|
+
// 如果用户不存在,需要抛出错误
|
|
11
|
+
if (!existingUser) {
|
|
12
|
+
throw new Error('User not found');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { emailVerified, phoneVerified, metadata = {} } = existingUser;
|
|
16
|
+
|
|
17
|
+
// 创建基础更新对象,只包含非空值
|
|
18
|
+
let updateData = {
|
|
19
|
+
did: user.did,
|
|
20
|
+
...omitBy(user, (x) => !x),
|
|
21
|
+
metadata: { ...metadata, ...user.metadata },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// 处理地址
|
|
25
|
+
if (user.address) {
|
|
26
|
+
updateData.address = {
|
|
27
|
+
...existingUser.address,
|
|
28
|
+
...(user.address ?? {}),
|
|
29
|
+
};
|
|
30
|
+
updateData.metadata = {
|
|
31
|
+
...updateData.metadata,
|
|
32
|
+
...(user.metadata ?? {}),
|
|
33
|
+
location: user.address?.city || '',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 处理电话信息
|
|
38
|
+
if (phoneVerified && updateData.metadata?.phone?.phoneNumber !== existingUser.phone) {
|
|
39
|
+
// 保持原号码相同
|
|
40
|
+
updateData.metadata.phone = {
|
|
41
|
+
country: '',
|
|
42
|
+
phoneNumber: existingUser.phone,
|
|
43
|
+
};
|
|
44
|
+
} else if (!phoneVerified && user.phone) {
|
|
45
|
+
// 从user.phone更新
|
|
46
|
+
updateData.metadata.phone = {
|
|
47
|
+
country: '',
|
|
48
|
+
phoneNumber: user.phone,
|
|
49
|
+
};
|
|
50
|
+
} else if (!phoneVerified && !user.phone && user.metadata?.phone) {
|
|
51
|
+
// 从user.metadata.phone更新
|
|
52
|
+
updateData.phone = user.metadata?.phone?.phoneNumber || '';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 处理邮件
|
|
56
|
+
if (user.metadata?.email) {
|
|
57
|
+
updateData.metadata = omit(updateData.metadata, ['email']);
|
|
58
|
+
if (!emailVerified) {
|
|
59
|
+
updateData.email = user.metadata.email;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 邮箱已验证,保持服务器上已验证的邮箱
|
|
64
|
+
if (emailVerified && updateData.email) {
|
|
65
|
+
updateData = omit(updateData, ['email']);
|
|
66
|
+
}
|
|
67
|
+
if (phoneVerified && updateData.phone) {
|
|
68
|
+
updateData = omit(updateData, ['phone']);
|
|
69
|
+
}
|
|
70
|
+
return updateData;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
module.exports = { generateUserUpdateData };
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.
|
|
6
|
+
"version": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,41 +19,41 @@
|
|
|
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.
|
|
23
|
-
"@abtnode/auth": "1.16.
|
|
24
|
-
"@abtnode/certificate-manager": "1.16.
|
|
25
|
-
"@abtnode/constant": "1.16.
|
|
26
|
-
"@abtnode/cron": "1.16.
|
|
27
|
-
"@abtnode/docker-utils": "1.16.
|
|
28
|
-
"@abtnode/logger": "1.16.
|
|
29
|
-
"@abtnode/models": "1.16.
|
|
30
|
-
"@abtnode/queue": "1.16.
|
|
31
|
-
"@abtnode/rbac": "1.16.
|
|
32
|
-
"@abtnode/router-provider": "1.16.
|
|
33
|
-
"@abtnode/static-server": "1.16.
|
|
34
|
-
"@abtnode/timemachine": "1.16.
|
|
35
|
-
"@abtnode/util": "1.16.
|
|
36
|
-
"@arcblock/did": "1.20.
|
|
37
|
-
"@arcblock/did-auth": "1.20.
|
|
38
|
-
"@arcblock/did-ext": "^1.20.
|
|
22
|
+
"@abtnode/analytics": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
23
|
+
"@abtnode/auth": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
24
|
+
"@abtnode/certificate-manager": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
25
|
+
"@abtnode/constant": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
26
|
+
"@abtnode/cron": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
27
|
+
"@abtnode/docker-utils": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
28
|
+
"@abtnode/logger": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
29
|
+
"@abtnode/models": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
30
|
+
"@abtnode/queue": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
31
|
+
"@abtnode/rbac": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
32
|
+
"@abtnode/router-provider": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
33
|
+
"@abtnode/static-server": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
34
|
+
"@abtnode/timemachine": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
35
|
+
"@abtnode/util": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
36
|
+
"@arcblock/did": "1.20.1",
|
|
37
|
+
"@arcblock/did-auth": "1.20.1",
|
|
38
|
+
"@arcblock/did-ext": "^1.20.1",
|
|
39
39
|
"@arcblock/did-motif": "^1.1.13",
|
|
40
|
-
"@arcblock/did-util": "1.20.
|
|
41
|
-
"@arcblock/event-hub": "1.20.
|
|
42
|
-
"@arcblock/jwt": "^1.20.
|
|
40
|
+
"@arcblock/did-util": "1.20.1",
|
|
41
|
+
"@arcblock/event-hub": "1.20.1",
|
|
42
|
+
"@arcblock/jwt": "^1.20.1",
|
|
43
43
|
"@arcblock/pm2-events": "^0.0.5",
|
|
44
|
-
"@arcblock/validator": "^1.20.
|
|
45
|
-
"@arcblock/vc": "1.20.
|
|
46
|
-
"@blocklet/constant": "1.16.
|
|
47
|
-
"@blocklet/did-space-js": "^1.0.
|
|
48
|
-
"@blocklet/env": "1.16.
|
|
49
|
-
"@blocklet/meta": "1.16.
|
|
50
|
-
"@blocklet/resolver": "1.16.
|
|
51
|
-
"@blocklet/sdk": "1.16.
|
|
52
|
-
"@blocklet/store": "1.16.
|
|
44
|
+
"@arcblock/validator": "^1.20.1",
|
|
45
|
+
"@arcblock/vc": "1.20.1",
|
|
46
|
+
"@blocklet/constant": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
47
|
+
"@blocklet/did-space-js": "^1.0.48",
|
|
48
|
+
"@blocklet/env": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
49
|
+
"@blocklet/meta": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
50
|
+
"@blocklet/resolver": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
51
|
+
"@blocklet/sdk": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
52
|
+
"@blocklet/store": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
53
53
|
"@fidm/x509": "^1.2.1",
|
|
54
|
-
"@ocap/mcrypto": "1.20.
|
|
55
|
-
"@ocap/util": "1.20.
|
|
56
|
-
"@ocap/wallet": "1.20.
|
|
54
|
+
"@ocap/mcrypto": "1.20.1",
|
|
55
|
+
"@ocap/util": "1.20.1",
|
|
56
|
+
"@ocap/wallet": "1.20.1",
|
|
57
57
|
"@slack/webhook": "^5.0.4",
|
|
58
58
|
"archiver": "^7.0.1",
|
|
59
59
|
"axios": "^1.7.9",
|
|
@@ -111,5 +111,5 @@
|
|
|
111
111
|
"jest": "^29.7.0",
|
|
112
112
|
"unzipper": "^0.10.11"
|
|
113
113
|
},
|
|
114
|
-
"gitHead": "
|
|
114
|
+
"gitHead": "207acad34e8ccf318cd7539c1ac717cee7951b53"
|
|
115
115
|
}
|