@abtnode/core 1.8.15 → 1.8.18

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.
@@ -5,13 +5,15 @@ const BaseState = require('./base');
5
5
  * This db is used to save arbitrary cached data.
6
6
  */
7
7
  class CacheState extends BaseState {
8
- constructor(baseDir, options = {}) {
9
- super(baseDir, { filename: 'cache.db', ...options });
8
+ constructor(baseDir, config = {}) {
9
+ super(baseDir, { filename: 'cache.db', ...config });
10
10
 
11
- this.db.ensureIndex({ fieldName: 'key', unique: true }, (error) => {
12
- if (error) {
13
- logger.error('ensure index failed', { error });
14
- }
11
+ this.onReady(() => {
12
+ this.ensureIndex({ fieldName: 'key', unique: true }, (error) => {
13
+ if (error) {
14
+ logger.error('ensure index failed', { error });
15
+ }
16
+ });
15
17
  });
16
18
  }
17
19
 
@@ -9,17 +9,17 @@ class ChallengeState extends BaseState {
9
9
  /**
10
10
  * Creates an instance of ChallengeState
11
11
  * @param {string} baseDir
12
- * @param {object} options
12
+ * @param {object} config
13
13
  * @memberof ChallengeState
14
14
  */
15
- constructor(baseDir, options = {}) {
16
- super(baseDir, { filename: 'challenge.db', ...options });
15
+ constructor(baseDir, config = {}) {
16
+ super(baseDir, { filename: 'challenge.db', ...config });
17
17
  }
18
18
 
19
19
  generate() {
20
20
  return new Promise((resolve, reject) => {
21
21
  const challenge = stripHexPrefix(Mcrypto.getRandomBytes(16)).toUpperCase();
22
- this.db.insert({ challenge }, (err, data) => {
22
+ this.insert({ challenge }, (err, data) => {
23
23
  if (err) {
24
24
  logger.error('generating error', { error: err });
25
25
  return reject(err);
@@ -38,7 +38,7 @@ class ChallengeState extends BaseState {
38
38
  return;
39
39
  }
40
40
 
41
- this.db.findOne({ challenge }, (err, data) => {
41
+ this.findOne({ challenge }, (err, data) => {
42
42
  if (err) {
43
43
  logger.error('error find challenge', { error: err });
44
44
  }
@@ -12,19 +12,19 @@ const ExtrasState = require('./blocklet-extras');
12
12
  const CacheState = require('./cache');
13
13
  const AuditLogState = require('./audit-log');
14
14
 
15
- const init = (dataDirs, options) => {
16
- const notificationState = new NotificationState(dataDirs.core, options);
17
- const nodeState = new NodeState(dataDirs.core, options, dataDirs, notificationState);
18
- const blockletState = new BlockletState(dataDirs.core, options);
19
- const challengeState = new ChallengeState(dataDirs.core, options);
20
- const siteState = new SiteState(dataDirs.core, options);
21
- const accessKeyState = new AccessKeyState(dataDirs.core, options);
22
- const webhookState = new WebhookState(dataDirs.core, options);
23
- const migrationState = new MigrationState(dataDirs.core, options);
24
- const sessionState = new SessionState(dataDirs.core, options);
25
- const extrasState = new ExtrasState(dataDirs.core, options);
26
- const cacheState = new CacheState(dataDirs.core, options);
27
- const auditLogState = new AuditLogState(dataDirs.core, options);
15
+ const init = (dataDirs, config) => {
16
+ const notificationState = new NotificationState(dataDirs.core, config);
17
+ const nodeState = new NodeState(dataDirs.core, config, dataDirs, notificationState);
18
+ const blockletState = new BlockletState(dataDirs.core, config);
19
+ const challengeState = new ChallengeState(dataDirs.core, config);
20
+ const siteState = new SiteState(dataDirs.core, config);
21
+ const accessKeyState = new AccessKeyState(dataDirs.core, config);
22
+ const webhookState = new WebhookState(dataDirs.core, config);
23
+ const migrationState = new MigrationState(dataDirs.core, config);
24
+ const sessionState = new SessionState(dataDirs.core, config);
25
+ const extrasState = new ExtrasState(dataDirs.core, config);
26
+ const cacheState = new CacheState(dataDirs.core, config);
27
+ const auditLogState = new AuditLogState(dataDirs.core, config);
28
28
 
29
29
  return {
30
30
  node: nodeState,
@@ -4,14 +4,14 @@ const logger = require('@abtnode/logger')('@abtnode/core:states:migration');
4
4
  const BaseState = require('./base');
5
5
 
6
6
  class MigrationState extends BaseState {
7
- constructor(baseDir, options = {}) {
8
- super(baseDir, { filename: 'migration.db', ...options });
7
+ constructor(baseDir, config = {}) {
8
+ super(baseDir, { filename: 'migration.db', ...config });
9
9
  }
10
10
 
11
11
  // eslint-disable-next-line no-unused-vars
12
12
  async isExecuted({ script, version }, context) {
13
13
  try {
14
- const item = await this.asyncDB.findOne({ script, version });
14
+ const item = await this.findOne({ script, version });
15
15
  return !!item;
16
16
  } catch (err) {
17
17
  logger.error('failed to find migration', { script, version });
@@ -22,7 +22,7 @@ class MigrationState extends BaseState {
22
22
  // eslint-disable-next-line no-unused-vars
23
23
  async markExecuted({ script, version }, context) {
24
24
  try {
25
- const result = await this.asyncDB.insert({ script, version, executedAt: new Date() });
25
+ const result = await this.insert({ script, version, executedAt: new Date() });
26
26
  logger.info('mark executed', result);
27
27
  return result;
28
28
  } catch (error) {
@@ -15,23 +15,23 @@ class NodeState extends BaseState {
15
15
  /**
16
16
  * Creates an instance of NodeState.
17
17
  * @param {string} baseDir
18
- * @param {object} options
18
+ * @param {object} config
19
19
  * @memberof NodeState
20
20
  */
21
- constructor(baseDir, options = {}, dataDirs = {}, notification) {
22
- super(baseDir, { filename: 'node.db', ...options });
21
+ constructor(baseDir, config = {}, dataDirs = {}, notification) {
22
+ super(baseDir, { filename: 'node.db', ...config });
23
23
 
24
24
  // Initialize the store
25
- if (!options.nodeSk) {
25
+ if (!config.nodeSk) {
26
26
  throw new Error('Can not initialize node store without valid nodeSk');
27
27
  }
28
- if (!options.nodePk) {
28
+ if (!config.nodePk) {
29
29
  throw new Error('Can not initialize node store without valid nodePk');
30
30
  }
31
- if (!options.nodeDid) {
31
+ if (!config.nodeDid) {
32
32
  throw new Error('Can not initialize node store without valid nodeDid');
33
33
  }
34
- if (!isFromPublicKey(options.nodeDid, options.nodePk)) {
34
+ if (!isFromPublicKey(config.nodeDid, config.nodePk)) {
35
35
  throw new Error('Node pk and did does not match');
36
36
  }
37
37
 
@@ -39,7 +39,7 @@ class NodeState extends BaseState {
39
39
  this.notification = notification;
40
40
 
41
41
  this.onReady(() => {
42
- this.db.ensureIndex({ fieldName: 'did', unique: true }, (err) => {
42
+ this.ensureIndex({ fieldName: 'did', unique: true }, (err) => {
43
43
  if (err) {
44
44
  console.error('Failed to ensure unique index', err);
45
45
  }
@@ -62,8 +62,8 @@ class NodeState extends BaseState {
62
62
  */
63
63
  read() {
64
64
  return new Promise((resolve, reject) => {
65
- const { nodeDid, dek } = this.options;
66
- this.db.findOne({ did: this.options.nodeDid }, (err, record) => {
65
+ const { nodeDid, dek } = this.config;
66
+ this.findOne({ did: nodeDid }, (err, record) => {
67
67
  if (err) {
68
68
  // eslint-disable-next-line no-console
69
69
  console.error(err);
@@ -97,7 +97,7 @@ class NodeState extends BaseState {
97
97
  enablePassportIssuance = true,
98
98
  trustedPassports = [],
99
99
  webWalletUrl,
100
- } = this.options;
100
+ } = this.config;
101
101
 
102
102
  if (nodeOwner && !validateOwner(nodeOwner)) {
103
103
  return reject(new Error('Node owner is invalid'));
@@ -107,7 +107,7 @@ class NodeState extends BaseState {
107
107
 
108
108
  return getDefaultConfigs()
109
109
  .then((defaultConfigs) =>
110
- this.db.insert(
110
+ this.insert(
111
111
  {
112
112
  ...(defaultConfigs || {}),
113
113
  name,
@@ -5,11 +5,11 @@ const { EVENTS } = require('@abtnode/constant');
5
5
  const BaseState = require('./base');
6
6
 
7
7
  class NotificationState extends BaseState {
8
- constructor(baseDir, options = {}) {
9
- super(baseDir, { filename: 'notification.db', ...options });
8
+ constructor(baseDir, config = {}) {
9
+ super(baseDir, { filename: 'notification.db', ...config });
10
10
 
11
- this.defaultSender = options.defaultSender || '';
12
- this.defaultReceiver = options.defaultReceiver || '';
11
+ this.defaultSender = config.defaultSender || '';
12
+ this.defaultReceiver = config.defaultReceiver || '';
13
13
  }
14
14
 
15
15
  setDefaultSender(sender) {
@@ -28,7 +28,7 @@ class NotificationState extends BaseState {
28
28
  });
29
29
 
30
30
  return new Promise((resolve, reject) => {
31
- this.db.insert(
31
+ this.insert(
32
32
  {
33
33
  sender: payload.sender || this.defaultSender,
34
34
  receiver: payload.receiver || this.defaultReceiver,
@@ -54,7 +54,7 @@ class NotificationState extends BaseState {
54
54
  });
55
55
  }
56
56
 
57
- async find({ receiver, sender, read, paging } = {}, context) {
57
+ async findPaginated({ receiver, sender, read, paging } = {}, context) {
58
58
  const conditions = {};
59
59
  // eslint-disable-next-line no-param-reassign
60
60
  receiver = receiver || get(context, 'user.did');
@@ -81,7 +81,7 @@ class NotificationState extends BaseState {
81
81
  logger.info('mark notification as read', { idList });
82
82
 
83
83
  return new Promise((resolve, reject) => {
84
- this.db.update(
84
+ this.update(
85
85
  { _id: { $in: idList } },
86
86
  { $set: { read: true } },
87
87
  { multi: true, upsert: false, returnUpdatedDocs: false },
@@ -101,7 +101,7 @@ class NotificationState extends BaseState {
101
101
  const idList = Array.isArray(id) ? id : [id];
102
102
 
103
103
  return new Promise((resolve, reject) => {
104
- this.db.update(
104
+ this.update(
105
105
  { _id: { $in: idList } },
106
106
  { $set: { read: false } },
107
107
  { multi: true, upsert: false, returnUpdatedDocs: false },
@@ -5,24 +5,26 @@ const BaseState = require('./base');
5
5
  * This db is used to save session data generated in a http session. the session is NOT user auth session.
6
6
  */
7
7
  class SessionState extends BaseState {
8
- constructor(baseDir, options = {}) {
9
- super(baseDir, { filename: 'session.db', ...options });
8
+ constructor(baseDir, config = {}) {
9
+ super(baseDir, { filename: 'session.db', ...config });
10
10
 
11
- this.db.ensureIndex({ fieldName: 'createdAt' }, (error) => {
12
- if (error) {
13
- logger.error('ensure createdAt index failed', { error });
14
- }
15
- });
11
+ this.onReady(() => {
12
+ this.ensureIndex({ fieldName: 'createdAt' }, (error) => {
13
+ if (error) {
14
+ logger.error('ensure createdAt index failed', { error });
15
+ }
16
+ });
16
17
 
17
- this.db.ensureIndex({ fieldName: 'expireDate', expireAfterSeconds: 0 }, (error) => {
18
- if (error) {
19
- logger.error('ensure expireDate index failed', { error });
20
- }
18
+ this.ensureIndex({ fieldName: 'expireDate', expireAfterSeconds: 0 }, (error) => {
19
+ if (error) {
20
+ logger.error('ensure expireDate index failed', { error });
21
+ }
22
+ });
21
23
  });
22
24
  }
23
25
 
24
26
  async start(initialData) {
25
- const { _id, ...data } = await this.asyncDB.insert(initialData);
27
+ const { _id, ...data } = await this.insert(initialData);
26
28
  return { id: _id, ...data };
27
29
  }
28
30
 
@@ -35,7 +37,7 @@ class SessionState extends BaseState {
35
37
 
36
38
  // eslint-disable-next-line no-underscore-dangle
37
39
  delete exist._id;
38
- await this.asyncDB.update({ _id: id }, { $set: { ...exist, ...data } }, { multi: false, upsert: false });
40
+ await super.update({ _id: id }, { $set: { ...exist, ...data } }, { multi: false, upsert: false });
39
41
 
40
42
  return { id, ...exist, ...data };
41
43
  }
@@ -57,7 +59,7 @@ class SessionState extends BaseState {
57
59
  throw new Error(`Session does not exist: ${id}`);
58
60
  }
59
61
 
60
- await this.asyncDB.remove({ _id: id });
62
+ await this.remove({ _id: id });
61
63
 
62
64
  data.id = id;
63
65
  return data;
@@ -4,12 +4,12 @@ const { toSlotDomain } = require('@abtnode/router-provider/lib/util');
4
4
  const BaseState = require('./base');
5
5
 
6
6
  class SiteState extends BaseState {
7
- constructor(baseDir, options = {}) {
8
- super(baseDir, { filename: 'routing_rule.db', ...options });
7
+ constructor(baseDir, config = {}) {
8
+ super(baseDir, { filename: 'routing_rule.db', ...config });
9
9
  }
10
10
 
11
11
  async add(rule) {
12
- const result = await this.asyncDB.insert(rule);
12
+ const result = await this.insert(rule);
13
13
 
14
14
  const tmpRule = SiteState.renameIdFiledName(result);
15
15
  logger.info('rule created', { rule: tmpRule });
@@ -17,7 +17,7 @@ class SiteState extends BaseState {
17
17
  }
18
18
 
19
19
  async addRuleToSite(id, rule) {
20
- const addedCount = await this.asyncDB.update({ _id: id }, { $addToSet: { rules: rule } });
20
+ const addedCount = await this.update({ _id: id }, { $addToSet: { rules: rule } });
21
21
 
22
22
  logger.info('added rule to site', { count: addedCount });
23
23
  return addedCount;
@@ -26,21 +26,21 @@ class SiteState extends BaseState {
26
26
  async getSites(...args) {
27
27
  let result = null;
28
28
  if (args.length === 0) {
29
- result = await this.asyncDB.find({});
29
+ result = await this.find({});
30
30
  } else {
31
- result = await this.asyncDB.find(...args);
31
+ result = await this.find(...args);
32
32
  }
33
33
 
34
34
  return SiteState.renameIdFiledName(result);
35
35
  }
36
36
 
37
37
  async getSitesByBlocklet(did) {
38
- const rules = await this.asyncDB.find({ 'rules.to.did': did });
38
+ const rules = await this.find({ 'rules.to.did': did });
39
39
  return SiteState.renameIdFiledName(rules);
40
40
  }
41
41
 
42
42
  async getRuleById(id) {
43
- const site = await this.asyncDB.findOne({ 'rules.id': id });
43
+ const site = await this.findOne({ 'rules.id': id });
44
44
  if (!site) {
45
45
  return null;
46
46
  }
@@ -48,20 +48,8 @@ class SiteState extends BaseState {
48
48
  return site.rules.find((x) => x.id === id);
49
49
  }
50
50
 
51
- async update(...args) {
52
- return this.asyncDB.update(...args);
53
- }
54
-
55
- async count(...args) {
56
- return this.asyncDB.count(...args);
57
- }
58
-
59
- async remove(...args) {
60
- return this.asyncDB.remove(...args);
61
- }
62
-
63
51
  async findOne(...args) {
64
- const site = await this.asyncDB.findOne(...args);
52
+ const site = await super.findOne(...args);
65
53
  if (!site) {
66
54
  return site;
67
55
  }
@@ -80,7 +68,7 @@ class SiteState extends BaseState {
80
68
  async findOneByDomain(domain) {
81
69
  // eslint-disable-next-line no-param-reassign
82
70
  domain = toSlotDomain(domain);
83
- return this.asyncDB.findOne({
71
+ return this.findOne({
84
72
  $or: [{ domain }, { domainAliases: domain }, { 'domainAliases.value': domain }],
85
73
  });
86
74
  }
@@ -5,20 +5,18 @@ const { PASSPORT_STATUS } = require('@abtnode/constant');
5
5
  const BaseState = require('./base');
6
6
  const { validateOwner } = require('../util');
7
7
 
8
- const fixPassports = (doc) => {
9
- doc.passports = (doc.passports || []).filter((x) => x.id);
10
- };
11
-
12
8
  const isNullOrUndefined = (x) => x === undefined || x === null;
13
9
 
14
10
  class User extends BaseState {
15
- constructor(baseDir, options = {}) {
16
- super(baseDir, { filename: 'user.db', ...options });
17
-
18
- this.db.ensureIndex({ fieldName: 'did', unique: true }, (error) => {
19
- if (error) {
20
- logger.error('ensure index failed', { error });
21
- }
11
+ constructor(baseDir, config = {}) {
12
+ super(baseDir, { filename: 'user.db', ...config });
13
+
14
+ this.onReady(() => {
15
+ this.ensureIndex({ fieldName: 'did', unique: true }, (error) => {
16
+ if (error) {
17
+ logger.error('ensure index failed', { error });
18
+ }
19
+ });
22
20
  });
23
21
  }
24
22
 
@@ -120,10 +118,6 @@ class User extends BaseState {
120
118
  // get data
121
119
  const { list, paging } = await this.paginate(queryParam, sortParam, inputPaging);
122
120
 
123
- if (list) {
124
- list.forEach(fixPassports); // backward compatible
125
- }
126
-
127
121
  return {
128
122
  list,
129
123
  paging,
@@ -131,11 +125,7 @@ class User extends BaseState {
131
125
  }
132
126
 
133
127
  async getUser(did) {
134
- const doc = await super.findOne({ did });
135
- if (doc) {
136
- fixPassports(doc); // backward compatible
137
- }
138
-
128
+ const doc = await this.findOne({ did });
139
129
  return doc;
140
130
  }
141
131
 
@@ -145,7 +135,7 @@ class User extends BaseState {
145
135
  * @param {string} status passport status
146
136
  */
147
137
  async _setPassportStatusById({ did, id, status } = {}) {
148
- const exist = await super.findOne({ did });
138
+ const exist = await this.findOne({ did });
149
139
 
150
140
  if (!exist) {
151
141
  throw new Error('did does not exist');
@@ -4,8 +4,8 @@ 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
11
  async create(info, { mock } = {}) {
@@ -30,7 +30,7 @@ class WebhookState extends BaseState {
30
30
  return data;
31
31
  }
32
32
 
33
- const webhook = await this.asyncDB.insert(data);
33
+ const webhook = await this.insert(data);
34
34
  return webhook;
35
35
  }
36
36
 
@@ -46,7 +46,7 @@ class WebhookState extends BaseState {
46
46
  throw new Error('webhookId should not be empty');
47
47
  }
48
48
  const webhook = await this.findOne(id);
49
- const num = await this.asyncDB.remove({ _id: id });
49
+ const num = await this.remove({ _id: id });
50
50
  if (num <= 0) {
51
51
  throw new Error(`${id} does not exist`);
52
52
  }
@@ -56,7 +56,7 @@ class WebhookState extends BaseState {
56
56
 
57
57
  async findOne(id) {
58
58
  try {
59
- const webhook = await this.asyncDB.findOne({ _id: id });
59
+ const webhook = await super.findOne({ _id: id });
60
60
 
61
61
  return webhook;
62
62
  } catch (error) {
@@ -11,6 +11,7 @@ const ssri = require('ssri');
11
11
  const diff = require('deep-diff');
12
12
 
13
13
  const { toHex } = require('@ocap/util');
14
+ const { isValid: isValidDid } = require('@arcblock/did');
14
15
  const logger = require('@abtnode/logger')('@abtnode/core:util:blocklet');
15
16
  const pm2 = require('@abtnode/util/lib/async-pm2');
16
17
  const sleep = require('@abtnode/util/lib/sleep');
@@ -58,11 +59,13 @@ const {
58
59
  getBlockletMetaFromUrls,
59
60
  getBlockletMetaFromUrl,
60
61
  } = require('@blocklet/meta/lib/util-meta');
62
+ const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-id');
61
63
 
62
64
  const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
63
65
 
64
66
  const isRequirementsSatisfied = require('./requirement');
65
67
  const { getDidDomainForBlocklet } = require('./get-domain-for-blocklet');
68
+ const { getBlockletDomainGroupName } = require('./router');
66
69
  const { isBeforeInstalled, expandBundle, findInterfacePortByName, validateBlockletMeta } = require('./index');
67
70
 
68
71
  /**
@@ -73,6 +76,7 @@ const { isBeforeInstalled, expandBundle, findInterfacePortByName, validateBlockl
73
76
  const getBlockletEngineNameByPlatform = (blockletMeta) => getBlockletEngine(blockletMeta).interpreter;
74
77
 
75
78
  const noop = () => {};
79
+ const noopAsync = async () => {};
76
80
 
77
81
  const statusMap = {
78
82
  online: BlockletStatus.running,
@@ -83,7 +87,7 @@ const statusMap = {
83
87
  };
84
88
 
85
89
  const PRIVATE_NODE_ENVS = [
86
- // 'NEDB_MULTI_PORT', // FIXME: 排查 abtnode 对外提供的 SDK(比如 @abtnode/queue), SDK 中不要自动使用 NEDB_MULTI_PORT 环境变量
90
+ 'NEDB_MULTI_PORT',
87
91
  'ABT_NODE_UPDATER_PORT',
88
92
  'ABT_NODE_SESSION_TTL',
89
93
  'ABT_NODE_ROUTER_PROVIDER',
@@ -208,7 +212,8 @@ const fillBlockletConfigs = (blocklet, configs) => {
208
212
  acc[x.key] = x.value;
209
213
  return acc;
210
214
  }, {});
211
- blocklet.environmentObj = (blocklet.environments || []).reduce((acc, x) => {
215
+ blocklet.environments = blocklet.environments || [];
216
+ blocklet.environmentObj = blocklet.environments.reduce((acc, x) => {
212
217
  acc[x.key] = x.value;
213
218
  return acc;
214
219
  }, {});
@@ -408,7 +413,7 @@ const getHealthyCheckTimeout = (blocklet, { checkHealthImmediately } = {}) => {
408
413
  */
409
414
  const startBlockletProcess = async (
410
415
  blocklet,
411
- { preStart = noop, nodeEnvironments, nodeInfo, e2eMode, skippedProcessIds = [] } = {}
416
+ { preStart = noop, postStart = noopAsync, nodeEnvironments, nodeInfo, e2eMode, skippedProcessIds = [] } = {}
412
417
  ) => {
413
418
  if (!blocklet) {
414
419
  throw new Error('blocklet should not be empty');
@@ -483,8 +488,12 @@ const startBlockletProcess = async (
483
488
  if (status === BlockletStatus.error) {
484
489
  throw new Error(`${processId} is not running within 5 seconds`);
485
490
  }
486
-
487
491
  logger.info('blocklet started', { processId, status });
492
+
493
+ // run hook
494
+ postStart(b, { env }).catch((err) => {
495
+ logger.error('blocklet post start failed', { processId, error: err });
496
+ });
488
497
  },
489
498
  { parallel: true }
490
499
  );
@@ -1223,6 +1232,72 @@ const ensureMeta = (meta, { name, did } = {}) => {
1223
1232
  return newMeta;
1224
1233
  };
1225
1234
 
1235
+ const getBlocklet = async ({
1236
+ did,
1237
+ dataDirs,
1238
+ states,
1239
+ e2eMode = false,
1240
+ validateEnv = true,
1241
+ throwOnNotExist = true,
1242
+ ensureDirs = true,
1243
+ } = {}) => {
1244
+ if (!did) {
1245
+ throw new Error('Blocklet did does not exist');
1246
+ }
1247
+ if (!isValidDid(did)) {
1248
+ throw new Error(`Blocklet did is invalid: ${did}`);
1249
+ }
1250
+
1251
+ if (!dataDirs) {
1252
+ throw new Error('dataDirs does not exist');
1253
+ }
1254
+
1255
+ if (!states) {
1256
+ throw new Error('states does not exist');
1257
+ }
1258
+
1259
+ const blocklet = await states.blocklet.getBlocklet(did);
1260
+ if (!blocklet) {
1261
+ if (throwOnNotExist) {
1262
+ throw new Error(`can not find blocklet in database by did ${did}`);
1263
+ }
1264
+ return null;
1265
+ }
1266
+
1267
+ // app settings
1268
+ const settings = await states.blockletExtras.getSettings(blocklet.meta.did);
1269
+ blocklet.trustedPassports = get(settings, 'trustedPassports') || [];
1270
+ blocklet.enablePassportIssuance = get(settings, 'enablePassportIssuance', true);
1271
+ blocklet.settings = settings || {};
1272
+
1273
+ // app site
1274
+ const sites = await states.site.getSites();
1275
+ const domain = getBlockletDomainGroupName(blocklet.meta.did);
1276
+ blocklet.site = (sites || []).find((x) => x.domain === domain);
1277
+
1278
+ await forEachBlocklet(blocklet, async (component, { id, level, ancestors }) => {
1279
+ // component env
1280
+ component.env = {
1281
+ id,
1282
+ name: getComponentName(component, ancestors),
1283
+ processId: getComponentProcessId(component, ancestors),
1284
+ ...getComponentDirs(component, {
1285
+ dataDirs,
1286
+ ensure: ensureDirs,
1287
+ validate: validateEnv,
1288
+ ancestors,
1289
+ e2eMode: level === 0 ? e2eMode : false,
1290
+ }),
1291
+ };
1292
+
1293
+ // component config
1294
+ const configs = await states.blockletExtras.getConfigs([...ancestors.map((x) => x.meta.did), component.meta.did]);
1295
+ fillBlockletConfigs(component, configs);
1296
+ });
1297
+
1298
+ return blocklet;
1299
+ };
1300
+
1226
1301
  module.exports = {
1227
1302
  forEachBlocklet,
1228
1303
  getBlockletMetaFromUrl: (url) => getBlockletMetaFromUrl(url, { logger }),
@@ -1261,4 +1336,5 @@ module.exports = {
1261
1336
  needBlockletDownload,
1262
1337
  findAvailableDid,
1263
1338
  ensureMeta,
1339
+ getBlocklet,
1264
1340
  };