@giteeteam/apps-cli 0.4.3 → 0.5.0-alpha.1

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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +1 -596
  3. package/package.json +13 -7
package/README.md CHANGED
@@ -18,5 +18,5 @@ $ giteeteam-apps build
18
18
 
19
19
  ## 调试插件function
20
20
  ```bash
21
- $ giteeteam-apps dev
21
+ $ giteeteam-apps tunnel
22
22
  ```
package/dist/index.js CHANGED
@@ -1,597 +1,2 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';
3
-
4
- require('dotenv/config');
5
- var commander = require('commander');
6
- var fse = require('fs-extra');
7
- var path = require('path');
8
- var archiver = require('archiver');
9
- var rollup = require('rollup');
10
- var fs = require('fs');
11
- var esbuild$1 = require('esbuild');
12
- var pluginNodeResolve = require('@rollup/plugin-node-resolve');
13
- var commonjs = require('@rollup/plugin-commonjs');
14
- var ora = require('ora');
15
- var appsManifest = require('@giteeteam/apps-manifest');
16
- var inquirer = require('inquirer');
17
- var simpleGit = require('simple-git');
18
- var chalk = require('chalk');
19
- var readline = require('readline');
20
- var execa = require('execa');
21
- var child_process = require('child_process');
22
- var chokidar = require('chokidar');
23
-
24
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
25
-
26
- var fse__default = /*#__PURE__*/_interopDefaultLegacy(fse);
27
- var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
28
- var archiver__default = /*#__PURE__*/_interopDefaultLegacy(archiver);
29
- var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
30
- var commonjs__default = /*#__PURE__*/_interopDefaultLegacy(commonjs);
31
- var ora__default = /*#__PURE__*/_interopDefaultLegacy(ora);
32
- var inquirer__default = /*#__PURE__*/_interopDefaultLegacy(inquirer);
33
- var simpleGit__default = /*#__PURE__*/_interopDefaultLegacy(simpleGit);
34
- var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);
35
- var execa__default = /*#__PURE__*/_interopDefaultLegacy(execa);
36
- var child_process__default = /*#__PURE__*/_interopDefaultLegacy(child_process);
37
- var chokidar__default = /*#__PURE__*/_interopDefaultLegacy(chokidar);
38
-
39
- var version = "0.4.3";
40
-
41
- const packageApp = async ({ outputDir, manifest, copyFiles }) => {
42
- const { resources } = manifest;
43
- if (resources) {
44
- for (const { key, path: resourcePath } of resources) {
45
- const src = path__default["default"].resolve(path__default["default"].join('./', resourcePath));
46
- const dest = path__default["default"].join(outputDir, key);
47
- await fse__default["default"].copy(src, dest);
48
- }
49
- }
50
- // copy的文件
51
- for (const file of copyFiles) {
52
- const srcFile = path__default["default"].resolve(file);
53
- const destFile = path__default["default"].join(outputDir, file);
54
- await fse__default["default"].copy(srcFile, destFile);
55
- }
56
- };
57
-
58
- const archiveApp = async (archiveDir, pkgName) => {
59
- const outputFile = path__default["default"].resolve(pkgName);
60
- await fse__default["default"].remove(outputFile);
61
- return new Promise((resolve, reject) => {
62
- const output = fse__default["default"].createWriteStream(outputFile);
63
- const archive = archiver__default["default"]('zip', {
64
- zlib: { level: 9 }, // Sets the compression level.
65
- });
66
- // listen for all archive data to be written
67
- // 'close' event is fired only when a file descriptor is involved
68
- output.on('close', function () {
69
- // console.log(archive.pointer() + ' total bytes');
70
- // console.log('archiver has been finalized and the output file descriptor has closed.');
71
- resolve();
72
- });
73
- // output.on('end', function () {
74
- // console.log('Data has been drained');
75
- // });
76
- // good practice to catch warnings (ie stat failures and other non-blocking errors)
77
- archive.on('warning', function (err) {
78
- console.log(err);
79
- if (err.code === 'ENOENT') ;
80
- else {
81
- // throw error
82
- reject(err);
83
- }
84
- });
85
- // good practice to catch this error explicitly
86
- archive.on('error', function (err) {
87
- console.log(err);
88
- reject(err);
89
- });
90
- // pipe archive data to the file
91
- archive.pipe(output);
92
- // append files from a sub-directory, putting its contents at the root of archive
93
- archive.directory(archiveDir, false);
94
- archive.finalize();
95
- });
96
- };
97
-
98
- const defaultOptions = {
99
- treeShaking: true,
100
- format: 'esm',
101
- loader: 'tsx',
102
- };
103
- function esbuild(options) {
104
- options = { ...defaultOptions, ...options };
105
- return {
106
- name: 'esbuild',
107
- resolveId(source, importer, opts) {
108
- // console.log('resolveId:');
109
- // console.dir({ source, importer, opts }, { depth: null });
110
- if (!importer || ['.ts', '.tsx', '.js', '.jsx', '.mjs'].some(ext => source.endsWith(ext))) {
111
- return source;
112
- }
113
- const dirPath = path.dirname(importer);
114
- let path$1;
115
- if (fs.existsSync((path$1 = path.resolve(dirPath, source, 'index.ts')))) {
116
- return path$1;
117
- }
118
- else if (fs.existsSync((path$1 = path.resolve(dirPath, source, 'index.tsx')))) {
119
- return path$1;
120
- }
121
- else if (fs.existsSync((path$1 = path.resolve(dirPath, source + '.ts')))) {
122
- return path$1;
123
- }
124
- else if (fs.existsSync((path$1 = path.resolve(dirPath, source + '.tsx')))) {
125
- return path$1;
126
- }
127
- else {
128
- console.error({ source, importer, options: opts });
129
- path$1 = path.relative('.', path.resolve(importer, source));
130
- throw new Error(`ENOENT: ${path$1.replace(/\\/g, '/')}`);
131
- }
132
- },
133
- async transform(src, id) {
134
- options.sourcefile = id;
135
- const { code, map } = await esbuild$1.transform(src, options);
136
- if (!map)
137
- return code;
138
- return { code, map };
139
- },
140
- };
141
- }
142
-
143
- var MODE;
144
- (function (MODE) {
145
- MODE["DEV"] = "development";
146
- MODE["PROD"] = "production";
147
- })(MODE || (MODE = {}));
148
- function getRollupOptions(input, outputFile, mode = MODE.DEV) {
149
- const plugins = [pluginNodeResolve.nodeResolve(), commonjs__default["default"]()];
150
- plugins.push(esbuild({
151
- sourcemap: mode === MODE.DEV,
152
- minify: mode !== MODE.DEV,
153
- target: 'es2018',
154
- jsx: 'transform',
155
- jsxFactory: 'AppsUI.createElement',
156
- jsxFragment: 'AppsUI.Fragment',
157
- }));
158
- const inputOptions = {
159
- input,
160
- plugins,
161
- };
162
- const outputOptions = {
163
- file: outputFile,
164
- format: 'es',
165
- sourcemap: mode === MODE.DEV,
166
- };
167
- return { inputOptions, outputOptions };
168
- }
169
- async function bundle(opts) {
170
- const { fileName, inputDir, outputDir, mode = MODE.DEV } = opts;
171
- const input = path__default["default"].join(inputDir, `${fileName}.ts`);
172
- try {
173
- await fs__default["default"].promises.access(input);
174
- }
175
- catch (e) {
176
- console.error(`${input} is not exist`);
177
- return;
178
- }
179
- const outputFile = path__default["default"].join(outputDir, `${fileName}.js`);
180
- const { inputOptions, outputOptions } = getRollupOptions(input, outputFile, mode);
181
- const build = await rollup.rollup(inputOptions);
182
- await build.write(outputOptions);
183
- }
184
-
185
- const bundleApp = async (opts) => {
186
- const { manifest, mode, outputDir, inputDir } = opts;
187
- const functionFiles = manifest.getFunctionFiles();
188
- const bundlePromise = functionFiles.map(async (fileName) => {
189
- await bundle({
190
- inputDir,
191
- fileName,
192
- outputDir,
193
- mode,
194
- });
195
- });
196
- await Promise.all(bundlePromise);
197
- };
198
-
199
- const execActionWithSpinner = async (message, action) => {
200
- const spinner = ora__default["default"](message.start).start();
201
- try {
202
- await action();
203
- }
204
- catch (e) {
205
- console.error(e.message);
206
- spinner.fail(message.error);
207
- throw e;
208
- }
209
- spinner.succeed(message.succeed);
210
- };
211
-
212
- const getManifest = async () => {
213
- const manifestFile = path__default["default"].resolve('manifest.yml');
214
- const strBuffer = await fse__default["default"].readFile(manifestFile);
215
- return new appsManifest.Manifest(strBuffer.toString());
216
- };
217
-
218
- var run$2 = async ({ outputDir, inputDir, prod, copyFiles, zip }) => {
219
- const manifest = await getManifest();
220
- const { version, key } = manifest.app;
221
- if (!key) {
222
- console.error('manifest app key is required');
223
- return;
224
- }
225
- if (!version) {
226
- console.error('manifest app version is required');
227
- return;
228
- }
229
- // clear output dir
230
- await fse__default["default"].emptyDir(outputDir);
231
- // bundle
232
- await execActionWithSpinner({
233
- start: 'start bundle',
234
- error: 'bundle failed',
235
- succeed: 'bundle success',
236
- }, () => bundleApp({ outputDir, inputDir, manifest, mode: prod ? MODE.PROD : MODE.DEV }));
237
- // package
238
- await execActionWithSpinner({
239
- start: 'start package',
240
- error: 'package failed',
241
- succeed: 'package success',
242
- }, () => packageApp({ outputDir, manifest, copyFiles }));
243
- if (zip) {
244
- const pkgName = `${key}_${version}.zip`;
245
- // archive
246
- await execActionWithSpinner({
247
- start: 'start archive',
248
- error: 'archive failed',
249
- succeed: 'archive success',
250
- }, () => archiveApp(outputDir, pkgName));
251
- }
252
- };
253
-
254
- const defaultCopyFiles = ['manifest.yml'];
255
- var build$1 = async (options) => {
256
- const { input = 'src', output = 'dist', prod, copy = [], zip } = options;
257
- await run$2({
258
- outputDir: path__default["default"].resolve(output),
259
- inputDir: path__default["default"].resolve(input),
260
- prod: !!prod,
261
- copyFiles: [...defaultCopyFiles, ...copy],
262
- zip: zip,
263
- });
264
- };
265
-
266
- const init$1 = async (projectPath) => {
267
- const git = simpleGit__default["default"](projectPath);
268
- await git.init();
269
- return;
270
- };
271
- const clone = async (repoUrl, projectPath) => {
272
- if (!(await fse__default["default"].pathExists(projectPath))) {
273
- await fse__default["default"].mkdir(projectPath);
274
- }
275
- const git = simpleGit__default["default"](projectPath);
276
- await git.clone(repoUrl, projectPath);
277
- return;
278
- };
279
-
280
- const templateURL = 'https://github.com/moriahq/apps-template.git';
281
- var TemplateType;
282
- (function (TemplateType) {
283
- TemplateType["micro"] = "micro";
284
- TemplateType["uikit"] = "uikit";
285
- })(TemplateType || (TemplateType = {}));
286
- // 重写替换文件内带模版的地方。格式为 {{field}}
287
- // options为字段变量
288
- const rewriteTemplateField = async (path, options) => {
289
- if (!(await fse__default["default"].pathExists(path))) {
290
- return;
291
- }
292
- const content = await fse__default["default"].readFile(path, { encoding: 'utf-8' });
293
- await fse__default["default"].writeFile(path, content.replace(/{{(\w+)}}/g, (match, key) => (typeof options[key] === 'string' ? options[key] : match)));
294
- };
295
-
296
- const toStartOfLine = (stream) => {
297
- if (!chalk.supportsColor) {
298
- stream.write('\r');
299
- return;
300
- }
301
- readline__default["default"].cursorTo(stream, 0);
302
- };
303
- const renderProgressBar = (curr, total) => {
304
- const ratio = Math.min(Math.max(curr / total, 0), 1);
305
- const bar = ` ${curr}/${total}`;
306
- const availableSpace = Math.max(0, process.stderr.columns - bar.length - 3);
307
- const width = Math.min(total, availableSpace);
308
- const completeLength = Math.round(width * ratio);
309
- const complete = `#`.repeat(completeLength);
310
- const incomplete = `-`.repeat(width - completeLength);
311
- toStartOfLine(process.stderr);
312
- process.stderr.write(`[${complete}${incomplete}]${bar}`);
313
- };
314
- const executeCommand = (command, args, cwd, env) => {
315
- return new Promise((resolve, reject) => {
316
- var _a;
317
- const child = execa__default["default"](command, args, {
318
- cwd,
319
- stdio: ['inherit', 'inherit', 'pipe'],
320
- env,
321
- });
322
- (_a = child.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (buffer) => {
323
- const str = buffer.toString();
324
- if (/warning/.test(str)) {
325
- return;
326
- }
327
- const progressBarMatch = str.match(/\[.*] (\d+)\/(\d+)/);
328
- if (progressBarMatch) {
329
- renderProgressBar(parseFloat(progressBarMatch[1]), parseFloat(progressBarMatch[2]));
330
- return;
331
- }
332
- process.stderr.write(buffer);
333
- });
334
- child.on('close', (code) => {
335
- if (code !== 0) {
336
- reject(new Error(`command failed: ${command} ${args.join(' ')}`));
337
- return;
338
- }
339
- resolve();
340
- });
341
- });
342
- };
343
- const command = {
344
- executeCommand,
345
- };
346
-
347
- // interface PromptResult {
348
- // [key: string]: string;
349
- // }
350
- // const selectTemplate = async (): Promise<TemplateType> => {
351
- // const prompt = inquirer.createPromptModule();
352
- // const result: PromptResult = await prompt({
353
- // type: 'list',
354
- // name: 'Please select template type',
355
- // choices: [TemplateType.micro],
356
- // });
357
- // return Object.values(result)[0] as TemplateType;
358
- // };
359
- const enterAppName = async () => {
360
- const prompt = inquirer__default["default"].createPromptModule();
361
- const result = await prompt({
362
- type: 'input',
363
- name: 'App Name',
364
- message: 'Please enter an app name',
365
- validate: (input) => {
366
- return !!input;
367
- },
368
- });
369
- return result['App Name'];
370
- };
371
- const enterAppKey = async () => {
372
- const prompt = inquirer__default["default"].createPromptModule();
373
- const result = await prompt({
374
- type: 'input',
375
- name: 'App key',
376
- message: 'Please enter a valid app key',
377
- validate: (input) => {
378
- if (!/^[a-z][a-z0-9_]*$/.test(input)) {
379
- // 需要一个空行来换行输出
380
- console.log('');
381
- console.log('only supports letters, numbers, underscores and starts with letters');
382
- return false;
383
- }
384
- return true;
385
- },
386
- });
387
- return result['App key'];
388
- };
389
- const cloneRepo = async (repoUrl, projectPath) => {
390
- await execActionWithSpinner({
391
- start: 'Start clone repository',
392
- error: 'Clone repository failed!',
393
- succeed: 'Clone repository success!',
394
- }, () => clone(repoUrl, projectPath));
395
- };
396
- const dependenciesInstall = async (projectPath) => {
397
- await execActionWithSpinner({
398
- start: 'Start install dependencies',
399
- error: 'Install dependencies failed!',
400
- succeed: 'Install dependencies success!',
401
- }, () => command.executeCommand('yarn', ['install'], projectPath));
402
- };
403
- var run$1 = async (options) => {
404
- const { cwd } = options;
405
- // 选择模板类型 micro or uikit
406
- // const templateType = await selectTemplate();
407
- // 暂时写死micro
408
- const templateType = 'micro';
409
- const appName = await enterAppName();
410
- const appKey = await enterAppKey();
411
- const projectPath = path__default["default"].join(cwd, appKey);
412
- if (await fse__default["default"].pathExists(projectPath)) {
413
- console.error(`Project path already exists: ${projectPath}`);
414
- return;
415
- }
416
- // 从远程仓库clone模板
417
- await cloneRepo(templateURL, projectPath);
418
- // 将指定模板复制到跟目录
419
- await fse__default["default"].copy(path__default["default"].join(projectPath, templateType), projectPath);
420
- // 删除各个模板文件夹
421
- await Promise.all(Object.values(TemplateType).map(t => fse__default["default"].remove(path__default["default"].join(projectPath, t))));
422
- // 删除源远程仓库的git
423
- await fse__default["default"].remove(path__default["default"].join(projectPath, './.git'));
424
- const files = [
425
- './manifest.yml',
426
- './package.json',
427
- './webpack.config.js',
428
- './public/index.html',
429
- './src/App.tsx',
430
- './src/index.tsx',
431
- ];
432
- // 模板替换
433
- await Promise.all(files.map(file => rewriteTemplateField(path__default["default"].join(projectPath, file), {
434
- appName,
435
- appKey,
436
- })));
437
- await dependenciesInstall(projectPath);
438
- await init$1(projectPath);
439
- console.log('Project init success!');
440
- console.log('Project path:' + projectPath);
441
- };
442
-
443
- var init = async () => {
444
- const cwd = process.cwd();
445
- await run$1({
446
- cwd,
447
- });
448
- };
449
-
450
- class DockerService {
451
- constructor(imageName) {
452
- this.imageName = imageName;
453
- }
454
- async downloadImage() {
455
- console.log(`Downloading image(${this.imageName}) ...`);
456
- await this.execPromise(`docker pull ${this.imageName}`);
457
- console.log(`Download image(${this.imageName}) success!`);
458
- }
459
- async runContainer({ port, env, name, volume = [] }) {
460
- // 先删掉容器
461
- await this.removeContainer(name);
462
- const envStr = Object.keys(env)
463
- .map(k => `-e ${k}=${env[k]}`)
464
- .join(' ');
465
- const volumeStr = volume === null || volume === void 0 ? void 0 : volume.map(v => `-v ${v}`).join(' ');
466
- const command = `docker run -d -p ${port}:${port} ${envStr} ${volumeStr} --name ${name} ${this.imageName}`;
467
- await this.execPromise(command);
468
- }
469
- async removeContainer(containerName) {
470
- await this.execPromise(`docker rm -f ${containerName}`).catch(() => { });
471
- }
472
- execPromise(cmd) {
473
- return new Promise((resolve, reject) => {
474
- child_process__default["default"].exec(cmd, (err, stdout, stderr) => {
475
- if (err) {
476
- return reject(err);
477
- }
478
- resolve({
479
- stdout: stdout,
480
- stderr: stderr,
481
- });
482
- });
483
- });
484
- }
485
- }
486
-
487
- const build = (functionFiles, inputDir, outputDir) => {
488
- for (const fileName of functionFiles) {
489
- bundle({
490
- inputDir,
491
- outputDir,
492
- fileName,
493
- mode: MODE.DEV,
494
- });
495
- }
496
- };
497
- const watchFiles = async (options) => {
498
- const { inputDir, outputDir } = options;
499
- const manifest = await getManifest();
500
- const functionFiles = manifest.getFunctionFiles();
501
- build(functionFiles, inputDir, outputDir);
502
- let timer;
503
- // 监听整个文件夹,有一个文件改动,则全部重新build
504
- // TODO 解析出文件之间的依赖关系,提升构建速度
505
- const watcher = chokidar__default["default"].watch(inputDir);
506
- console.log(`watch: ${inputDir}`);
507
- watcher.on('change', path => {
508
- clearTimeout(timer);
509
- timer = setTimeout(() => {
510
- console.log(`${path} has change`);
511
- build(functionFiles, inputDir, outputDir);
512
- }, 1000);
513
- });
514
- };
515
-
516
- var _a, _b;
517
- const image = {
518
- repository: 'docker-hub.gitee.work/gitee-prod/proxima-apps-runtime-server',
519
- tag: (_a = process.env.IMAGE_TAG) !== null && _a !== void 0 ? _a : 'latest',
520
- };
521
- const containerPort = Number((_b = process.env.CONTAINER_PORT) !== null && _b !== void 0 ? _b : 8455);
522
- const containerName = 'cli-dev-apps-runtime-server';
523
- const tempApp = '/app/production/1.0';
524
- const tempAppDir = `${tempApp}/server-side`;
525
- const containerEnv = {
526
- PORT: containerPort,
527
- APPS_DIR: '/usr/src/app/apps',
528
- LRU_TTL: 1,
529
- DEBUG: 'runtime*',
530
- PARSE_PUBLIC_SERVER_URL: process.env.PARSE_PUBLIC_SERVER_URL,
531
- PARSE_SERVER_MASTER_KEY: process.env.PARSE_SERVER_MASTER_KEY,
532
- PROXIMA_CORE_URL: process.env.PROXIMA_CORE_URL,
533
- PGSQL_CLIENT_HOST: process.env.PGSQL_CLIENT_HOST,
534
- PGSQL_CLIENT_PORT: process.env.PGSQL_CLIENT_PORT,
535
- PGSQL_CLIENT_USER: process.env.PGSQL_CLIENT_USER,
536
- PGSQL_CLIENT_PASSWORD: process.env.PGSQL_CLIENT_PASSWORD,
537
- };
538
- const copyManifest = async (appDir) => {
539
- const manifestFile = path__default["default"].resolve('manifest.yml');
540
- const targetFile = path__default["default"].join(appDir, 'manifest.yml');
541
- await fse__default["default"].copy(manifestFile, targetFile);
542
- };
543
- var run = async (options) => {
544
- const { inputDir, outputDir, server } = options;
545
- await fse__default["default"].emptyDir(outputDir);
546
- const imageName = `${image.repository}:${image.tag}`;
547
- const appDir = path__default["default"].join(outputDir, tempAppDir);
548
- const dockerService = new DockerService(imageName);
549
- if (server) {
550
- await dockerService.downloadImage();
551
- await dockerService.runContainer({
552
- port: containerPort,
553
- env: containerEnv,
554
- volume: [`${outputDir}:/usr/src/app/apps`],
555
- name: containerName,
556
- });
557
- }
558
- process.on('SIGINT', async () => {
559
- await dockerService.removeContainer(containerName);
560
- await fse__default["default"].remove(outputDir);
561
- process.exit();
562
- });
563
- await copyManifest(appDir);
564
- await watchFiles({ inputDir, outputDir: appDir });
565
- if (server) {
566
- console.log('You can use this url for test:');
567
- console.log(`POST http://localhost:${containerPort}/v1/apps${tempApp}/functions/:key`);
568
- }
569
- };
570
-
571
- var dev = async (options) => {
572
- const { input = 'src', output = 'cache', server = true } = options;
573
- await run({
574
- outputDir: path__default["default"].resolve(output),
575
- inputDir: path__default["default"].resolve(input),
576
- server,
577
- });
578
- };
579
-
580
- const program = new commander.Command();
581
- program.version(version).description('Giteeteam Apps Cli');
582
- program
583
- .command('build')
584
- .option('--prod', 'build in production')
585
- .option('--no-zip', 'no archive')
586
- .option('-c --copy [letters...]', 'copy files')
587
- .option('-i --input [dir]', 'input dir')
588
- .option('-o --output [dir]', 'output dir')
589
- .action(build$1);
590
- program.command('init').action(init);
591
- program
592
- .command('dev')
593
- .option('-i --input [dir]', 'input dir')
594
- .option('-o --output [dir]', 'output dir,default cache')
595
- .option('--no-server', 'no server')
596
- .action(dev);
597
- program.parse(process.argv);
2
+ "use strict";require("dotenv/config");var e=require("commander"),t=require("fs-extra"),a=require("path"),r=require("archiver"),o=require("rollup"),s=require("fs"),i=require("esbuild"),n=require("@rollup/plugin-node-resolve"),c=require("@rollup/plugin-commonjs"),u=require("ora"),l=require("@giteeteam/apps-manifest"),p=require("inquirer"),d=require("simple-git"),m=require("chalk"),f=require("readline"),w=require("execa"),v=require("child_process"),y=require("axios"),g=require("localtunnel"),h=require("lowdb"),E=require("lowdb/adapters/FileSync"),P=require("chokidar"),D=require("crypto"),S=require("base64url");function $(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var _=$(t),R=$(a),x=$(r),T=$(s),j=$(c),k=$(u),q=$(p),L=$(d),O=$(f),N=$(w),C=$(v),I=$(y),b=$(g),A=$(h),F=$(E),M=$(P),U=$(D),G=$(S),V="0.5.0-alpha.1";const z={treeShaking:!0,format:"esm",loader:"tsx"};var B;function Q(e,t,r=B.DEV){const o=[n.nodeResolve(),j.default()];var c;o.push((c={sourcemap:r===B.DEV,minify:r!==B.DEV,target:"es2018",jsx:"transform",jsxFactory:"AppsUI.createElement",jsxFragment:"AppsUI.Fragment"},c={...z,...c},{name:"esbuild",resolveId(e,t,r){if(!t||[".ts",".tsx",".js",".jsx",".mjs"].some((t=>e.endsWith(t))))return e;const o=a.dirname(t);let i;if(s.existsSync(i=a.resolve(o,e,"index.ts")))return i;if(s.existsSync(i=a.resolve(o,e,"index.tsx")))return i;if(s.existsSync(i=a.resolve(o,e+".ts")))return i;if(s.existsSync(i=a.resolve(o,e+".tsx")))return i;throw console.error({source:e,importer:t,options:r}),i=a.relative(".",a.resolve(t,e)),new Error(`ENOENT: ${i.replace(/\\/g,"/")}`)},async transform(e,t){c.sourcefile=t;const{code:a,map:r}=await i.transform(e,c);return r?{code:a,map:r}:a}}));return{inputOptions:{input:e,plugins:o},outputOptions:{file:t,format:"es",sourcemap:r===B.DEV}}}async function K(e){const{fileName:t,inputDir:a,outputDir:r,mode:s=B.DEV}=e,i=R.default.join(a,`${t}.ts`);try{await T.default.promises.access(i)}catch(e){return void console.error(`${i} is not exist`)}const n=R.default.join(r,`${t}.js`),{inputOptions:c,outputOptions:u}=Q(i,n,s),l=await o.rollup(c);await l.write(u)}!function(e){e.DEV="development",e.PROD="production"}(B||(B={}));const H=async(e,t)=>{const a=k.default(e.start).start();try{await t()}catch(t){throw console.error(t.message),a.fail(e.error),t}a.succeed(e.succeed)},W=async()=>{const e=R.default.resolve("manifest.yml"),t=await _.default.readFile(e);return new l.Manifest(t.toString())};var J=async({outputDir:e,inputDir:t,prod:a,copyFiles:r,zip:o})=>{const s=await W(),{version:i,key:n}=s.app;if(n)if(i){if(await _.default.emptyDir(e),await H({start:"start bundle",error:"bundle failed",succeed:"bundle success"},(()=>(async e=>{const{manifest:t,mode:a,outputDir:r,inputDir:o}=e,s=t.getFunctionFiles().map((async e=>{await K({inputDir:o,fileName:e,outputDir:r,mode:a})}));await Promise.all(s)})({outputDir:e,inputDir:t,manifest:s,mode:a?B.PROD:B.DEV}))),await H({start:"start package",error:"package failed",succeed:"package success"},(()=>(async({outputDir:e,manifest:t,copyFiles:a})=>{const{resources:r}=t;if(r)for(const{key:t,path:a}of r){const r=R.default.resolve(R.default.join("./",a)),o=R.default.join(e,t);await _.default.copy(r,o)}for(const t of a){const a=R.default.resolve(t),r=R.default.join(e,t);await _.default.copy(a,r)}})({outputDir:e,manifest:s,copyFiles:r}))),o){const t=`${n}_${i}.zip`;await H({start:"start archive",error:"archive failed",succeed:"archive success"},(()=>(async(e,t)=>{const a=R.default.resolve(t);return await _.default.remove(a),new Promise(((t,r)=>{const o=_.default.createWriteStream(a),s=x.default("zip",{zlib:{level:9}});o.on("close",(function(){t()})),s.on("warning",(function(e){console.log(e),"ENOENT"===e.code||r(e)})),s.on("error",(function(e){console.log(e),r(e)})),s.pipe(o),s.directory(e,!1),s.finalize()}))})(e,t)))}}else console.error("manifest app version is required");else console.error("manifest app key is required")};const Y=["manifest.yml"];var X;!function(e){e.micro="micro",e.uikit="uikit"}(X||(X={}));const Z=(e,t)=>{const a=Math.min(Math.max(e/t,0),1),r=` ${e}/${t}`,o=Math.max(0,process.stderr.columns-r.length-3),s=Math.min(t,o),i=Math.round(s*a),n="#".repeat(i),c="-".repeat(s-i);var u;u=process.stderr,m.supportsColor?O.default.cursorTo(u,0):u.write("\r"),process.stderr.write(`[${n}${c}]${r}`)},ee=(e,t,a,r)=>new Promise(((o,s)=>{var i;const n=N.default(e,t,{cwd:a,stdio:["inherit","inherit","pipe"],env:r});null===(i=n.stderr)||void 0===i||i.on("data",(e=>{const t=e.toString();if(/warning/.test(t))return;const a=t.match(/\[.*] (\d+)\/(\d+)/);a?Z(parseFloat(a[1]),parseFloat(a[2])):process.stderr.write(e)})),n.on("close",(a=>{0===a?o():s(new Error(`command failed: ${e} ${t.join(" ")}`))}))})),te=async(e,t)=>{await H({start:"Start clone repository",error:"Clone repository failed!",succeed:"Clone repository success!"},(()=>(async(e,t)=>{await _.default.pathExists(t)||await _.default.mkdir(t);const a=L.default(t);await a.clone(e,t)})(e,t)))};var ae=async e=>{const{cwd:t}=e,a=await(async()=>{const e=q.default.createPromptModule();return(await e({type:"input",name:"App Name",message:"Please enter an app name",validate:e=>!!e}))["App Name"]})(),r=await(async()=>{const e=q.default.createPromptModule();return(await e({type:"input",name:"App key",message:"Please enter a valid app key",validate:e=>!!/^[a-z][a-z0-9_]*$/.test(e)||(console.log(""),console.log("only supports letters, numbers, underscores and starts with letters"),!1)}))["App key"]})(),o=R.default.join(t,r);if(await _.default.pathExists(o))return void console.error(`Project path already exists: ${o}`);await te("https://github.com/moriahq/apps-template.git",o),await _.default.copy(R.default.join(o,"micro"),o),await Promise.all(Object.values(X).map((e=>_.default.remove(R.default.join(o,e))))),await _.default.remove(R.default.join(o,"./.git"));await Promise.all(["./manifest.yml","./package.json","./webpack.config.js","./public/index.html","./src/App.tsx","./src/index.tsx"].map((e=>(async(e,t)=>{if(!await _.default.pathExists(e))return;const a=await _.default.readFile(e,{encoding:"utf-8"});await _.default.writeFile(e,a.replace(/{{(\w+)}}/g,((e,a)=>"string"==typeof t[a]?t[a]:e)))})(R.default.join(o,e),{appName:a,appKey:r})))),await(async e=>{await H({start:"Start install dependencies",error:"Install dependencies failed!",succeed:"Install dependencies success!"},(()=>ee("yarn",["install"],e)))})(o),await(async e=>{const t=L.default(e);await t.init()})(o),console.log("Project init success!"),console.log("Project path:"+o)};class re{constructor(e){this.imageName=e}async downloadImage(){console.log(`Downloading image(${this.imageName}) ...`),await this.execPromise(`docker pull ${this.imageName}`),console.log(`Download image(${this.imageName}) success!`)}async runContainer({port:e,env:t,name:a,volume:r=[]}){await this.removeContainer(a);const o=`docker run -d -p ${e}:${e} ${Object.keys(t).map((e=>`-e ${e}=${t[e]}`)).join(" ")} ${null==r?void 0:r.map((e=>`-v ${e}`)).join(" ")} --name ${a} ${this.imageName}`;await this.execPromise(o)}async removeContainer(e){await this.execPromise(`docker rm -f ${e}`).catch((()=>{}))}execPromise(e){return new Promise(((t,a)=>{C.default.exec(e,((e,r,o)=>{if(e)return a(e);t({stdout:r,stderr:o})}))}))}}const oe=R.default.join(__dirname,"user.json"),se=new F.default(oe),ie=A.default(se);(()=>{const e=ie.get("version").value();e&&e===V||ie.defaults({version:V,user:{}}).write()})();const ne=e=>{ie.set("user",e).write()},ce=()=>ie.get("user").value(),ue=process.env.RESOURCES||"[]",le=(e,t,a)=>{for(const r of e)K({inputDir:t,outputDir:a,fileName:r,mode:B.DEV})};var pe;const de=process.env.RUNTIME_IMAGE||"docker-hub.gitee.work/gitee-prod/proxima-apps-runtime-server:latest",me=Number(null!==(pe=process.env.CONTAINER_PORT)&&void 0!==pe?pe:8455),fe="cli-dev-apps-runtime-server",we={PORT:me,APPS_DIR:"/usr/src/app/apps",LRU_TTL:1,DEBUG:"runtime*",FS_MODE:"local",PARSE_PUBLIC_SERVER_URL:process.env.PARSE_PUBLIC_SERVER_URL,PARSE_SERVER_MASTER_KEY:process.env.PARSE_SERVER_MASTER_KEY,PROXIMA_CORE_URL:process.env.PROXIMA_CORE_URL,PGSQL_CLIENT_HOST:process.env.PGSQL_CLIENT_HOST,PGSQL_CLIENT_PORT:process.env.PGSQL_CLIENT_PORT,PGSQL_CLIENT_USER:process.env.PGSQL_CLIENT_USER,PGSQL_CLIENT_PASSWORD:process.env.PGSQL_CLIENT_PASSWORD};var ve=async e=>{const{inputDir:t,outputDir:a,server:r}=e;await _.default.emptyDir(a);const o=await W(),s=o.app.key,i=o.app.version;if(!s)throw new Error("appKey is required!");if(!i)throw new Error("version is required!");const n=`/${s}/development/${i}`,c=`${n}/server-side`,u=R.default.join(a,c),l=new re(de);if(r&&(await l.downloadImage(),await l.runContainer({port:me,env:we,volume:[`${a}:/usr/src/app/apps`],name:fe})),process.on("SIGINT",(async()=>{await l.removeContainer(fe),await _.default.remove(a),await(async e=>{const{domain:t}=ce();await I.default({method:"DELETE",url:`${t}/apps/api/v1/apps/tunnel/${e}`}).catch((e=>{console.info("removeTunnel error",null==e?void 0:e.message)}))})(s),process.exit()})),await(async e=>{const t=R.default.resolve("manifest.yml"),a=R.default.join(e,"manifest.yml");await _.default.copy(t,a)})(u),await(async e=>{const{inputDir:t,outputDir:a}=e,r=(await W()).getFunctionFiles();let o;le(r,t,a);const s=M.default.watch(t);console.log(`watch: ${t}`),s.on("change",(e=>{clearTimeout(o),o=setTimeout((()=>{console.log(`${e} has change`),le(r,t,a)}),1e3)}))})({inputDir:t,outputDir:u}),r){const e=await(async(e,t)=>{try{const a=await b.default({port:e,subdomain:t.replace(/_/g,"-"),host:"http://tunnel.gitee.work:1777"});return console.info("tunnel url",a.url),a.url}catch(e){return console.info("runTunnel error",null==e?void 0:e.message),""}})(me,s);await(async(e,t)=>{const{domain:a}=ce();if(!a)throw new Error("Please login in first!");await I.default({method:"POST",url:`${a}/apps/api/v1/apps/tunnel/${e}`,data:{resources:JSON.parse(ue),runtimeHost:t}}).catch((e=>{console.info("addTunnel error",null==e?void 0:e.message)}))})(s,e),console.log("You can use this url for test:"),console.log(`POST http://localhost:${me}/v1/apps${n}/functions/:key`),console.log(`POST ${e}/v1/apps${n}/functions/:key`)}};const ye=Buffer.from("ABCDEFGHIJKLM_iv","utf-8"),ge=Buffer.from("ABCDEFGHIJKL_key","utf-8"),he=e=>{try{const t=U.default.createCipheriv("aes-128-cbc",ge,ye);let a=t.update(e,"utf8","base64");return a+=t.final("base64"),G.default.toBase64(a)}catch(e){return console.error(`Encryption error: ${e}`),null}};var Ee=async()=>{const e=await(async()=>{const e=q.default.createPromptModule();return(await e({type:"input",name:"Domain",message:"Please enter the domain address",validate:e=>!!e})).Domain})(),t=(e=>{const[,t]=e.split("//");return(e=>/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.test(e))(t)})(e);if(t)ne({domain:e,dev:t}),console.info("Login success!");else{const a=await(async()=>{const e=q.default.createPromptModule();return(await e({type:"input",name:"Username",message:"Please enter username",validate:e=>!!e})).Username})(),r=await(async()=>{const e=q.default.createPromptModule();return(await e({type:"password",name:"Password",message:"Please enter password",validate:e=>!!e})).Password})(),{cookie:o}=await(async({baseUrl:e,username:t,password:a})=>{var r;try{return{cookie:null===(r=(await I.default({method:"POST",url:`${e}/api/gateway/login`,data:{username:t,password:a}})).headers)||void 0===r?void 0:r["set-cookie"]}}catch(e){return console.error("Login error:",null==e?void 0:e.message),{cookie:""}}})({baseUrl:e,username:a,password:he(r)||r});o&&(ne({domain:e,username:a,cookie:o,dev:t}),console.info("Login success!"))}};const Pe=new e.Command;Pe.version(V).description("Giteeteam Apps Cli"),Pe.command("build").option("--prod","build in production").option("--no-zip","no archive").option("-c --copy [letters...]","copy files").option("-i --input [dir]","input dir").option("-o --output [dir]","output dir").action((async e=>{const{input:t="src",output:a="dist",prod:r,copy:o=[],zip:s}=e;await J({outputDir:R.default.resolve(a),inputDir:R.default.resolve(t),prod:!!r,copyFiles:[...Y,...o],zip:s})})),Pe.command("init").action((async()=>{const e=process.cwd();await ae({cwd:e})})),Pe.command("tunnel").option("-i --input [dir]","input dir").option("-o --output [dir]","output dir,default cache").option("--no-server","no server").action((async e=>{const{input:t="src",output:a="cache",server:r=!0}=e;await ve({outputDir:R.default.resolve(a),inputDir:R.default.resolve(t),server:r})})),Pe.command("login").option("-u --user [username]","login user").action((async()=>{await Ee()})),Pe.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@giteeteam/apps-cli",
3
- "version": "0.4.3",
3
+ "version": "0.5.0-alpha.1",
4
4
  "description": "Giteeteam Apps cli",
5
5
  "keywords": [
6
6
  "typescript",
@@ -38,10 +38,12 @@
38
38
  "registry": "https://registry.npmjs.org/"
39
39
  },
40
40
  "dependencies": {
41
- "@giteeteam/apps-manifest": "^0.3.0",
41
+ "@giteeteam/apps-manifest": "^0.4.1",
42
42
  "@rollup/plugin-commonjs": "^22.0.0",
43
43
  "@rollup/plugin-node-resolve": "13.3.0",
44
44
  "archiver": "^5.3.1",
45
+ "axios": "^1.4.0",
46
+ "base64url": "^3.0.1",
45
47
  "chalk": "^4.1.2",
46
48
  "chokidar": "^3.5.3",
47
49
  "commander": "^9.3.0",
@@ -50,18 +52,22 @@
50
52
  "execa": "^5.1.1",
51
53
  "fs-extra": "^10.1.0",
52
54
  "inquirer": "^8.2.4",
55
+ "localtunnel": "2.0.2",
56
+ "lowdb": "1.0.0",
53
57
  "ora": "^5.4.1",
54
58
  "rollup": "^2.79.0",
55
- "simple-git": "^3.7.1",
59
+ "simple-git": "^3.19.1",
56
60
  "yaml": "^2.1.1"
57
61
  },
58
62
  "devDependencies": {
59
- "typescript": "^4.8.3",
60
- "@rollup/plugin-json": "^6.0.0",
63
+ "@rollup/plugin-json": "^6.0.0",
64
+ "@rollup/plugin-terser": "^0.4.3",
61
65
  "@types/archiver": "^5.3.1",
62
66
  "@types/fs-extra": "^9.0.13",
63
67
  "@types/inquirer": "^8.2.1",
64
- "@types/uuid": "^8.3.4",
65
- "rollup-plugin-typescript2": "^0.31.2"
68
+ "@types/localtunnel": "2.0.1",
69
+ "@types/lowdb": "^1.0.11",
70
+ "rollup-plugin-typescript2": "^0.31.2",
71
+ "typescript": "^4.8.3"
66
72
  }
67
73
  }