@abtnode/core 1.15.17 → 1.16.0-beta-8ee536d7

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 +1680 -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 +576 -500
  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 +195 -138
  70. package/lib/states/blocklet.js +371 -110
  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
@@ -0,0 +1,177 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const omit = require('lodash/omit');
4
+
5
+ const { forEachBlockletSync, getBlockletAppIdList } = require('@blocklet/meta/lib/util');
6
+ const getBlockletInfo = require('@blocklet/meta/lib/info');
7
+
8
+ const { BLOCKLET_CONFIGURABLE_KEY } = require('@blocklet/constant');
9
+
10
+ const logger = require('@abtnode/logger')('@abtnode/core:install-app-backup');
11
+
12
+ const { validateBlocklet, checkDuplicateAppSk, getAppDirs } = require('../../../util/blocklet');
13
+
14
+ /**
15
+ * backup 目录结构
16
+ * /blocklets/<name1>version>
17
+ * /blocklets/<name2>version>
18
+ * /blocklets/<name3>version>
19
+ * /data
20
+ * /blocklet.json
21
+ * /blocklet_extras.json
22
+ * @see Blocklet 端到端备份方案的设计与实现(一期) https://team.arcblock.io/comment/discussions/e62084d5-fafa-489e-91d5-defcd6e93223
23
+ * @param {{ url: string, appSk: string, moveDir: boolean, manager: import('../disk'), states: import('../../../states/index'), context: Record<string, string> }}
24
+ * @return {Promise<any>}
25
+ */
26
+ const installApplicationFromBackup = async ({ url, appSk, moveDir, context = {}, states, manager } = {}) => {
27
+ // TODO: support more url schema feature (http, did-spaces)
28
+ if (!url.startsWith('file://')) {
29
+ throw new Error('url must starts with file://');
30
+ }
31
+
32
+ const dir = url.replace('file://', '');
33
+
34
+ if (!dir || !fs.existsSync(dir)) {
35
+ throw new Error(`dir(${dir}) does not exist`);
36
+ }
37
+
38
+ // parse data from source dir
39
+ const srcBundleDirs = await getAppDirs(path.join(dir, 'blocklets'));
40
+
41
+ const srcDataDir = path.join(dir, 'data');
42
+
43
+ /** @type {import('@abtnode/client').BlockletState} */
44
+ const state = omit(fs.readJSONSync(path.join(dir, 'blocklet.json')), [
45
+ '_id',
46
+ 'createdAt',
47
+ 'updatedAt',
48
+ 'installedAt',
49
+ 'startedAt',
50
+ ]);
51
+
52
+ if (!state.structVersion) {
53
+ throw new Error(
54
+ 'Only application of structVersion 2 can be restored on this server. Please migrate you application and re-backup your application on your previous server.'
55
+ );
56
+ }
57
+
58
+ const { meta } = state;
59
+ const { did, name: appName } = meta;
60
+
61
+ const extra = omit(fs.readJSONSync(path.join(dir, 'blocklet-extras.json')), ['_id', 'createdAt', 'updatedAt']);
62
+
63
+ if (state.meta.did !== extra.did) {
64
+ throw new Error(`did does not match in blocklet.json (${state.meta.did}) and blocklet_extra.json ${extra.did}`);
65
+ }
66
+
67
+ forEachBlockletSync(state, (component) => {
68
+ delete component.status;
69
+ delete component.ports;
70
+ delete component.environments;
71
+ });
72
+
73
+ await validateBlocklet({ meta });
74
+
75
+ const existState = await states.blocklet.hasBlocklet(did);
76
+
77
+ if (existState) {
78
+ logger.error('blocklet is already exist', { did });
79
+ throw new Error(`blocklet is already exist. did: ${did}`);
80
+ }
81
+
82
+ if (appSk) {
83
+ extra.configs = extra.configs || [];
84
+ const skConfig = extra.configs.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK);
85
+ if (skConfig) {
86
+ skConfig.value = appSk;
87
+ skConfig.secure = true;
88
+ skConfig.shared = false;
89
+ } else {
90
+ extra.configs.push({
91
+ key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK,
92
+ value: appSk,
93
+ secure: true,
94
+ shared: false,
95
+ });
96
+ }
97
+ }
98
+
99
+ // validate appDid
100
+ const nodeInfo = await states.node.read();
101
+ const appIdList = getBlockletAppIdList(state);
102
+ const { wallet } = getBlockletInfo({ meta: state.meta, configs: extra.configs, environments: [] }, nodeInfo.sk);
103
+ if (appIdList.includes(wallet.address) === false) {
104
+ throw new Error('blocklet appDid is different from the previous one');
105
+ }
106
+ await checkDuplicateAppSk({ sk: wallet.secretKey, states });
107
+
108
+ states.blockletExtras.encryptSecurityData({ data: extra, rootDid: extra.did });
109
+
110
+ logger.info('installFromBackup', { srcBundleDirs, srcDataDir });
111
+
112
+ try {
113
+ // copy extra
114
+ const existExtra = await states.blockletExtras.find({ did });
115
+ if (existExtra) {
116
+ // 如果数据存在, 当前视为脏数据, 直接删除
117
+ logger.error('old extra state exists and will be force removed', { existExtra });
118
+ await states.blockletExtras.remove({ did });
119
+ }
120
+ await states.blockletExtras.insert(extra);
121
+ logger.info('blocklet extra is copied successfully');
122
+
123
+ // add blocklet
124
+ await states.blocklet.addBlocklet(state);
125
+ logger.info('blocklet state is added successfully');
126
+
127
+ // copy bundle
128
+ // 假设相同名称的应用,肯定是同一个应用
129
+ // 假设版本号相同时, 应用不会变更
130
+ // FIXME: blocklet bundle name/did 不是唯一的. 修改 blocklet bundle name/did 生成方式 使 name/bundle 唯一
131
+ await Promise.all(
132
+ srcBundleDirs.map(async ({ key: bundleName, dir: srcDir }) => {
133
+ const installDir = path.join(manager.dataDirs.blocklets, bundleName);
134
+ if (fs.existsSync(installDir)) {
135
+ logger.info(`${bundleName} is already exist`);
136
+ return;
137
+ }
138
+
139
+ fs.mkdirSync(installDir, { recursive: true });
140
+ if (moveDir) {
141
+ await fs.move(srcDir, installDir, { overwrite: true });
142
+ } else {
143
+ await fs.copy(srcDir, installDir);
144
+ }
145
+ logger.info(`bundle is ${moveDir ? 'moved' : 'copied'} successfully`, { installDir });
146
+ })
147
+ );
148
+ // 从 store 下载 blocklet
149
+ await manager.blockletDownloader.download(state, { skipCheckIntegrity: true });
150
+
151
+ const dataDir = path.join(manager.dataDirs.data, appName);
152
+ if (fs.existsSync(dataDir)) {
153
+ logger.error('old data exists and will be force removed', { dataDir });
154
+ await fs.remove(dataDir);
155
+ }
156
+ fs.mkdirSync(dataDir, { recursive: true });
157
+ if (fs.existsSync(srcDataDir)) {
158
+ if (moveDir) {
159
+ await fs.move(srcDataDir, dataDir, { overwrite: true });
160
+ } else {
161
+ await fs.copy(srcDataDir, dataDir);
162
+ }
163
+ logger.info(`data is ${moveDir ? 'moved' : 'copied'} successfully`);
164
+ }
165
+ } catch (error) {
166
+ logger.error('installFromBackup failed', { did, error });
167
+
168
+ await manager._rollback('install', did);
169
+
170
+ throw error;
171
+ }
172
+
173
+ logger.info('start install blocklet', { did });
174
+ return manager._installBlocklet({ did, context });
175
+ };
176
+
177
+ module.exports = { installApplicationFromBackup };
@@ -0,0 +1,94 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+
4
+ const { toSvg: createDidLogo } =
5
+ process.env.NODE_ENV !== 'test' ? require('@arcblock/did-motif') : require('@arcblock/did-motif/dist/did-motif.cjs');
6
+ const { BlockletStatus, BLOCKLET_MODES, fromBlockletStatus, BlockletSource } = require('@blocklet/constant');
7
+
8
+ const logger = require('@abtnode/logger')('@abtnode/core:install-app-dev');
9
+ const { ensureMeta } = require('../../../util/blocklet');
10
+
11
+ /**
12
+ *
13
+ * @param {{
14
+ * manager: import('../disk'),
15
+ * states: import('../../../states/index')
16
+ * }}
17
+ * @returns
18
+ */
19
+ const installApplicationFromDev = async ({ folder, meta, states, manager } = {}) => {
20
+ const { did, version } = meta;
21
+
22
+ const exist = await states.blocklet.getBlocklet(did);
23
+ if (exist) {
24
+ if (exist.mode === BLOCKLET_MODES.PRODUCTION) {
25
+ throw new Error('The blocklet of production mode already exists, please remove it before developing');
26
+ }
27
+
28
+ const status = fromBlockletStatus(exist.status);
29
+ if (['starting', 'running'].includes(status)) {
30
+ throw new Error(`The blocklet is already on ${status}, please stop it before developing`);
31
+ }
32
+
33
+ logger.info('remove blocklet for dev', { did, version });
34
+
35
+ await manager.delete({ did, keepLogsDir: false });
36
+ }
37
+
38
+ // delete process
39
+ try {
40
+ await manager.deleteProcess({ did });
41
+ logger.info('delete blocklet precess for dev', { did, version });
42
+ } catch (err) {
43
+ if (process.env.NODE_ENV !== 'development') {
44
+ logger.error('failed to delete blocklet process for dev', { error: err });
45
+ }
46
+ }
47
+
48
+ // create component
49
+ const component = {
50
+ meta: ensureMeta(meta),
51
+ mountPoint: '/',
52
+ source: BlockletSource.local,
53
+ deployedFrom: folder,
54
+ status: BlockletStatus.installed,
55
+ mode: BLOCKLET_MODES.DEVELOPMENT,
56
+ };
57
+
58
+ // create app
59
+ const added = await manager._addBlocklet({
60
+ component,
61
+ name: meta.name,
62
+ did: meta.did,
63
+ mode: BLOCKLET_MODES.DEVELOPMENT,
64
+ });
65
+ logger.info('add blocklet for dev', { did, version, meta });
66
+
67
+ await manager._downloadBlocklet(added);
68
+
69
+ // Add Config
70
+ await manager._setConfigsFromMeta(did);
71
+
72
+ // should ensure blocklet integrity
73
+ let blocklet = await manager.ensureBlocklet(did);
74
+
75
+ // pre install
76
+ await manager._runPreInstallHook(blocklet);
77
+
78
+ // Add environments
79
+ await manager._updateBlockletEnvironment(did);
80
+ blocklet = await manager.getBlocklet(did);
81
+
82
+ // post install
83
+ await manager._runPostInstallHook(blocklet);
84
+
85
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
86
+
87
+ blocklet = await manager.getBlocklet(did);
88
+
89
+ await fs.writeFile(path.join(blocklet.env.dataDir, 'logo.svg'), createDidLogo(blocklet.meta.did));
90
+
91
+ return blocklet;
92
+ };
93
+
94
+ module.exports = { installApplicationFromDev };
@@ -0,0 +1,188 @@
1
+ const joi = require('joi');
2
+
3
+ const { BLOCKLET_INSTALL_TYPE, NODE_MODES } = require('@abtnode/constant');
4
+ const { BlockletStatus, BlockletEvents, BLOCKLET_CONFIGURABLE_KEY } = require('@blocklet/constant');
5
+
6
+ const logger = require('@abtnode/logger')('@abtnode/core:install-app-general');
7
+ const getApplicationWallet = require('@blocklet/meta/lib/wallet');
8
+
9
+ const StoreUtil = require('../../../util/store');
10
+ const { getBlockletMetaFromUrl, ensureMeta, validateStore, validateInServerless } = require('../../../util/blocklet');
11
+
12
+ /**
13
+ *
14
+ * @param {{
15
+ * manager: import('../disk'),
16
+ * states: import('../../../states/index')
17
+ * }} param0
18
+ * @returns
19
+ */
20
+ const installApplicationFromGeneral = async ({
21
+ type,
22
+ appSk,
23
+ sync,
24
+ delay,
25
+ controller,
26
+ title,
27
+ description,
28
+ did: bundleDid,
29
+ storeUrl,
30
+ url: inputUrl,
31
+ context = {},
32
+ states,
33
+ manager,
34
+ } = {}) => {
35
+ const nodeInfo = await states.node.read();
36
+
37
+ let componentSourceUrl;
38
+ if (type === BLOCKLET_INSTALL_TYPE.STORE) {
39
+ if (!storeUrl) {
40
+ throw new Error('store url should not be empty');
41
+ }
42
+ componentSourceUrl = StoreUtil.getBlockletMetaUrl({ did: bundleDid, storeUrl });
43
+ await validateStore(nodeInfo, componentSourceUrl);
44
+ } else if (type === BLOCKLET_INSTALL_TYPE.URL) {
45
+ componentSourceUrl = inputUrl;
46
+ await validateStore(nodeInfo, componentSourceUrl);
47
+ } else if (type === BLOCKLET_INSTALL_TYPE.CREATE) {
48
+ await joi.string().label('title').max(20).required().validateAsync(title);
49
+ await joi.string().label('description').max(80).required().validateAsync(description);
50
+ } else {
51
+ throw new Error(`Should not be here: unknown type ${type}`);
52
+ }
53
+
54
+ // check install count
55
+ if (controller?.nftId) {
56
+ // sometimes nedb will throw error if use states.blocklet.count({ ['controller.nftId']: controller.nftId })
57
+ const installedCount = await states.blockletExtras.count({ 'controller.nftId': controller.nftId });
58
+
59
+ if (installedCount >= (controller.appMaxCount || 1)) {
60
+ throw new Error(
61
+ `You can only install ${controller.appMaxCount} blocklet with this credential: ${controller.nftId}`
62
+ );
63
+ }
64
+ }
65
+
66
+ // app wallet
67
+ const wallet = getApplicationWallet(appSk);
68
+ const did = wallet.address;
69
+ const name = wallet.address;
70
+
71
+ // check exist
72
+ const exist = await states.blocklet.hasBlocklet(did);
73
+ if (exist) {
74
+ throw new Error(`blocklet ${did} already exists`);
75
+ }
76
+
77
+ // remove dirty data
78
+ const oldExtraState = await states.blockletExtras.findOne({ did });
79
+ if (oldExtraState) {
80
+ logger.error('find dirty data in blocklet extra', { did });
81
+ await states.blockletExtras.remove({ did });
82
+ }
83
+
84
+ // create component
85
+ let component;
86
+ if (componentSourceUrl) {
87
+ const meta = await getBlockletMetaFromUrl(componentSourceUrl);
88
+
89
+ if (nodeInfo.mode === NODE_MODES.SERVERLESS) {
90
+ validateInServerless({ blockletMeta: meta });
91
+ }
92
+
93
+ component = {
94
+ meta: ensureMeta(meta),
95
+ mountPoint: '/',
96
+ bundleSource: { url: componentSourceUrl },
97
+ };
98
+ }
99
+
100
+ // create app
101
+ const blocklet = await manager._addBlocklet({ component, name, did, title, description });
102
+ logger.info('blocklet added to database', { did: blocklet.meta.did });
103
+
104
+ // create config
105
+ try {
106
+ await states.blockletExtras.addMeta({ did, meta: { did, name }, controller });
107
+ await manager._setConfigsFromMeta(did);
108
+ await states.blockletExtras.setConfigs(did, [
109
+ {
110
+ key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK,
111
+ value: appSk,
112
+ secure: true,
113
+ },
114
+ ]);
115
+ } catch (err) {
116
+ await manager._rollback('install', did, {});
117
+ }
118
+
119
+ if (!blocklet.children.length) {
120
+ return manager._installBlocklet({ did, context });
121
+ }
122
+
123
+ try {
124
+ const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
125
+ manager.emit(BlockletEvents.added, blocklet1);
126
+
127
+ const action = 'install';
128
+ const downloadParams = {
129
+ blocklet: { ...blocklet1 },
130
+ context,
131
+ postAction: action,
132
+ };
133
+
134
+ // backup rollback data
135
+ await manager._rollbackCache.backup({ did, action });
136
+
137
+ if (sync) {
138
+ await manager._downloadAndInstall({ ...downloadParams, throwOnError: true });
139
+ return states.blocklet.getBlocklet(did);
140
+ }
141
+
142
+ setTimeout(() => {
143
+ const ticket = manager.installQueue.push(
144
+ {
145
+ entity: 'blocklet',
146
+ action: 'download',
147
+ id: did,
148
+ ...downloadParams,
149
+ },
150
+ did
151
+ );
152
+ ticket.on('failed', async (err) => {
153
+ const componentDid = component?.meta?.did;
154
+ logger.error('failed to install blocklet', { did, componentDid, error: err });
155
+ try {
156
+ await manager._rollback('install', did, {});
157
+ } catch (e) {
158
+ logger.error('failed to remove blocklet on install error', { did, componentDid, error: e });
159
+ }
160
+
161
+ manager._createNotification(did, {
162
+ title: 'Blocklet Install Failed',
163
+ description: `Blocklet ${title || component?.meta?.title} install failed with error: ${
164
+ err.message || 'queue exception'
165
+ }`,
166
+ entityType: 'blocklet',
167
+ entityId: did,
168
+ severity: 'error',
169
+ });
170
+ });
171
+ }, delay || 0);
172
+
173
+ return blocklet1;
174
+ } catch (err) {
175
+ const componentDid = component?.meta?.did;
176
+ logger.error('failed to install blocklet', { did, componentDid, error: err });
177
+
178
+ try {
179
+ await manager._rollback('install', did, {});
180
+ } catch (e) {
181
+ logger.error('failed to remove blocklet on install error', { did, componentDid, error: e });
182
+ }
183
+
184
+ throw err;
185
+ }
186
+ };
187
+
188
+ module.exports = { installApplicationFromGeneral };
@@ -0,0 +1,84 @@
1
+ const logger = require('@abtnode/logger')('@abtnode/core:install-component-dev');
2
+
3
+ const { BlockletStatus, BlockletSource, BLOCKLET_MODES, fromBlockletStatus } = require('@blocklet/constant');
4
+ const {
5
+ parseComponents,
6
+ filterDuplicateComponents,
7
+ ensureMeta,
8
+ checkVersionCompatibility,
9
+ validateBlocklet,
10
+ } = require('../../../util/blocklet');
11
+ const { formatName } = require('../../../util/get-domain-for-blocklet');
12
+
13
+ const installComponentFromDev = async ({ folder, meta, rootDid, mountPoint, manager, states }) => {
14
+ const { did, version } = meta;
15
+
16
+ const existRoot = await states.blocklet.getBlocklet(rootDid);
17
+ if (!existRoot) {
18
+ throw new Error('Root blocklet does not exist');
19
+ }
20
+
21
+ const exist = existRoot.children.find((x) => x.meta.did === meta.did);
22
+ if (exist) {
23
+ if (exist.mode === BLOCKLET_MODES.PRODUCTION) {
24
+ throw new Error('The blocklet component of production mode already exists, please remove it before developing');
25
+ }
26
+
27
+ const status = fromBlockletStatus(exist.status);
28
+ if (['starting', 'running'].includes(status)) {
29
+ throw new Error(`The blocklet component is already on ${status}, please stop it before developing`);
30
+ }
31
+
32
+ logger.info('remove blocklet component for dev', { did, version });
33
+
34
+ await manager.deleteComponent({ did, rootDid });
35
+ }
36
+
37
+ let defaultPath = formatName(meta.name);
38
+ if (!existRoot.children.map((x) => x.mountPoint).includes('/')) {
39
+ defaultPath = '';
40
+ }
41
+
42
+ const component = {
43
+ meta: ensureMeta(meta),
44
+ mountPoint: mountPoint || `/${defaultPath}`,
45
+ source: BlockletSource.local,
46
+ deployedFrom: folder,
47
+ status: BlockletStatus.installed,
48
+ mode: BLOCKLET_MODES.DEVELOPMENT,
49
+ };
50
+ const { dynamicComponents } = await parseComponents(component);
51
+ dynamicComponents.unshift(component);
52
+ const children = filterDuplicateComponents(dynamicComponents, existRoot.children);
53
+ checkVersionCompatibility([...children, ...existRoot.children]);
54
+ await states.blocklet.addChildren(rootDid, children);
55
+
56
+ const newBlocklet = await states.blocklet.getBlocklet(rootDid);
57
+ await validateBlocklet(newBlocklet);
58
+ await manager._downloadBlocklet(newBlocklet);
59
+ await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.stopped);
60
+
61
+ // Add Config
62
+ await manager._setConfigsFromMeta(rootDid);
63
+
64
+ // should ensure blocklet integrity
65
+ let blocklet = await manager.ensureBlocklet(rootDid);
66
+
67
+ // pre install
68
+ await manager._runPreInstallHook(blocklet);
69
+
70
+ // Add environments
71
+ await manager._updateBlockletEnvironment(rootDid);
72
+ blocklet = await manager.getBlocklet(rootDid);
73
+
74
+ // post install
75
+ await manager._runPostInstallHook(blocklet);
76
+
77
+ logger.info('add blocklet component for dev', { did, version, meta });
78
+
79
+ blocklet = await manager.getBlocklet(rootDid);
80
+
81
+ return blocklet;
82
+ };
83
+
84
+ module.exports = { installComponentFromDev };