@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.
Files changed (87) hide show
  1. package/README.md +32 -25
  2. package/bin/blocklet.js +292 -1
  3. package/config.example.yml +33 -0
  4. package/lib/arcblock.js +53 -0
  5. package/lib/commands/blocklet/add.js +124 -0
  6. package/lib/commands/blocklet/assets/git-ignore +28 -0
  7. package/lib/commands/blocklet/assets/index.html +9 -0
  8. package/lib/commands/blocklet/assets/index.js +14 -0
  9. package/lib/commands/blocklet/assets/logo.png +0 -0
  10. package/lib/commands/blocklet/bundle/bundle.js +184 -0
  11. package/lib/commands/blocklet/bundle/bundlers/blocklet.js +138 -0
  12. package/lib/commands/blocklet/bundle/bundlers/changelog.js +100 -0
  13. package/lib/commands/blocklet/bundle/bundlers/logo.js +56 -0
  14. package/lib/commands/blocklet/bundle/bundlers/markdown.js +241 -0
  15. package/lib/commands/blocklet/bundle/bundlers/preference.js +50 -0
  16. package/lib/commands/blocklet/bundle/bundlers/readme.js +43 -0
  17. package/lib/commands/blocklet/bundle/bundlers/screenshots.js +94 -0
  18. package/lib/commands/blocklet/bundle/bundlers/simple.js +70 -0
  19. package/lib/commands/blocklet/bundle/compact/bundle-compact-file.js +48 -0
  20. package/lib/commands/blocklet/bundle/compact/bundle-merge-extra.js +66 -0
  21. package/lib/commands/blocklet/bundle/compact/default-external.js +5 -0
  22. package/lib/commands/blocklet/bundle/compact/index.js +88 -0
  23. package/lib/commands/blocklet/bundle/index.js +139 -0
  24. package/lib/commands/blocklet/bundle/pack.js +8 -0
  25. package/lib/commands/blocklet/bundle/parse-external-dependencies.js +97 -0
  26. package/lib/commands/blocklet/bundle/simple/index.js +62 -0
  27. package/lib/commands/blocklet/bundle/zip/archive.js +35 -0
  28. package/lib/commands/blocklet/bundle/zip/dependencies.js +333 -0
  29. package/lib/commands/blocklet/bundle/zip/index.js +165 -0
  30. package/lib/commands/blocklet/bundle/zip/main.js +124 -0
  31. package/lib/commands/blocklet/bundle/zip/node.js +59 -0
  32. package/lib/commands/blocklet/bundle/zip/resolve.js +93 -0
  33. package/lib/commands/blocklet/cleanup.js +52 -0
  34. package/lib/commands/blocklet/config.js +108 -0
  35. package/lib/commands/blocklet/connect.js +87 -0
  36. package/lib/commands/blocklet/create.js +38 -0
  37. package/lib/commands/blocklet/deploy.js +435 -0
  38. package/lib/commands/blocklet/dev.js +1000 -0
  39. package/lib/commands/blocklet/document.js +39 -0
  40. package/lib/commands/blocklet/exec.js +106 -0
  41. package/lib/commands/blocklet/init.js +300 -0
  42. package/lib/commands/blocklet/meta.js +22 -0
  43. package/lib/commands/blocklet/remove.js +35 -0
  44. package/lib/commands/blocklet/test.js +201 -0
  45. package/lib/commands/blocklet/upload.js +105 -0
  46. package/lib/commands/blocklet/version.js +81 -0
  47. package/lib/commands/server/cleanup.js +32 -0
  48. package/lib/commands/server/command.js +131 -0
  49. package/lib/commands/server/info.js +92 -0
  50. package/lib/commands/server/init.js +433 -0
  51. package/lib/commands/server/logs.js +99 -0
  52. package/lib/commands/server/rescue.js +71 -0
  53. package/lib/commands/server/start.js +821 -0
  54. package/lib/commands/server/status.js +107 -0
  55. package/lib/commands/server/stop.js +163 -0
  56. package/lib/commands/server/upgrade.js +123 -0
  57. package/lib/constant.js +21 -2
  58. package/lib/debug.js +20 -0
  59. package/lib/manager/config.js +122 -0
  60. package/lib/manager/deploy.js +75 -0
  61. package/lib/manager/index.js +23 -0
  62. package/lib/manager/process.js +47 -0
  63. package/lib/node.js +214 -0
  64. package/lib/port.js +19 -0
  65. package/lib/postinstall.js +3 -0
  66. package/lib/process/daemon.js +196 -0
  67. package/lib/process/service.js +86 -0
  68. package/lib/ui.js +137 -0
  69. package/lib/util/blocklet/config.js +78 -0
  70. package/lib/util/blocklet/env.js +172 -0
  71. package/lib/util/blocklet/meta.js +36 -0
  72. package/lib/util/blocklet/payment.js +88 -0
  73. package/lib/util/blocklet/sign.js +21 -0
  74. package/lib/util/blocklet/tar.js +119 -0
  75. package/lib/util/convert-to-nosources-sourcemap.js +37 -0
  76. package/lib/util/docker-status-log.js +17 -0
  77. package/lib/util/exit-when-server-stopped.js +44 -0
  78. package/lib/util/get-cli-binary-name.js +8 -0
  79. package/lib/util/get-download-bundle-step.js +36 -0
  80. package/lib/util/get-service-instance-number.js +12 -0
  81. package/lib/util/index.js +626 -0
  82. package/lib/util/print-error.js +11 -0
  83. package/lib/util/print.js +9 -0
  84. package/lib/util/what-uri.js +40 -0
  85. package/package.json +123 -27
  86. package/lib/run.d.ts +0 -2
  87. package/lib/run.js +0 -73
@@ -0,0 +1,626 @@
1
+ const path = require('path');
2
+ const chalk = require('chalk');
3
+ const toLower = require('lodash/toLower');
4
+ const get = require('lodash/get');
5
+ const os = require('os');
6
+ const rc = require('rc');
7
+ const updateNotifier = require('update-notifier');
8
+ const { filesize } = require('filesize');
9
+ const fs = require('fs-extra');
10
+ const git = require('git-rev-sync');
11
+ const uniq = require('lodash/uniq');
12
+ const portUsed = require('port-used');
13
+ const pRetry = require('p-retry');
14
+ const { joinURL } = require('ufo');
15
+ const getNodeWallet = require('@abtnode/util/lib/get-app-wallet');
16
+ const isDocker = require('@abtnode/util/lib/is-docker');
17
+ const isGitpod = require('@abtnode/util/lib/is-gitpod');
18
+ const ensureListening = require('@abtnode/util/lib/ensure-listening');
19
+ const pm2 = require('@abtnode/util/lib/async-pm2');
20
+ const getIP = require('@abtnode/util/lib/get-ip');
21
+ const sleep = require('@abtnode/util/lib/sleep');
22
+ const axios = require('@abtnode/util/lib/axios');
23
+ const cloud = require('@abtnode/util/lib/cloud');
24
+ const { updateServerDocument } = require('@abtnode/util/lib/did-document');
25
+ const { getProvider } = require('@abtnode/router-provider');
26
+ const { decideHttpPort, decideHttpsPort } = require('@abtnode/router-provider/lib/util');
27
+ const tryWithTimeout = require('@abtnode/util/lib/try-with-timeout');
28
+ const codespaces = require('@abtnode/util/lib/codespaces');
29
+ const {
30
+ PROCESS_NAME_EVENT_HUB,
31
+ PROXY_MAX_MEM_LIMIT_IN_MB,
32
+ DEFAULT_DESCRIPTION,
33
+ DEFAULT_HTTP_PORT,
34
+ NODE_MODES,
35
+ DEFAULT_HTTPS_PORT,
36
+ } = require('@abtnode/constant');
37
+ const gitUserName = require('git-user-name');
38
+
39
+ const pkg = require('../../package.json');
40
+ const { symbols, wrapSpinner } = require('../ui');
41
+ const { getInternalPort: getPort } = require('../port');
42
+ const debug = require('../debug')('util');
43
+ const getCLIBinaryName = require('./get-cli-binary-name');
44
+ const printError = require('./print-error');
45
+ const { print } = require('./print');
46
+
47
+ const { version } = require('../../package.json');
48
+ const { HELP_DOCS_GITHUB_CODESPACES_URL } = require('../constant');
49
+
50
+ function printInfo(...args) {
51
+ print.apply(null, [symbols.info, ...args]);
52
+ }
53
+
54
+ function printSuccess(...args) {
55
+ print.apply(null, [symbols.success, ...args]);
56
+ }
57
+
58
+ function printWarning(...args) {
59
+ print.apply(null, [symbols.warning, ...args]);
60
+ }
61
+
62
+ const isValidYamlFileName = (filePath) => ['.yml', '.yaml'].includes(toLower(path.extname(filePath)));
63
+
64
+ function getNPMConfig(key) {
65
+ const conf = rc('npm');
66
+ return get(conf, key, '');
67
+ }
68
+
69
+ function getUserName(author) {
70
+ return author || gitUserName() || os.userInfo().username;
71
+ }
72
+
73
+ function checkUpdate() {
74
+ debug('check update');
75
+ const UPDATE_CHECK_INTERVAL = 1000 * 60 * 60 * 24; // one day
76
+ const notifier = updateNotifier({
77
+ pkg: { name: pkg.name, version: pkg.version },
78
+ updateCheckInterval: UPDATE_CHECK_INTERVAL,
79
+ });
80
+ if (notifier && notifier.update) {
81
+ notifier.notify({
82
+ message:
83
+ // eslint-disable-next-line
84
+ 'New version available! ' +
85
+ chalk.dim(notifier.update.current) +
86
+ chalk.reset(' → ') +
87
+ chalk.green(notifier.update.latest) +
88
+ ' \nRun ' +
89
+ chalk.cyan('blocklet server upgrade') +
90
+ ' to get latest version',
91
+ });
92
+ }
93
+ }
94
+
95
+ const cleanupProcessByName = async (name) => {
96
+ try {
97
+ const [info] = await pm2.describeAsync(name);
98
+ if (info) {
99
+ await pm2.deleteAsync(name);
100
+ }
101
+ } catch {
102
+ // ignore
103
+ }
104
+ };
105
+
106
+ /**
107
+ * @param {string} info.provider routing provider name
108
+ * @param {number} info.httpPort
109
+ * @param {number} info.httpsPort
110
+ */
111
+ const checkRoutingProvider = async (info, { configDir } = {}) => {
112
+ const Provider = getProvider(info.provider);
113
+ if (!Provider) {
114
+ return true;
115
+ }
116
+
117
+ const result = await Provider.check({ configDir });
118
+ if (!result.available) {
119
+ printError(result.error);
120
+ printError('For more info on how to solve the problem: https://developer.blocklet.io/docs');
121
+ return false;
122
+ }
123
+
124
+ // ensure ports are available for the routing engine
125
+ if (!result.running && !result.managed) {
126
+ const httpPort = decideHttpPort(info.httpPort);
127
+ if (await portUsed.check(httpPort)) {
128
+ printError(
129
+ `Port ${chalk.cyan(httpPort)} is required by routing engine ${chalk.cyan(
130
+ info.provider
131
+ )}, but already in use, please free the port before retry.`
132
+ );
133
+ return false;
134
+ }
135
+
136
+ const httpsPort = decideHttpsPort(info.httpsPort);
137
+ if (await portUsed.check(httpsPort)) {
138
+ printError(
139
+ `Port ${chalk.cyan(httpsPort)} is required by routing engine ${chalk.cyan(
140
+ info.provider
141
+ )}, but already in use, please free the port before retry.`
142
+ );
143
+ return false;
144
+ }
145
+ }
146
+
147
+ return true;
148
+ };
149
+
150
+ const stopRouting = async ({ info, routerDir }) => {
151
+ const providerName = get(info, 'routing.provider', '');
152
+ const Provider = getProvider(providerName);
153
+ if (!Provider) {
154
+ return;
155
+ }
156
+
157
+ const httpPort = info.routing.httpPort || DEFAULT_HTTP_PORT;
158
+ const httpsPort = info.routing.httpsPort || DEFAULT_HTTPS_PORT;
159
+
160
+ const provider = new Provider({ configDir: path.join(routerDir, providerName), httpPort, httpsPort });
161
+ await provider.stop();
162
+ };
163
+
164
+ const getFileSize = (file) => {
165
+ try {
166
+ const stats = fs.statSync(file);
167
+ return filesize(stats.size, { base: 2 });
168
+ } catch (err) {
169
+ return 'NaN';
170
+ }
171
+ };
172
+
173
+ const getCLICommandName = () => {
174
+ const binaryName = getCLIBinaryName();
175
+ const [, , action] = process.argv;
176
+
177
+ if (action === 'server') {
178
+ return `${binaryName} ${action}`;
179
+ }
180
+
181
+ return binaryName;
182
+ };
183
+
184
+ const getCLIVersion = () => {
185
+ return version;
186
+ };
187
+
188
+ function formatGQLError(error) {
189
+ const err = error.response ? error.response.data : error;
190
+ if (Array.isArray(err.errors)) {
191
+ return err.errors.map((x) => x.message).join(', ');
192
+ }
193
+ return err.message;
194
+ }
195
+
196
+ /**
197
+ * @param {Array} url[<url>]
198
+ * @param {String} url[].url
199
+ * @param {String} url[].type
200
+ */
201
+ const printAccessUrls = (urls, indent = 0) => {
202
+ const paddingLeft = Array.from(Array(indent).keys()).reduce((s) => `${s} `, '');
203
+ const httpUrls = urls.filter((x) => x.url.startsWith('http://'));
204
+ const httpsUrls = urls.filter((x) => x.url.startsWith('https://'));
205
+
206
+ if (httpUrls.length) {
207
+ print(`\n${paddingLeft}HTTP URLs:\n`);
208
+ httpUrls.forEach((x) => print(`${paddingLeft}- ${x.url}`.padStart(10)));
209
+ }
210
+ if (httpsUrls.length) {
211
+ print(`\n${paddingLeft}Secure URLs (Recommended):\n`);
212
+ httpsUrls.forEach((x) => print(`${paddingLeft}- ${x.url}`.padStart(10)));
213
+ }
214
+ };
215
+
216
+ const getGitHash = (dir) => git.long(dir);
217
+
218
+ const getCliCwd = () => path.dirname(path.dirname(__dirname));
219
+
220
+ const startEventHub = async (logDir, maxMemoryRestart = PROXY_MAX_MEM_LIMIT_IN_MB) => {
221
+ const port = getPort(PROCESS_NAME_EVENT_HUB);
222
+ debug('start event hub', { port });
223
+
224
+ const tryStartEventHub = async () => {
225
+ try {
226
+ await wrapSpinner('Starting event hub...', async () => {
227
+ await pm2.startAsync({
228
+ namespace: 'daemon',
229
+ name: PROCESS_NAME_EVENT_HUB,
230
+ script: require.resolve('@arcblock/event-hub/lib/server-abtnode.js'),
231
+ max_memory_restart: `${maxMemoryRestart}M`,
232
+ output: path.join(logDir, 'event.output.log'),
233
+ error: path.join(logDir, 'event.error.log'),
234
+ cwd: getCliCwd(),
235
+ wait_ready: true,
236
+ max_restarts: 3,
237
+ listen_timeout: 3000,
238
+ time: true,
239
+ env: {
240
+ ABT_NODE_EVENT_PORT: port,
241
+ },
242
+ });
243
+ await tryWithTimeout(() => ensureListening(port), 10000);
244
+ });
245
+
246
+ process.env.ABT_NODE_EVENT_PORT = port;
247
+ } catch (err) {
248
+ debug('Blocklet Event Hub start failed: ', err);
249
+ printError(`Blocklet Event Hub start failed: ${err.message}`);
250
+ }
251
+ };
252
+
253
+ await tryStartEventHub();
254
+
255
+ return port;
256
+ };
257
+
258
+ const killPm2Process = async (name) => {
259
+ const [info] = await pm2.describeAsync(name);
260
+ if (!info) {
261
+ printWarning(`${name} is not running`);
262
+ return null;
263
+ }
264
+
265
+ const proc = await pm2.deleteAsync(name);
266
+ return proc;
267
+ };
268
+
269
+ const fixFiles = (meta, dir) => {
270
+ const files = meta.files || ['blocklet.md', 'screenshots'];
271
+ const packageFile = path.join(dir, 'package.json');
272
+ let packageFiles = [];
273
+ if (fs.existsSync(packageFile)) {
274
+ try {
275
+ const packageJson = JSON.parse(fs.readdirSync(packageFile).toString());
276
+ if (Array.isArray(packageJson.files)) {
277
+ packageFiles = packageJson.files.filter((x) => typeof x === 'string');
278
+ }
279
+ } catch (err) {
280
+ // Do nothing
281
+ }
282
+ }
283
+
284
+ const uniqFiles = uniq([...files, ...packageFiles]).filter((file) => {
285
+ return !(!file || typeof file !== 'string');
286
+ });
287
+
288
+ meta.files = uniqFiles;
289
+ };
290
+
291
+ const getDevUrl = async ({
292
+ isGitpod: _isGitpod = isGitpod,
293
+ gitpodWorkspaceURL = process.env.GITPOD_WORKSPACE_URL,
294
+ abtnodeHttpPort = process.env.ABT_NODE_HTTP_PORT,
295
+ isDocker: _isDocker = isDocker,
296
+ getUrl = () => '',
297
+ }) => {
298
+ // Gitpod
299
+ if (_isGitpod()) {
300
+ const gitpodURL = gitpodWorkspaceURL;
301
+ return gitpodURL.replace(/^https?:\/\//g, (p) => `${p}${abtnodeHttpPort}-`);
302
+ }
303
+
304
+ // Docker
305
+ if (_isDocker() && !process.env.ABT_NODE_HOST) {
306
+ return 'http://127.0.0.1';
307
+ }
308
+
309
+ // Local
310
+ const url = await getUrl();
311
+ return url || '';
312
+ };
313
+
314
+ const getDataDir = () => path.join(os.homedir(), '.arcblock');
315
+
316
+ const readInitInfoFromEc2 = () => {
317
+ try {
318
+ const info = fs.readFileSync(path.join(os.homedir(), '.arcblock/abtnode/user-data')).toString().trim();
319
+ return JSON.parse(info);
320
+ } catch {
321
+ return {
322
+ ownerDid: null,
323
+ issuerDid: null,
324
+ initialBlocklets: [],
325
+ };
326
+ }
327
+ };
328
+
329
+ const printVersionTip = () => {
330
+ const versionTip = `${getCLIBinaryName()} ${process.argv[2]} v${version}`;
331
+ print(chalk.bold(versionTip));
332
+ debug(`Nodejs: ${process.version}`);
333
+ };
334
+
335
+ const checkTerminalProxy = (name) => {
336
+ const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy || '';
337
+ const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy || '';
338
+ if (httpsProxy) {
339
+ printWarning(
340
+ chalk.black(chalk.bgYellow(`HTTPS_PROXY detected: ${httpsProxy}, which may cause ${name} not working properly.`))
341
+ );
342
+ printWarning(
343
+ chalk.black(chalk.bgYellow(`If that happens, please clear the environment variable and restart ${name}.`))
344
+ );
345
+ } else if (httpProxy) {
346
+ printWarning(
347
+ chalk.black(chalk.bgYellow(`HTTP_PROXY detected: ${httpProxy}, which may cause ${name} not working properly.`))
348
+ );
349
+ printWarning(
350
+ chalk.black(chalk.bgYellow(`If that happens, please clear the environment variable and restart ${name}.`))
351
+ );
352
+ }
353
+ };
354
+
355
+ const getIpDescription = async () => {
356
+ let defaultIP = '';
357
+ let nodeDescription = '';
358
+ const ips = await getIP({ timeout: 1000 });
359
+
360
+ if (isDocker()) {
361
+ nodeDescription = 'Blocklet Server on docker';
362
+ } else if (await cloud.isInCloud()) {
363
+ defaultIP = ips.external || ips.internal; // use external ip by default on AWS EC2
364
+ nodeDescription = `Blocklet Server on cloud [${defaultIP}]`;
365
+ } else {
366
+ defaultIP = ips.internal || ips.external; // use internal ip by default on local
367
+ nodeDescription = `Blocklet Server on [${defaultIP}]`;
368
+ }
369
+
370
+ return { ip: defaultIP, description: nodeDescription };
371
+ };
372
+
373
+ const getDefaultName = () => `Blocklet Server [${os.userInfo().username}]`;
374
+
375
+ const getDefaultDescription = async () => {
376
+ try {
377
+ // eslint-disable-next-line no-use-before-define
378
+ const { description } = await lib.getIpDescription(); // module.exports.getIpDescription is for unit test
379
+ return description;
380
+ } catch {
381
+ // do nothing
382
+ return DEFAULT_DESCRIPTION;
383
+ }
384
+ };
385
+
386
+ const isDaemonIpAccessible = async ({ ip, port, adminPath }) => {
387
+ try {
388
+ const urlObj = new URL(`http://${ip}`);
389
+ urlObj.port = port;
390
+ urlObj.pathname = joinURL(adminPath, '/api/gql');
391
+
392
+ const url = urlObj.href;
393
+
394
+ const ping = async () => {
395
+ debug(`ping daemon(${ip}:${port}), url: ${url}`);
396
+ const { data } = await axios.post(
397
+ url,
398
+ JSON.stringify({
399
+ query: `{
400
+ getNodeInfo {
401
+ code
402
+ info {
403
+ did
404
+ }
405
+ }
406
+ }`,
407
+ }),
408
+ {
409
+ headers: {
410
+ 'Content-Type': 'application/json',
411
+ Accept: 'application/json',
412
+ },
413
+ timeout: 3 * 1000,
414
+ }
415
+ );
416
+
417
+ const ok = !!get(data, 'data.getNodeInfo.info.did');
418
+ if (!ok) {
419
+ await sleep(1000);
420
+ throw new Error('Daemon is unavailable');
421
+ }
422
+ };
423
+
424
+ // 重试 2 次,总共 ping 3 次
425
+ await pRetry(ping, { retries: 2 });
426
+ return true;
427
+ } catch (error) {
428
+ debug(`check daemon ip(${ip}:${port}) is accessible failed`, error.message);
429
+ return false;
430
+ }
431
+ };
432
+
433
+ const getAccessibleIps = async (info, forceIntranet = false) => {
434
+ const nodeHttpPort = info.routing.httpPort;
435
+
436
+ const ips = await getIP({ includeExternal: !forceIntranet });
437
+ const getDaemonPort = (port, defaultPort) => (port && port !== defaultPort ? `${port}` : '');
438
+ const port = getDaemonPort(nodeHttpPort, DEFAULT_HTTP_PORT);
439
+ const result = { internal: ips.internal };
440
+
441
+ // 云环境下下完全相信获取到的 IP 信息
442
+ if ((await cloud.isInCloud()) === true) {
443
+ result.external = ips.external;
444
+ return result;
445
+ }
446
+
447
+ // eslint-disable-next-line no-use-before-define
448
+ if (await lib.isDaemonIpAccessible({ ip: ips.external, port, adminPath: info.routing.adminPath })) {
449
+ result.external = ips.external;
450
+ }
451
+
452
+ return result;
453
+ };
454
+
455
+ const prettyAvailableModes = () =>
456
+ Object.values(NODE_MODES)
457
+ .map((d) => `"${d}"`)
458
+ .join(', ');
459
+
460
+ const printInvalidModeInfo = () => {
461
+ printError('Invalid mode');
462
+ printInfo(`Valid mode should be ${prettyAvailableModes()}`);
463
+ };
464
+
465
+ const wrapDefaultStoreUrl =
466
+ (url) =>
467
+ ({ source: { name } }) => {
468
+ printInfo(`Using store ${chalk.cyan(url)} to download component ${chalk.cyan(name)}`);
469
+ return url;
470
+ };
471
+
472
+ const isValidMode = (mode) => Object.values(NODE_MODES).includes(mode);
473
+
474
+ const ensurePermission = (dataDir) => {
475
+ try {
476
+ // eslint-disable-next-line no-bitwise
477
+ fs.accessSync(dataDir, fs.constants.R_OK | fs.constants.W_OK);
478
+ } catch (err) {
479
+ printError(`Can not access directory ${chalk.cyan(dataDir)}, please check the permission`);
480
+ process.exit(1);
481
+ }
482
+ };
483
+
484
+ /**
485
+ * if index.html or index.htm in not in folder meta.main (cwd: dir), throw error
486
+ */
487
+ const checkEntryFileForStaticBlocklet = (meta, dir) => {
488
+ const main = meta.main || '.';
489
+ const mainDir = path.join(dir, main);
490
+ const hasEntryFile =
491
+ fs.existsSync(path.join(mainDir, 'index.html')) || fs.existsSync(path.join(mainDir, 'index.htm'));
492
+
493
+ if (!hasEntryFile) {
494
+ throw new Error(`Can not find index.html or index.htm in ${mainDir}`);
495
+ }
496
+ };
497
+
498
+ const updateDidDocument = async (...args) => {
499
+ try {
500
+ await updateServerDocument(...args);
501
+ return { status: 'success' };
502
+ } catch (err) {
503
+ return { status: 'error', message: get(err, 'response.data.error') || err.message };
504
+ }
505
+ };
506
+
507
+ const getDaemonAccessUrls = async ({ info, wallet, getBaseUrls, forceIntranet }) => {
508
+ let accessUrls = [];
509
+
510
+ if (codespaces.isCodespaces()) {
511
+ const url = codespaces.getAccessUrl({ port: info.routing.httpsPort, pathName: info.routing.adminPath });
512
+ accessUrls.push({ url });
513
+ } else {
514
+ const accessibleIps = [];
515
+ if (process.env.ABT_NODE_HOST) {
516
+ accessibleIps.push(process.env.ABT_NODE_HOST);
517
+ } else {
518
+ const ips = await wrapSpinner(
519
+ `Fetching accessible IPs (forceIntranet: ${JSON.stringify(forceIntranet)})...`,
520
+ () => getAccessibleIps(info, forceIntranet),
521
+ {
522
+ throwOnError: false,
523
+ printErrorFn: printError,
524
+ }
525
+ );
526
+
527
+ if (ips.external) {
528
+ accessibleIps.push(ips.external); // 如果公网 IP 可访问,那么它是 accessibleIps 的第一个元素
529
+ }
530
+
531
+ if (ips.internal) {
532
+ accessibleIps.push(ips.internal);
533
+ }
534
+ }
535
+
536
+ debug('accessible ips', accessibleIps);
537
+
538
+ if (accessibleIps.length > 0) {
539
+ if (wallet) {
540
+ await wrapSpinner(
541
+ 'Updating DID Domain...',
542
+ async () => {
543
+ const result = await updateDidDocument({
544
+ ips: [accessibleIps[0]],
545
+ didRegistryUrl: info.didRegistry,
546
+ wallet,
547
+ domain: info.didDomain,
548
+ blockletServerVersion: version,
549
+ });
550
+
551
+ if (result.status === 'success') {
552
+ return;
553
+ }
554
+
555
+ throw new Error(result.message);
556
+ },
557
+ { throwOnError: false, printErrorFn: printError }
558
+ );
559
+ }
560
+
561
+ printSuccess('You can access your Blocklet Server with either of the following URLs');
562
+ accessUrls = await getBaseUrls(accessibleIps);
563
+ }
564
+ }
565
+
566
+ return accessUrls;
567
+ };
568
+
569
+ const printCodespacesDevelopmentGuide = () => {
570
+ printInfo(
571
+ `For detailed guidance on developing blocklets in GitHub Codespaces, please visit: ${chalk.cyan(HELP_DOCS_GITHUB_CODESPACES_URL)}`
572
+ );
573
+ };
574
+
575
+ const printBlockletDevelopmentGuide = () => {
576
+ if (codespaces.isCodespaces()) {
577
+ printCodespacesDevelopmentGuide();
578
+ }
579
+ };
580
+
581
+ const lib = {
582
+ checkRoutingProvider,
583
+ checkTerminalProxy,
584
+ print,
585
+ printError,
586
+ printInfo,
587
+ printSuccess,
588
+ printWarning,
589
+ printBlockletDevelopmentGuide,
590
+ isValidYamlFileName,
591
+ getNPMConfig,
592
+ checkUpdate,
593
+ stopRouting,
594
+ getFileSize,
595
+ getCLIBinaryName,
596
+ getCLICommandName,
597
+ getCLIVersion,
598
+ getAccessibleIps,
599
+ formatGQLError,
600
+ printAccessUrls,
601
+ getGitHash,
602
+ getCliCwd,
603
+ startEventHub,
604
+ killPm2Process,
605
+ getUserName,
606
+ fixFiles,
607
+ getDevUrl,
608
+ getDataDir,
609
+ getWallet: getNodeWallet,
610
+ readInitInfoFromEc2,
611
+ printVersionTip,
612
+ printInvalidModeInfo,
613
+ getIpDescription,
614
+ getDefaultName,
615
+ getDefaultDescription,
616
+ wrapDefaultStoreUrl,
617
+ isValidMode,
618
+ prettyAvailableModes,
619
+ isDaemonIpAccessible,
620
+ ensurePermission,
621
+ checkEntryFileForStaticBlocklet,
622
+ cleanupProcessByName,
623
+ getDaemonAccessUrls,
624
+ };
625
+
626
+ module.exports = lib;
@@ -0,0 +1,11 @@
1
+ const { symbols } = require('../ui');
2
+ const debug = require('../debug')('util');
3
+
4
+ module.exports = function printError(...args) {
5
+ debug(...args);
6
+ if (args.length && args[0] instanceof Error) {
7
+ args[0] = args[0].message;
8
+ }
9
+
10
+ console.error.apply(null, [symbols.error, ...args]);
11
+ };
@@ -0,0 +1,9 @@
1
+ const shell = require('shelljs');
2
+
3
+ function print(...args) {
4
+ shell.echo.apply(null, args);
5
+ }
6
+
7
+ module.exports = {
8
+ print,
9
+ };
@@ -0,0 +1,40 @@
1
+ const isUrl = require('is-url');
2
+ const isURI = require('validate.io-uri');
3
+
4
+ /**
5
+ *
6
+ *
7
+ * @param {string} uri
8
+ * @return {boolean}
9
+ */
10
+ function isAnchor(uri) {
11
+ return uri && uri.startsWith('#');
12
+ }
13
+
14
+ /**
15
+ *
16
+ *
17
+ * @param {string} uri
18
+ * @return {boolean}
19
+ */
20
+ function isNoHeaderUri(uri) {
21
+ return uri && (uri.startsWith('://') || uri.startsWith('//'));
22
+ }
23
+
24
+ /**
25
+ *
26
+ *
27
+ * @param {string} uri
28
+ * @return {boolean}
29
+ */
30
+ function isLocalUri(uri) {
31
+ if (!uri) {
32
+ return false;
33
+ }
34
+
35
+ return !(isURI(uri) || isAnchor(uri) || isNoHeaderUri(uri) || isUrl(uri));
36
+ }
37
+
38
+ module.exports = {
39
+ isLocalUri,
40
+ };