dinorex 1.0.1 → 1.0.3

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,108 @@
1
+ import { glob } from "glob";
2
+ import { readFileSync } from "fs";
3
+ import path from "path";
4
+ const ROUTE_PATTERNS = [
5
+ "**/routes/**/*.{js,ts,tsx}",
6
+ "**/route/**/*.{js,ts,tsx}",
7
+ "**/router/**/*.{js,ts,tsx}",
8
+ "**/*route*.{js,ts,tsx}",
9
+ "**/*router*.{js,ts,tsx}",
10
+ "**/*Route*.{js,ts,tsx}",
11
+ "**/*Router*.{js,ts,tsx}",
12
+ ];
13
+ const CONTROLLER_PATTERNS = [
14
+ "**/controllers/**/*.{js,ts,tsx}",
15
+ "**/controller/**/*.{js,ts,tsx}",
16
+ "**/*controller*.{js,ts,tsx}",
17
+ "**/*Controller*.{js,ts,tsx}",
18
+ ];
19
+ const SERVICE_PATTERNS = [
20
+ "**/services/**/*.{js,ts,tsx}",
21
+ "**/service/**/*.{js,ts,tsx}",
22
+ "**/*service*.{js,ts,tsx}",
23
+ "**/*Service*.{js,ts,tsx}",
24
+ ];
25
+ const MODEL_PATTERNS = [
26
+ "**/models/**/*.{js,ts,tsx}",
27
+ "**/model/**/*.{js,ts,tsx}",
28
+ "**/schemas/**/*.{js,ts,tsx}",
29
+ "**/schema/**/*.{js,ts,tsx}",
30
+ "**/entities/**/*.{js,ts,tsx}",
31
+ "**/dto/**/*.{js,ts,tsx}",
32
+ "**/dtos/**/*.{js,ts,tsx}",
33
+ "**/*model*.{js,ts,tsx}",
34
+ "**/*Model*.{js,ts,tsx}",
35
+ "**/*schema*.{js,ts,tsx}",
36
+ "**/*Schema*.{js,ts,tsx}",
37
+ "**/*entity*.{js,ts,tsx}",
38
+ "**/*Entity*.{js,ts,tsx}",
39
+ "**/*.dto.{ts,tsx}",
40
+ ];
41
+ const IGNORE_DIRS = [
42
+ "**/node_modules/**",
43
+ "**/.git/**",
44
+ "**/dist/**",
45
+ "**/build/**",
46
+ "**/.next/**",
47
+ "**/coverage/**",
48
+ "**/*.test.*",
49
+ "**/*.spec.*",
50
+ "**/__tests__/**",
51
+ ];
52
+ async function findFiles(patterns, cwd) {
53
+ const results = new Set();
54
+ for (const pattern of patterns) {
55
+ const files = await glob(pattern, { cwd, ignore: IGNORE_DIRS, absolute: true });
56
+ files.forEach((f) => results.add(f));
57
+ }
58
+ return [...results];
59
+ }
60
+ function readFile(filePath) {
61
+ try {
62
+ return readFileSync(filePath, "utf-8");
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ function truncate(content, maxChars = 8000) {
69
+ if (content.length <= maxChars)
70
+ return content;
71
+ return content.slice(0, maxChars) + "\n\n... [truncated for length]";
72
+ }
73
+ export async function scanProject(targetDir) {
74
+ const cwd = path.resolve(targetDir);
75
+ console.log(`\nšŸ¦• Dinorex scanning: ${cwd}\n`);
76
+ const [routeFiles, controllerFiles, serviceFiles, modelFiles] = await Promise.all([
77
+ findFiles(ROUTE_PATTERNS, cwd),
78
+ findFiles(CONTROLLER_PATTERNS, cwd),
79
+ findFiles(SERVICE_PATTERNS, cwd),
80
+ findFiles(MODEL_PATTERNS, cwd),
81
+ ]);
82
+ const summary = {
83
+ routes: routeFiles.length,
84
+ controllers: controllerFiles.length,
85
+ services: serviceFiles.length,
86
+ models: modelFiles.length,
87
+ };
88
+ const collected = {
89
+ routes: routeFiles.map((f) => ({
90
+ path: path.relative(cwd, f),
91
+ content: truncate(readFile(f) ?? ""),
92
+ })),
93
+ controllers: controllerFiles.map((f) => ({
94
+ path: path.relative(cwd, f),
95
+ content: truncate(readFile(f) ?? ""),
96
+ })),
97
+ services: serviceFiles.map((f) => ({
98
+ path: path.relative(cwd, f),
99
+ content: truncate(readFile(f) ?? ""),
100
+ })),
101
+ models: modelFiles.map((f) => ({
102
+ path: path.relative(cwd, f),
103
+ content: truncate(readFile(f) ?? ""),
104
+ })),
105
+ };
106
+ return { cwd, summary, collected };
107
+ }
108
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Server } from "http";
2
+ import { type ApiSpec } from "./store.js";
3
+ interface ServerOptions {
4
+ port?: number;
5
+ _cachedSpec?: ApiSpec | null;
6
+ }
7
+ interface ServerResult {
8
+ server: Server;
9
+ port: number;
10
+ url: string;
11
+ }
12
+ export declare function startServer(targetDir: string, options?: ServerOptions): Promise<ServerResult>;
13
+ export {};
14
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAG9B,OAAO,EAAkC,KAAK,OAAO,EAAkB,MAAM,YAAY,CAAC;AAU1F,UAAU,aAAa;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC9B;AAED,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA+GvB"}
package/dist/server.js ADDED
@@ -0,0 +1,116 @@
1
+ import express from "express";
2
+ import cors from "cors";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ import { scanProject } from "./scanner.js";
6
+ import { analyzeWithAI, analyzeIncremental } from "./agent.js";
7
+ import { loadStore, saveStore, diffScan } from "./store.js";
8
+ import { createHash } from "crypto";
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+ export async function startServer(targetDir, options = {}) {
11
+ const { port = 4321, _cachedSpec = null } = options;
12
+ const app = express();
13
+ app.use(cors());
14
+ app.use(express.json());
15
+ app.use(express.static(path.join(__dirname, "public")));
16
+ let specCache = _cachedSpec;
17
+ let isAnalyzing = false;
18
+ let analysisStatus = _cachedSpec
19
+ ? { state: "ready" }
20
+ : { state: "pending", message: "Starting analysis..." };
21
+ async function runAnalysis(forceRescan = false) {
22
+ if (isAnalyzing)
23
+ return;
24
+ isAnalyzing = true;
25
+ try {
26
+ const { collected } = await scanProject(targetDir);
27
+ const allFiles = [
28
+ ...collected.routes,
29
+ ...collected.controllers,
30
+ ...collected.services,
31
+ ...collected.models,
32
+ ];
33
+ const stored = loadStore(targetDir);
34
+ if (!forceRescan && stored?.spec && stored?.hashes) {
35
+ analysisStatus = { state: "analyzing", message: "Checking for new/changed endpoints..." };
36
+ const diff = diffScan(stored.hashes, allFiles);
37
+ const { spec, changed } = await analyzeIncremental(stored.spec, diff);
38
+ specCache = spec;
39
+ if (changed) {
40
+ const storeData = {
41
+ spec,
42
+ hashes: diff.newHashes,
43
+ lastScan: new Date().toISOString(),
44
+ };
45
+ saveStore(targetDir, storeData);
46
+ analysisStatus = { state: "ready", message: "Spec updated with new endpoints." };
47
+ }
48
+ else {
49
+ analysisStatus = { state: "ready", message: "No changes detected." };
50
+ }
51
+ }
52
+ else {
53
+ analysisStatus = { state: "analyzing", message: "Running full AI analysis..." };
54
+ const projectName = path.basename(targetDir);
55
+ specCache = await analyzeWithAI(collected, projectName);
56
+ const hashes = {};
57
+ for (const f of allFiles) {
58
+ hashes[f.path] = { hash: createHash("md5").update(f.content).digest("hex") };
59
+ }
60
+ saveStore(targetDir, { spec: specCache, hashes, lastScan: new Date().toISOString() });
61
+ analysisStatus = { state: "ready", message: "Full analysis complete." };
62
+ }
63
+ }
64
+ catch (err) {
65
+ analysisStatus = {
66
+ state: "error",
67
+ message: err instanceof Error ? err.message : String(err),
68
+ };
69
+ }
70
+ finally {
71
+ isAnalyzing = false;
72
+ }
73
+ }
74
+ if (!specCache) {
75
+ const stored = loadStore(targetDir);
76
+ if (stored?.spec) {
77
+ specCache = stored.spec;
78
+ analysisStatus = { state: "ready", message: "Loaded from cache." };
79
+ runAnalysis(false);
80
+ }
81
+ else {
82
+ runAnalysis(true);
83
+ }
84
+ }
85
+ else {
86
+ analysisStatus = { state: "ready" };
87
+ }
88
+ // ── Routes ──────────────────────────────────────────────────────────────
89
+ app.get("/api/status", (_req, res) => res.json(analysisStatus));
90
+ app.get("/api/spec", (_req, res) => {
91
+ if (!specCache)
92
+ return void res.json({ _loading: true, status: analysisStatus });
93
+ res.json(specCache);
94
+ });
95
+ app.post("/api/rescan", (_req, res) => {
96
+ if (isAnalyzing)
97
+ return void res.json({ message: "Already scanning..." });
98
+ runAnalysis(false);
99
+ res.json({ message: "Rescan started" });
100
+ });
101
+ app.post("/api/rescan/full", (_req, res) => {
102
+ if (isAnalyzing)
103
+ return void res.json({ message: "Already scanning..." });
104
+ runAnalysis(true);
105
+ res.json({ message: "Full rescan started" });
106
+ });
107
+ app.get("*", (_req, res) => {
108
+ res.sendFile(path.join(__dirname, "public", "index.html"));
109
+ });
110
+ return new Promise((resolve) => {
111
+ const server = app.listen(port, () => {
112
+ resolve({ server, port, url: `http://localhost:${port}` });
113
+ });
114
+ });
115
+ }
116
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ export interface FileEntry {
2
+ path: string;
3
+ content: string;
4
+ }
5
+ export interface FileHash {
6
+ hash: string;
7
+ }
8
+ export interface SpecStore {
9
+ spec: ApiSpec;
10
+ hashes: Record<string, FileHash>;
11
+ lastScan: string;
12
+ }
13
+ export interface ApiSpec {
14
+ projectName: string;
15
+ baseUrl: string;
16
+ version: string;
17
+ description: string;
18
+ collections: Collection[];
19
+ }
20
+ export interface Collection {
21
+ name: string;
22
+ description: string;
23
+ endpoints: Endpoint[];
24
+ }
25
+ export interface Endpoint {
26
+ id: string;
27
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
28
+ path: string;
29
+ summary: string;
30
+ description: string;
31
+ requiresAuth: boolean;
32
+ pathParams: Param[];
33
+ queryParams: Param[];
34
+ requestBody?: RequestBody;
35
+ responses: Record<string, ResponseDef>;
36
+ }
37
+ export interface Param {
38
+ name: string;
39
+ type: string;
40
+ description: string;
41
+ example: string | number;
42
+ }
43
+ export interface RequestBody {
44
+ contentType: string;
45
+ schema: Record<string, FieldDef>;
46
+ }
47
+ export interface FieldDef {
48
+ type: string;
49
+ example: unknown;
50
+ required: boolean;
51
+ description: string;
52
+ }
53
+ export interface ResponseDef {
54
+ description: string;
55
+ example?: unknown;
56
+ }
57
+ export interface DiffResult {
58
+ newFiles: FileEntry[];
59
+ changedFiles: FileEntry[];
60
+ removedFiles: string[];
61
+ unchanged: FileEntry[];
62
+ newHashes: Record<string, FileHash>;
63
+ }
64
+ export declare function loadStore(projectDir: string): SpecStore | null;
65
+ export declare function saveStore(projectDir: string, data: SpecStore): void;
66
+ /**
67
+ * Compare new scan against stored file hashes.
68
+ * Returns:
69
+ * - newFiles : files that didn't exist before
70
+ * - changedFiles: files whose content changed
71
+ * - removedFiles: files that no longer exist
72
+ * - unchanged : everything else
73
+ */
74
+ export declare function diffScan(storedHashes: Record<string, FileHash> | undefined, currentFiles: FileEntry[]): DiffResult;
75
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,KAAK,EAAE,CAAC;IACpB,WAAW,EAAE,KAAK,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,YAAY,EAAE,SAAS,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CACrC;AAcD,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAQ9D;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAQnE;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,YAAK,EAC3C,YAAY,EAAE,SAAS,EAAE,GACxB,UAAU,CA8BZ"}
package/dist/store.js ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Persistent spec store — saves to .dinorex/spec.json in the user's project.
3
+ * Tracks which files have been seen so we can detect new/changed routes.
4
+ */
5
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
6
+ import path from "path";
7
+ import crypto from "crypto";
8
+ function storePath(projectDir) {
9
+ return path.join(projectDir, ".dinorex");
10
+ }
11
+ function specFile(projectDir) {
12
+ return path.join(storePath(projectDir), "spec.json");
13
+ }
14
+ function hashContent(content) {
15
+ return crypto.createHash("md5").update(content).digest("hex");
16
+ }
17
+ export function loadStore(projectDir) {
18
+ const file = specFile(projectDir);
19
+ if (!existsSync(file))
20
+ return null;
21
+ try {
22
+ return JSON.parse(readFileSync(file, "utf-8"));
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ export function saveStore(projectDir, data) {
29
+ const dir = storePath(projectDir);
30
+ mkdirSync(dir, { recursive: true });
31
+ const gi = path.join(dir, ".gitignore");
32
+ if (!existsSync(gi))
33
+ writeFileSync(gi, "*\n");
34
+ writeFileSync(specFile(projectDir), JSON.stringify(data, null, 2));
35
+ }
36
+ /**
37
+ * Compare new scan against stored file hashes.
38
+ * Returns:
39
+ * - newFiles : files that didn't exist before
40
+ * - changedFiles: files whose content changed
41
+ * - removedFiles: files that no longer exist
42
+ * - unchanged : everything else
43
+ */
44
+ export function diffScan(storedHashes = {}, currentFiles) {
45
+ const currentHashes = {};
46
+ for (const f of currentFiles) {
47
+ currentHashes[f.path] = { hash: hashContent(f.content), content: f.content };
48
+ }
49
+ const newFiles = [];
50
+ const changedFiles = [];
51
+ const unchanged = [];
52
+ for (const f of currentFiles) {
53
+ const prev = storedHashes[f.path];
54
+ if (!prev) {
55
+ newFiles.push(f);
56
+ }
57
+ else if (prev.hash !== currentHashes[f.path].hash) {
58
+ changedFiles.push(f);
59
+ }
60
+ else {
61
+ unchanged.push(f);
62
+ }
63
+ }
64
+ const currentPaths = new Set(currentFiles.map((f) => f.path));
65
+ const removedFiles = Object.keys(storedHashes).filter((p) => !currentPaths.has(p));
66
+ const newHashes = {};
67
+ for (const f of currentFiles) {
68
+ newHashes[f.path] = { hash: currentHashes[f.path].hash };
69
+ }
70
+ return { newFiles, changedFiles, removedFiles, unchanged, newHashes };
71
+ }
72
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "dinorex",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "AI-powered API documentation generator — one command, full docs.",
5
- "main": "src/index.js",
6
5
  "type": "module",
6
+ "main": "./dist/cli.js",
7
7
  "bin": {
8
- "dinorex": "src/cli.js"
8
+ "dinorex": "./dist/cli.js"
9
9
  },
10
10
  "scripts": {
11
- "start": "node src/server.js",
12
- "dev": "nodemon src/server.js"
11
+ "build": "tsc && cp -r src/public dist/public",
12
+ "dev": "tsc --watch",
13
+ "start": "node dist/server.js",
14
+ "prepare": "npm run build"
13
15
  },
14
16
  "keywords": [
15
17
  "api",
@@ -25,16 +27,28 @@
25
27
  "dependencies": {
26
28
  "@anthropic-ai/sdk": "^0.20.0",
27
29
  "chalk": "^5.3.0",
30
+ "chokidar": "^3.5.3",
28
31
  "commander": "^11.1.0",
29
32
  "cors": "^2.8.5",
30
33
  "express": "^4.18.2",
31
34
  "glob": "^10.3.10",
32
35
  "js-yaml": "^4.1.0",
33
36
  "multer": "^1.4.5-lts.1",
34
- "ora": "^7.0.1",
35
- "chokidar": "^3.5.3"
37
+ "ora": "^7.0.1"
38
+ },
39
+ "devDependencies": {
40
+ "@types/cors": "^2.8.17",
41
+ "@types/express": "^4.17.21",
42
+ "@types/js-yaml": "^4.0.9",
43
+ "@types/multer": "^1.4.11",
44
+ "@types/node": "^20.11.0",
45
+ "typescript": "^5.3.3"
36
46
  },
37
47
  "engines": {
38
48
  "node": ">=18.0.0"
39
- }
49
+ },
50
+ "files": [
51
+ "dist",
52
+ "src/public"
53
+ ]
40
54
  }