@abtnode/core 1.15.17 → 1.16.0-beta-b16cb035

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.
Files changed (119) hide show
  1. package/lib/api/node.js +67 -69
  2. package/lib/api/team.js +386 -55
  3. package/lib/blocklet/downloader/blocklet-downloader.js +226 -0
  4. package/lib/blocklet/downloader/bundle-downloader.js +272 -0
  5. package/lib/blocklet/downloader/constants.js +3 -0
  6. package/lib/blocklet/downloader/resolve-download.js +199 -0
  7. package/lib/blocklet/extras.js +83 -26
  8. package/lib/blocklet/hooks.js +18 -65
  9. package/lib/blocklet/manager/base.js +10 -16
  10. package/lib/blocklet/manager/disk.js +1679 -1566
  11. package/lib/blocklet/manager/helper/install-application-from-backup.js +177 -0
  12. package/lib/blocklet/manager/helper/install-application-from-dev.js +94 -0
  13. package/lib/blocklet/manager/helper/install-application-from-general.js +188 -0
  14. package/lib/blocklet/manager/helper/install-component-from-dev.js +84 -0
  15. package/lib/blocklet/manager/helper/install-component-from-upload.js +181 -0
  16. package/lib/blocklet/manager/helper/install-component-from-url.js +173 -0
  17. package/lib/blocklet/manager/helper/migrate-application-to-struct-v2.js +450 -0
  18. package/lib/blocklet/manager/helper/rollback-cache.js +41 -0
  19. package/lib/blocklet/manager/helper/upgrade-components.js +152 -0
  20. package/lib/blocklet/migration.js +30 -52
  21. package/lib/blocklet/storage/backup/audit-log.js +27 -0
  22. package/lib/blocklet/storage/backup/base.js +62 -0
  23. package/lib/blocklet/storage/backup/blocklet-extras.js +92 -0
  24. package/lib/blocklet/storage/backup/blocklet.js +70 -0
  25. package/lib/blocklet/storage/backup/blocklets.js +74 -0
  26. package/lib/blocklet/storage/backup/data.js +19 -0
  27. package/lib/blocklet/storage/backup/logs.js +24 -0
  28. package/lib/blocklet/storage/backup/routing-rule.js +19 -0
  29. package/lib/blocklet/storage/backup/spaces.js +240 -0
  30. package/lib/blocklet/storage/restore/base.js +67 -0
  31. package/lib/blocklet/storage/restore/blocklet-extras.js +86 -0
  32. package/lib/blocklet/storage/restore/blocklet.js +56 -0
  33. package/lib/blocklet/storage/restore/blocklets.js +43 -0
  34. package/lib/blocklet/storage/restore/logs.js +21 -0
  35. package/lib/blocklet/storage/restore/spaces.js +156 -0
  36. package/lib/blocklet/storage/utils/hash.js +51 -0
  37. package/lib/blocklet/storage/utils/zip.js +43 -0
  38. package/lib/cert.js +206 -0
  39. package/lib/event.js +237 -64
  40. package/lib/index.js +191 -83
  41. package/lib/migrations/1.0.21-update-config.js +1 -1
  42. package/lib/migrations/1.0.22-max-memory.js +1 -1
  43. package/lib/migrations/1.0.25.js +1 -1
  44. package/lib/migrations/1.0.32-update-config.js +1 -1
  45. package/lib/migrations/1.0.33-blocklets.js +1 -1
  46. package/lib/migrations/1.5.20-registry.js +15 -0
  47. package/lib/migrations/1.6.17-blocklet-children.js +48 -0
  48. package/lib/migrations/1.6.21-rename-ip-echo-domain.js +35 -0
  49. package/lib/migrations/1.6.4-security.js +59 -0
  50. package/lib/migrations/1.6.5-security.js +60 -0
  51. package/lib/migrations/1.6.9-update-node-info-and-certificate.js +38 -0
  52. package/lib/migrations/1.7.1-blocklet-setup.js +18 -0
  53. package/lib/migrations/1.7.12-blocklet-meta.js +51 -0
  54. package/lib/migrations/1.7.15-blocklet-bundle-source.js +42 -0
  55. package/lib/migrations/1.7.20-blocklet-component.js +41 -0
  56. package/lib/migrations/1.8.33-blocklet-mem-limit.js +20 -0
  57. package/lib/migrations/README.md +1 -1
  58. package/lib/migrations/index.js +6 -2
  59. package/lib/monitor/blocklet-runtime-monitor.js +200 -0
  60. package/lib/monitor/get-history-list.js +37 -0
  61. package/lib/monitor/node-runtime-monitor.js +228 -0
  62. package/lib/router/helper.js +572 -497
  63. package/lib/router/index.js +85 -21
  64. package/lib/router/manager.js +146 -187
  65. package/lib/states/README.md +36 -1
  66. package/lib/states/access-key.js +39 -17
  67. package/lib/states/audit-log.js +462 -0
  68. package/lib/states/base.js +4 -213
  69. package/lib/states/blocklet-extras.js +194 -138
  70. package/lib/states/blocklet.js +361 -104
  71. package/lib/states/cache.js +8 -6
  72. package/lib/states/challenge.js +5 -5
  73. package/lib/states/index.js +19 -36
  74. package/lib/states/migration.js +4 -4
  75. package/lib/states/node.js +135 -46
  76. package/lib/states/notification.js +22 -35
  77. package/lib/states/session.js +17 -9
  78. package/lib/states/site.js +50 -25
  79. package/lib/states/user.js +74 -20
  80. package/lib/states/webhook.js +10 -6
  81. package/lib/team/manager.js +124 -7
  82. package/lib/util/blocklet.js +1223 -246
  83. package/lib/util/chain.js +1 -1
  84. package/lib/util/default-node-config.js +5 -23
  85. package/lib/util/disk-monitor.js +13 -10
  86. package/lib/util/domain-status.js +84 -15
  87. package/lib/util/get-accessible-external-node-ip.js +2 -2
  88. package/lib/util/get-domain-for-blocklet.js +13 -0
  89. package/lib/util/get-meta-from-url.js +33 -0
  90. package/lib/util/index.js +207 -272
  91. package/lib/util/ip.js +6 -0
  92. package/lib/util/maintain.js +233 -0
  93. package/lib/util/public-to-store.js +85 -0
  94. package/lib/util/ready.js +1 -1
  95. package/lib/util/requirement.js +28 -9
  96. package/lib/util/reset-node.js +22 -7
  97. package/lib/util/router.js +13 -0
  98. package/lib/util/rpc.js +16 -0
  99. package/lib/util/store.js +179 -0
  100. package/lib/util/sysinfo.js +44 -0
  101. package/lib/util/ua.js +54 -0
  102. package/lib/validators/blocklet-extra.js +24 -0
  103. package/lib/validators/node.js +25 -12
  104. package/lib/validators/permission.js +16 -1
  105. package/lib/validators/role.js +17 -3
  106. package/lib/validators/router.js +40 -20
  107. package/lib/validators/trusted-passport.js +1 -0
  108. package/lib/validators/util.js +22 -5
  109. package/lib/webhook/index.js +45 -35
  110. package/lib/webhook/sender/index.js +5 -0
  111. package/lib/webhook/sender/slack/index.js +1 -1
  112. package/lib/webhook/sender/wallet/index.js +48 -0
  113. package/package.json +54 -36
  114. package/lib/blocklet/registry.js +0 -205
  115. package/lib/states/https-cert.js +0 -67
  116. package/lib/util/get-ip-dns-domain-for-blocklet.js +0 -19
  117. package/lib/util/service.js +0 -66
  118. package/lib/util/upgrade.js +0 -178
  119. /package/lib/{queue.js → util/queue.js} +0 -0
@@ -1,22 +1,34 @@
1
1
  const logger = require('@abtnode/logger')('@abtnode/core:states:site');
2
+ const { toSlotDomain } = require('@abtnode/router-provider/lib/util');
2
3
 
3
4
  const BaseState = require('./base');
5
+ const { getBlockletDomainGroupName } = require('../util/router');
6
+ const { validateUpdateDomainAliases } = require('../validators/router');
7
+
8
+ // type Site = {
9
+ // id: string;
10
+ // domain: string;
11
+ // domainAliases: Array<{value: string, isProtected: boolean}>;
12
+ // isProtected: boolean;
13
+ // rules: Array<Rule>;
14
+ // corsAllowedOrigins: Array<string>;
15
+ // };
4
16
 
5
17
  class SiteState extends BaseState {
6
- constructor(baseDir, options = {}) {
7
- super(baseDir, { filename: 'routing_rule.db', ...options });
18
+ constructor(baseDir, config = {}) {
19
+ super(baseDir, { filename: 'routing_rule.db', ...config });
8
20
  }
9
21
 
10
- async add(rule) {
11
- const result = await this.asyncDB.insert(rule);
22
+ async add(site) {
23
+ const result = await this.insert(site);
12
24
 
13
- const tmpRule = SiteState.renameIdFiledName(result);
14
- logger.info('rule created', { rule: tmpRule });
15
- return tmpRule;
25
+ const tmpSite = SiteState.renameIdFiledName(result);
26
+ logger.info('site created', { site: tmpSite });
27
+ return tmpSite;
16
28
  }
17
29
 
18
30
  async addRuleToSite(id, rule) {
19
- const addedCount = await this.asyncDB.update({ _id: id }, { $addToSet: { rules: rule } });
31
+ const addedCount = await this.update({ _id: id }, { $addToSet: { rules: rule } });
20
32
 
21
33
  logger.info('added rule to site', { count: addedCount });
22
34
  return addedCount;
@@ -25,21 +37,21 @@ class SiteState extends BaseState {
25
37
  async getSites(...args) {
26
38
  let result = null;
27
39
  if (args.length === 0) {
28
- result = await this.asyncDB.find({});
40
+ result = await this.find({});
29
41
  } else {
30
- result = await this.asyncDB.find(...args);
42
+ result = await this.find(...args);
31
43
  }
32
44
 
33
45
  return SiteState.renameIdFiledName(result);
34
46
  }
35
47
 
36
48
  async getSitesByBlocklet(did) {
37
- const rules = await this.asyncDB.find({ 'rules.to.did': did });
49
+ const rules = await this.find({ 'rules.to.did': did });
38
50
  return SiteState.renameIdFiledName(rules);
39
51
  }
40
52
 
41
53
  async getRuleById(id) {
42
- const site = await this.asyncDB.findOne({ 'rules.id': id });
54
+ const site = await this.findOne({ 'rules.id': id });
43
55
  if (!site) {
44
56
  return null;
45
57
  }
@@ -47,20 +59,8 @@ class SiteState extends BaseState {
47
59
  return site.rules.find((x) => x.id === id);
48
60
  }
49
61
 
50
- async update(...args) {
51
- return this.asyncDB.update(...args);
52
- }
53
-
54
- async count(...args) {
55
- return this.asyncDB.count(...args);
56
- }
57
-
58
- async remove(...args) {
59
- return this.asyncDB.remove(...args);
60
- }
61
-
62
62
  async findOne(...args) {
63
- const site = await this.asyncDB.findOne(...args);
63
+ const site = await super.findOne(...args);
64
64
  if (!site) {
65
65
  return site;
66
66
  }
@@ -75,6 +75,31 @@ class SiteState extends BaseState {
75
75
 
76
76
  return count > 0;
77
77
  }
78
+
79
+ async findOneByDomain(domain) {
80
+ // eslint-disable-next-line no-param-reassign
81
+ domain = toSlotDomain(domain);
82
+ return this.findOne({
83
+ $or: [{ domain }, { domainAliases: domain }, { 'domainAliases.value': domain }],
84
+ });
85
+ }
86
+
87
+ async findOneByBlocklet(did) {
88
+ const result = await this.findOne({ domain: getBlockletDomainGroupName(did) });
89
+
90
+ return BaseState.renameIdFiledName(result);
91
+ }
92
+
93
+ async getBlockletDomains(did) {
94
+ const site = await this.findOneByBlocklet(did);
95
+ return (site?.domainAliases || []).map((x) => x.value).filter(Boolean);
96
+ }
97
+
98
+ async updateDomainAliasList(id, domainAliases) {
99
+ await validateUpdateDomainAliases(domainAliases);
100
+
101
+ return super.update({ _id: id }, { $set: { domainAliases } });
102
+ }
78
103
  }
79
104
 
80
105
  module.exports = SiteState;
@@ -1,20 +1,24 @@
1
+ const pickBy = require('lodash/pickBy');
2
+ const escapeStringRegexp = require('escape-string-regexp');
3
+
1
4
  const logger = require('@abtnode/logger')('@abtnode/core:states:user');
5
+ const { isValid } = require('@arcblock/did');
2
6
  const { PASSPORT_STATUS } = require('@abtnode/constant');
3
7
  const BaseState = require('./base');
4
8
  const { validateOwner } = require('../util');
5
9
 
6
- const fixPassports = (doc) => {
7
- doc.passports = (doc.passports || []).filter((x) => x.id);
8
- };
10
+ const isNullOrUndefined = (x) => x === undefined || x === null;
9
11
 
10
12
  class User extends BaseState {
11
- constructor(baseDir, options = {}) {
12
- super(baseDir, { filename: 'user.db', ...options });
13
-
14
- this.db.ensureIndex({ fieldName: 'did', unique: true }, (error) => {
15
- if (error) {
16
- logger.error('ensure index failed', { error });
17
- }
13
+ constructor(baseDir, config = {}) {
14
+ super(baseDir, { filename: 'user.db', ...config });
15
+
16
+ this.onReady(() => {
17
+ this.ensureIndex({ fieldName: 'did', unique: true }, (error) => {
18
+ if (error) {
19
+ logger.error('ensure index failed', { error });
20
+ }
21
+ });
18
22
  });
19
23
  }
20
24
 
@@ -85,21 +89,71 @@ class User extends BaseState {
85
89
  return doc;
86
90
  }
87
91
 
88
- async getUsers() {
89
- const docs = await super.find();
90
- if (docs) {
91
- docs.forEach(fixPassports); // backward compatible
92
+ async getUsers({ query, sort, paging: inputPaging } = {}) {
93
+ const { approved, role, search } = query || {};
94
+
95
+ // make query param
96
+ const queryParam = {};
97
+
98
+ if (!isNullOrUndefined(approved)) {
99
+ queryParam.approved = !!approved;
100
+ }
101
+
102
+ if (search) {
103
+ if (search.length > 50) {
104
+ throw new Error('the length of search text should not more than 50');
105
+ }
106
+
107
+ if (isValid(search)) {
108
+ queryParam.did = search;
109
+ } else {
110
+ const reg = new RegExp(escapeStringRegexp(search), 'i');
111
+
112
+ queryParam.fullName = { $regex: reg };
113
+ }
114
+ }
115
+
116
+ if (role && role !== '$all') {
117
+ if (role === '$none') {
118
+ queryParam.passports = { $size: 0 };
119
+ } else {
120
+ queryParam.passports = { $elemMatch: { name: role, status: PASSPORT_STATUS.VALID } };
121
+ }
122
+ }
123
+
124
+ const sortParam = pickBy(sort, (x) => !isNullOrUndefined(x));
125
+
126
+ if (!Object.keys(sortParam).length) {
127
+ sortParam.createdAt = -1;
92
128
  }
93
129
 
94
- return docs;
130
+ // get data
131
+ const { list, paging } = await this.paginate(queryParam, sortParam, inputPaging);
132
+
133
+ return {
134
+ list,
135
+ paging,
136
+ };
95
137
  }
96
138
 
97
- async getUser(did) {
98
- const doc = await super.findOne({ did });
99
- if (doc) {
100
- fixPassports(doc); // backward compatible
139
+ async getUsersByDids({ dids, query } = {}) {
140
+ const { approved } = query || {};
141
+ const didList = dids || [];
142
+
143
+ const queryParam = {
144
+ did: { $in: didList },
145
+ };
146
+
147
+ if (!isNullOrUndefined(approved)) {
148
+ queryParam.approved = !!approved;
101
149
  }
102
150
 
151
+ // get data
152
+ return this.find(queryParam);
153
+ }
154
+
155
+ async getUser(did) {
156
+ const doc = await this.findOne({ did });
103
157
  return doc;
104
158
  }
105
159
 
@@ -109,7 +163,7 @@ class User extends BaseState {
109
163
  * @param {string} status passport status
110
164
  */
111
165
  async _setPassportStatusById({ did, id, status } = {}) {
112
- const exist = await super.findOne({ did });
166
+ const exist = await this.findOne({ did });
113
167
 
114
168
  if (!exist) {
115
169
  throw new Error('did does not exist');
@@ -4,11 +4,11 @@ const BaseState = require('./base');
4
4
  const { validateWebhook } = require('../validators/webhook');
5
5
 
6
6
  class WebhookState extends BaseState {
7
- constructor(baseDir, options = {}) {
8
- super(baseDir, { filename: 'webhook.db', ...options });
7
+ constructor(baseDir, config = {}) {
8
+ super(baseDir, { filename: 'webhook.db', ...config });
9
9
  }
10
10
 
11
- async create(info) {
11
+ async create(info, { mock } = {}) {
12
12
  const { type, params } = info;
13
13
  const filterParams = params.map((item) => {
14
14
  const data = {
@@ -26,7 +26,11 @@ class WebhookState extends BaseState {
26
26
 
27
27
  await validateWebhook(data);
28
28
 
29
- const webhook = await this.asyncDB.insert(data);
29
+ if (mock) {
30
+ return data;
31
+ }
32
+
33
+ const webhook = await this.insert(data);
30
34
  return webhook;
31
35
  }
32
36
 
@@ -42,7 +46,7 @@ class WebhookState extends BaseState {
42
46
  throw new Error('webhookId should not be empty');
43
47
  }
44
48
  const webhook = await this.findOne(id);
45
- const num = await this.asyncDB.remove({ _id: id });
49
+ const num = await this.remove({ _id: id });
46
50
  if (num <= 0) {
47
51
  throw new Error(`${id} does not exist`);
48
52
  }
@@ -52,7 +56,7 @@ class WebhookState extends BaseState {
52
56
 
53
57
  async findOne(id) {
54
58
  try {
55
- const webhook = await this.asyncDB.findOne({ _id: id });
59
+ const webhook = await super.findOne({ _id: id });
56
60
 
57
61
  return webhook;
58
62
  } catch (error) {
@@ -5,11 +5,14 @@ const path = require('path');
5
5
  const { EventEmitter } = require('events');
6
6
  const upperFirst = require('lodash/upperFirst');
7
7
  const get = require('lodash/get');
8
+ const pick = require('lodash/pick');
8
9
 
9
10
  const { createRBAC, MemoryStorage, NedbStorage } = require('@abtnode/rbac');
10
11
  const logger = require('@abtnode/logger')('@abtnode/core:team:manager');
11
12
  const { ROLES, RBAC_CONFIG } = require('@abtnode/constant');
13
+ const { BlockletEvents } = require('@blocklet/constant');
12
14
  const Lock = require('@abtnode/util/lib/lock');
15
+ const sleep = require('@abtnode/util/lib/sleep');
13
16
  const UserState = require('../states/user');
14
17
  const SessionState = require('../states/session');
15
18
 
@@ -17,6 +20,23 @@ const { isCLI } = require('../util');
17
20
 
18
21
  const rbacCreationLock = new Lock('rbac-creation-lock');
19
22
 
23
+ const closeDatabase = async (db) =>
24
+ new Promise((resolve, reject) => {
25
+ if (!db) {
26
+ resolve(true);
27
+ return;
28
+ }
29
+
30
+ db.closeDatabase((err) => {
31
+ if (err) {
32
+ reject(err);
33
+ return;
34
+ }
35
+
36
+ resolve(true);
37
+ });
38
+ });
39
+
20
40
  class TeamManager extends EventEmitter {
21
41
  constructor({ nodeDid, dataDirs, states }) {
22
42
  super();
@@ -48,10 +68,6 @@ class TeamManager extends EventEmitter {
48
68
  });
49
69
  });
50
70
 
51
- this.states.blocklet.on('remove', ({ meta: { did } }) => {
52
- this.cache[did] = null;
53
- });
54
-
55
71
  // init blocklet
56
72
  this.states.blocklet
57
73
  .getBlocklets()
@@ -96,7 +112,7 @@ class TeamManager extends EventEmitter {
96
112
 
97
113
  async getUserState(did) {
98
114
  // validate exist
99
- if (!this.isNodeTeam(did) && !(await this.states.blocklet.getBlocklet(did))) {
115
+ if (!this.isNodeTeam(did) && !(await this.states.blocklet.hasBlocklet(did))) {
100
116
  logger.error('Did does not exist', { action: 'getUserState', did });
101
117
  throw new Error(`Did does not exist: ${did}`);
102
118
  }
@@ -135,7 +151,7 @@ class TeamManager extends EventEmitter {
135
151
 
136
152
  async getSessionState(did) {
137
153
  // validate exist
138
- if (!this.isNodeTeam(did) && !(await this.states.blocklet.getBlocklet(did))) {
154
+ if (!this.isNodeTeam(did) && !(await this.states.blocklet.hasBlocklet(did))) {
139
155
  logger.error('Did does not exist', { action: 'getSessionState', did });
140
156
  throw new Error(`Did does not exist: ${did}`);
141
157
  }
@@ -174,7 +190,7 @@ class TeamManager extends EventEmitter {
174
190
  logger.info('get rbac', { did });
175
191
 
176
192
  // validate exist
177
- if (!this.isNodeTeam(did) && !(await this.states.blocklet.getBlocklet(did))) {
193
+ if (!this.isNodeTeam(did) && !(await this.states.blocklet.hasBlocklet(did))) {
178
194
  logger.error('Did does not exist', { action: 'getRBAC', did });
179
195
  throw new Error(`Did does not exist: ${did}`);
180
196
  }
@@ -234,6 +250,14 @@ class TeamManager extends EventEmitter {
234
250
  return this.states.blockletExtras.setSettings(did, { trustedPassports });
235
251
  }
236
252
 
253
+ async configWhoCanAccess(did, value) {
254
+ if (this.isNodeTeam(did)) {
255
+ throw new Error('Cannot be node did');
256
+ }
257
+
258
+ return this.states.blockletExtras.setSettings(did, { whoCanAccess: value });
259
+ }
260
+
237
261
  async configPassportIssuance(did, enable) {
238
262
  const enablePassportIssuance = enable;
239
263
  if (this.isNodeTeam(did)) {
@@ -259,6 +283,99 @@ class TeamManager extends EventEmitter {
259
283
  }
260
284
  }
261
285
 
286
+ async getStoreList(did) {
287
+ if (this.isNodeTeam(did)) {
288
+ const nodeInfo = await this.states.node.read();
289
+ return nodeInfo.blockletRegistryList || [];
290
+ }
291
+
292
+ const settings = await this.states.blockletExtras.getSettings(did);
293
+ return get(settings, 'storeList', []) || [];
294
+ }
295
+
296
+ async updateStoreList(did, list) {
297
+ if (this.isNodeTeam(did)) {
298
+ await this.states.node.updateNodeInfo({ blockletRegistryList: list });
299
+ return;
300
+ }
301
+
302
+ await this.states.blockletExtras.setSettings(did, { storeList: list });
303
+ this.emit(BlockletEvents.storeChange, { meta: { did } });
304
+ }
305
+
306
+ async getOwner(did) {
307
+ let owner;
308
+ if (this.isNodeTeam(did)) {
309
+ const nodeInfo = await this.states.node.read();
310
+ owner = get(nodeInfo, 'nodeOwner');
311
+ } else {
312
+ const settings = await this.states.blockletExtras.getSettings(did);
313
+ owner = get(settings, 'owner');
314
+ }
315
+
316
+ return owner;
317
+ }
318
+
319
+ async getRoles(did) {
320
+ const rbac = await this.getRBAC(did);
321
+
322
+ const roles = await rbac.getRoles();
323
+
324
+ return roles.map((d) => pick(d, ['name', 'grants', 'title', 'description']));
325
+ }
326
+
327
+ async initTeam(did) {
328
+ if (!did) {
329
+ logger.error('initTeam: did does not exist');
330
+ return;
331
+ }
332
+
333
+ logger.info('initTeam', { did });
334
+
335
+ const rbac = await this.getRBAC(did);
336
+ const user = await this.getUserState(did);
337
+ const session = await this.getSessionState(did);
338
+
339
+ this.cache[did] = {
340
+ rbac,
341
+ user,
342
+ session,
343
+ };
344
+ }
345
+
346
+ async deleteTeam(did, { closeDatabase: closeDB = true } = {}) {
347
+ if (!did) {
348
+ logger.error('deleteTeam: did does not exist');
349
+ return;
350
+ }
351
+
352
+ logger.info('deleteTeam', { did, closeDB });
353
+
354
+ if (closeDB && this.cache[did]) {
355
+ try {
356
+ if (this.cache[did].rbac) {
357
+ await closeDatabase(this.cache[did].rbac.storage.db);
358
+ }
359
+
360
+ if (this.cache[did].user) {
361
+ await closeDatabase(this.cache[did].user.db);
362
+ }
363
+
364
+ if (this.cache[did].session) {
365
+ await closeDatabase(this.cache[did].session.db);
366
+ }
367
+
368
+ // NOTICE: wait for nedb to finish closeDatabase
369
+ const timeout = process.env.NODE_ENV !== 'test' ? 2000 : 200;
370
+ await sleep(timeout);
371
+ } catch (error) {
372
+ logger.error('Failed to close database', { did, error });
373
+ }
374
+ }
375
+
376
+ this.cache[did] = null;
377
+ }
378
+
262
379
  // =======
263
380
  // Private
264
381
  // =======