zero-doc 1.0.9 → 1.0.10
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/dist/cli.js +198 -4
- package/dist/config.json +2 -1
- package/package.json +1 -1
- package/scripts/inject-config.js +6 -2
package/dist/cli.js
CHANGED
|
@@ -39,8 +39,11 @@ const ai_analyzer_1 = require("./ai-analyzer");
|
|
|
39
39
|
const fs = __importStar(require("fs"));
|
|
40
40
|
const path = __importStar(require("path"));
|
|
41
41
|
const child_process_1 = require("child_process");
|
|
42
|
+
const os = __importStar(require("os"));
|
|
42
43
|
const tmp = __importStar(require("tmp"));
|
|
43
44
|
const fse = __importStar(require("fs-extra"));
|
|
45
|
+
const http = __importStar(require("http"));
|
|
46
|
+
const url_1 = require("url");
|
|
44
47
|
function updateProgress(current, total, label = '') {
|
|
45
48
|
const percentage = Math.min(100, Math.round((current / total) * 100));
|
|
46
49
|
const barLength = 30;
|
|
@@ -63,13 +66,32 @@ function displayUrl(url) {
|
|
|
63
66
|
const underline = '\x1b[4m';
|
|
64
67
|
process.stdout.write(`${red}➜${reset} ${bold}Local:${reset} ${blue}${underline}${url}${reset}\n`);
|
|
65
68
|
}
|
|
69
|
+
function getBaseUrl() {
|
|
70
|
+
const configPath = path.join(__dirname, 'config.json');
|
|
71
|
+
if (fs.existsSync(configPath)) {
|
|
72
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
73
|
+
if (config.baseUrl) {
|
|
74
|
+
return config.baseUrl;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
66
78
|
function displayPlansLink() {
|
|
67
79
|
const reset = '\x1b[0m';
|
|
68
80
|
const red = '\x1b[31m';
|
|
69
81
|
const blue = '\x1b[34m';
|
|
70
82
|
const bold = '\x1b[1m';
|
|
71
83
|
const underline = '\x1b[4m';
|
|
72
|
-
|
|
84
|
+
const baseUrl = getBaseUrl();
|
|
85
|
+
process.stdout.write(`${red}➜${reset} ${bold}Access plans:${reset} ${blue}${underline}${baseUrl}/plans${reset}\n`);
|
|
86
|
+
}
|
|
87
|
+
function displayLoginLink() {
|
|
88
|
+
const reset = '\x1b[0m';
|
|
89
|
+
const red = '\x1b[31m';
|
|
90
|
+
const blue = '\x1b[34m';
|
|
91
|
+
const bold = '\x1b[1m';
|
|
92
|
+
const underline = '\x1b[4m';
|
|
93
|
+
const baseUrl = getBaseUrl();
|
|
94
|
+
process.stdout.write(`${red}➜${reset} ${bold}Login:${reset} ${blue}${underline}${baseUrl}/login${reset}\n`);
|
|
73
95
|
}
|
|
74
96
|
commander_1.program
|
|
75
97
|
.name('zero-doc')
|
|
@@ -448,8 +470,8 @@ commander_1.program
|
|
|
448
470
|
clearProgress();
|
|
449
471
|
process.stdout.write('\n');
|
|
450
472
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
451
|
-
// Check if it's a 403 error
|
|
452
|
-
if (errorMessage.includes('403')) {
|
|
473
|
+
// Check if it's a 401 or 403 error
|
|
474
|
+
if (errorMessage.includes('401') || errorMessage.includes('403')) {
|
|
453
475
|
// Extract the actual error message from the API response
|
|
454
476
|
let apiErrorMessage = errorMessage;
|
|
455
477
|
try {
|
|
@@ -467,7 +489,15 @@ commander_1.program
|
|
|
467
489
|
// If parsing fails, use the original message
|
|
468
490
|
}
|
|
469
491
|
console.error('❌ Error:', apiErrorMessage);
|
|
470
|
-
|
|
492
|
+
if (errorMessage.includes('401')) {
|
|
493
|
+
// For 401, show only login
|
|
494
|
+
displayLoginLink();
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
// For 403, show plans and login
|
|
498
|
+
displayPlansLink();
|
|
499
|
+
displayLoginLink();
|
|
500
|
+
}
|
|
471
501
|
// Don't exit - keep the session open
|
|
472
502
|
}
|
|
473
503
|
else {
|
|
@@ -476,6 +506,170 @@ commander_1.program
|
|
|
476
506
|
}
|
|
477
507
|
}
|
|
478
508
|
});
|
|
509
|
+
commander_1.program
|
|
510
|
+
.command('login')
|
|
511
|
+
.description('Login to zero-doc and save authentication token')
|
|
512
|
+
.action(async () => {
|
|
513
|
+
const CALLBACK_PORT = 7778;
|
|
514
|
+
const CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
515
|
+
const baseUrl = getBaseUrl();
|
|
516
|
+
const LOGIN_URL = `${baseUrl}/login?callback=${encodeURIComponent(CALLBACK_URL)}`;
|
|
517
|
+
const TOKEN_FILE = path.join(os.homedir(), '.zero-doc', 'token.json');
|
|
518
|
+
console.log('🔐 Starting login process...\n');
|
|
519
|
+
// Create directory if it doesn't exist
|
|
520
|
+
const tokenDir = path.dirname(TOKEN_FILE);
|
|
521
|
+
if (!fs.existsSync(tokenDir)) {
|
|
522
|
+
fs.mkdirSync(tokenDir, { recursive: true });
|
|
523
|
+
}
|
|
524
|
+
return new Promise((resolve, reject) => {
|
|
525
|
+
let server = null;
|
|
526
|
+
let timeout = null;
|
|
527
|
+
const cleanup = () => {
|
|
528
|
+
if (timeout) {
|
|
529
|
+
clearTimeout(timeout);
|
|
530
|
+
timeout = null;
|
|
531
|
+
}
|
|
532
|
+
if (server) {
|
|
533
|
+
server.close();
|
|
534
|
+
server = null;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
// 5 minute timeout
|
|
538
|
+
timeout = setTimeout(() => {
|
|
539
|
+
cleanup();
|
|
540
|
+
console.error('\n❌ Timeout: Login was not completed within 5 minutes');
|
|
541
|
+
process.exit(1);
|
|
542
|
+
}, 5 * 60 * 1000);
|
|
543
|
+
server = http.createServer((req, res) => {
|
|
544
|
+
if (req.url?.startsWith('/callback')) {
|
|
545
|
+
try {
|
|
546
|
+
const url = new url_1.URL(req.url, `http://localhost:${CALLBACK_PORT}`);
|
|
547
|
+
const token = url.searchParams.get('token');
|
|
548
|
+
const error = url.searchParams.get('error');
|
|
549
|
+
if (error) {
|
|
550
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
551
|
+
res.end(`
|
|
552
|
+
<!DOCTYPE html>
|
|
553
|
+
<html>
|
|
554
|
+
<head>
|
|
555
|
+
<title>Login Error</title>
|
|
556
|
+
<style>
|
|
557
|
+
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
|
|
558
|
+
.error { color: #dc2626; }
|
|
559
|
+
</style>
|
|
560
|
+
</head>
|
|
561
|
+
<body>
|
|
562
|
+
<h1 class="error">Login Error</h1>
|
|
563
|
+
<p>${error}</p>
|
|
564
|
+
<p>You can close this window.</p>
|
|
565
|
+
</body>
|
|
566
|
+
</html>
|
|
567
|
+
`);
|
|
568
|
+
cleanup();
|
|
569
|
+
console.error(`\n❌ Error: ${error}`);
|
|
570
|
+
process.exit(1);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (token) {
|
|
574
|
+
// Save token
|
|
575
|
+
const tokenData = {
|
|
576
|
+
token: token,
|
|
577
|
+
savedAt: new Date().toISOString()
|
|
578
|
+
};
|
|
579
|
+
fs.writeFileSync(TOKEN_FILE, JSON.stringify(tokenData, null, 2), 'utf-8');
|
|
580
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
581
|
+
res.end(`
|
|
582
|
+
<!DOCTYPE html>
|
|
583
|
+
<html>
|
|
584
|
+
<head>
|
|
585
|
+
<title>Login Successful</title>
|
|
586
|
+
<style>
|
|
587
|
+
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
|
|
588
|
+
.success { color: #16a34a; }
|
|
589
|
+
</style>
|
|
590
|
+
</head>
|
|
591
|
+
<body>
|
|
592
|
+
<h1 class="success">✅ Login Successful!</h1>
|
|
593
|
+
<p>Token saved successfully.</p>
|
|
594
|
+
<p>You can close this window and return to the terminal.</p>
|
|
595
|
+
</body>
|
|
596
|
+
</html>
|
|
597
|
+
`);
|
|
598
|
+
cleanup();
|
|
599
|
+
console.log('\n✅ Login successful!');
|
|
600
|
+
console.log(`💾 Token saved to: ${TOKEN_FILE}`);
|
|
601
|
+
resolve();
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
605
|
+
res.end(`
|
|
606
|
+
<!DOCTYPE html>
|
|
607
|
+
<html>
|
|
608
|
+
<head>
|
|
609
|
+
<title>Error</title>
|
|
610
|
+
<style>
|
|
611
|
+
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
|
|
612
|
+
.error { color: #dc2626; }
|
|
613
|
+
</style>
|
|
614
|
+
</head>
|
|
615
|
+
<body>
|
|
616
|
+
<h1 class="error">Token not received</h1>
|
|
617
|
+
<p>You can close this window and try again.</p>
|
|
618
|
+
</body>
|
|
619
|
+
</html>
|
|
620
|
+
`);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
catch (error) {
|
|
624
|
+
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
625
|
+
res.end('Internal Server Error');
|
|
626
|
+
cleanup();
|
|
627
|
+
reject(error);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
632
|
+
res.end('Not Found');
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
server.listen(CALLBACK_PORT, () => {
|
|
636
|
+
console.log(`📡 Callback server started at http://localhost:${CALLBACK_PORT}`);
|
|
637
|
+
console.log(`🌐 Opening browser...\n`);
|
|
638
|
+
// Open browser
|
|
639
|
+
let openCommand;
|
|
640
|
+
if (process.platform === 'win32') {
|
|
641
|
+
openCommand = 'start';
|
|
642
|
+
}
|
|
643
|
+
else if (process.platform === 'darwin') {
|
|
644
|
+
openCommand = 'open';
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
openCommand = 'xdg-open';
|
|
648
|
+
}
|
|
649
|
+
(0, child_process_1.spawn)(openCommand, [LOGIN_URL], { shell: true, stdio: 'ignore' });
|
|
650
|
+
console.log('⏳ Waiting for authentication in browser...');
|
|
651
|
+
console.log('💡 If the browser does not open automatically, visit:');
|
|
652
|
+
console.log(` ${LOGIN_URL}\n`);
|
|
653
|
+
});
|
|
654
|
+
server.on('error', (error) => {
|
|
655
|
+
if (error.code === 'EADDRINUSE') {
|
|
656
|
+
console.error(`❌ Error: Port ${CALLBACK_PORT} is already in use`);
|
|
657
|
+
console.error('💡 Close other processes using this port or wait a few seconds');
|
|
658
|
+
}
|
|
659
|
+
else {
|
|
660
|
+
console.error('❌ Error starting server:', error.message);
|
|
661
|
+
}
|
|
662
|
+
cleanup();
|
|
663
|
+
process.exit(1);
|
|
664
|
+
});
|
|
665
|
+
// Cleanup on exit
|
|
666
|
+
process.on('SIGINT', () => {
|
|
667
|
+
cleanup();
|
|
668
|
+
console.log('\n❌ Login cancelled');
|
|
669
|
+
process.exit(0);
|
|
670
|
+
});
|
|
671
|
+
});
|
|
672
|
+
});
|
|
479
673
|
commander_1.program
|
|
480
674
|
.command('deploy')
|
|
481
675
|
.description('Deploy documentation to zero-doc cloud')
|
package/dist/config.json
CHANGED
package/package.json
CHANGED
package/scripts/inject-config.js
CHANGED
|
@@ -24,15 +24,17 @@ if (fs.existsSync(envPath)) {
|
|
|
24
24
|
// Get API URL from environment variables
|
|
25
25
|
// Priority: Environment variable (CI/CD) > .env file
|
|
26
26
|
const apiUrl = process.env.ZERO_DOC_API_URL;
|
|
27
|
+
const baseUrl = process.env.ZERO_DOC_URL;
|
|
27
28
|
|
|
28
29
|
// Ensure dist directory exists
|
|
29
30
|
if (!fs.existsSync(distDir)) {
|
|
30
31
|
fs.mkdirSync(distDir, { recursive: true });
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
// Create config file with API URL
|
|
34
|
+
// Create config file with API URL and base URL
|
|
34
35
|
const config = {
|
|
35
|
-
apiUrl: apiUrl || ''
|
|
36
|
+
apiUrl: apiUrl || '',
|
|
37
|
+
baseUrl: baseUrl
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
@@ -44,3 +46,5 @@ if (apiUrl) {
|
|
|
44
46
|
console.warn(' Set ZERO_DOC_API_URL in .env or CI/CD environment variables.');
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
console.log(`✅ Base URL set to: ${baseUrl}`);
|
|
50
|
+
|