@abtnode/core 1.16.16 → 1.16.17-beta-8cacb9b3

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.
@@ -167,6 +167,17 @@ const { sessionConfigSchema } = require('../../validators/util');
167
167
 
168
168
  const request = require('../../util/request');
169
169
  const ConfigSynchronizer = require('./config-synchronizer');
170
+ const {
171
+ createProject,
172
+ getProject,
173
+ getProjects,
174
+ updateProject,
175
+ deleteProject,
176
+ createRelease,
177
+ getReleases,
178
+ getRelease,
179
+ deleteRelease,
180
+ } = require('../project');
170
181
 
171
182
  const { formatEnvironments, getBlockletMeta, validateOwner, isCLI } = util;
172
183
 
@@ -1521,8 +1532,14 @@ class DiskBlockletManager extends BaseBlockletManager {
1521
1532
  return getBlocklet({ ...opts, states, dataDirs: this.dataDirs, did, ensureIntegrity: true });
1522
1533
  }
1523
1534
 
1524
- getBlocklet(did, opts = {}) {
1525
- return getBlocklet({ ...opts, states, dataDirs: this.dataDirs, did, ensureIntegrity: false });
1535
+ async getBlocklet(did, opts = {}) {
1536
+ if (opts.useCache && this.cachedBlocklets.has(did)) {
1537
+ return this.cachedBlocklets.get(did);
1538
+ }
1539
+
1540
+ const blocklet = await getBlocklet({ ...opts, states, dataDirs: this.dataDirs, did, ensureIntegrity: false });
1541
+ this.cachedBlocklets.set(did, blocklet);
1542
+ return blocklet;
1526
1543
  }
1527
1544
 
1528
1545
  hasBlocklet({ did }) {
@@ -1869,10 +1886,55 @@ class DiskBlockletManager extends BaseBlockletManager {
1869
1886
  return this.configSynchronizer.syncAppConfig(did, { serverVersion });
1870
1887
  }
1871
1888
 
1889
+ createProject({ did, ...params } = {}) {
1890
+ return createProject({ did, ...params, manager: this });
1891
+ }
1892
+
1893
+ getProjects({ did } = {}) {
1894
+ return getProjects({ did, manager: this });
1895
+ }
1896
+
1897
+ getProject({ did, projectId } = {}) {
1898
+ return getProject({ did, projectId, manager: this });
1899
+ }
1900
+
1901
+ updateProject({ did, projectId, ...params } = {}) {
1902
+ return updateProject({ did, projectId, ...params, manager: this });
1903
+ }
1904
+
1905
+ deleteProject({ did, projectId } = {}) {
1906
+ return deleteProject({ did, projectId, manager: this });
1907
+ }
1908
+
1909
+ // eslint-disable-next-line no-unused-vars
1910
+ createRelease({ did, projectId, ...params } = {}, context) {
1911
+ return createRelease({ did, projectId, ...params, manager: this });
1912
+ }
1913
+
1914
+ getReleases({ did, projectId } = {}) {
1915
+ return getReleases({ did, projectId, manager: this });
1916
+ }
1917
+
1918
+ getRelease({ did, projectId, releaseId } = {}) {
1919
+ return getRelease({ did, projectId, releaseId, manager: this });
1920
+ }
1921
+
1922
+ deleteRelease({ did, projectId, releaseId } = {}) {
1923
+ return deleteRelease({ did, projectId, releaseId, manager: this });
1924
+ }
1925
+
1872
1926
  // ============================================================================================
1873
1927
  // Private API that are used by self of helper function
1874
1928
  // ============================================================================================
1875
1929
 
1930
+ _getProjectState(did) {
1931
+ return this.teamManager.getProjectState(did);
1932
+ }
1933
+
1934
+ _getSessionState(did) {
1935
+ return this.teamManager.getSessionState(did);
1936
+ }
1937
+
1876
1938
  /**
1877
1939
  *
1878
1940
  *
@@ -2747,17 +2809,36 @@ class DiskBlockletManager extends BaseBlockletManager {
2747
2809
  }
2748
2810
  logger.info('done migration on upgrading', { did, componentDids });
2749
2811
 
2750
- if (oldBlocklet.status === BlockletStatus.running) {
2751
- try {
2752
- await this.start({ did, componentDids }, context);
2753
- logger.info('started blocklet for upgrading', { did, version, componentDids });
2754
- } catch (error) {
2755
- logger.error('failed to start blocklet for upgrading', { did, version, componentDids, error });
2756
- }
2812
+ if (action === INSTALL_ACTIONS.INSTALL_COMPONENT) {
2813
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.installed, { componentDids });
2757
2814
  } else {
2758
- const status =
2759
- oldBlocklet.status === BlockletStatus.installed ? BlockletStatus.installed : BlockletStatus.stopped;
2760
- await states.blocklet.setBlockletStatus(did, status, { componentDids });
2815
+ const runningDids = [];
2816
+ const stoppedDids = [];
2817
+ const installedDids = [];
2818
+ for (const componentDid of componentDids) {
2819
+ const old = oldBlocklet.children.find((x) => x.meta.did === componentDid);
2820
+ if (old?.status === BlockletStatus.running) {
2821
+ runningDids.push(componentDid);
2822
+ } else if (old?.status === BlockletStatus.installed) {
2823
+ installedDids.push(componentDid);
2824
+ } else {
2825
+ stoppedDids.push(componentDid);
2826
+ }
2827
+ }
2828
+ if (runningDids.length) {
2829
+ try {
2830
+ await this.start({ did, componentDids: runningDids }, context);
2831
+ logger.info('started blocklet for upgrading', { did, version, runningDids });
2832
+ } catch (error) {
2833
+ logger.error('failed to start blocklet for upgrading', { did, version, runningDids, error });
2834
+ }
2835
+ }
2836
+ if (stoppedDids.length) {
2837
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, { componentDids: stoppedDids });
2838
+ }
2839
+ if (installedDids.length) {
2840
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.installed, { componentDids: installedDids });
2841
+ }
2761
2842
  }
2762
2843
 
2763
2844
  blocklet = await this.getBlocklet(did, context);
@@ -2,7 +2,7 @@ const { sign } = require('@arcblock/jwt');
2
2
 
3
3
  const logger = require('@abtnode/logger')('@abtnode/core:install-component-url');
4
4
 
5
- const { isFreeBlocklet, isComponentBlocklet } = require('@blocklet/meta/lib/util');
5
+ const { isFreeBlocklet } = require('@blocklet/meta/lib/util');
6
6
  const { titleSchema } = require('@blocklet/meta/lib/schema');
7
7
  const hasReservedKey = require('@blocklet/meta/lib/has-reserved-key');
8
8
 
@@ -40,7 +40,7 @@ const installComponentFromUrl = async ({
40
40
 
41
41
  checkStructVersion(blocklet);
42
42
 
43
- const { inStore } = await StoreUtil.parseSourceUrl(url);
43
+ const { inStore, registryUrl } = await StoreUtil.parseSourceUrl(url);
44
44
 
45
45
  const meta = await getBlockletMetaFromUrl(url);
46
46
 
@@ -66,14 +66,6 @@ const installComponentFromUrl = async ({
66
66
  };
67
67
  }
68
68
 
69
- if (!isComponentBlocklet(meta)) {
70
- throw new Error(
71
- `The blocklet cannot be a component : ${
72
- meta.title || meta.name
73
- }. The reason may be that the developer set capabilities.component to false in blocklet.yml`
74
- );
75
- }
76
-
77
69
  if (title) {
78
70
  meta.title = await titleSchema.validateAsync(title);
79
71
  }
@@ -84,7 +76,14 @@ const installComponentFromUrl = async ({
84
76
  const newChild = {
85
77
  meta: newChildMeta,
86
78
  mountPoint: mountPoint || formatName(newChildMeta.name),
87
- bundleSource: { url },
79
+ bundleSource: inStore
80
+ ? {
81
+ store: registryUrl,
82
+ name: meta.bundleName || meta.name,
83
+ // FIXME @linchen version should be specified
84
+ version: 'latest',
85
+ }
86
+ : { url },
88
87
  };
89
88
 
90
89
  const { dynamicComponents } = await parseComponents(newChild);
@@ -110,7 +109,7 @@ const installComponentFromUrl = async ({
110
109
  checkVersionCompatibility(blocklet.children);
111
110
 
112
111
  const oldBlocklet = await manager._getBlockletForInstallation(rootDid);
113
- const action = index > 0 ? INSTALL_ACTIONS.UPGRADE_COMPONENT : INSTALL_ACTIONS.INSTALL_COMPONENT;
112
+ const action = index >= 0 ? INSTALL_ACTIONS.UPGRADE_COMPONENT : INSTALL_ACTIONS.INSTALL_COMPONENT;
114
113
  try {
115
114
  // add component to db
116
115
  await states.blocklet.addChildren(rootDid, newChildren);
@@ -0,0 +1,325 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const createArchive = require('archiver');
4
+ const { slugify } = require('transliteration');
5
+ const { BLOCKLET_META_FILE, PROJECT } = require('@blocklet/constant');
6
+ const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
7
+ const { createRelease: createBlockletRelease } = require('@abtnode/util/lib/create-blocklet-release');
8
+ const { titleSchema } = require('@blocklet/meta/lib/schema');
9
+ const { validateNewDid } = require('@blocklet/meta/lib/name');
10
+ const urlPathFriendly = require('@blocklet/meta/lib/url-path-friendly').default;
11
+
12
+ const logger = require('@abtnode/logger')('create-resource-blocklet');
13
+
14
+ const { createReleaseSchema } = require('../../validators/project');
15
+
16
+ const createRandomStr = () => Math.random().toString(36).substring(2, 8);
17
+
18
+ // project
19
+
20
+ const createProject = async ({ did, type, blockletTitle, blockletDid, manager }) => {
21
+ await titleSchema.validateAsync(blockletTitle);
22
+ validateNewDid(blockletDid);
23
+ if (!PROJECT.TYPES[type]) {
24
+ throw new Error(`type is invalid: ${type}`);
25
+ }
26
+
27
+ const blocklet = await manager.getBlocklet(did, { useCache: true });
28
+ const { projectState } = await manager._getProjectState(did);
29
+
30
+ const project = await projectState.createProject({ blockletTitle, blockletDid, type });
31
+
32
+ // create project dir
33
+ const projectDir = path.join(blocklet.env.dataDir, PROJECT.DIR, `${project.id}`);
34
+ const releasesDir = path.join(projectDir, PROJECT.RELEASE_DIR);
35
+ const tmpResourceDir = path.join(projectDir, PROJECT.RESOURCE_DIR);
36
+ const assetDir = path.join(projectDir, PROJECT.ASSET_DIR);
37
+ await fs.ensureDir(releasesDir);
38
+ await fs.ensureDir(tmpResourceDir);
39
+ await fs.ensureDir(assetDir);
40
+
41
+ return project;
42
+ };
43
+
44
+ const getProjects = async ({ did, manager }) => {
45
+ const { projectState } = await manager._getProjectState(did);
46
+ const projects = await projectState.getProjects();
47
+ return { projects };
48
+ };
49
+
50
+ const getProject = async ({ did, projectId, manager }) => {
51
+ const { projectState } = await manager._getProjectState(did);
52
+ const project = await projectState.findOne({ id: projectId });
53
+ return project;
54
+ };
55
+
56
+ const updateProject = async ({ did, projectId, manager, ...params }) => {
57
+ const { projectState } = await manager._getProjectState(did);
58
+ const project = await projectState.updateProject(projectId, params);
59
+ return project;
60
+ };
61
+
62
+ const deleteProject = async ({ did, projectId, manager }) => {
63
+ if (!projectId) {
64
+ throw new Error('projectId is required');
65
+ }
66
+ const { projectState, releaseState } = await manager._getProjectState(did);
67
+ const blocklet = await manager.getBlocklet(did);
68
+ const projectDir = path.join(blocklet.env.dataDir, PROJECT.DIR, `${projectId}`);
69
+
70
+ await projectState.remove({ id: projectId });
71
+ await releaseState.remove({ projectId });
72
+ await fs.remove(projectDir);
73
+ };
74
+
75
+ // release
76
+ const getReleases = async ({ did, projectId, manager }) => {
77
+ const { releaseState } = await manager._getProjectState(did);
78
+ const releases = await releaseState.getReleases({ projectId });
79
+ return { releases };
80
+ };
81
+ const getRelease = async ({ did, projectId, releaseId, manager }) => {
82
+ const { releaseState } = await manager._getProjectState(did);
83
+ const release = await releaseState.findOne({ projectId, id: releaseId });
84
+ return release;
85
+ };
86
+ const deleteRelease = async ({ did, projectId, releaseId, manager }) => {
87
+ if (!projectId) {
88
+ throw new Error('projectId is required');
89
+ }
90
+ if (!releaseId) {
91
+ throw new Error('releaseId is required');
92
+ }
93
+
94
+ const blocklet = await manager.getBlocklet(did);
95
+ const { releaseState } = await manager._getProjectState(did);
96
+ const releaseDir = path.join(blocklet.env.dataDir, PROJECT.DIR, `${projectId}`, PROJECT.RELEASE_DIR, `${releaseId}`);
97
+
98
+ await releaseState.remove({ projectId, id: releaseId });
99
+ await fs.remove(releaseDir);
100
+ };
101
+
102
+ const createRelease = async ({
103
+ did,
104
+ projectId,
105
+ releaseId,
106
+ blockletTitle,
107
+ blockletDescription,
108
+ blockletVersion,
109
+ blockletIntroduction,
110
+ blockletLogo,
111
+ blockletScreenshots,
112
+ note,
113
+ manager,
114
+ status,
115
+ }) => {
116
+ if (!projectId) {
117
+ throw new Error('projectId is required');
118
+ }
119
+ if (!PROJECT.RELEASE_STATUS[status]) {
120
+ throw new Error(`status is invalid: ${status}`);
121
+ }
122
+
123
+ const params = {
124
+ blockletVersion,
125
+ blockletTitle,
126
+ blockletDescription,
127
+ blockletLogo,
128
+ blockletIntroduction,
129
+ blockletScreenshots,
130
+ note,
131
+ };
132
+
133
+ const releaseSchema = createReleaseSchema(status);
134
+ await releaseSchema.validateAsync(params);
135
+
136
+ const blocklet = await manager.getBlocklet(did);
137
+ const { projectState, releaseState } = await manager._getProjectState(did);
138
+
139
+ const project = await projectState.findOne({ id: projectId });
140
+ if (!project) {
141
+ throw new Error('project not found');
142
+ }
143
+
144
+ const action = releaseId ? 'update' : 'create';
145
+
146
+ if (action === 'update') {
147
+ const release = await releaseState.findOne({ projectId, id: releaseId });
148
+ if (!release) {
149
+ throw new Error('release not found');
150
+ }
151
+ if (release.status !== 'draft') {
152
+ throw new Error('Can not update a published release');
153
+ }
154
+ }
155
+
156
+ const existVersion = await releaseState.findOne({ projectId, blockletVersion });
157
+ if (existVersion && (action === 'create' || existVersion.id !== releaseId)) {
158
+ throw new Error(`blockletVersion ${blockletVersion} already exists`);
159
+ }
160
+
161
+ const { blockletDid } = project;
162
+
163
+ params.blockletDid = blockletDid;
164
+
165
+ const release = await releaseState.upsertRelease({
166
+ ...params,
167
+ projectId,
168
+ releaseId,
169
+ status,
170
+ });
171
+ await projectState.updateProject(projectId, params);
172
+
173
+ const _releaseId = release.id;
174
+
175
+ const projectDir = path.join(blocklet.env.dataDir, PROJECT.DIR, `${projectId}`);
176
+ const tmpDir = path.join(manager.dataDirs.tmp, PROJECT.DIR, `${blockletDid}-${createRandomStr()}`);
177
+ const releaseDir = path.join(projectDir, PROJECT.RELEASE_DIR, `${_releaseId}`);
178
+ const resourceDir = path.join(releaseDir, PROJECT.RESOURCE_DIR);
179
+ const tmpResourceDir = path.join(projectDir, PROJECT.RESOURCE_DIR);
180
+
181
+ await fs.ensureDir(releaseDir);
182
+
183
+ // move tmp resource to release
184
+ if (action === 'create') {
185
+ await fs.ensureDir(tmpResourceDir);
186
+ await fs.remove(releaseDir);
187
+ await fs.ensureDir(releaseDir);
188
+ await fs.move(tmpResourceDir, resourceDir);
189
+ await fs.ensureDir(tmpResourceDir);
190
+ }
191
+
192
+ if (status === PROJECT.RELEASE_STATUS.draft) {
193
+ return release;
194
+ }
195
+
196
+ // create a release
197
+ if (fs.existsSync(tmpDir)) {
198
+ await fs.remove(tmpDir);
199
+ }
200
+
201
+ const tmpExportDir = path.join(tmpDir, 'export');
202
+ const tmpBundleDir = path.join(tmpExportDir, 'bundle');
203
+
204
+ const moniker = (urlPathFriendly(slugify(release.blockletTitle)) || 'blocklet').toLowerCase();
205
+ const releaseFileName = `${moniker}-${release.blockletVersion}.zip`;
206
+ const releaseFile = path.join(releaseDir, releaseFileName);
207
+ if (fs.existsSync(releaseFile)) {
208
+ logger.error('release file already exists, remove it', releaseFile);
209
+ await fs.remove(releaseFile);
210
+ }
211
+
212
+ try {
213
+ await fs.ensureDir(tmpBundleDir);
214
+
215
+ // create logo
216
+ const logoFile = project.blockletLogo
217
+ ? path.join(projectDir, PROJECT.ASSET_DIR, project.blockletLogo)
218
+ : path.join(__dirname, 'logo.png');
219
+ const logoExt = path.extname(logoFile);
220
+ const logoFileName = `logo${logoExt}`;
221
+ await fs.copy(logoFile, path.join(tmpBundleDir, logoFileName));
222
+
223
+ // create screenshots
224
+ const screenshotsDistDir = path.join(tmpBundleDir, 'screenshots');
225
+ await fs.ensureDir(screenshotsDistDir);
226
+ if (project.blockletScreenshots?.length) {
227
+ await Promise.all(
228
+ project.blockletScreenshots.map(async (screenshot) => {
229
+ const screenshotFile = path.join(projectDir, PROJECT.ASSET_DIR, screenshot);
230
+ await fs.copy(screenshotFile, path.join(screenshotsDistDir, screenshot));
231
+ })
232
+ );
233
+ }
234
+
235
+ // create readme
236
+ if (blockletIntroduction) {
237
+ await fs.outputFile(path.join(tmpBundleDir, 'README.md'), blockletIntroduction);
238
+ }
239
+
240
+ // create blocklet.yml
241
+ const meta = {
242
+ did: blockletDid,
243
+ name: blockletDid,
244
+ title: blockletTitle,
245
+ description: blockletDescription,
246
+ version: blockletVersion,
247
+ logo: logoFileName,
248
+ resources: ['/resource'],
249
+ components: [],
250
+ files: ['screenshots'],
251
+ screenshots: project.blockletScreenshots || [],
252
+ };
253
+
254
+ await updateMetaFile(path.join(tmpBundleDir, BLOCKLET_META_FILE), meta);
255
+
256
+ // changelog
257
+ const changelogDistFile = path.join(tmpBundleDir, 'CHANGELOG.md');
258
+ const releases = await releaseState.getReleases({ projectId, status: PROJECT.RELEASE_STATUS.published });
259
+ const changelog = releases.map((_release) => {
260
+ const { blockletVersion: version, note: content } = _release;
261
+ return `## ${version}\n\n${content}`;
262
+ });
263
+ await fs.outputFile(changelogDistFile, changelog.join('\n\n'));
264
+
265
+ // create resource
266
+ await fs.ensureDir(resourceDir);
267
+ await fs.copy(resourceDir, path.join(tmpBundleDir, 'resource'));
268
+
269
+ // copy resource to tmpResourceDir
270
+ await fs.remove(tmpResourceDir);
271
+ await fs.copy(resourceDir, tmpResourceDir);
272
+
273
+ // create release
274
+ await createBlockletRelease(tmpExportDir, { printError: logger.error, printInfo: logger.info });
275
+
276
+ // archive
277
+ const archive = createArchive('zip', { zlib: { level: 9 } });
278
+ const writeStream = fs.createWriteStream(releaseFile);
279
+
280
+ await new Promise((resolve, reject) => {
281
+ archive
282
+ .directory(tmpExportDir, false)
283
+ .on('error', (err) => reject(err))
284
+ .pipe(writeStream);
285
+
286
+ writeStream.on('close', () => resolve(releaseFile));
287
+ archive.finalize();
288
+ });
289
+
290
+ const res2 = await releaseState.upsertRelease({
291
+ projectId,
292
+ releaseId: _releaseId,
293
+ files: [releaseFileName],
294
+ });
295
+
296
+ await fs.remove(tmpDir);
297
+
298
+ logger.info('create release success', res2);
299
+
300
+ return res2;
301
+ } catch (error) {
302
+ await fs.remove(tmpDir);
303
+ await fs.remove(releaseFile);
304
+ if (action === 'create') {
305
+ await fs.remove(releaseDir);
306
+ await releaseState.remove({ projectId, id: _releaseId });
307
+ } else {
308
+ await releaseState.update({ id: _releaseId }, { $set: { status: PROJECT.RELEASE_STATUS.draft } });
309
+ }
310
+ logger.error(`export ${project.type} error`, error);
311
+ throw error;
312
+ }
313
+ };
314
+
315
+ module.exports = {
316
+ createProject,
317
+ getProjects,
318
+ getProject,
319
+ updateProject,
320
+ deleteProject,
321
+ createRelease,
322
+ getReleases,
323
+ getRelease,
324
+ deleteRelease,
325
+ };
Binary file
package/lib/index.js CHANGED
@@ -278,6 +278,17 @@ function ABTNode(options) {
278
278
  migrateApplicationToStructV2: blockletManager.migrateApplicationToStructV2.bind(blockletManager),
279
279
  syncAppConfig: blockletManager.syncAppConfig.bind(blockletManager),
280
280
 
281
+ // blocklet project
282
+ createProject: blockletManager.createProject.bind(blockletManager),
283
+ deleteProject: blockletManager.deleteProject.bind(blockletManager),
284
+ getProjects: blockletManager.getProjects.bind(blockletManager),
285
+ getProject: blockletManager.getProject.bind(blockletManager),
286
+ updateProject: blockletManager.updateProject.bind(blockletManager),
287
+ createRelease: blockletManager.createRelease.bind(blockletManager),
288
+ getReleases: blockletManager.getReleases.bind(blockletManager),
289
+ getRelease: blockletManager.getRelease.bind(blockletManager),
290
+ deleteRelease: blockletManager.deleteRelease.bind(blockletManager),
291
+
281
292
  // For diagnose purpose
282
293
  syncBlockletStatus: blockletManager.status.bind(blockletManager),
283
294
  ensureBlockletIntegrity: blockletManager.ensureBlocklet.bind(blockletManager),
@@ -1209,6 +1209,8 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1209
1209
 
1210
1210
  const providers = {}; // we need to keep reference for different router instances
1211
1211
  const handleRouting = async (nodeInfo) => {
1212
+ const now = Date.now();
1213
+ logger.info('start handle routing');
1212
1214
  const providerName = get(nodeInfo, 'routing.provider', null);
1213
1215
  const httpsEnabled = get(nodeInfo, 'routing.https', true);
1214
1216
  logger.debug('handle routing', { providerName, httpsEnabled });
@@ -1272,6 +1274,8 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1272
1274
 
1273
1275
  await providers[providerName].start();
1274
1276
  }
1277
+
1278
+ logger.info('done handle routing', { cost: Date.now() - now });
1275
1279
  };
1276
1280
 
1277
1281
  const rotateRouterLog = async () => {
@@ -0,0 +1,45 @@
1
+ const pickBy = require('lodash/pickBy');
2
+ const pick = require('lodash/pick');
3
+ const BaseState = require('./base');
4
+
5
+ const isUndefinedOrNull = (x) => x === undefined || x === null;
6
+
7
+ /**
8
+ * @extends BaseState<import('@abtnode/models').ProjectState>
9
+ */
10
+ class Project extends BaseState {
11
+ createProject({ type, blockletDid, blockletTitle }) {
12
+ return this.insert({ id: blockletDid, type, blockletDid, blockletTitle });
13
+ }
14
+
15
+ getProjects() {
16
+ return this.find(
17
+ {},
18
+ {},
19
+ {
20
+ createdAt: -1,
21
+ }
22
+ );
23
+ }
24
+
25
+ async updateProject(id, params) {
26
+ const _params = pickBy(
27
+ pick(params, [
28
+ 'name',
29
+ 'blockletLogo',
30
+ 'blockletVersion',
31
+ 'blockletIntroduction',
32
+ 'blockletTitle',
33
+ 'blockletDescription',
34
+ 'blockletDid',
35
+ 'blockletScreenshots',
36
+ ]),
37
+ (x) => !isUndefinedOrNull(x)
38
+ );
39
+
40
+ const [, [updated]] = await this.update({ id }, { $set: _params });
41
+ return updated;
42
+ }
43
+ }
44
+
45
+ module.exports = Project;
@@ -0,0 +1,46 @@
1
+ const pick = require('lodash/pick');
2
+ const BaseState = require('./base');
3
+
4
+ /**
5
+ * @extends BaseState<import('@abtnode/models').ReleaseState>
6
+ */
7
+ class Release extends BaseState {
8
+ getReleases({ projectId, status } = {}) {
9
+ const query = { projectId };
10
+ if (status) {
11
+ query.status = status;
12
+ }
13
+ return this.find(
14
+ query,
15
+ {},
16
+ {
17
+ createdAt: -1,
18
+ }
19
+ );
20
+ }
21
+
22
+ async upsertRelease({ releaseId, ...params }) {
23
+ const _params = pick(params, [
24
+ 'projectId',
25
+ 'blockletDid',
26
+ 'blockletVersion',
27
+ 'blockletTitle',
28
+ 'blockletDescription',
29
+ 'blockletLogo',
30
+ 'blockletIntroduction',
31
+ 'blockletScreenshots',
32
+ 'note',
33
+ 'status',
34
+ 'files',
35
+ ]);
36
+
37
+ if (!releaseId) {
38
+ return this.insert(_params);
39
+ }
40
+
41
+ const [, [updated]] = await this.update({ id: releaseId }, { $set: _params });
42
+ return updated;
43
+ }
44
+ }
45
+
46
+ module.exports = Release;
@@ -32,6 +32,8 @@ const States = {
32
32
  ConnectedAccount: require('../states/connect-account'),
33
33
  Session: require('../states/session'),
34
34
  Tag: require('../states/tag'),
35
+ Project: require('../states/project'),
36
+ Release: require('../states/release'),
35
37
  };
36
38
 
37
39
  const getDefaultTeamState = () => ({
@@ -41,6 +43,8 @@ const getDefaultTeamState = () => ({
41
43
  connectedAccount: null,
42
44
  session: null,
43
45
  tag: null,
46
+ project: null,
47
+ release: null,
44
48
  });
45
49
 
46
50
  class TeamManager extends EventEmitter {
@@ -119,6 +123,13 @@ class TeamManager extends EventEmitter {
119
123
  return this.getState(teamDid, 'session');
120
124
  }
121
125
 
126
+ async getProjectState(teamDid) {
127
+ return {
128
+ projectState: await this.getState(teamDid, 'project'),
129
+ releaseState: await this.getState(teamDid, 'release'),
130
+ };
131
+ }
132
+
122
133
  async getState(teamDid, key) {
123
134
  const pid = await this.getPid(teamDid);
124
135
  if (!pid) {
@@ -1723,6 +1723,10 @@ const getBlockletStatus = (blocklet) => {
1723
1723
  return;
1724
1724
  }
1725
1725
 
1726
+ if (status === BlockletStatus.stopped) {
1727
+ return;
1728
+ }
1729
+
1726
1730
  status = component.status;
1727
1731
  });
1728
1732
 
package/lib/util/store.js CHANGED
@@ -111,7 +111,7 @@ const parseSourceUrl = async (url) => {
111
111
  };
112
112
  }
113
113
  } catch {
114
- // meat is not in store, do nothing
114
+ // meta is not in store, do nothing
115
115
  }
116
116
  }
117
117
 
@@ -0,0 +1,29 @@
1
+ const { Joi, titleSchema, descriptionSchema } = require('@blocklet/meta/lib/schema');
2
+ const { PROJECT } = require('@blocklet/constant');
3
+
4
+ const note = Joi.string().min(1).max(1000);
5
+ const blockletIntroduction = Joi.string().max(3000).allow('').allow(null);
6
+ const blockletScreenshots = Joi.array().items(Joi.string().min(1).max(200));
7
+ const blockletLogo = Joi.string().max(200).allow(null).allow('');
8
+
9
+ const createReleaseSchema = (status) =>
10
+ Joi.object({
11
+ note: status === PROJECT.RELEASE_STATUS.published ? note.required() : note.allow(''),
12
+ blockletVersion: Joi.semver().valid().required(),
13
+ blockletTitle: titleSchema.required(),
14
+ blockletDescription:
15
+ status === PROJECT.RELEASE_STATUS.published
16
+ ? descriptionSchema.required()
17
+ : descriptionSchema.allow('').allow(null),
18
+ blockletScreenshots,
19
+ blockletIntroduction,
20
+ blockletLogo,
21
+ });
22
+
23
+ module.exports = {
24
+ note,
25
+ blockletIntroduction,
26
+ blockletScreenshots,
27
+ blockletLogo,
28
+ createReleaseSchema,
29
+ };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.16",
6
+ "version": "1.16.17-beta-8cacb9b3",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,39 +19,39 @@
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.16",
23
- "@abtnode/auth": "1.16.16",
24
- "@abtnode/certificate-manager": "1.16.16",
25
- "@abtnode/constant": "1.16.16",
26
- "@abtnode/cron": "1.16.16",
27
- "@abtnode/logger": "1.16.16",
28
- "@abtnode/models": "1.16.16",
29
- "@abtnode/queue": "1.16.16",
30
- "@abtnode/rbac": "1.16.16",
31
- "@abtnode/router-provider": "1.16.16",
32
- "@abtnode/static-server": "1.16.16",
33
- "@abtnode/timemachine": "1.16.16",
34
- "@abtnode/util": "1.16.16",
35
- "@arcblock/did": "1.18.90",
36
- "@arcblock/did-auth": "1.18.90",
37
- "@arcblock/did-ext": "^1.18.90",
22
+ "@abtnode/analytics": "1.16.17-beta-8cacb9b3",
23
+ "@abtnode/auth": "1.16.17-beta-8cacb9b3",
24
+ "@abtnode/certificate-manager": "1.16.17-beta-8cacb9b3",
25
+ "@abtnode/constant": "1.16.17-beta-8cacb9b3",
26
+ "@abtnode/cron": "1.16.17-beta-8cacb9b3",
27
+ "@abtnode/logger": "1.16.17-beta-8cacb9b3",
28
+ "@abtnode/models": "1.16.17-beta-8cacb9b3",
29
+ "@abtnode/queue": "1.16.17-beta-8cacb9b3",
30
+ "@abtnode/rbac": "1.16.17-beta-8cacb9b3",
31
+ "@abtnode/router-provider": "1.16.17-beta-8cacb9b3",
32
+ "@abtnode/static-server": "1.16.17-beta-8cacb9b3",
33
+ "@abtnode/timemachine": "1.16.17-beta-8cacb9b3",
34
+ "@abtnode/util": "1.16.17-beta-8cacb9b3",
35
+ "@arcblock/did": "1.18.91",
36
+ "@arcblock/did-auth": "1.18.91",
37
+ "@arcblock/did-ext": "^1.18.91",
38
38
  "@arcblock/did-motif": "^1.1.13",
39
- "@arcblock/did-util": "1.18.90",
40
- "@arcblock/event-hub": "1.18.90",
41
- "@arcblock/jwt": "^1.18.90",
39
+ "@arcblock/did-util": "1.18.91",
40
+ "@arcblock/event-hub": "1.18.91",
41
+ "@arcblock/jwt": "^1.18.91",
42
42
  "@arcblock/pm2-events": "^0.0.5",
43
- "@arcblock/validator": "^1.18.90",
44
- "@arcblock/vc": "1.18.90",
45
- "@blocklet/constant": "1.16.16",
46
- "@blocklet/env": "1.16.16",
47
- "@blocklet/meta": "1.16.16",
48
- "@blocklet/resolver": "1.16.16",
49
- "@blocklet/sdk": "1.16.16",
43
+ "@arcblock/validator": "^1.18.91",
44
+ "@arcblock/vc": "1.18.91",
45
+ "@blocklet/constant": "1.16.17-beta-8cacb9b3",
46
+ "@blocklet/env": "1.16.17-beta-8cacb9b3",
47
+ "@blocklet/meta": "1.16.17-beta-8cacb9b3",
48
+ "@blocklet/resolver": "1.16.17-beta-8cacb9b3",
49
+ "@blocklet/sdk": "1.16.17-beta-8cacb9b3",
50
50
  "@did-space/client": "^0.3.8",
51
51
  "@fidm/x509": "^1.2.1",
52
- "@ocap/mcrypto": "1.18.90",
53
- "@ocap/util": "1.18.90",
54
- "@ocap/wallet": "1.18.90",
52
+ "@ocap/mcrypto": "1.18.91",
53
+ "@ocap/util": "1.18.91",
54
+ "@ocap/wallet": "1.18.91",
55
55
  "@slack/webhook": "^5.0.4",
56
56
  "archiver": "^5.3.1",
57
57
  "axios": "^0.27.2",
@@ -70,6 +70,7 @@
70
70
  "is-base64": "^1.1.0",
71
71
  "is-url": "^1.2.4",
72
72
  "joi": "17.7.0",
73
+ "joi-extension-semver": "^5.0.0",
73
74
  "js-yaml": "^4.1.0",
74
75
  "kill-port": "^2.0.1",
75
76
  "lodash": "^4.17.21",
@@ -100,5 +101,5 @@
100
101
  "jest": "^27.5.1",
101
102
  "unzipper": "^0.10.11"
102
103
  },
103
- "gitHead": "2de4f6dbad086bd861273a4fc9ca8a87ddda4778"
104
+ "gitHead": "0e3266f543b6d419a004ca94ee9efb572e3d9809"
104
105
  }