apiforge-analyzer 1.2.1 → 1.3.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.
- package/README.md +166 -197
- package/dist/cjs/arch-detect.js +154 -0
- package/dist/cjs/cli.js +547 -46
- package/dist/cjs/export.js +2 -0
- package/dist/cjs/frameworks/nestjs.js +38 -0
- package/dist/cjs/index.js +41 -3
- package/dist/cjs/modules/express.js +65 -0
- package/dist/cjs/modules/nestjs.js +50 -0
- package/dist/cjs/uploader.js +3 -1
- package/dist/esm/arch-detect.js +151 -0
- package/dist/esm/cli.js +548 -47
- package/dist/esm/export.js +2 -0
- package/dist/esm/frameworks/nestjs.js +35 -0
- package/dist/esm/index.js +39 -3
- package/dist/esm/modules/express.js +60 -0
- package/dist/esm/modules/nestjs.js +47 -0
- package/dist/esm/uploader.js +3 -1
- package/dist/types/arch-detect.d.ts +9 -0
- package/dist/types/export.d.ts +2 -0
- package/dist/types/frameworks/nestjs.d.ts +10 -0
- package/dist/types/index.d.ts +11 -1
- package/dist/types/modules/express.d.ts +22 -0
- package/dist/types/modules/nestjs.d.ts +6 -0
- package/dist/types/uploader.d.ts +7 -0
- package/package.json +3 -2
package/dist/esm/export.js
CHANGED
|
@@ -54,6 +54,8 @@ export function enrichRoute(route, index) {
|
|
|
54
54
|
routeKey,
|
|
55
55
|
tag,
|
|
56
56
|
tags: route.tags?.length ? route.tags : [tag],
|
|
57
|
+
module: route.module,
|
|
58
|
+
service: route.service,
|
|
57
59
|
summary: route.summary || generateSummary(route.method, route.path),
|
|
58
60
|
description: route.description || generateDescription(route.method, route.path, tag),
|
|
59
61
|
authRequired,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { analyzeExpress } from './express.js';
|
|
2
|
+
import { detectNestModules } from '../modules/nestjs.js';
|
|
3
|
+
import { detectExpressModules, annotateRoutesWithModules } from '../modules/express.js';
|
|
4
|
+
/**
|
|
5
|
+
* Analyze a NestJS application by extracting the underlying Express (or Fastify)
|
|
6
|
+
* HTTP adapter and reusing the existing Express route-walker.
|
|
7
|
+
*
|
|
8
|
+
* NestJS wraps an inner Express app under app.getHttpServer()._events.request.
|
|
9
|
+
* When that's available we get full runtime accuracy. Otherwise we warn and
|
|
10
|
+
* fall back to an empty array so the CLI can report the limitation.
|
|
11
|
+
*/
|
|
12
|
+
export async function analyzeNestJS(app, rootDir) {
|
|
13
|
+
if (!app || typeof app.getHttpServer !== 'function') {
|
|
14
|
+
console.warn('⚠️ APIForge: NestJS app instance required. Pass the Nest application object.');
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
const httpServer = app.getHttpServer();
|
|
18
|
+
// NestJS wraps Express under _events.request when using the default adapter
|
|
19
|
+
const innerApp = httpServer?._events?.request ||
|
|
20
|
+
httpServer?._events?.['request'] ||
|
|
21
|
+
null;
|
|
22
|
+
if (!innerApp || typeof innerApp !== 'function') {
|
|
23
|
+
console.warn('⚠️ APIForge: Could not access inner Express adapter from NestJS app.');
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const routes = await analyzeExpress(innerApp);
|
|
27
|
+
if (routes.length === 0)
|
|
28
|
+
return [];
|
|
29
|
+
// Detect module structure and annotate each route
|
|
30
|
+
const dir = rootDir || process.cwd();
|
|
31
|
+
const modules = detectNestModules(dir).length > 0
|
|
32
|
+
? detectNestModules(dir)
|
|
33
|
+
: detectExpressModules(dir);
|
|
34
|
+
return annotateRoutesWithModules(routes, modules);
|
|
35
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -8,9 +8,13 @@ import { analyzeNextPages } from './frameworks/nextjs-pages.js';
|
|
|
8
8
|
import { analyzeNextApp } from './frameworks/nextjs-app.js';
|
|
9
9
|
import { analyzeVite } from './frameworks/vite.js';
|
|
10
10
|
import { analyzeReactRouter } from './frameworks/react-router.js';
|
|
11
|
+
import { analyzeNestJS } from './frameworks/nestjs.js';
|
|
11
12
|
import { detectFramework } from './detect.js';
|
|
12
13
|
import { exportToJSON } from './export.js';
|
|
13
14
|
import { uploadRoutes, writeStatusFile } from './uploader.js';
|
|
15
|
+
import { detectArchitectureType } from './arch-detect.js';
|
|
16
|
+
import { detectExpressModules, annotateRoutesWithModules } from './modules/express.js';
|
|
17
|
+
import { detectNestModules } from './modules/nestjs.js';
|
|
14
18
|
// ─── Env file loader — no dotenv dependency ───────────────────────────────────
|
|
15
19
|
/**
|
|
16
20
|
* Read a single variable from a .env-style file.
|
|
@@ -66,8 +70,10 @@ export async function analyze(app, options) {
|
|
|
66
70
|
if (options.skipInProduction !== false && process.env.NODE_ENV === 'production') {
|
|
67
71
|
return [];
|
|
68
72
|
}
|
|
69
|
-
// File-based debounce — survives nodemon restarts
|
|
70
|
-
|
|
73
|
+
// File-based debounce — survives nodemon restarts.
|
|
74
|
+
// Skipped in collection mode (statusFile set) because the CLI controls each service start
|
|
75
|
+
// and the shared .apiforge-last-run.json would cause services 2+ to be skipped.
|
|
76
|
+
if (options.runOnce !== false && !options.statusFile) {
|
|
71
77
|
const elapsed = Date.now() - readLastRunMs();
|
|
72
78
|
if (elapsed < DEBOUNCE_MS) {
|
|
73
79
|
console.log(`⚡ APIForge: skipped (last run ${Math.round(elapsed / 1000)}s ago)`);
|
|
@@ -103,6 +109,9 @@ export async function analyze(app, options) {
|
|
|
103
109
|
}
|
|
104
110
|
try {
|
|
105
111
|
switch (framework) {
|
|
112
|
+
case 'nestjs':
|
|
113
|
+
routes = await analyzeNestJS(app, options.nextDir || process.cwd());
|
|
114
|
+
break;
|
|
106
115
|
case 'express':
|
|
107
116
|
if (!app) {
|
|
108
117
|
const msg = 'Express app instance required — pass your app object to analyze()';
|
|
@@ -111,6 +120,16 @@ export async function analyze(app, options) {
|
|
|
111
120
|
return [];
|
|
112
121
|
}
|
|
113
122
|
routes = await analyzeExpress(app);
|
|
123
|
+
// For modular-monolithic: annotate each route with its module name
|
|
124
|
+
if (options.architectureType === 'modular-monolithic') {
|
|
125
|
+
const dir = options.nextDir || process.cwd();
|
|
126
|
+
const modules = detectNestModules(dir).length > 0
|
|
127
|
+
? detectNestModules(dir)
|
|
128
|
+
: detectExpressModules(dir);
|
|
129
|
+
if (modules.length > 0) {
|
|
130
|
+
routes = annotateRoutesWithModules(routes, modules);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
114
133
|
break;
|
|
115
134
|
case 'nextjs-pages':
|
|
116
135
|
routes = await analyzeNextPages(options.nextDir || 'pages/api');
|
|
@@ -147,21 +166,36 @@ export async function analyze(app, options) {
|
|
|
147
166
|
if (options.saveJson) {
|
|
148
167
|
await exportToJSON(routes, options.projectName, options.jsonPath || 'api-export.json', options.baseUrl);
|
|
149
168
|
}
|
|
169
|
+
// Stamp service name on routes if running in microservices mode
|
|
170
|
+
if (options.service) {
|
|
171
|
+
routes = routes.map(r => ({ ...r, service: options.service }));
|
|
172
|
+
}
|
|
173
|
+
// Multi-service collection mode: write routes to a per-service file for the CLI to aggregate.
|
|
174
|
+
// The CLI spawns each service individually, collects via this file, then uploads once.
|
|
175
|
+
if (options.statusFile) {
|
|
176
|
+
try {
|
|
177
|
+
writeFileSync(join(process.cwd(), options.statusFile), JSON.stringify({ status: 'collected', service: options.service, routes, routeCount: routes.length }), 'utf-8');
|
|
178
|
+
}
|
|
179
|
+
catch { }
|
|
180
|
+
return routes;
|
|
181
|
+
}
|
|
150
182
|
if (options.upload !== false && options.apiKey) {
|
|
151
183
|
await uploadRoutes(routes, {
|
|
152
184
|
projectName: options.projectName,
|
|
153
185
|
apiKey: options.apiKey,
|
|
154
186
|
baseUrl: options.baseUrl,
|
|
155
187
|
apiForgeUrl: options.apiForgeUrl,
|
|
188
|
+
architectureType: options.architectureType,
|
|
156
189
|
});
|
|
157
190
|
}
|
|
158
191
|
return routes;
|
|
159
192
|
}
|
|
160
193
|
// Re-exports for library consumers
|
|
161
|
-
export { analyzeExpress, analyzeNextPages, analyzeNextApp, analyzeVite, analyzeReactRouter };
|
|
194
|
+
export { analyzeExpress, analyzeNextPages, analyzeNextApp, analyzeVite, analyzeReactRouter, analyzeNestJS };
|
|
162
195
|
export { exportToJSON } from './export.js';
|
|
163
196
|
export { uploadRoutes } from './uploader.js';
|
|
164
197
|
export { detectFramework } from './detect.js';
|
|
198
|
+
export { detectArchitectureType } from './arch-detect.js';
|
|
165
199
|
export default {
|
|
166
200
|
analyze,
|
|
167
201
|
analyzeExpress,
|
|
@@ -169,7 +203,9 @@ export default {
|
|
|
169
203
|
analyzeNextApp,
|
|
170
204
|
analyzeVite,
|
|
171
205
|
analyzeReactRouter,
|
|
206
|
+
analyzeNestJS,
|
|
172
207
|
exportToJSON,
|
|
173
208
|
uploadRoutes,
|
|
174
209
|
detectFramework,
|
|
210
|
+
detectArchitectureType,
|
|
175
211
|
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Detect Express feature-module structure by scanning standard directory patterns.
|
|
5
|
+
* Works for: src/modules/, src/features/, src/domains/ conventions.
|
|
6
|
+
*/
|
|
7
|
+
export function detectExpressModules(rootDir) {
|
|
8
|
+
const modules = [];
|
|
9
|
+
const srcDir = join(rootDir, 'src');
|
|
10
|
+
for (const parentDir of ['modules', 'features', 'domains']) {
|
|
11
|
+
const dir = existsSync(srcDir)
|
|
12
|
+
? join(srcDir, parentDir)
|
|
13
|
+
: join(rootDir, parentDir);
|
|
14
|
+
if (!existsSync(dir))
|
|
15
|
+
continue;
|
|
16
|
+
const subdirs = readdirSync(dir, { withFileTypes: true })
|
|
17
|
+
.filter(entry => entry.isDirectory())
|
|
18
|
+
.map(entry => entry.name);
|
|
19
|
+
for (const name of subdirs) {
|
|
20
|
+
const routePrefix = `/${name}`;
|
|
21
|
+
modules.push({ name, routePrefix });
|
|
22
|
+
}
|
|
23
|
+
if (modules.length > 0)
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
return modules;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Given a route path, return the module name it belongs to.
|
|
30
|
+
* Falls back to the tag (first meaningful path segment) when no module matches.
|
|
31
|
+
*/
|
|
32
|
+
export function resolveModuleForPath(routePath, modules) {
|
|
33
|
+
if (modules.length === 0)
|
|
34
|
+
return undefined;
|
|
35
|
+
// Strip /api/v1/ etc. prefixes before matching
|
|
36
|
+
const normalized = routePath.replace(/^\/(api\/)?(v\d+\/)?/, '/');
|
|
37
|
+
for (const mod of modules) {
|
|
38
|
+
if (normalized.startsWith(mod.routePrefix + '/') || normalized === mod.routePrefix) {
|
|
39
|
+
return mod.name;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Fallback: first non-param, non-version segment
|
|
43
|
+
const segment = normalized.split('/').filter(s => s && !s.startsWith(':'))[0];
|
|
44
|
+
return segment || undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Annotate a list of routes with their module names using path-prefix matching.
|
|
48
|
+
*/
|
|
49
|
+
export function annotateRoutesWithModules(routes, modules) {
|
|
50
|
+
return routes.map(route => ({
|
|
51
|
+
...route,
|
|
52
|
+
module: resolveModuleForPath(route.path, modules) || inferModuleFromPath(route.path),
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
function inferModuleFromPath(routePath) {
|
|
56
|
+
const skip = new Set(['api', 'v1', 'v2', 'v3']);
|
|
57
|
+
return (routePath
|
|
58
|
+
.split('/')
|
|
59
|
+
.filter(s => s && !s.startsWith(':') && !skip.has(s))[0] || 'general');
|
|
60
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'fs';
|
|
2
|
+
import { join, basename } from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Detect NestJS modules by scanning for *.module.ts files and extracting
|
|
5
|
+
* their declared controllers with the @Module() decorator.
|
|
6
|
+
*/
|
|
7
|
+
export function detectNestModules(rootDir) {
|
|
8
|
+
const srcDir = join(rootDir, 'src');
|
|
9
|
+
const searchDir = existsSync(srcDir) ? srcDir : rootDir;
|
|
10
|
+
const moduleFiles = findModuleFiles(searchDir);
|
|
11
|
+
if (moduleFiles.length === 0)
|
|
12
|
+
return [];
|
|
13
|
+
const modules = [];
|
|
14
|
+
for (const filePath of moduleFiles) {
|
|
15
|
+
const name = basename(filePath).replace('.module.ts', '');
|
|
16
|
+
// Skip the root AppModule — it's the container, not a domain module
|
|
17
|
+
if (name === 'app')
|
|
18
|
+
continue;
|
|
19
|
+
const routePrefix = inferPrefixFromModuleName(name);
|
|
20
|
+
modules.push({ name, routePrefix });
|
|
21
|
+
}
|
|
22
|
+
return modules;
|
|
23
|
+
}
|
|
24
|
+
function findModuleFiles(dir, depth = 0) {
|
|
25
|
+
if (depth > 8)
|
|
26
|
+
return [];
|
|
27
|
+
const results = [];
|
|
28
|
+
try {
|
|
29
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
if (['node_modules', 'dist', '.next'].includes(entry.name))
|
|
32
|
+
continue;
|
|
33
|
+
if (entry.isDirectory()) {
|
|
34
|
+
results.push(...findModuleFiles(join(dir, entry.name), depth + 1));
|
|
35
|
+
}
|
|
36
|
+
else if (entry.isFile() && entry.name.endsWith('.module.ts')) {
|
|
37
|
+
results.push(join(dir, entry.name));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch { }
|
|
42
|
+
return results;
|
|
43
|
+
}
|
|
44
|
+
function inferPrefixFromModuleName(name) {
|
|
45
|
+
// user-profile → /user-profile, users → /users
|
|
46
|
+
return `/${name}`;
|
|
47
|
+
}
|
package/dist/esm/uploader.js
CHANGED
|
@@ -34,13 +34,15 @@ export async function uploadRoutes(routes, options) {
|
|
|
34
34
|
routes: enrichedRoutes,
|
|
35
35
|
baseUrl: options.baseUrl,
|
|
36
36
|
framework: enrichedRoutes[0]?.framework || 'unknown',
|
|
37
|
+
architectureType: options.architectureType || 'monolithic',
|
|
38
|
+
services: options.services || [],
|
|
37
39
|
};
|
|
38
40
|
try {
|
|
39
41
|
const response = await axios.post(`${backendUrl}/api/cli/submit`, payload, {
|
|
40
42
|
headers: {
|
|
41
43
|
'Content-Type': 'application/json',
|
|
42
44
|
'X-API-Key': options.apiKey,
|
|
43
|
-
'User-Agent': 'apiforge-analyzer/1.
|
|
45
|
+
'User-Agent': 'apiforge-analyzer/1.3.0',
|
|
44
46
|
},
|
|
45
47
|
timeout: 30000,
|
|
46
48
|
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ArchitectureType = 'monolithic' | 'modular-monolithic' | 'microservices';
|
|
2
|
+
export interface ArchDetectResult {
|
|
3
|
+
type: ArchitectureType;
|
|
4
|
+
confidence: number;
|
|
5
|
+
evidence: string[];
|
|
6
|
+
moduleNames: string[];
|
|
7
|
+
servicePaths: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function detectArchitectureType(rootDir: string): ArchDetectResult;
|
package/dist/types/export.d.ts
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Route } from '../export.js';
|
|
2
|
+
/**
|
|
3
|
+
* Analyze a NestJS application by extracting the underlying Express (or Fastify)
|
|
4
|
+
* HTTP adapter and reusing the existing Express route-walker.
|
|
5
|
+
*
|
|
6
|
+
* NestJS wraps an inner Express app under app.getHttpServer()._events.request.
|
|
7
|
+
* When that's available we get full runtime accuracy. Otherwise we warn and
|
|
8
|
+
* fall back to an empty array so the CLI can report the limitation.
|
|
9
|
+
*/
|
|
10
|
+
export declare function analyzeNestJS(app: any, rootDir?: string): Promise<Route[]>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -6,9 +6,12 @@ import { analyzeNextPages } from './frameworks/nextjs-pages.js';
|
|
|
6
6
|
import { analyzeNextApp } from './frameworks/nextjs-app.js';
|
|
7
7
|
import { analyzeVite } from './frameworks/vite.js';
|
|
8
8
|
import { analyzeReactRouter } from './frameworks/react-router.js';
|
|
9
|
+
import { analyzeNestJS } from './frameworks/nestjs.js';
|
|
9
10
|
import { detectFramework } from './detect.js';
|
|
10
11
|
import { exportToJSON } from './export.js';
|
|
11
12
|
import { uploadRoutes } from './uploader.js';
|
|
13
|
+
import { detectArchitectureType } from './arch-detect.js';
|
|
14
|
+
import type { ArchitectureType } from './arch-detect.js';
|
|
12
15
|
export interface AnalyzerOptions {
|
|
13
16
|
projectName: string;
|
|
14
17
|
baseUrl?: string;
|
|
@@ -21,12 +24,17 @@ export interface AnalyzerOptions {
|
|
|
21
24
|
nextDir?: string;
|
|
22
25
|
skipInProduction?: boolean;
|
|
23
26
|
runOnce?: boolean;
|
|
27
|
+
architectureType?: ArchitectureType;
|
|
28
|
+
service?: string;
|
|
29
|
+
/** CLI multi-service mode: write routes to this file and exit without uploading */
|
|
30
|
+
statusFile?: string;
|
|
24
31
|
}
|
|
25
32
|
export declare function analyze(app: any, options: AnalyzerOptions): Promise<any[]>;
|
|
26
|
-
export { analyzeExpress, analyzeNextPages, analyzeNextApp, analyzeVite, analyzeReactRouter };
|
|
33
|
+
export { analyzeExpress, analyzeNextPages, analyzeNextApp, analyzeVite, analyzeReactRouter, analyzeNestJS };
|
|
27
34
|
export { exportToJSON } from './export.js';
|
|
28
35
|
export { uploadRoutes } from './uploader.js';
|
|
29
36
|
export { detectFramework } from './detect.js';
|
|
37
|
+
export { detectArchitectureType } from './arch-detect.js';
|
|
30
38
|
declare const _default: {
|
|
31
39
|
analyze: typeof analyze;
|
|
32
40
|
analyzeExpress: typeof analyzeExpress;
|
|
@@ -34,8 +42,10 @@ declare const _default: {
|
|
|
34
42
|
analyzeNextApp: typeof analyzeNextApp;
|
|
35
43
|
analyzeVite: typeof analyzeVite;
|
|
36
44
|
analyzeReactRouter: typeof analyzeReactRouter;
|
|
45
|
+
analyzeNestJS: typeof analyzeNestJS;
|
|
37
46
|
exportToJSON: typeof exportToJSON;
|
|
38
47
|
uploadRoutes: typeof uploadRoutes;
|
|
39
48
|
detectFramework: typeof detectFramework;
|
|
49
|
+
detectArchitectureType: typeof detectArchitectureType;
|
|
40
50
|
};
|
|
41
51
|
export default _default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ModuleInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
routePrefix: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Detect Express feature-module structure by scanning standard directory patterns.
|
|
7
|
+
* Works for: src/modules/, src/features/, src/domains/ conventions.
|
|
8
|
+
*/
|
|
9
|
+
export declare function detectExpressModules(rootDir: string): ModuleInfo[];
|
|
10
|
+
/**
|
|
11
|
+
* Given a route path, return the module name it belongs to.
|
|
12
|
+
* Falls back to the tag (first meaningful path segment) when no module matches.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveModuleForPath(routePath: string, modules: ModuleInfo[]): string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Annotate a list of routes with their module names using path-prefix matching.
|
|
17
|
+
*/
|
|
18
|
+
export declare function annotateRoutesWithModules<T extends {
|
|
19
|
+
path: string;
|
|
20
|
+
}>(routes: T[], modules: ModuleInfo[]): (T & {
|
|
21
|
+
module: string;
|
|
22
|
+
})[];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ModuleInfo } from './express.js';
|
|
2
|
+
/**
|
|
3
|
+
* Detect NestJS modules by scanning for *.module.ts files and extracting
|
|
4
|
+
* their declared controllers with the @Module() decorator.
|
|
5
|
+
*/
|
|
6
|
+
export declare function detectNestModules(rootDir: string): ModuleInfo[];
|
package/dist/types/uploader.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { Route } from './export.js';
|
|
2
|
+
import type { ArchitectureType } from './arch-detect.js';
|
|
3
|
+
export interface ServiceMeta {
|
|
4
|
+
name: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
}
|
|
2
7
|
export interface UploadOptions {
|
|
3
8
|
projectName: string;
|
|
4
9
|
baseUrl?: string;
|
|
5
10
|
apiForgeUrl?: string;
|
|
6
11
|
apiKey: string;
|
|
12
|
+
architectureType?: ArchitectureType;
|
|
13
|
+
services?: ServiceMeta[];
|
|
7
14
|
}
|
|
8
15
|
export interface UploadResult {
|
|
9
16
|
pendingImportId: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apiforge-analyzer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Universal API documentation generator for Express, Next.js, Vite, React Router, and Node.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"build:esm": "tsc -p tsconfig.esm.json",
|
|
27
27
|
"build:cjs": "tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
|
|
28
28
|
"build:types": "tsc -p tsconfig.types.json",
|
|
29
|
-
"prepublishOnly": "npm run build"
|
|
29
|
+
"prepublishOnly": "npm run build",
|
|
30
|
+
"test": "node ../test-apps/run-all.cjs"
|
|
30
31
|
},
|
|
31
32
|
"keywords": [
|
|
32
33
|
"api",
|