apiforge-analyzer 1.1.0

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.
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ /**
3
+ * Next.js App Router analyzer
4
+ * Analyzes route handlers in app directory
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.analyzeNextApp = analyzeNextApp;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const export_js_1 = require("../export.js");
44
+ const uploader_js_1 = require("../uploader.js");
45
+ /**
46
+ * Analyze Next.js App Router routes
47
+ */
48
+ async function analyzeNextApp(options = 'app') {
49
+ // Support both string path and options object
50
+ const appDir = typeof options === 'string' ? options : (options.appDir || 'app');
51
+ const opts = typeof options === 'string' ? { projectName: '' } : options;
52
+ const routes = [];
53
+ try {
54
+ const baseDir = path.join(process.cwd(), appDir);
55
+ if (!fs.existsSync(baseDir)) {
56
+ console.warn('app directory not found');
57
+ return routes;
58
+ }
59
+ // Recursively scan for route.ts/route.js files
60
+ const scanDir = (dir, basePath = '') => {
61
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
62
+ for (const entry of entries) {
63
+ const fullPath = path.join(dir, entry.name);
64
+ if (entry.isDirectory()) {
65
+ // Handle dynamic routes like [id]
66
+ const dirName = entry.name.startsWith('[') && entry.name.endsWith(']')
67
+ ? `:${entry.name.slice(1, -1)}`
68
+ : entry.name;
69
+ // Skip non-route directories
70
+ if (['_components', '_lib', '_utils'].includes(entry.name)) {
71
+ continue;
72
+ }
73
+ scanDir(fullPath, `${basePath}/${dirName}`);
74
+ }
75
+ else if (entry.isFile() && /route\.(ts|js)$/.test(entry.name)) {
76
+ // Found a route file
77
+ const content = fs.readFileSync(fullPath, 'utf-8');
78
+ const methods = detectAppRouterMethods(content);
79
+ methods.forEach(method => {
80
+ const pathString = basePath || '/';
81
+ const operationId = `${method.toLowerCase()}_${pathString.replace(/[^a-zA-Z0-9]/g, '_').replace(/_+/g, '_').replace(/^_|_$/g, '')}`;
82
+ const tags = pathString.startsWith('/api') ? ['api'] : ['app'];
83
+ const middleware = detectMiddleware(content);
84
+ const authRequired = middleware.includes('auth');
85
+ const pathParams = extractParameters(pathString).map(p => p.name);
86
+ // Basic static extraction
87
+ const queryParams = [];
88
+ const queryHits = [...content.matchAll(/searchParams\.get\(['"]([^'"]+)['"]\)/g)];
89
+ queryHits.forEach(m => queryParams.push(m[1]));
90
+ const requestBodyFields = [];
91
+ const bodyDestruct = content.match(/const\s+\{([^}]+)\}\s*=\s*await\s+req\.json\(\)/);
92
+ if (bodyDestruct) {
93
+ bodyDestruct[1].split(',').map(s => s.trim().split(':')[0]).filter(Boolean).forEach(m => requestBodyFields.push(m));
94
+ }
95
+ routes.push({
96
+ method,
97
+ path: pathString,
98
+ tag: tags[0] || 'General',
99
+ operationId,
100
+ summary: `${method} ${pathString}`,
101
+ middleware,
102
+ authRequired,
103
+ pathParams: Array.from(new Set(pathParams)),
104
+ queryParams: Array.from(new Set(queryParams)),
105
+ requestBodyFields: Array.from(new Set(requestBodyFields)),
106
+ linkedPaths: [],
107
+ hasAuth: authRequired,
108
+ framework: 'nextjs-app'
109
+ });
110
+ });
111
+ }
112
+ }
113
+ };
114
+ scanDir(baseDir);
115
+ console.log(`✅ Found ${routes.length} routes`);
116
+ // Export to JSON if requested
117
+ if (opts.saveJson && opts.projectName) {
118
+ const filePath = opts.jsonPath || 'api-export.json';
119
+ await (0, export_js_1.exportToJSON)(routes, opts.projectName, filePath, opts.baseUrl);
120
+ }
121
+ // Upload to APIForge if requested
122
+ if (opts.upload && opts.apiKey && opts.projectName) {
123
+ await (0, uploader_js_1.uploadRoutes)(routes, {
124
+ projectName: opts.projectName,
125
+ apiKey: opts.apiKey,
126
+ baseUrl: opts.baseUrl,
127
+ apiForgeUrl: opts.apiForgeUrl
128
+ });
129
+ }
130
+ }
131
+ catch (error) {
132
+ console.error('Error analyzing Next.js App routes:', error.message);
133
+ }
134
+ return routes;
135
+ }
136
+ /**
137
+ * Detect exported HTTP method handlers
138
+ */
139
+ function detectAppRouterMethods(content) {
140
+ const methods = [];
141
+ const httpMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];
142
+ httpMethods.forEach(method => {
143
+ // Check for export async function METHOD or export function METHOD
144
+ const regex = new RegExp(`export\\s+(async\\s+)?function\\s+${method}\\s*\\(`, 'g');
145
+ if (regex.test(content)) {
146
+ methods.push(method);
147
+ }
148
+ });
149
+ return methods;
150
+ }
151
+ /**
152
+ * Detect middleware usage
153
+ */
154
+ function detectMiddleware(content) {
155
+ const middleware = [];
156
+ if (content.includes('auth') || content.includes('authenticate')) {
157
+ middleware.push('auth');
158
+ }
159
+ if (content.includes('cors')) {
160
+ middleware.push('cors');
161
+ }
162
+ return middleware;
163
+ }
164
+ /**
165
+ * Extract parameters from route path
166
+ */
167
+ function extractParameters(routePath) {
168
+ const params = [];
169
+ const paramMatches = routePath.match(/:(\w+)/g) || [];
170
+ paramMatches.forEach(param => {
171
+ const name = param.slice(1);
172
+ params.push({
173
+ name,
174
+ in: 'path',
175
+ required: true,
176
+ type: 'string',
177
+ description: `Path parameter: ${name}`
178
+ });
179
+ });
180
+ return params;
181
+ }
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ /**
3
+ * Next.js Pages Router analyzer
4
+ * Analyzes API routes in pages/api directory
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.analyzeNextPages = analyzeNextPages;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ /**
44
+ * Analyze Next.js Pages Router API routes
45
+ */
46
+ async function analyzeNextPages(pagesDir = 'pages/api') {
47
+ const routes = [];
48
+ try {
49
+ const apiDir = path.join(process.cwd(), pagesDir);
50
+ if (!fs.existsSync(apiDir)) {
51
+ console.warn('pages/api directory not found');
52
+ return routes;
53
+ }
54
+ // Recursively scan API directory
55
+ const scanDir = (dir, basePath = '') => {
56
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
57
+ for (const entry of entries) {
58
+ const fullPath = path.join(dir, entry.name);
59
+ if (entry.isDirectory()) {
60
+ // Handle dynamic routes like [id]
61
+ const dirName = entry.name.startsWith('[') && entry.name.endsWith(']')
62
+ ? `:${entry.name.slice(1, -1)}`
63
+ : entry.name;
64
+ scanDir(fullPath, `${basePath}/${dirName}`);
65
+ }
66
+ else if (entry.isFile() && /\.(ts|js)$/.test(entry.name)) {
67
+ // Convert filename to route path
68
+ const fileName = entry.name.replace(/\.(ts|js)$/, '');
69
+ let routePath = basePath;
70
+ if (fileName !== 'index') {
71
+ // Handle dynamic params like [id].ts
72
+ const paramName = fileName.startsWith('[') && fileName.endsWith(']')
73
+ ? `:${fileName.slice(1, -1)}`
74
+ : fileName;
75
+ routePath += `/${paramName}`;
76
+ }
77
+ // Read file to detect HTTP methods
78
+ const content = fs.readFileSync(fullPath, 'utf-8');
79
+ const methods = detectMethods(content);
80
+ // Create route for each detected method
81
+ methods.forEach(method => {
82
+ routes.push({
83
+ method,
84
+ path: `/api${routePath}`,
85
+ description: `${method} /api${routePath}`,
86
+ tags: ['api'],
87
+ middleware: detectMiddleware(content),
88
+ parameters: extractParameters(routePath),
89
+ responses: {
90
+ '200': { description: 'Successful response' }
91
+ }
92
+ });
93
+ });
94
+ }
95
+ }
96
+ };
97
+ scanDir(apiDir);
98
+ }
99
+ catch (error) {
100
+ console.error('Error analyzing Next.js Pages routes:', error.message);
101
+ }
102
+ return routes;
103
+ }
104
+ /**
105
+ * Detect HTTP methods in Next.js API route
106
+ */
107
+ function detectMethods(content) {
108
+ const methods = new Set();
109
+ // Check for req.method checks
110
+ const methodChecks = content.match(/req\.method\s*===?\s*['"`](\w+)['"`]/g) || [];
111
+ methodChecks.forEach(check => {
112
+ const match = check.match(/['"`](\w+)['"`]/);
113
+ if (match)
114
+ methods.add(match[1]);
115
+ });
116
+ // If no explicit methods found, assume it handles all methods
117
+ if (methods.size === 0) {
118
+ methods.add('GET');
119
+ methods.add('POST');
120
+ }
121
+ return Array.from(methods);
122
+ }
123
+ /**
124
+ * Detect middleware usage
125
+ */
126
+ function detectMiddleware(content) {
127
+ const middleware = [];
128
+ // Check for common middleware patterns
129
+ if (content.includes('auth') || content.includes('authenticate')) {
130
+ middleware.push('auth');
131
+ }
132
+ if (content.includes('cors')) {
133
+ middleware.push('cors');
134
+ }
135
+ return middleware;
136
+ }
137
+ /**
138
+ * Extract parameters from route path
139
+ */
140
+ function extractParameters(routePath) {
141
+ const params = [];
142
+ const paramMatches = routePath.match(/:(\w+)/g) || [];
143
+ paramMatches.forEach(param => {
144
+ const name = param.slice(1);
145
+ params.push({
146
+ name,
147
+ in: 'path',
148
+ required: true,
149
+ type: 'string',
150
+ description: `Path parameter: ${name}`
151
+ });
152
+ });
153
+ return params;
154
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ /**
3
+ * React Router analyzer
4
+ * Analyzes React Router route definitions
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.analyzeReactRouter = analyzeReactRouter;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ /**
44
+ * Analyze React Router routes
45
+ */
46
+ async function analyzeReactRouter(routesFile = 'src/routes.tsx') {
47
+ const routes = [];
48
+ try {
49
+ const routesPath = path.join(process.cwd(), routesFile);
50
+ if (!fs.existsSync(routesPath)) {
51
+ console.warn(`Routes file not found: ${routesFile}`);
52
+ return routes;
53
+ }
54
+ const content = fs.readFileSync(routesPath, 'utf-8');
55
+ // Extract routes from React Router
56
+ // Look for <Route path="/..." />
57
+ const routeRegex = /<Route\s+path=["']([^"']+)["']/g;
58
+ let match;
59
+ while ((match = routeRegex.exec(content)) !== null) {
60
+ const routePath = match[1];
61
+ routes.push({
62
+ method: 'GET',
63
+ path: routePath,
64
+ description: `React Router: ${routePath}`,
65
+ tags: ['frontend'],
66
+ middleware: [],
67
+ parameters: extractParameters(routePath),
68
+ responses: {
69
+ '200': { description: 'Page rendered' }
70
+ }
71
+ });
72
+ }
73
+ // Also check for createBrowserRouter routes
74
+ const browserRouterRegex = /path:\s*["']([^"']+)["']/g;
75
+ while ((match = browserRouterRegex.exec(content)) !== null) {
76
+ const routePath = match[1];
77
+ if (!routes.find(r => r.path === routePath)) {
78
+ routes.push({
79
+ method: 'GET',
80
+ path: routePath,
81
+ description: `React Router: ${routePath}`,
82
+ tags: ['frontend'],
83
+ middleware: [],
84
+ parameters: extractParameters(routePath),
85
+ responses: {
86
+ '200': { description: 'Page rendered' }
87
+ }
88
+ });
89
+ }
90
+ }
91
+ console.log(`✅ Found ${routes.length} React Router routes`);
92
+ }
93
+ catch (error) {
94
+ console.error('Error analyzing React Router:', error.message);
95
+ }
96
+ return routes;
97
+ }
98
+ /**
99
+ * Extract parameters from route path
100
+ */
101
+ function extractParameters(routePath) {
102
+ const params = [];
103
+ const paramMatches = routePath.match(/:(\w+)/g) || [];
104
+ paramMatches.forEach(param => {
105
+ const name = param.slice(1);
106
+ params.push({
107
+ name,
108
+ in: 'path',
109
+ required: true,
110
+ type: 'string',
111
+ description: `Path parameter: ${name}`
112
+ });
113
+ });
114
+ return params;
115
+ }
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ /**
3
+ * Vite analyzer
4
+ * Analyzes Vite projects with API proxy configurations
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.analyzeVite = analyzeVite;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ /**
44
+ * Analyze Vite API proxy routes
45
+ */
46
+ async function analyzeVite(viteConfigPath = 'vite.config.js') {
47
+ const routes = [];
48
+ try {
49
+ const configPath = path.join(process.cwd(), viteConfigPath);
50
+ if (!fs.existsSync(configPath)) {
51
+ console.warn('vite.config.js not found');
52
+ return routes;
53
+ }
54
+ const content = fs.readFileSync(configPath, 'utf-8');
55
+ // Extract proxy configurations
56
+ const proxyRegex = /proxy:\s*{([^}]+)}/gs;
57
+ const proxyMatch = content.match(proxyRegex);
58
+ if (proxyMatch) {
59
+ const proxyContent = proxyMatch[0];
60
+ // Extract proxy routes like '/api': { target: 'http://localhost:3000' }
61
+ const routeRegex = /['"`]([^'"`]+)['"`]\s*:\s*{/g;
62
+ let match;
63
+ while ((match = routeRegex.exec(proxyContent)) !== null) {
64
+ const proxyPath = match[1];
65
+ // Create route entry
66
+ routes.push({
67
+ method: 'ALL',
68
+ path: proxyPath,
69
+ description: `Vite proxy: ${proxyPath}`,
70
+ tags: ['proxy'],
71
+ middleware: [],
72
+ responses: {
73
+ '200': { description: 'Proxied response' }
74
+ }
75
+ });
76
+ }
77
+ }
78
+ console.log(`✅ Found ${routes.length} Vite proxy routes`);
79
+ }
80
+ catch (error) {
81
+ console.error('Error analyzing Vite config:', error.message);
82
+ }
83
+ return routes;
84
+ }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /**
3
+ * Main analyzer entry point with dual module support
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.detectFramework = exports.uploadRoutes = exports.exportToJSON = exports.analyzeReactRouter = exports.analyzeVite = exports.analyzeNextApp = exports.analyzeNextPages = exports.analyzeExpress = void 0;
7
+ exports.analyze = analyze;
8
+ const express_js_1 = require("./frameworks/express.js");
9
+ Object.defineProperty(exports, "analyzeExpress", { enumerable: true, get: function () { return express_js_1.analyzeExpress; } });
10
+ const nextjs_pages_js_1 = require("./frameworks/nextjs-pages.js");
11
+ Object.defineProperty(exports, "analyzeNextPages", { enumerable: true, get: function () { return nextjs_pages_js_1.analyzeNextPages; } });
12
+ const nextjs_app_js_1 = require("./frameworks/nextjs-app.js");
13
+ Object.defineProperty(exports, "analyzeNextApp", { enumerable: true, get: function () { return nextjs_app_js_1.analyzeNextApp; } });
14
+ const vite_js_1 = require("./frameworks/vite.js");
15
+ Object.defineProperty(exports, "analyzeVite", { enumerable: true, get: function () { return vite_js_1.analyzeVite; } });
16
+ const react_router_js_1 = require("./frameworks/react-router.js");
17
+ Object.defineProperty(exports, "analyzeReactRouter", { enumerable: true, get: function () { return react_router_js_1.analyzeReactRouter; } });
18
+ const detect_js_1 = require("./detect.js");
19
+ const export_js_1 = require("./export.js");
20
+ const uploader_js_1 = require("./uploader.js");
21
+ // Global state for debouncing
22
+ const analysisState = new Map();
23
+ const DEBOUNCE_TIME = 5000;
24
+ /**
25
+ * Main analyze function with auto-detection
26
+ */
27
+ async function analyze(app, options) {
28
+ // Skip in production
29
+ if (options.skipInProduction !== false && process.env.NODE_ENV === 'production') {
30
+ console.log('⏭️ Skipping analysis in production');
31
+ return [];
32
+ }
33
+ // Debounce check
34
+ if (options.runOnce !== false) {
35
+ const cached = analysisState.get(options.projectName);
36
+ const now = Date.now();
37
+ if (cached && (now - cached.timestamp) < DEBOUNCE_TIME) {
38
+ console.log(`⚡ Analysis skipped - already ran ${Math.round((now - cached.timestamp) / 1000)}s ago`);
39
+ return cached.routes;
40
+ }
41
+ }
42
+ console.log(`🔍 Analyzing ${options.projectName}...`);
43
+ // CRITICAL: Prevent restart loops - force saveJson=false when uploading
44
+ if (options.upload !== false && options.apiKey) {
45
+ options.saveJson = false;
46
+ }
47
+ let routes = [];
48
+ let framework = options.framework;
49
+ // Auto-detect framework if not specified
50
+ if (!framework) {
51
+ const detected = (0, detect_js_1.detectFramework)(app);
52
+ framework = detected.name;
53
+ console.log(`📦 Detected framework: ${framework}`);
54
+ }
55
+ // Analyze based on framework
56
+ switch (framework) {
57
+ case 'express':
58
+ if (!app) {
59
+ console.error('❌ Express app instance required');
60
+ return [];
61
+ }
62
+ routes = await (0, express_js_1.analyzeExpress)(app);
63
+ break;
64
+ case 'nextjs-pages':
65
+ routes = await (0, nextjs_pages_js_1.analyzeNextPages)(options.nextDir || 'pages/api');
66
+ break;
67
+ case 'nextjs-app':
68
+ routes = await (0, nextjs_app_js_1.analyzeNextApp)(options.nextDir || 'app');
69
+ break;
70
+ case 'vite':
71
+ routes = await (0, vite_js_1.analyzeVite)(options.nextDir || 'vite.config.js');
72
+ break;
73
+ case 'react-router':
74
+ routes = await (0, react_router_js_1.analyzeReactRouter)(options.nextDir || 'src/routes.tsx');
75
+ break;
76
+ case 'node-http':
77
+ case 'unknown':
78
+ default:
79
+ console.warn(`⚠️ Framework "${framework}" not supported yet`);
80
+ console.log('💡 Supported: express, nextjs-pages, nextjs-app, vite, react-router');
81
+ console.log('💡 Tip: Specify framework manually: { framework: "express" }');
82
+ return [];
83
+ }
84
+ console.log(`✅ Found ${routes.length} routes`);
85
+ // Cache results
86
+ if (options.runOnce !== false) {
87
+ analysisState.set(options.projectName, {
88
+ timestamp: Date.now(),
89
+ routes
90
+ });
91
+ }
92
+ // Save JSON (only if not uploading)
93
+ if (options.saveJson) {
94
+ const filePath = options.jsonPath || 'api-export.json';
95
+ await (0, export_js_1.exportToJSON)(routes, options.projectName, filePath, options.baseUrl);
96
+ }
97
+ // Upload to APIForge
98
+ if (options.upload !== false && options.apiKey) {
99
+ await (0, uploader_js_1.uploadRoutes)(routes, {
100
+ projectName: options.projectName,
101
+ apiKey: options.apiKey,
102
+ baseUrl: options.baseUrl,
103
+ apiForgeUrl: options.apiForgeUrl,
104
+ });
105
+ }
106
+ return routes;
107
+ }
108
+ var export_js_2 = require("./export.js");
109
+ Object.defineProperty(exports, "exportToJSON", { enumerable: true, get: function () { return export_js_2.exportToJSON; } });
110
+ var uploader_js_2 = require("./uploader.js");
111
+ Object.defineProperty(exports, "uploadRoutes", { enumerable: true, get: function () { return uploader_js_2.uploadRoutes; } });
112
+ var detect_js_2 = require("./detect.js");
113
+ Object.defineProperty(exports, "detectFramework", { enumerable: true, get: function () { return detect_js_2.detectFramework; } });
114
+ // Default export for CommonJS
115
+ exports.default = {
116
+ analyze,
117
+ analyzeExpress: express_js_1.analyzeExpress,
118
+ analyzeNextPages: nextjs_pages_js_1.analyzeNextPages,
119
+ analyzeNextApp: nextjs_app_js_1.analyzeNextApp,
120
+ analyzeVite: vite_js_1.analyzeVite,
121
+ analyzeReactRouter: react_router_js_1.analyzeReactRouter,
122
+ exportToJSON: export_js_1.exportToJSON,
123
+ uploadRoutes: uploader_js_1.uploadRoutes,
124
+ detectFramework: detect_js_1.detectFramework
125
+ };
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}