zero-doc 1.0.12 → 1.0.14

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.
@@ -3,11 +3,13 @@ export interface AIAnalyzerOptions {
3
3
  apiUrl: string;
4
4
  projectRoot: string;
5
5
  filePatterns: string[];
6
+ token?: string;
6
7
  }
7
8
  export declare class AIAnalyzer {
8
9
  private apiUrl;
9
10
  private projectRoot;
10
11
  private filePatterns;
12
+ private token?;
11
13
  constructor(options: AIAnalyzerOptions);
12
14
  analyzeProject(): Promise<APIInventory>;
13
15
  private findProjectFiles;
@@ -42,6 +42,7 @@ class AIAnalyzer {
42
42
  this.apiUrl = options.apiUrl;
43
43
  this.projectRoot = options.projectRoot;
44
44
  this.filePatterns = options.filePatterns;
45
+ this.token = options.token;
45
46
  }
46
47
  async analyzeProject() {
47
48
  const files = await this.findProjectFiles();
@@ -151,11 +152,16 @@ class AIAnalyzer {
151
152
  throw new Error(`Invalid API URL: "${url}". URL must start with http:// or https://`);
152
153
  }
153
154
  try {
155
+ const headers = {
156
+ 'Content-Type': 'application/json',
157
+ };
158
+ // Add authorization token if available
159
+ if (this.token) {
160
+ headers['Authorization'] = `Bearer ${this.token}`;
161
+ }
154
162
  const response = await fetch(url, {
155
163
  method: 'POST',
156
- headers: {
157
- 'Content-Type': 'application/json',
158
- },
164
+ headers,
159
165
  body: JSON.stringify({ prompt }),
160
166
  });
161
167
  if (!response.ok) {
package/dist/cli.js CHANGED
@@ -74,6 +74,20 @@ function getBaseUrl() {
74
74
  return config.baseUrl;
75
75
  }
76
76
  }
77
+ return 'https://zero-doc.com';
78
+ }
79
+ function getToken() {
80
+ try {
81
+ const tokenFile = path.join(os.homedir(), '.zero-doc', 'token.json');
82
+ if (fs.existsSync(tokenFile)) {
83
+ const tokenData = JSON.parse(fs.readFileSync(tokenFile, 'utf-8'));
84
+ return tokenData.token;
85
+ }
86
+ }
87
+ catch (error) {
88
+ // Token file doesn't exist or is invalid
89
+ }
90
+ return undefined;
77
91
  }
78
92
  function displayPlansLink() {
79
93
  const reset = '\x1b[0m';
@@ -116,91 +130,7 @@ commander_1.program
116
130
  }
117
131
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
118
132
  console.log('✅ Created zero-doc.config.json');
119
- console.log('💡 Run: zero-doc generate');
120
- });
121
- commander_1.program
122
- .command('generate')
123
- .description('Generate API inventory from project using AI')
124
- .option('-i, --input <pattern>', 'Source files glob pattern', 'src/**/*.{ts,js,py,java,go,rs,php,rb}')
125
- .option('-o, --output <path>', 'Output file path', 'api-inventory.json')
126
- .option('-n, --name <name>', 'Project name')
127
- .option('--ai-provider <provider>', 'AI provider: gemini', 'gemini')
128
- .action(async (options) => {
129
- console.log('🤖 Analyzing project with AI...\n');
130
- const configPath = path.join(process.cwd(), 'zero-doc.config.json');
131
- let config = {};
132
- if (fs.existsSync(configPath)) {
133
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
134
- }
135
- try {
136
- let generateApiUrl;
137
- const generateConfigPath = path.join(__dirname, 'config.json');
138
- if (fs.existsSync(generateConfigPath)) {
139
- try {
140
- const generateConfig = JSON.parse(fs.readFileSync(generateConfigPath, 'utf-8'));
141
- generateApiUrl = generateConfig.apiUrl;
142
- }
143
- catch (error) {
144
- }
145
- }
146
- if (!generateApiUrl || generateApiUrl.trim() === '') {
147
- console.error('❌ Error: API configuration not found');
148
- console.error('💡 This should not happen. The package should include the configuration.');
149
- console.error('💡 Please reinstall: npm install -g zero-doc');
150
- process.exit(1);
151
- }
152
- let projectName = options.name || config.name;
153
- let projectVersion;
154
- let projectDescription;
155
- const packageJsonPath = path.join(process.cwd(), 'package.json');
156
- if (fs.existsSync(packageJsonPath)) {
157
- try {
158
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
159
- projectName = projectName || packageJson.name;
160
- projectVersion = packageJson.version;
161
- projectDescription = packageJson.description;
162
- }
163
- catch (error) {
164
- }
165
- }
166
- const inputPattern = options.input || config.input || 'src/**/*.{ts,js}';
167
- const patterns = inputPattern.includes('{') && inputPattern.includes('}')
168
- ? [inputPattern]
169
- : inputPattern.split(',').map(p => p.trim());
170
- console.log(`📋 Using patterns: ${patterns.join(', ')}\n`);
171
- const analyzer = new ai_analyzer_1.AIAnalyzer({
172
- apiUrl: generateApiUrl,
173
- projectRoot: process.cwd(),
174
- filePatterns: patterns,
175
- });
176
- const inventory = await analyzer.analyzeProject();
177
- inventory.project.name = inventory.project.name || projectName;
178
- inventory.project.version = inventory.project.version || projectVersion;
179
- inventory.project.description = inventory.project.description || projectDescription;
180
- if (!inventory.baseUrl) {
181
- inventory.baseUrl = 'https://api.example.com';
182
- }
183
- const outputPath = options.output || config.output || 'api-inventory.json';
184
- const json = JSON.stringify(inventory, null, 2);
185
- const dir = path.dirname(outputPath);
186
- if (!fs.existsSync(dir)) {
187
- fs.mkdirSync(dir, { recursive: true });
188
- }
189
- fs.writeFileSync(outputPath, json, 'utf-8');
190
- console.log('✅ Analysis complete!\n');
191
- console.log(`📊 Statistics:`);
192
- console.log(` Total endpoints: ${inventory.stats.totalEndpoints}`);
193
- console.log(` Framework: ${inventory.project.framework}`);
194
- console.log('');
195
- Object.entries(inventory.stats.byMethod).forEach(([method, count]) => {
196
- console.log(` ${method}: ${count}`);
197
- });
198
- console.log(`\n💾 File generated: ${outputPath}`);
199
- }
200
- catch (error) {
201
- console.error('❌ Error:', error instanceof Error ? error.message : error);
202
- process.exit(1);
203
- }
133
+ console.log('💡 Run: zero-doc preview');
204
134
  });
205
135
  commander_1.program
206
136
  .command('preview')
@@ -303,10 +233,12 @@ commander_1.program
303
233
  const patterns = inputPattern.includes('{') && inputPattern.includes('}')
304
234
  ? [inputPattern]
305
235
  : inputPattern.split(',').map(p => p.trim());
236
+ const token = getToken();
306
237
  const analyzer = new ai_analyzer_1.AIAnalyzer({
307
238
  apiUrl: apiUrl,
308
239
  projectRoot: process.cwd(),
309
240
  filePatterns: patterns,
241
+ token: token,
310
242
  });
311
243
  updateProgress(20, 100, 'Analyzing project');
312
244
  const inventory = await analyzer.analyzeProject();
@@ -529,15 +461,26 @@ commander_1.program
529
461
  timeout = null;
530
462
  }
531
463
  if (server) {
532
- server.close();
464
+ server.close(() => {
465
+ // Server closed
466
+ });
533
467
  server = null;
534
468
  }
535
469
  };
470
+ const finish = () => {
471
+ cleanup();
472
+ resolve();
473
+ // Exit after resolving promise
474
+ setTimeout(() => {
475
+ process.exit(0);
476
+ }, 100);
477
+ };
536
478
  // 5 minute timeout
537
479
  timeout = setTimeout(() => {
538
- cleanup();
539
480
  console.error('❌ Timeout: Login was not completed within 5 minutes');
540
- process.exit(1);
481
+ cleanup();
482
+ resolve();
483
+ setTimeout(() => process.exit(1), 100);
541
484
  }, 5 * 60 * 1000);
542
485
  server = http.createServer((req, res) => {
543
486
  if (req.url?.startsWith('/callback')) {
@@ -564,9 +507,10 @@ commander_1.program
564
507
  </body>
565
508
  </html>
566
509
  `);
567
- cleanup();
568
510
  console.error(`❌ Error: ${error}`);
569
- process.exit(1);
511
+ cleanup();
512
+ resolve();
513
+ setTimeout(() => process.exit(1), 100);
570
514
  return;
571
515
  }
572
516
  if (token) {
@@ -583,63 +527,121 @@ commander_1.program
583
527
  <head>
584
528
  <title>Login Successful</title>
585
529
  <style>
586
- body {
587
- font-family: Arial, sans-serif;
588
- text-align: center;
589
- padding: 50px;
590
- background: #f9fafb;
530
+ * {
531
+ margin: 0;
532
+ padding: 0;
533
+ box-sizing: border-box;
534
+ }
535
+
536
+ body {
537
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
538
+ min-height: 100vh;
539
+ display: flex;
540
+ align-items: center;
541
+ justify-content: center;
542
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
543
+ padding: 20px;
591
544
  }
545
+
592
546
  .container {
593
547
  background: white;
594
- border-radius: 8px;
595
- padding: 40px;
596
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
597
- max-width: 400px;
598
- margin: 0 auto;
548
+ border-radius: 16px;
549
+ padding: 48px 40px;
550
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
551
+ max-width: 420px;
552
+ width: 100%;
553
+ text-align: center;
554
+ animation: slideIn 0.3s ease-out;
555
+ }
556
+
557
+ @keyframes slideIn {
558
+ from {
559
+ opacity: 0;
560
+ transform: translateY(-20px);
561
+ }
562
+ to {
563
+ opacity: 1;
564
+ transform: translateY(0);
565
+ }
566
+ }
567
+
568
+ .icon {
569
+ width: 80px;
570
+ height: 80px;
571
+ margin: 0 auto 24px;
572
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
573
+ border-radius: 50%;
574
+ display: flex;
575
+ align-items: center;
576
+ justify-content: center;
577
+ font-size: 48px;
578
+ animation: scaleIn 0.4s ease-out 0.1s both;
579
+ }
580
+
581
+ @keyframes scaleIn {
582
+ from {
583
+ transform: scale(0);
584
+ }
585
+ to {
586
+ transform: scale(1);
587
+ }
588
+ }
589
+
590
+ h1 {
591
+ font-size: 28px;
592
+ font-weight: 700;
593
+ color: #1f2937;
594
+ margin-bottom: 12px;
595
+ }
596
+
597
+ .subtitle {
598
+ font-size: 16px;
599
+ color: #6b7280;
600
+ margin-bottom: 32px;
601
+ line-height: 1.5;
602
+ }
603
+
604
+ .message {
605
+ font-size: 14px;
606
+ color: #9ca3af;
607
+ margin-top: 24px;
608
+ padding-top: 24px;
609
+ border-top: 1px solid #e5e7eb;
599
610
  }
600
- .success { color: #16a34a; }
601
- .icon { font-size: 48px; margin-bottom: 20px; }
602
611
  </style>
603
612
  <script>
604
- // Try to close window immediately, if that fails, try after a delay
605
- function tryClose() {
613
+ // Close window after 5 seconds
614
+ setTimeout(function() {
606
615
  try {
607
616
  window.close();
608
- // If we're still here after 100ms, the close was blocked
617
+ } catch (e) {
618
+ // If close fails, try again
609
619
  setTimeout(function() {
610
- // Try again - some browsers allow close after user interaction
611
620
  window.close();
612
621
  }, 100);
613
- } catch (e) {
614
- // Ignore errors
615
622
  }
616
- }
623
+ }, 5000);
617
624
 
618
- // Try to close after page loads
619
- window.addEventListener('load', function() {
620
- setTimeout(tryClose, 500);
625
+ // Also allow manual close on click
626
+ document.addEventListener('click', function() {
627
+ try {
628
+ window.close();
629
+ } catch (e) {}
621
630
  });
622
-
623
- // Also try on user interaction (some browsers require this)
624
- document.addEventListener('click', tryClose);
625
- document.addEventListener('keydown', tryClose);
626
631
  </script>
627
632
  </head>
628
633
  <body>
629
634
  <div class="container">
630
- <div class="icon">✅</div>
631
- <h1 class="success">Login Successful!</h1>
632
- <p>Token saved successfully.</p>
633
- <p style="font-size: 14px; color: #6b7280; margin-top: 20px;">
634
- You can close this window and return to your terminal.
635
- </p>
635
+ <div class="icon">✓</div>
636
+ <h1>Login Successful!</h1>
637
+ <p class="subtitle">Your token has been saved successfully.</p>
638
+ <p class="message">This window will close automatically in a few seconds...</p>
636
639
  </div>
637
640
  </body>
638
641
  </html>
639
642
  `);
640
- cleanup();
641
643
  console.log('✅ Login successful!');
642
- resolve();
644
+ finish();
643
645
  }
644
646
  else {
645
647
  res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zero-doc",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "Zero-Config API Documentation Generator - Generate beautiful API docs from your code automatically",
5
5
  "main": "dist/index.js",
6
6
  "bin": {