@blocklet/cli 1.16.33 → 1.16.34-beta-20241120-080738-bbbe036c
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.
- package/README.md +32 -25
- package/bin/blocklet.js +292 -1
- package/config.example.yml +33 -0
- package/lib/arcblock.js +53 -0
- package/lib/commands/blocklet/add.js +124 -0
- package/lib/commands/blocklet/assets/git-ignore +28 -0
- package/lib/commands/blocklet/assets/index.html +9 -0
- package/lib/commands/blocklet/assets/index.js +14 -0
- package/lib/commands/blocklet/assets/logo.png +0 -0
- package/lib/commands/blocklet/bundle/bundle.js +184 -0
- package/lib/commands/blocklet/bundle/bundlers/blocklet.js +138 -0
- package/lib/commands/blocklet/bundle/bundlers/changelog.js +100 -0
- package/lib/commands/blocklet/bundle/bundlers/logo.js +56 -0
- package/lib/commands/blocklet/bundle/bundlers/markdown.js +241 -0
- package/lib/commands/blocklet/bundle/bundlers/preference.js +50 -0
- package/lib/commands/blocklet/bundle/bundlers/readme.js +43 -0
- package/lib/commands/blocklet/bundle/bundlers/screenshots.js +94 -0
- package/lib/commands/blocklet/bundle/bundlers/simple.js +70 -0
- package/lib/commands/blocklet/bundle/compact/bundle-compact-file.js +48 -0
- package/lib/commands/blocklet/bundle/compact/bundle-merge-extra.js +66 -0
- package/lib/commands/blocklet/bundle/compact/default-external.js +5 -0
- package/lib/commands/blocklet/bundle/compact/index.js +88 -0
- package/lib/commands/blocklet/bundle/index.js +139 -0
- package/lib/commands/blocklet/bundle/pack.js +8 -0
- package/lib/commands/blocklet/bundle/parse-external-dependencies.js +97 -0
- package/lib/commands/blocklet/bundle/simple/index.js +62 -0
- package/lib/commands/blocklet/bundle/zip/archive.js +35 -0
- package/lib/commands/blocklet/bundle/zip/dependencies.js +333 -0
- package/lib/commands/blocklet/bundle/zip/index.js +165 -0
- package/lib/commands/blocklet/bundle/zip/main.js +124 -0
- package/lib/commands/blocklet/bundle/zip/node.js +59 -0
- package/lib/commands/blocklet/bundle/zip/resolve.js +93 -0
- package/lib/commands/blocklet/cleanup.js +52 -0
- package/lib/commands/blocklet/config.js +108 -0
- package/lib/commands/blocklet/connect.js +87 -0
- package/lib/commands/blocklet/create.js +38 -0
- package/lib/commands/blocklet/deploy.js +435 -0
- package/lib/commands/blocklet/dev.js +1000 -0
- package/lib/commands/blocklet/document.js +39 -0
- package/lib/commands/blocklet/exec.js +106 -0
- package/lib/commands/blocklet/init.js +300 -0
- package/lib/commands/blocklet/meta.js +22 -0
- package/lib/commands/blocklet/remove.js +35 -0
- package/lib/commands/blocklet/test.js +201 -0
- package/lib/commands/blocklet/upload.js +105 -0
- package/lib/commands/blocklet/version.js +81 -0
- package/lib/commands/server/cleanup.js +32 -0
- package/lib/commands/server/command.js +131 -0
- package/lib/commands/server/info.js +92 -0
- package/lib/commands/server/init.js +433 -0
- package/lib/commands/server/logs.js +99 -0
- package/lib/commands/server/rescue.js +71 -0
- package/lib/commands/server/start.js +821 -0
- package/lib/commands/server/status.js +107 -0
- package/lib/commands/server/stop.js +163 -0
- package/lib/commands/server/upgrade.js +123 -0
- package/lib/constant.js +21 -2
- package/lib/debug.js +20 -0
- package/lib/manager/config.js +122 -0
- package/lib/manager/deploy.js +75 -0
- package/lib/manager/index.js +23 -0
- package/lib/manager/process.js +47 -0
- package/lib/node.js +214 -0
- package/lib/port.js +19 -0
- package/lib/postinstall.js +3 -0
- package/lib/process/daemon.js +196 -0
- package/lib/process/service.js +86 -0
- package/lib/ui.js +137 -0
- package/lib/util/blocklet/config.js +78 -0
- package/lib/util/blocklet/env.js +172 -0
- package/lib/util/blocklet/meta.js +36 -0
- package/lib/util/blocklet/payment.js +88 -0
- package/lib/util/blocklet/sign.js +21 -0
- package/lib/util/blocklet/tar.js +119 -0
- package/lib/util/convert-to-nosources-sourcemap.js +37 -0
- package/lib/util/docker-status-log.js +17 -0
- package/lib/util/exit-when-server-stopped.js +44 -0
- package/lib/util/get-cli-binary-name.js +8 -0
- package/lib/util/get-download-bundle-step.js +36 -0
- package/lib/util/get-service-instance-number.js +12 -0
- package/lib/util/index.js +626 -0
- package/lib/util/print-error.js +11 -0
- package/lib/util/print.js +9 -0
- package/lib/util/what-uri.js +40 -0
- package/package.json +123 -27
- package/lib/run.d.ts +0 -2
- package/lib/run.js +0 -73
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/* eslint-disable indent */
|
|
2
|
+
require('dotenv-flow').config({ silent: true, node_env: 'development' });
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const expandTilde = require('expand-tilde');
|
|
7
|
+
const tar = require('tar');
|
|
8
|
+
const FormData = require('form-data');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const slugify = require('slugify');
|
|
11
|
+
const { joinURL } = require('ufo');
|
|
12
|
+
|
|
13
|
+
const { isValid: isValidDid, toAddress } = require('@arcblock/did');
|
|
14
|
+
const Client = require('@abtnode/client');
|
|
15
|
+
const hashFiles = require('@abtnode/util/lib/hash-files');
|
|
16
|
+
const { default: axios } = require('axios');
|
|
17
|
+
const isPathPrefixEqual = require('@abtnode/util/lib/is-path-prefix-equal');
|
|
18
|
+
const getBlockletMeta = require('@blocklet/meta/lib/parse');
|
|
19
|
+
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
20
|
+
const { hasMountPoint } = require('@blocklet/meta/lib/engine');
|
|
21
|
+
const { BLOCKLET_BUNDLE_FOLDER } = require('@blocklet/constant');
|
|
22
|
+
const hasReservedKey = require('@blocklet/meta/lib/has-reserved-key');
|
|
23
|
+
const urlPathFriendly = require('@blocklet/meta/lib/url-path-friendly').default;
|
|
24
|
+
const { ROLES } = require('@abtnode/constant');
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
print,
|
|
28
|
+
printError,
|
|
29
|
+
printInfo,
|
|
30
|
+
printSuccess,
|
|
31
|
+
printWarning,
|
|
32
|
+
formatGQLError,
|
|
33
|
+
getCLIBinaryName,
|
|
34
|
+
} = require('../../util');
|
|
35
|
+
const { wrapSpinner } = require('../../ui');
|
|
36
|
+
const { getNode } = require('../../node');
|
|
37
|
+
const { checkRunning, deployManager } = require('../../manager');
|
|
38
|
+
const { version } = require('../../../package.json');
|
|
39
|
+
const debug = require('../../debug')('blocklet:deploy');
|
|
40
|
+
|
|
41
|
+
const { signWithAccessKey, validateAccessKey } = Client;
|
|
42
|
+
const { fileFilter, printDeployFileInfo } = deployManager;
|
|
43
|
+
|
|
44
|
+
const makeFormData = ({ tarFile: file, hasDiff, did, serverVersion, deleteSet, rootDid, mountPoint }) => {
|
|
45
|
+
let varFields = hasDiff
|
|
46
|
+
? '$file: Upload!, $did: String, $diffVersion: String, $deleteSet: [String!]'
|
|
47
|
+
: '$file: Upload!';
|
|
48
|
+
let inputFields = hasDiff
|
|
49
|
+
? 'file: $file, did: $did, diffVersion: $diffVersion, deleteSet: $deleteSet'
|
|
50
|
+
: 'file: $file';
|
|
51
|
+
|
|
52
|
+
varFields = `${varFields}, $rootDid: String, $mountPoint: String`;
|
|
53
|
+
inputFields = `${inputFields}, rootDid: $rootDid, mountPoint: $mountPoint`;
|
|
54
|
+
|
|
55
|
+
const variables = hasDiff
|
|
56
|
+
? {
|
|
57
|
+
file: null,
|
|
58
|
+
did,
|
|
59
|
+
diffVersion: serverVersion,
|
|
60
|
+
deleteSet,
|
|
61
|
+
}
|
|
62
|
+
: {
|
|
63
|
+
file: null,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
variables.rootDid = rootDid;
|
|
67
|
+
variables.mountPoint = mountPoint;
|
|
68
|
+
|
|
69
|
+
const apiName = 'installComponent';
|
|
70
|
+
const query = `
|
|
71
|
+
mutation (${varFields}) {
|
|
72
|
+
${apiName}(input: { ${inputFields} } ) {
|
|
73
|
+
code
|
|
74
|
+
blocklet {
|
|
75
|
+
meta {
|
|
76
|
+
did
|
|
77
|
+
name
|
|
78
|
+
title
|
|
79
|
+
version
|
|
80
|
+
description
|
|
81
|
+
}
|
|
82
|
+
status
|
|
83
|
+
source
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
88
|
+
const gql = {
|
|
89
|
+
query,
|
|
90
|
+
variables,
|
|
91
|
+
};
|
|
92
|
+
const map = {
|
|
93
|
+
file0: ['variables.file'],
|
|
94
|
+
};
|
|
95
|
+
const form = new FormData();
|
|
96
|
+
form.append('operations', JSON.stringify(gql));
|
|
97
|
+
form.append('map', JSON.stringify(map));
|
|
98
|
+
form.append('file0', fs.createReadStream(file));
|
|
99
|
+
return { form, apiName };
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const deploy = async (dir, { endpoint, accessKey, accessSecret, appDid, appId, mountPoint: inputMountPoint }) => {
|
|
103
|
+
let bundleDir = dir;
|
|
104
|
+
if (fs.existsSync(path.join(dir, BLOCKLET_BUNDLE_FOLDER))) {
|
|
105
|
+
bundleDir = path.join(dir, BLOCKLET_BUNDLE_FOLDER);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const rootDid = appDid || appId;
|
|
109
|
+
|
|
110
|
+
const fullEndpoint = joinURL(endpoint, '/api/gql');
|
|
111
|
+
const client = new Client(fullEndpoint, `BlockletCLI/${version}`);
|
|
112
|
+
client.setAuthAccessKey({
|
|
113
|
+
accessKeyId: accessKey,
|
|
114
|
+
accessKeySecret: accessSecret,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// check mountPoint when deploy a component
|
|
118
|
+
const { blocklet: app } = await client.getBlocklet({
|
|
119
|
+
input: {
|
|
120
|
+
did: rootDid,
|
|
121
|
+
attachRuntimeInfo: false,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (!app) {
|
|
126
|
+
printError(`App ${chalk.cyan(rootDid)} not found`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (new URL(endpoint).protocol === 'http:' && new URL(endpoint).hostname !== '127.0.0.1') {
|
|
131
|
+
printWarning(
|
|
132
|
+
`You are deploying to an insecure endpoint of ${chalk.cyan('http')} protocol, you should use ${chalk.cyan(
|
|
133
|
+
'https'
|
|
134
|
+
)} to achieve better security.`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// get local blocklet meta
|
|
139
|
+
let localMeta;
|
|
140
|
+
try {
|
|
141
|
+
localMeta = getBlockletMeta(bundleDir);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
debug('get blocklet error', error);
|
|
144
|
+
throw new Error(`Get blocklet meta failed: ${error.message}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
printInfo(
|
|
148
|
+
`Try to deploy ${chalk.cyan(`${localMeta.title}@${localMeta.version}`)} from`,
|
|
149
|
+
`${chalk.cyan(bundleDir)} to ${chalk.cyan(app.meta.title)} in server ${chalk.cyan(endpoint)}.`
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
if (hasReservedKey(localMeta.environments)) {
|
|
153
|
+
throw new Error('Blocklet key of environments can not start with `ABT_NODE_` or `BLOCKLET_`');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// mountPoint
|
|
157
|
+
let mountPoint;
|
|
158
|
+
if (hasMountPoint(localMeta)) {
|
|
159
|
+
if (inputMountPoint) {
|
|
160
|
+
mountPoint = inputMountPoint;
|
|
161
|
+
printInfo(`Use mountPoint from input: ${chalk.cyan(inputMountPoint)}`);
|
|
162
|
+
} else if (process.env.BLOCKLET_DEPLOY_MOUNT_POINT) {
|
|
163
|
+
printInfo(`Use mountPoint from env: ${chalk.cyan(process.env.BLOCKLET_DEPLOY_MOUNT_POINT)}`);
|
|
164
|
+
mountPoint = process.env.BLOCKLET_DEPLOY_MOUNT_POINT;
|
|
165
|
+
} else {
|
|
166
|
+
const { name, title } = localMeta;
|
|
167
|
+
mountPoint = `/${urlPathFriendly(title) || urlPathFriendly(name)}`.toLowerCase();
|
|
168
|
+
printInfo(`Use default mountPoint: ${chalk.cyan(mountPoint)}`);
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
mountPoint = `/${localMeta.did}`;
|
|
172
|
+
printInfo(`Use fake mountPoint: ${chalk.cyan(mountPoint)}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ensure entry file/folder exist
|
|
176
|
+
try {
|
|
177
|
+
await validateBlockletEntry(bundleDir, localMeta);
|
|
178
|
+
} catch (err) {
|
|
179
|
+
throw new Error(err.message);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// get hashFiles
|
|
183
|
+
const { files } = await hashFiles(bundleDir);
|
|
184
|
+
|
|
185
|
+
// check node_modules
|
|
186
|
+
const fileNames = Object.keys(files);
|
|
187
|
+
for (let i = 0; i < fileNames.length; i++) {
|
|
188
|
+
if (fileNames[i].includes('node_modules')) {
|
|
189
|
+
printError(`${chalk.bold('node_modules')} cannot be in the list of uploaded files`);
|
|
190
|
+
process.exit();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
let blockletDiff;
|
|
195
|
+
try {
|
|
196
|
+
blockletDiff = await client.getBlockletDiff({
|
|
197
|
+
input: {
|
|
198
|
+
did: localMeta.did,
|
|
199
|
+
hashFiles: Object.entries(files).map(([file, hash]) => ({ file, hash })),
|
|
200
|
+
rootDid: rootDid || '',
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
} catch (error) {
|
|
204
|
+
throw new Error(`Blocklet deploy failed when fetching diff: ${formatGQLError(error)}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const {
|
|
208
|
+
addSet = [],
|
|
209
|
+
changeSet = [],
|
|
210
|
+
deleteSet = [],
|
|
211
|
+
hasBlocklet: hasDiff,
|
|
212
|
+
version: serverVersion,
|
|
213
|
+
} = blockletDiff.blockletDiff || {};
|
|
214
|
+
const diffList = hasDiff ? [...addSet, ...changeSet] : null;
|
|
215
|
+
|
|
216
|
+
// if no diff and mountPoint not changed, stop deploy
|
|
217
|
+
if (hasDiff && localMeta.version === serverVersion && !addSet.length && !changeSet.length && !deleteSet.length) {
|
|
218
|
+
let needNotDeploy = true;
|
|
219
|
+
const child = app.children.find((x) => x.meta.did === localMeta.did);
|
|
220
|
+
needNotDeploy = isPathPrefixEqual(mountPoint, child.mountPoint);
|
|
221
|
+
|
|
222
|
+
if (needNotDeploy) {
|
|
223
|
+
print(`${localMeta.title}@${localMeta.version} already exists in ${app.meta.title}`);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
printInfo(`Name: ${chalk.cyan(localMeta.name)}`);
|
|
228
|
+
printInfo(`DID: ${chalk.cyan(localMeta.did)}`);
|
|
229
|
+
printInfo(`Version: ${chalk.cyan(localMeta.version)}`);
|
|
230
|
+
|
|
231
|
+
if (hasDiff) {
|
|
232
|
+
printDeployFileInfo(addSet, changeSet, deleteSet);
|
|
233
|
+
} else {
|
|
234
|
+
printDeployFileInfo(Object.keys(files));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// build tarFile
|
|
238
|
+
const tarFile = path.join(process.cwd(), `${slugify(localMeta.name)}-${localMeta.version}.tgz`);
|
|
239
|
+
|
|
240
|
+
await tar.c(
|
|
241
|
+
{
|
|
242
|
+
file: tarFile,
|
|
243
|
+
cwd: bundleDir,
|
|
244
|
+
filter: (f) =>
|
|
245
|
+
!diffList ||
|
|
246
|
+
fileFilter(f.replace(/^\.\//, ''), {
|
|
247
|
+
diffList,
|
|
248
|
+
}),
|
|
249
|
+
},
|
|
250
|
+
['.']
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
// do upload
|
|
254
|
+
const { form } = makeFormData({
|
|
255
|
+
tarFile,
|
|
256
|
+
hasDiff,
|
|
257
|
+
did: localMeta.did,
|
|
258
|
+
serverVersion,
|
|
259
|
+
deleteSet,
|
|
260
|
+
mountPoint,
|
|
261
|
+
rootDid,
|
|
262
|
+
});
|
|
263
|
+
try {
|
|
264
|
+
const timestamp = Date.now();
|
|
265
|
+
const timer = setInterval(() => {
|
|
266
|
+
// travis will close task if no output has been received in the last 10m0s
|
|
267
|
+
if (process.env.CI && process.env.TRAVIS) {
|
|
268
|
+
print('Uploading...');
|
|
269
|
+
}
|
|
270
|
+
}, 1000 * 500);
|
|
271
|
+
const res = await wrapSpinner(`Uploading ${localMeta.name}...`, () =>
|
|
272
|
+
axios({
|
|
273
|
+
url: fullEndpoint,
|
|
274
|
+
method: 'POST',
|
|
275
|
+
data: form,
|
|
276
|
+
headers: {
|
|
277
|
+
...form.getHeaders(),
|
|
278
|
+
'user-agent': `BlockletCLI/${version}`,
|
|
279
|
+
'x-access-key-id': accessKey,
|
|
280
|
+
'x-access-stamp': timestamp,
|
|
281
|
+
'x-access-signature': signWithAccessKey({
|
|
282
|
+
accessKeyId: accessKey,
|
|
283
|
+
accessKeySecret: accessSecret,
|
|
284
|
+
message: `${timestamp}-${accessKey}`,
|
|
285
|
+
}),
|
|
286
|
+
},
|
|
287
|
+
timeout: 1000 * 60 * 30, // 30min
|
|
288
|
+
// max file size is limited by server, so here is infinity
|
|
289
|
+
maxContentLength: Number.POSITIVE_INFINITY,
|
|
290
|
+
maxBodyLength: Number.POSITIVE_INFINITY,
|
|
291
|
+
})); // prettier-ignore
|
|
292
|
+
clearInterval(timer);
|
|
293
|
+
if (Array.isArray(res.data.errors) && res.data.errors.length) {
|
|
294
|
+
const error = new Error('GraphQL Response Error');
|
|
295
|
+
error.errors = res.data.errors;
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
if (fs.existsSync(tarFile)) {
|
|
299
|
+
fs.unlinkSync(tarFile);
|
|
300
|
+
}
|
|
301
|
+
printSuccess(
|
|
302
|
+
`${chalk.cyan(localMeta.title)}@${chalk.cyan(localMeta.version)} was successfully deployed to ${chalk.cyan(
|
|
303
|
+
app.meta.title
|
|
304
|
+
)} in server ${chalk.cyan(endpoint)}.`
|
|
305
|
+
);
|
|
306
|
+
} catch (error) {
|
|
307
|
+
if (fs.existsSync(tarFile)) {
|
|
308
|
+
fs.unlinkSync(tarFile);
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`Blocklet deploy failed when uploading: ${formatGQLError(error)}`);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const getNodeAsync = async ({ dir }) => {
|
|
315
|
+
const { node } = await getNode({ dir });
|
|
316
|
+
return new Promise((resolve) => {
|
|
317
|
+
node.onReady(() => resolve({ node }));
|
|
318
|
+
});
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const deployToLocal = async (dir, opts) => {
|
|
322
|
+
const isRunning = await checkRunning();
|
|
323
|
+
if (!isRunning) {
|
|
324
|
+
const startCommand = chalk.cyan(`${getCLIBinaryName()} start`);
|
|
325
|
+
printError('Blocklet Server is not running, can not deploy anything!');
|
|
326
|
+
printInfo(`To start Blocklet Server, use ${startCommand}`);
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const { node } = await getNodeAsync({ dir: process.cwd() });
|
|
331
|
+
|
|
332
|
+
const nodeInfo = await node.getNodeInfo();
|
|
333
|
+
const endpoint = `http://127.0.0.1:${nodeInfo.port}`;
|
|
334
|
+
const { accessKeyId, accessKeySecret } = await node.createAccessKey({
|
|
335
|
+
remark: 'Local CLI',
|
|
336
|
+
passport: ROLES.ADMIN,
|
|
337
|
+
});
|
|
338
|
+
try {
|
|
339
|
+
await deploy(dir, {
|
|
340
|
+
endpoint,
|
|
341
|
+
accessKey: accessKeyId,
|
|
342
|
+
accessSecret: accessKeySecret,
|
|
343
|
+
...opts,
|
|
344
|
+
});
|
|
345
|
+
await node.deleteAccessKey({ accessKeyId });
|
|
346
|
+
process.exit(0);
|
|
347
|
+
} catch (err) {
|
|
348
|
+
printError(err.message);
|
|
349
|
+
await node.deleteAccessKey({ accessKeyId });
|
|
350
|
+
process.exit(1);
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const deployToRemote = async (dir, opts) => {
|
|
355
|
+
try {
|
|
356
|
+
await deploy(dir, opts);
|
|
357
|
+
process.exit(0);
|
|
358
|
+
} catch (err) {
|
|
359
|
+
printError(err.message);
|
|
360
|
+
process.exit(1);
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
const checkAppID = (opts) => {
|
|
365
|
+
if (!opts.appDid && !opts.appId) {
|
|
366
|
+
printError('appId must exist. Please use --app-id to specify appId');
|
|
367
|
+
printInfo('If you want to deploy this blocklet as an application, please install from your Blocklet Server');
|
|
368
|
+
printInfo(`See ${chalk.cyan('https://developer.blocklet.io/docs/d6e08589-278a-448a-92e1-1e5f8bd4cc70')}`);
|
|
369
|
+
process.exit(1);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (opts.appId) {
|
|
373
|
+
if (!isValidDid(opts.appId)) {
|
|
374
|
+
printError('Invalid appId');
|
|
375
|
+
process.exit(1);
|
|
376
|
+
} else {
|
|
377
|
+
opts.appId = toAddress(opts.appId);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (opts.appDid) {
|
|
382
|
+
if (!isValidDid(opts.appDid)) {
|
|
383
|
+
printError('Invalid appDid');
|
|
384
|
+
process.exit(1);
|
|
385
|
+
} else {
|
|
386
|
+
opts.appDid = toAddress(opts.appDid);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
exports.run = (dirRaw, { endpoint, accessKey, accessSecret, ...opts }) => {
|
|
392
|
+
const dirExpanded = expandTilde(dirRaw);
|
|
393
|
+
const dir = [dirExpanded, path.join(process.cwd(), dirExpanded)].filter((x) => fs.existsSync(x)).pop();
|
|
394
|
+
|
|
395
|
+
if (!dir) {
|
|
396
|
+
printError(`Can not deploy blocklet from a non-existent directory ${chalk.red(dirRaw)}`);
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (!opts.appDid && !opts.appId) {
|
|
401
|
+
opts.appDid = process.env.BLOCKLET_DEPLOY_APP_DID || process.env.BLOCKLET_DEPLOY_APP_ID;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (endpoint || accessKey || accessSecret) {
|
|
405
|
+
if (!endpoint) {
|
|
406
|
+
printError('Can not deploy to remote Blocklet Server with empty endpoint!');
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
try {
|
|
410
|
+
const { protocol } = new URL(endpoint);
|
|
411
|
+
if (!/https?/.test(protocol)) {
|
|
412
|
+
printError('Invalid endpoint protocol:', protocol.replace(':', ''));
|
|
413
|
+
process.exit(1);
|
|
414
|
+
}
|
|
415
|
+
} catch (error) {
|
|
416
|
+
printError('Invalid endpoint:', endpoint);
|
|
417
|
+
process.exit(1);
|
|
418
|
+
}
|
|
419
|
+
if (!accessKey) {
|
|
420
|
+
printError('Can not deploy to remote Blocklet Server with empty access-key!');
|
|
421
|
+
process.exit(1);
|
|
422
|
+
}
|
|
423
|
+
if (!accessSecret) {
|
|
424
|
+
printError('Can not deploy to remote Blocklet Server with empty access-secret!');
|
|
425
|
+
process.exit(1);
|
|
426
|
+
}
|
|
427
|
+
validateAccessKey({ accessKeyId: accessKey, accessKeySecret: accessSecret });
|
|
428
|
+
|
|
429
|
+
checkAppID(opts);
|
|
430
|
+
deployToRemote(dir, { endpoint, accessKey, accessSecret, ...opts });
|
|
431
|
+
} else {
|
|
432
|
+
checkAppID(opts);
|
|
433
|
+
deployToLocal(dir, opts);
|
|
434
|
+
}
|
|
435
|
+
};
|