@abtnode/core 1.7.18 → 1.7.21

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.
@@ -53,7 +53,7 @@ async function runScripts({
53
53
  const { script: scriptPath } = pendingScripts[i];
54
54
  try {
55
55
  printInfo(`Migration script started: ${scriptPath}`);
56
- await runScript(`node ${path.join(scriptsDir, scriptPath)}`, [blocklet.env.appId, 'migration'].join(':'), {
56
+ await runScript(`node ${path.join(scriptsDir, scriptPath)}`, [blocklet.env.processId, 'migration'].join(':'), {
57
57
  cwd: appDir,
58
58
  env: getSafeEnv(env),
59
59
  silent: false,
package/lib/index.js CHANGED
@@ -247,9 +247,10 @@ function ABTNode(options) {
247
247
  addBlockletStore: nodeAPI.addRegistry.bind(nodeAPI),
248
248
  deleteBlockletStore: nodeAPI.deleteRegistry.bind(nodeAPI),
249
249
  selectBlockletStore: nodeAPI.selectRegistry.bind(nodeAPI),
250
+ getDelegationState: nodeAPI.getDelegationState.bind(nodeAPI),
250
251
  cleanupDirtyUpgradeState: states.node.cleanupDirtyUpgradeState.bind(states.node),
251
- addNodeOwner: states.node.addNodeOwner.bind(states.node),
252
252
  updateNodeOwner: states.node.updateNodeOwner.bind(states.node),
253
+ updateNftHolder: states.node.updateNftHolder.bind(states.node),
253
254
  updateNodeRouting,
254
255
  isInitialized,
255
256
  resetNode: (params, context) =>
@@ -261,7 +262,9 @@ function ABTNode(options) {
261
262
  // Team && Access control
262
263
 
263
264
  // Invitation
264
- createInvitation: teamAPI.createInvitation.bind(teamAPI),
265
+ createMemberInvitation: teamAPI.createMemberInvitation.bind(teamAPI),
266
+ createTransferInvitation: teamAPI.createTransferInvitation.bind(teamAPI),
267
+ getInvitation: teamAPI.getInvitation.bind(teamAPI),
265
268
  getInvitations: teamAPI.getInvitations.bind(teamAPI),
266
269
  processInvitation: teamAPI.processInvitation.bind(teamAPI),
267
270
  deleteInvitation: teamAPI.deleteInvitation.bind(teamAPI),
@@ -0,0 +1,41 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ /* eslint-disable no-continue */
3
+
4
+ module.exports = async ({ states, printInfo }) => {
5
+ printInfo('Try to delete realDid, realInterface and add componentId in db...');
6
+
7
+ const sites = await states.site.find({});
8
+
9
+ for (const site of sites) {
10
+ let changed = false;
11
+ for (const rule of site.rules || []) {
12
+ if (!rule.to) {
13
+ continue;
14
+ }
15
+
16
+ if (rule.to.type !== 'blocklet') {
17
+ continue;
18
+ }
19
+
20
+ if (rule.to.componentId) {
21
+ continue;
22
+ }
23
+
24
+ if (!rule.to.realDid || rule.to.did === rule.to.realDid) {
25
+ rule.to.componentId = rule.to.did;
26
+ } else {
27
+ rule.to.componentId = `${rule.to.did}/${rule.to.realDid}`;
28
+ }
29
+
30
+ delete rule.to.realDid;
31
+ delete rule.to.realInterfaceName;
32
+
33
+ changed = true;
34
+ }
35
+
36
+ if (changed) {
37
+ await states.site.update({ _id: site._id }, site);
38
+ printInfo(`site ${site.domain} has been updated`);
39
+ }
40
+ }
41
+ };
@@ -334,7 +334,7 @@ const ensureWellknownRule = async (sites) => {
334
334
  .sort((a, b) => (a.from.pathPrefix.length > b.from.pathPrefix.length ? 1 : -1));
335
335
  if (blockletRules.length) {
336
336
  // get pathPrefix for blocklet-service
337
- const rootBlockletRule = blockletRules.find((x) => x.to.did === x.to.realDid);
337
+ const rootBlockletRule = blockletRules.find((x) => x.to.did === x.to.componentId);
338
338
  const pathPrefix = joinUrl(rootBlockletRule?.from?.pathPrefix || '/', WELLKNOWN_SERVICE_PATH_PREFIX);
339
339
 
340
340
  // requests for /.well-known/service will stay in blocklet-service and never proxy back to blocklet
@@ -206,7 +206,7 @@ Router.formatSites = (sites = []) => {
206
206
  type: ROUTING_RULE_TYPES.DAEMON,
207
207
  port: daemonRule.to.port,
208
208
  did: rule.to.did,
209
- realDid: rule.to.realDid,
209
+ componentId: rule.to.componentId,
210
210
  },
211
211
  });
212
212
 
@@ -29,6 +29,7 @@ const {
29
29
  BLOCKLET_INTERFACE_TYPE_WEB,
30
30
  BlockletGroup,
31
31
  } = require('@blocklet/meta/lib/constants');
32
+ const { forEachChildSync } = require('@blocklet/meta/lib/util');
32
33
 
33
34
  const {
34
35
  validateAddSite,
@@ -112,7 +113,7 @@ class RouterManager extends EventEmitter {
112
113
  for (const rule of newSite.rules) {
113
114
  this.fixRootBlockletRule(rule);
114
115
  checkPathPrefixInBlackList(rule.from.pathPrefix, dynamicPathBlackList);
115
- rules.push(...(await this.getRules(rule)));
116
+ rules.push(...(await this.getRulesForMutation(rule)));
116
117
  }
117
118
  }
118
119
  newSite.rules = rules;
@@ -281,7 +282,7 @@ class RouterManager extends EventEmitter {
281
282
  await this.validateRouterConfig('addRoutingRule', { id, rule });
282
283
 
283
284
  // add child blocklet rules
284
- for (const x of await this.getRules(rule)) {
285
+ for (const x of await this.getRulesForMutation(rule)) {
285
286
  await states.site.addRuleToSite(id, x);
286
287
  }
287
288
 
@@ -323,7 +324,7 @@ class RouterManager extends EventEmitter {
323
324
  // update rules
324
325
  const newRules = [
325
326
  ...dbSite.rules.filter((x) => (x.groupId && x.groupId !== rule.id) || x.id !== rule.id), // 有些路由没有 rule.groupId
326
- ...(await this.getRules(rule)),
327
+ ...(await this.getRulesForMutation(rule)),
327
328
  ];
328
329
 
329
330
  const updateResult = await states.site.update({ _id: id }, { $set: { rules: newRules } });
@@ -604,8 +605,7 @@ class RouterManager extends EventEmitter {
604
605
  rule.from.pathPrefix = normalizePathPrefix(rule.from.pathPrefix);
605
606
  if (rule.to.type === ROUTING_RULE_TYPES.BLOCKLET) {
606
607
  rule.from.groupPathPrefix = rule.from.pathPrefix;
607
- rule.to.realDid = rule.to.did;
608
- rule.to.realInterfaceName = rule.to.interfaceName;
608
+ rule.to.componentId = rule.to.did;
609
609
  }
610
610
  if (rule.to.url) {
611
611
  rule.to.url = normalizeRedirectUrl(rule.to.url);
@@ -616,7 +616,7 @@ class RouterManager extends EventEmitter {
616
616
  * get all rules to be add or update to site from root rule
617
617
  * @param {*} rule
618
618
  */
619
- async getRules(rule) {
619
+ async getRulesForMutation(rule) {
620
620
  if (rule.to.type !== ROUTING_RULE_TYPES.BLOCKLET) {
621
621
  return [rule];
622
622
  }
@@ -626,23 +626,27 @@ class RouterManager extends EventEmitter {
626
626
 
627
627
  // get child rules
628
628
  const blocklet = await states.blocklet.getBlocklet(rule.to.did);
629
- for (const child of blocklet.children || []) {
630
- const { mountPoint } = child;
629
+ forEachChildSync(blocklet, (component, { id, ancestors }) => {
630
+ if (component.meta.group === BlockletGroup.gateway) {
631
+ return;
632
+ }
633
+
634
+ const { mountPoint } = component;
631
635
  if (!mountPoint) {
632
- logger.error(`mountPoint of child ${child.meta.name} does not exist`);
636
+ logger.error(`mountPoint of child ${component.meta.name} does not exist`);
633
637
  // eslint-disable-next-line no-continue
634
- continue;
638
+ return;
635
639
  }
636
640
 
637
- const childWebInterface = findWebInterface(child);
641
+ const childWebInterface = findWebInterface(component);
638
642
  if (!childWebInterface) {
639
- logger.error(`web interface of child ${child.meta.name} does not exist`);
643
+ logger.error(`web interface of child ${component.meta.name} does not exist`);
640
644
  // eslint-disable-next-line no-continue
641
- continue;
645
+ return;
642
646
  }
643
647
 
644
- const pathPrefix = path.join(rule.from.pathPrefix, mountPoint);
645
- const isRootPath = pathPrefix === rule.from.pathPrefix;
648
+ const pathPrefix = path.join(rule.from.pathPrefix, ...ancestors.map((x) => x.mountPoint || ''), mountPoint);
649
+ const isRootPath = normalizePathPrefix(pathPrefix) === normalizePathPrefix(rule.from.pathPrefix);
646
650
  if (isRootPath) {
647
651
  occupied = true;
648
652
  }
@@ -657,17 +661,16 @@ class RouterManager extends EventEmitter {
657
661
  },
658
662
  to: {
659
663
  type: ROUTING_RULE_TYPES.BLOCKLET,
660
- port: findInterfacePortByName(child, childWebInterface.name),
661
- did: rule.to.did, // root blocklet did
662
- interfaceName: rule.to.interfaceName, // root blocklet interface
663
- realDid: child.meta.did, // child blocklet did
664
- realInterfaceName: childWebInterface.name,
664
+ port: findInterfacePortByName(component, childWebInterface.name),
665
+ did: rule.to.did, // root component did
666
+ interfaceName: rule.to.interfaceName, // root component interface
667
+ componentId: id,
665
668
  },
666
669
  isProtected: isRootPath ? rule.isProtected : true,
667
670
  };
668
671
 
669
672
  rules.push(childRule);
670
- }
673
+ });
671
674
 
672
675
  // get root rule
673
676
  if (!occupied && blocklet.meta.group !== BlockletGroup.gateway) {
@@ -110,7 +110,7 @@ const getLogContent = async (action, args, context, result, info, node) => {
110
110
  case 'deleteComponent':
111
111
  return `removed component ${args.did} from blocklet ${getBlockletInfo(result, info)}`;
112
112
  case 'configBlocklet':
113
- return `updated following ${args.childDid ? `child ${args.childDid}` : ''} config for blocklet ${getBlockletInfo(result, info)}:\n${args.configs.map(x => `- ${x.key}: ${x.value}\n`)}`; // prettier-ignore
113
+ return `updated following config for blocklet ${getBlockletInfo(result, info)}:\n${args.configs.map(x => `- ${x.key}: ${x.value}\n`)}`; // prettier-ignore
114
114
  case 'upgradeBlocklet':
115
115
  return `upgraded blocklet ${getBlockletInfo(result, info)} to v${result.meta.version}`;
116
116
  case 'updateChildBlocklets':
@@ -154,7 +154,7 @@ const getLogContent = async (action, args, context, result, info, node) => {
154
154
  return `${args.user.approved ? 'enabled' : 'disabled'} user ${user} for ${team}`;
155
155
  case 'deletePassportIssuance':
156
156
  return `removed passport issuance ${args.sessionId} from ${team}`;
157
- case 'createInvitation':
157
+ case 'createMemberInvitation':
158
158
  return `created member invitation(${result.inviteId}: ${args.remark}) with **${args.role}** passport for ${team}`; // prettier-ignore
159
159
  case 'deleteInvitation':
160
160
  return `removed unused member invitation(${args.inviteId}) from ${team}`;
@@ -169,6 +169,8 @@ const getLogContent = async (action, args, context, result, info, node) => {
169
169
  return `removed all trusted passport issuers for ${team}`;
170
170
  }
171
171
  return `updated trusted passport issuers to following for ${team}: \n${args.trustedPassports.map(x => `- ${x.remark}: ${x.issuerDid}`).join('\n')}`; // prettier-ignore
172
+ case 'delegateTransferNFT':
173
+ return `${args.owner} ${args.reason}`;
172
174
 
173
175
  // accessKeys
174
176
  case 'createAccessKey':
@@ -258,12 +260,13 @@ const getLogCategory = (action) => {
258
260
  case 'revokeUserPassport':
259
261
  case 'enableUserPassport':
260
262
  case 'updateUserApproval':
261
- case 'createInvitation':
263
+ case 'createMemberInvitation':
262
264
  case 'deleteInvitation':
263
265
  case 'createRole':
264
266
  case 'updateRole':
265
267
  case 'updatePermissionsForRole':
266
268
  case 'configTrustedPassports':
269
+ case 'delegateTransferNFT':
267
270
  return 'team';
268
271
 
269
272
  // accessKeys
@@ -299,6 +302,25 @@ const getLogCategory = (action) => {
299
302
  }
300
303
  };
301
304
 
305
+ const getScope = (args = {}) => {
306
+ // this param usually means mutating an application (server or blocklet)
307
+ if (args.teamDid) {
308
+ return args.teamDid;
309
+ }
310
+
311
+ // this param usually means mutating a child component
312
+ if (args.rootDid) {
313
+ return args.rootDid;
314
+ }
315
+
316
+ // this param usually means mutating a nested child component
317
+ if (Array.isArray(args.did)) {
318
+ return args.did[0];
319
+ }
320
+
321
+ return null;
322
+ };
323
+
302
324
  class AuditLogState extends BaseState {
303
325
  constructor(baseDir, options = {}) {
304
326
  super(baseDir, { filename: 'audit-log.db', ...options });
@@ -355,7 +377,7 @@ class AuditLogState extends BaseState {
355
377
  const [info, geoInfo, uaInfo] = await Promise.all([node.states.node.read(), lookup(ip), parse(ua)]);
356
378
 
357
379
  const data = await this.asyncDB.insert({
358
- scope: args.teamDid || info.did, // server or blocklet did
380
+ scope: getScope(args) || info.did, // server or blocklet did
359
381
  action,
360
382
  category: await getLogCategory(action, args, context, result, info, node),
361
383
  content: (await getLogContent(action, args, context, result, info, node)).trim(),
@@ -52,22 +52,14 @@ class BlockletExtrasState extends BaseState {
52
52
  methods.forEach((method) => {
53
53
  this.extras.forEach((extra) => {
54
54
  const fn = camelCase(`${method} ${extra.name}`); // getConfigs, getRules
55
- this[fn] = this.generateExtraFn(method, extra);
56
- });
57
- });
58
-
59
- const childMethods = ['get', 'set', 'del'];
60
- childMethods.forEach((method) => {
61
- this.childExtras.forEach((extra) => {
62
- const childFn = camelCase(`${method} child ${extra.name}`); // getChildConfigs, getChildRules
63
- this[childFn] = this.generateExtraChildFn(method, extra);
55
+ this[fn] = this.generateFn(method, extra);
64
56
  });
65
57
  });
66
58
  }
67
59
 
68
- // generate extra functions
60
+ // generate functions
69
61
 
70
- generateExtraFn(method, extra) {
62
+ generateFn(method, extra) {
71
63
  if (method === 'get') {
72
64
  return this.generateGetFn(extra);
73
65
  }
@@ -86,11 +78,20 @@ class BlockletExtrasState extends BaseState {
86
78
  }
87
79
 
88
80
  generateGetFn(extra) {
89
- return async (did, path, defaultValue) => {
81
+ return async (dids, path, defaultValue) => {
82
+ // eslint-disable-next-line no-param-reassign
83
+ dids = [].concat(dids);
84
+ const [rootDid, ...childDids] = dids;
90
85
  const { dek } = this.options;
91
86
  const { name, afterGet = noop('data') } = extra;
92
- const item = await this.asyncDB.findOne({ did });
93
- const data = afterGet({ data: item ? item[name] : item, did, dek });
87
+
88
+ let item = await this.asyncDB.findOne({ did: rootDid });
89
+ while (item && childDids.length) {
90
+ const did = childDids.shift();
91
+ item = (item.children || []).find((x) => x.did === did);
92
+ }
93
+
94
+ const data = afterGet({ data: item ? item[name] : item, did: rootDid, dek });
94
95
  if (!path) {
95
96
  return data;
96
97
  }
@@ -99,43 +100,71 @@ class BlockletExtrasState extends BaseState {
99
100
  }
100
101
 
101
102
  generateSetFn(extra) {
102
- return async (did, data) => {
103
+ return async (dids, data) => {
104
+ // eslint-disable-next-line no-param-reassign
105
+ dids = [].concat(dids);
106
+ const [rootDid, ...childDids] = dids;
103
107
  const { dek } = this.options;
104
108
  const { name, beforeSet = noop('cur') } = extra;
105
- const item = await this.asyncDB.findOne({ did });
109
+ const exist = await this.asyncDB.findOne({ did: rootDid });
110
+
111
+ const item = exist || { did: rootDid };
112
+ let component = item;
113
+ while (childDids.length) {
114
+ const did = childDids.shift();
115
+ component.children = component.children || [];
116
+ let child = component.children.find((x) => x.did === did);
117
+ if (!child) {
118
+ child = { did };
119
+ component.children.push(child);
120
+ }
121
+ component = child;
122
+ }
106
123
 
107
- if (!item) {
108
- const insertData = {
109
- did,
110
- [name]: beforeSet({ old: undefined, cur: data, did, dek }),
111
- };
112
-
113
- const info = await this.asyncDB.insert(insertData);
114
- logger.info('create info success');
115
- return info[name];
124
+ const old = component[name];
125
+ const newData = beforeSet({ old, cur: data, did: rootDid, dek });
126
+ component[name] = newData;
127
+
128
+ if (!exist) {
129
+ await this.asyncDB.insert(item);
130
+ logger.info('create extra success', { name, dids });
131
+ } else {
132
+ await this.update(item._id, item);
133
+ logger.info('update extra success', { name, dids });
116
134
  }
117
135
 
118
- const itemNameValue = item[name];
119
- const updated = await this.update(item._id, {
120
- $set: {
121
- [name]: beforeSet({ old: itemNameValue, cur: data, did, dek }),
122
- },
123
- });
124
- return updated[name];
136
+ return newData;
125
137
  };
126
138
  }
127
139
 
128
140
  generateDelFn(extra) {
129
- return async (did) => {
141
+ return async (dids) => {
142
+ // eslint-disable-next-line no-param-reassign
143
+ dids = [].concat(dids);
144
+ const [rootDid, ...childDids] = dids;
130
145
  const { name } = extra;
131
- const item = await this.asyncDB.findOne({ did });
146
+ const item = await this.asyncDB.findOne({ did: rootDid });
132
147
 
133
148
  if (!item) {
134
- return item;
149
+ return null;
150
+ }
151
+
152
+ let component = item;
153
+ while (component && childDids.length) {
154
+ const did = childDids.shift();
155
+ component = (component.children || []).find((x) => x.did === did);
135
156
  }
136
157
 
137
- await this.update(item._id, { $set: { [name]: null } });
138
- return item[name];
158
+ if (!component) {
159
+ return null;
160
+ }
161
+
162
+ const updated = component[name];
163
+ component[name] = null;
164
+
165
+ await this.update(item._id, item);
166
+
167
+ return updated;
139
168
  };
140
169
  }
141
170
 
@@ -153,128 +182,6 @@ class BlockletExtrasState extends BaseState {
153
182
  return list;
154
183
  };
155
184
  }
156
-
157
- // generate extra child functions
158
-
159
- generateExtraChildFn(method, extra) {
160
- if (method === 'get') {
161
- return this.generateGetChildFn(extra);
162
- }
163
-
164
- if (method === 'set') {
165
- return this.generateSetChildFn(extra);
166
- }
167
-
168
- if (method === 'del') {
169
- return this.generateDelChildFn(extra);
170
- }
171
- }
172
-
173
- generateGetChildFn(extra) {
174
- return async (did, childDid) => {
175
- const { dek } = this.options;
176
- const { name, afterGet = noop('data') } = extra;
177
- const item = await this.asyncDB.findOne({ did });
178
- const children = (item || {}).children || [];
179
- const subItem = (children || []).find((x) => x.did === childDid);
180
- return afterGet({ data: subItem ? subItem[name] : null, did, dek });
181
- };
182
- }
183
-
184
- generateSetChildFn(extra) {
185
- return async (did, childDid, data) => {
186
- const { dek } = this.options;
187
- const { name, beforeSet = noop('cur') } = extra;
188
- const item = await this.asyncDB.findOne({ did });
189
-
190
- if (!item) {
191
- const newData = beforeSet({ old: undefined, cur: data, did, dek });
192
- const insertData = {
193
- did,
194
- children: [
195
- {
196
- did: childDid,
197
- [name]: newData,
198
- },
199
- ],
200
- };
201
- await this.asyncDB.insert(insertData);
202
-
203
- logger.info('create info success; insert child info success');
204
-
205
- return newData;
206
- }
207
-
208
- const children = (item || {}).children || [];
209
- const subItem = (children || []).find((x) => x.did === childDid);
210
-
211
- if (!subItem) {
212
- const newData = beforeSet({ old: undefined, cur: data, did, dek });
213
- await this.update(item._id, {
214
- $addToSet: {
215
- children: {
216
- did: childDid,
217
- [name]: newData,
218
- },
219
- },
220
- });
221
-
222
- logger.info('insert child info success');
223
- return newData;
224
- }
225
-
226
- const newData = beforeSet({ old: subItem[name], cur: data, did, dek });
227
-
228
- children.forEach((x) => {
229
- if (x.did === childDid) {
230
- x[name] = newData;
231
- }
232
- });
233
-
234
- await this.update(item._id, {
235
- $set: {
236
- children,
237
- },
238
- });
239
-
240
- return newData;
241
- };
242
- }
243
-
244
- generateDelChildFn(extra) {
245
- return async (did, childDid) => {
246
- const { name } = extra;
247
- const item = await this.asyncDB.findOne({ did });
248
-
249
- if (!item) {
250
- return null;
251
- }
252
-
253
- const children = (item || {}).children || [];
254
- const subItem = (children || []).find((x) => x.did === childDid);
255
-
256
- if (!subItem) {
257
- return null;
258
- }
259
-
260
- let updated = null;
261
-
262
- children.forEach((x) => {
263
- if (x.did === childDid) {
264
- updated = x[name];
265
- x[name] = null;
266
- }
267
- });
268
-
269
- await this.update(item._id, {
270
- $set: {
271
- children,
272
- },
273
- });
274
-
275
- return updated;
276
- };
277
- }
278
185
  }
279
186
 
280
187
  module.exports = BlockletExtrasState;