botversion-sdk 1.0.4 → 1.0.6

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/cli/detector.js CHANGED
@@ -356,7 +356,7 @@ function detectMonorepo(cwd) {
356
356
 
357
357
  // ─── FRAMEWORK DETECTION ─────────────────────────────────────────────────────
358
358
 
359
- const SUPPORTED_FRAMEWORKS = ["express", "next"];
359
+ const SUPPORTED_FRAMEWORKS = ["next", "express"];
360
360
  const UNSUPPORTED_FRAMEWORKS = [
361
361
  "fastify",
362
362
  "koa",
@@ -377,6 +377,10 @@ function detectFramework(pkg) {
377
377
  if (deps[fw]) return { name: fw, supported: false };
378
378
  }
379
379
 
380
+ // If BOTH next and express exist, always pick next
381
+ // because express is just being used as a custom server wrapper
382
+ if (deps["next"]) return { name: "next", supported: true };
383
+
380
384
  for (const fw of SUPPORTED_FRAMEWORKS) {
381
385
  if (deps[fw]) return { name: fw, supported: true };
382
386
  }
@@ -462,61 +466,311 @@ function detectNextVersion(pkg) {
462
466
  return { raw: version, major };
463
467
  }
464
468
 
465
- // ─── EXPRESS ENTRY POINT DETECTION ───────────────────────────────────────────
469
+ // ─── SCORING FUNCTIONS ────────────────────────────────────────────────────────
470
+
471
+ function scoreExpressFile(content, filePath) {
472
+ let score = 0;
473
+ const filename = path.basename(filePath);
474
+ const normalizedPath = filePath.replace(/\\/g, "/");
475
+
476
+ // ── EXISTING POSITIVE SIGNALS ──────────────────────────────────
477
+ if (/express\s*\(\s*\)/.test(content)) score += 10;
478
+ if (/class\s+\w+\s+extends\s+express/.test(content)) score += 10;
479
+ if (/(?:function|const|let|var)\s+(create|make|build|setup)App/.test(content))
480
+ score += 8;
481
+ if (/\.listen\s*\(/.test(content)) score += 8;
482
+ if (/\.use\s*\(\s*['"`\/]/.test(content)) score += 5;
483
+ if (/app\.use\s*\(/.test(content)) score += 4;
484
+ if (
485
+ /require\s*\(\s*['"]express['"]\s*\)|from\s+['"]express['"]/.test(content)
486
+ )
487
+ score += 1;
488
+
489
+ // ── NEW POSITIVE SIGNALS — real API server ─────────────────────
490
+ const hasApiRoutes = /\.(get|post|put|delete|patch)\s*\(\s*['"`]\//.test(
491
+ content,
492
+ );
493
+ const returnsJson = /res\.json\s*\(/.test(content);
494
+ const hasRouterFiles = /require\s*\(['"`]\.\/routes/.test(content);
495
+ const hasControllers = /require\s*\(['"`]\.\/controllers/.test(content);
496
+
497
+ if (hasApiRoutes) score += 6;
498
+ if (returnsJson) score += 5;
499
+ if (hasRouterFiles) score += 4;
500
+ if (hasControllers) score += 3;
501
+
502
+ // ── EXISTING PENALTIES ─────────────────────────────────────────
503
+ if (/^(?:const|let|var)\s+router\s*=\s*express\.Router\s*\(/m.test(content))
504
+ score -= 8;
505
+ if (/(test_|_test|\.test\.|\.spec\.|conftest)/.test(filename)) score -= 10;
506
+ if (/dist\/|build\//.test(filePath)) score -= 10;
507
+
508
+ // ── NEW PENALTIES ──────────────────────────────────────────────
509
+
510
+ // Category 1: PHP servers
511
+ if (content.includes("php-express")) score -= 20;
512
+ if (content.includes("phpExpress")) score -= 20;
513
+ if (/app\.engine\s*\(\s*['"]php['"]/.test(content)) score -= 20;
514
+
515
+ // Category 2: View-only servers (any template engine, no API)
516
+ const hasViewEngine = /app\.set\s*\(\s*['"]view engine['"]/.test(content);
517
+ if (hasViewEngine && !hasApiRoutes && !returnsJson) score -= 15;
518
+
519
+ // Category 3: Static-only servers
520
+ const hasStatic = /express\.static\s*\(/.test(content);
521
+ const hasOnlyStatic = hasStatic && !hasApiRoutes && !returnsJson;
522
+ if (hasOnlyStatic) score -= 15;
523
+
524
+ // Category 4: Proxy servers
525
+ if (
526
+ content.includes("http-proxy-middleware") ||
527
+ content.includes("createProxyMiddleware")
528
+ )
529
+ score -= 15;
530
+
531
+ // Category 5: WebSocket-only servers
532
+ const hasSocketIO =
533
+ content.includes("socket.io") || content.includes("new Server(");
534
+ if (hasSocketIO && !hasApiRoutes) score -= 15;
535
+
536
+ // Category 6: Job/Queue servers
537
+ if (
538
+ (content.includes("require('bull')") ||
539
+ content.includes('require("bull")') ||
540
+ content.includes("bullmq") ||
541
+ content.includes("agenda")) &&
542
+ !hasApiRoutes
543
+ )
544
+ score -= 15;
545
+
546
+ // Category 7: Webhook-only servers
547
+ const hasWebhook = /['"`]\/webhook['"`]/.test(content);
548
+ const onlyWebhook = hasWebhook && !hasApiRoutes;
549
+ if (onlyWebhook) score -= 10;
550
+
551
+ // Category 8: Dev tooling servers
552
+ if (
553
+ content.includes("webpack-dev-middleware") ||
554
+ content.includes("webpackDevMiddleware") ||
555
+ content.includes("storybook")
556
+ )
557
+ score -= 15;
558
+
559
+ // Category 9: Test/mock servers (path-based)
560
+ if (/__mocks__|fixtures\/|test\/|__tests__\//.test(normalizedPath))
561
+ score -= 15;
562
+
563
+ // ── FILENAME BONUSES ───────────────────────────────────────────
564
+ if (["server.js", "server.ts", "app.js", "app.ts"].includes(filename))
565
+ score += 3;
566
+ if (["index.js", "index.ts", "main.js", "main.ts"].includes(filename))
567
+ score += 2;
568
+
569
+ return score;
570
+ }
571
+
572
+ // ─── PARSE ENTRY FROM CONFIG FILES ───────────────────────────────────────────
573
+
574
+ function parseEntryFromConfigFiles(cwd) {
575
+ /**
576
+ * Extracts likely entry point from Procfile or Dockerfile.
577
+ * Covers patterns like:
578
+ * Procfile: web: node server.js
579
+ * Procfile: web: nodemon src/index.js
580
+ * Dockerfile: CMD ["node", "server.js"]
581
+ * Dockerfile: CMD ["nodemon", "src/index.js"]
582
+ */
583
+
584
+ function resolveFile(cwd, filePath) {
585
+ const full = path.join(cwd, filePath);
586
+ if (fs.existsSync(full)) return full;
587
+ return null;
588
+ }
589
+
590
+ // ── 1. Check Procfile ─────────────────────────────────────────────────────
591
+ const procfilePath = path.join(cwd, "Procfile");
592
+ if (fs.existsSync(procfilePath)) {
593
+ try {
594
+ const lines = fs.readFileSync(procfilePath, "utf8").split("\n");
595
+ for (const line of lines) {
596
+ if (!line.trim() || line.startsWith("#")) continue;
597
+
598
+ // node/nodemon/ts-node/tsx server.js or src/index.ts
599
+ const match = line.match(
600
+ /(?:node|nodemon|ts-node|ts-node-dev|tsx)\s+([\w./\\-]+\.[jt]s)/,
601
+ );
602
+ if (match) {
603
+ const result = resolveFile(cwd, match[1]);
604
+ if (result) return result;
605
+ }
606
+ }
607
+ } catch {}
608
+ }
609
+
610
+ // ── 2. Check Dockerfile ───────────────────────────────────────────────────
611
+ const dockerfilePath = path.join(cwd, "Dockerfile");
612
+ if (fs.existsSync(dockerfilePath)) {
613
+ try {
614
+ const lines = fs.readFileSync(dockerfilePath, "utf8").split("\n");
615
+ for (const line of lines) {
616
+ if (!line.trim() || line.startsWith("#")) continue;
617
+
618
+ // CMD ["node", "server.js"]
619
+ // CMD ["nodemon", "src/index.js"]
620
+ const cmdMatch = line.match(
621
+ /(?:CMD|ENTRYPOINT)\s*\[.*?"(?:node|nodemon|ts-node|tsx)",\s*"([\w./\\-]+\.[jt]s)"/,
622
+ );
623
+ if (cmdMatch) {
624
+ const result = resolveFile(cwd, cmdMatch[1]);
625
+ if (result) return result;
626
+ }
627
+
628
+ // CMD node server.js (shell form)
629
+ const shellMatch = line.match(
630
+ /(?:CMD|ENTRYPOINT)\s+(?:node|nodemon|ts-node|tsx)\s+([\w./\\-]+\.[jt]s)/,
631
+ );
632
+ if (shellMatch) {
633
+ const result = resolveFile(cwd, shellMatch[1]);
634
+ if (result) return result;
635
+ }
636
+ }
637
+ } catch {}
638
+ }
639
+
640
+ return null;
641
+ }
466
642
 
467
643
  function detectExpressEntry(cwd, pkg) {
468
- // Strategy 1: "main" field in package.json
644
+ const SKIP_ENTRY_DIRS = ["dist", "build", "out", ".next", "coverage"];
645
+
646
+ function isCompiledPath(filePath) {
647
+ const normalized = filePath.replace(/\\/g, "/");
648
+ return SKIP_ENTRY_DIRS.some(
649
+ (dir) =>
650
+ normalized.includes(`/${dir}/`) ||
651
+ normalized.endsWith(`/${dir}`) ||
652
+ normalized.startsWith(`${dir}/`),
653
+ );
654
+ }
655
+
656
+ // ── Strategy 1: package.json "main" field ─────────────────────────────────
469
657
  if (pkg && pkg.main) {
470
658
  const mainPath = path.join(cwd, pkg.main);
471
- if (fs.existsSync(mainPath)) return mainPath;
659
+ if (fs.existsSync(mainPath) && !isCompiledPath(pkg.main)) {
660
+ return mainPath;
661
+ }
472
662
  }
473
663
 
474
- // Strategy 2: scripts.start / scripts.dev
664
+ // ── Strategy 2: scripts.start / scripts.dev ───────────────────────────────
475
665
  if (pkg && pkg.scripts) {
476
- const scripts = [pkg.scripts.start, pkg.scripts.dev, pkg.scripts.serve];
666
+ const scripts = [
667
+ pkg.scripts.dev,
668
+ pkg.scripts.serve,
669
+ pkg.scripts["dev-server"],
670
+ pkg.scripts.start,
671
+ ];
672
+ for (const script of scripts) {
673
+ if (!script) continue;
674
+ const match = script.match(
675
+ /(?:node|nodemon|ts-node|ts-node-dev|tsx)\s+([^\s]+\.(js|ts))/,
676
+ );
677
+ if (match) {
678
+ const scriptPath = match[1];
679
+ if (isCompiledPath(scriptPath)) continue;
680
+ const filePath = path.join(cwd, scriptPath);
681
+ if (fs.existsSync(filePath)) return filePath;
682
+ }
683
+ }
684
+
685
+ // Strategy 2b: compiled path fallback — find TS source equivalent
477
686
  for (const script of scripts) {
478
687
  if (!script) continue;
479
688
  const match = script.match(
480
- /(?:node|nodemon|ts-node|tsx)\s+([^\s]+\.(js|ts))/,
689
+ /(?:node|nodemon|ts-node|ts-node-dev|tsx)\s+([^\s]+\.(js|ts))/,
481
690
  );
482
691
  if (match) {
483
- const filePath = path.join(cwd, match[1]);
692
+ const tsEquivalent = match[1]
693
+ .replace(/^backend\/dist\//, "backend/")
694
+ .replace(/^dist\//, "")
695
+ .replace(/\.js$/, ".ts");
696
+ const filePath = path.join(cwd, tsEquivalent);
484
697
  if (fs.existsSync(filePath)) return filePath;
485
698
  }
486
699
  }
487
700
  }
488
701
 
489
- // Strategy 3: common file names
490
- const candidates = [
491
- "server.js",
492
- "server.ts",
493
- "index.js",
494
- "index.ts",
495
- "app.js",
496
- "app.ts",
497
- "main.js",
498
- "main.ts",
499
- "src/server.js",
500
- "src/server.ts",
501
- "src/index.js",
502
- "src/index.ts",
503
- "src/app.js",
504
- "src/app.ts",
505
- "src/main.js",
506
- "src/main.ts",
507
- ];
702
+ // ── Strategy 3: Scoring — scan all JS/TS files ────────────────────────────
703
+ const skipDirs = new Set([
704
+ ...SKIP_DIRS,
705
+ "dist",
706
+ "build",
707
+ "out",
708
+ "coverage",
709
+ "tests",
710
+ "test",
711
+ "__tests__",
712
+ "scripts",
713
+ "docs",
714
+ ]);
715
+
716
+ const scoredCandidates = [];
717
+
718
+ function walk(directory, depth) {
719
+ if (depth > 3) return;
720
+ let entries;
721
+ try {
722
+ entries = fs.readdirSync(directory);
723
+ } catch {
724
+ return;
725
+ }
726
+
727
+ for (const entry of entries) {
728
+ if (skipDirs.has(entry) || entry.startsWith(".")) continue;
729
+
730
+ const fullPath = path.join(directory, entry);
731
+ let stat;
732
+ try {
733
+ stat = fs.statSync(fullPath);
734
+ } catch {
735
+ continue;
736
+ }
508
737
 
509
- for (const candidate of candidates) {
510
- const filePath = path.join(cwd, candidate);
511
- if (fs.existsSync(filePath)) {
512
- const content = fs.readFileSync(filePath, "utf8");
513
- if (content.includes("express") || content.includes("app.listen")) {
514
- return filePath;
738
+ if (stat.isDirectory()) {
739
+ walk(fullPath, depth + 1);
740
+ } else if (/\.(js|ts)$/.test(entry) && !/\.d\.ts$/.test(entry)) {
741
+ try {
742
+ const content = fs.readFileSync(fullPath, "utf8");
743
+ const score = scoreExpressFile(content, fullPath);
744
+ if (score > 0) {
745
+ scoredCandidates.push({ score, filePath: fullPath });
746
+ }
747
+ } catch {
748
+ continue;
749
+ }
515
750
  }
516
751
  }
517
752
  }
518
753
 
519
- // Strategy 4: any .js/.ts file containing app.listen()
754
+ walk(cwd, 0);
755
+
756
+ if (scoredCandidates.length > 0) {
757
+ scoredCandidates.sort((a, b) => b.score - a.score);
758
+ const best = scoredCandidates[0];
759
+
760
+ // If best score is weak, cross-check with Procfile/Dockerfile
761
+ if (best.score <= 3) {
762
+ const configEntry = parseEntryFromConfigFiles(cwd);
763
+ if (configEntry) return configEntry;
764
+ }
765
+
766
+ return best.filePath;
767
+ }
768
+
769
+ // ── Strategy 4: Procfile/Dockerfile fallback ──────────────────────────────
770
+ const configEntry = parseEntryFromConfigFiles(cwd);
771
+ if (configEntry) return configEntry;
772
+
773
+ // ── Strategy 5: Last resort deep scan ────────────────────────────────────
520
774
  return findFileWithContent(cwd, ".listen(", [".js", ".ts"], 2);
521
775
  }
522
776
 
@@ -575,136 +829,6 @@ function findCreateServer(filePath) {
575
829
  return null;
576
830
  }
577
831
 
578
- // ─── AUTH DETECTION ──────────────────────────────────────────────────────────
579
-
580
- const AUTH_LIBS = [
581
- {
582
- name: "next-auth",
583
- packages: ["next-auth"],
584
- detect: (deps) => !!deps["next-auth"],
585
- getVersion: (deps) => {
586
- const v = deps["next-auth"] || "";
587
- const major = parseInt(v.replace(/[^0-9]/, ""), 10);
588
- return major >= 5 ? "v5" : "v4";
589
- },
590
- },
591
- {
592
- name: "clerk",
593
- packages: ["@clerk/nextjs", "@clerk/clerk-sdk-node", "@clerk/express"],
594
- detect: (deps) =>
595
- !!deps["@clerk/nextjs"] ||
596
- !!deps["@clerk/clerk-sdk-node"] ||
597
- !!deps["@clerk/express"],
598
- getPackage: (deps) =>
599
- deps["@clerk/nextjs"]
600
- ? "@clerk/nextjs"
601
- : deps["@clerk/express"]
602
- ? "@clerk/express"
603
- : "@clerk/clerk-sdk-node",
604
- },
605
- {
606
- name: "supabase",
607
- packages: ["@supabase/supabase-js", "@supabase/ssr"],
608
- detect: (deps) =>
609
- !!deps["@supabase/supabase-js"] || !!deps["@supabase/ssr"],
610
- },
611
- {
612
- name: "passport",
613
- packages: ["passport"],
614
- detect: (deps) => !!deps["passport"],
615
- },
616
- {
617
- name: "lucia",
618
- packages: ["lucia"],
619
- detect: (deps) => !!deps["lucia"],
620
- },
621
- {
622
- name: "auth0",
623
- packages: ["@auth0/nextjs-auth0", "express-openid-connect"],
624
- detect: (deps) =>
625
- !!deps["@auth0/nextjs-auth0"] || !!deps["express-openid-connect"],
626
- },
627
- {
628
- name: "firebase",
629
- packages: ["firebase-admin", "firebase"],
630
- detect: (deps) => !!deps["firebase-admin"] || !!deps["firebase"],
631
- },
632
- {
633
- name: "jwt",
634
- packages: ["jsonwebtoken"],
635
- detect: (deps) => !!deps["jsonwebtoken"],
636
- },
637
- {
638
- name: "express-session",
639
- packages: ["express-session"],
640
- detect: (deps) => !!deps["express-session"],
641
- },
642
- ];
643
-
644
- function detectAuth(pkg) {
645
- if (!pkg) return { name: null, supported: false };
646
-
647
- const deps = {
648
- ...(pkg.dependencies || {}),
649
- ...(pkg.devDependencies || {}),
650
- };
651
-
652
- for (const lib of AUTH_LIBS) {
653
- if (lib.detect(deps)) {
654
- const version = lib.getVersion ? lib.getVersion(deps) : null;
655
- const pkg2 = lib.getPackage ? lib.getPackage(deps) : lib.packages[0];
656
- const supported = [
657
- "next-auth",
658
- "clerk",
659
- "supabase",
660
- "passport",
661
- "jwt",
662
- "express-session",
663
- ].includes(lib.name);
664
- return { name: lib.name, version, package: pkg2, supported };
665
- }
666
- }
667
-
668
- return { name: null, supported: false };
669
- }
670
-
671
- // ─── NEXT-AUTH CONFIG LOCATION ───────────────────────────────────────────────
672
-
673
- function findNextAuthConfig(cwd) {
674
- const candidates = [
675
- "pages/api/auth/[...nextauth].js",
676
- "pages/api/auth/[...nextauth].ts",
677
- "app/api/auth/[...nextauth]/route.js",
678
- "app/api/auth/[...nextauth]/route.ts",
679
- "src/pages/api/auth/[...nextauth].js",
680
- "src/pages/api/auth/[...nextauth].ts",
681
- "src/app/api/auth/[...nextauth]/route.js",
682
- "src/app/api/auth/[...nextauth]/route.ts",
683
- "lib/auth.js",
684
- "lib/auth.ts",
685
- "lib/authOptions.js",
686
- "lib/authOptions.ts",
687
- "utils/auth.js",
688
- "utils/auth.ts",
689
- "auth.js",
690
- "auth.ts",
691
- ];
692
-
693
- for (const candidate of candidates) {
694
- const fullPath = path.join(cwd, candidate);
695
- if (fs.existsSync(fullPath)) {
696
- return { path: fullPath, relativePath: candidate };
697
- }
698
- }
699
-
700
- const found = findFileWithContent(cwd, "authOptions", [".js", ".ts"], 3);
701
- if (found) {
702
- return { path: found, relativePath: path.relative(cwd, found) };
703
- }
704
-
705
- return null;
706
- }
707
-
708
832
  // ─── PACKAGE MANAGER DETECTION ───────────────────────────────────────────────
709
833
 
710
834
  function detectPackageManager(cwd) {
@@ -770,13 +894,79 @@ function findFileWithContent(dir, searchString, extensions, maxDepth) {
770
894
  function detectAppVarName(filePath) {
771
895
  try {
772
896
  const content = fs.readFileSync(filePath, "utf8");
773
- const match = content.match(/(?:const|let|var)\s+(\w+)\s*=\s*express\s*\(/);
774
- return match ? match[1] : "app";
897
+
898
+ // Pattern 1: const app = express()
899
+ const match1 = content.match(
900
+ /(?:const|let|var)\s+(\w+)\s*=\s*express\s*\(/,
901
+ );
902
+ if (match1) return match1[1];
903
+
904
+ // Pattern 2: const app = require('express')()
905
+ const match2 = content.match(
906
+ /(?:const|let|var)\s+(\w+)\s*=\s*require\s*\(\s*['"]express['"]\s*\)\s*\(/,
907
+ );
908
+ if (match2) return match2[1];
909
+
910
+ // Pattern 3: factory function — createApp(), makeApp() etc.
911
+ // const app = createApp()
912
+ const match3 = content.match(
913
+ /(?:const|let|var)\s+(\w+)\s*=\s*(?:create|make|build|setup)App\s*\(/,
914
+ );
915
+ if (match3) return match3[1];
916
+
917
+ // Pattern 4: subclass — class MyApp extends express
918
+ // const app = new MyApp()
919
+ const subclassNames = [
920
+ ...content.matchAll(/class\s+(\w+)\s+extends\s+express/g),
921
+ ].map((m) => m[1]);
922
+ for (const name of subclassNames) {
923
+ const subMatch = content.match(
924
+ new RegExp(`(?:const|let|var)\\s+(\\w+)\\s*=\\s*new\\s+${name}\\s*\\(`),
925
+ );
926
+ if (subMatch) return subMatch[1];
927
+ }
928
+
929
+ // Pattern 5: const server = app.listen( → return "app"
930
+ const match5 = content.match(
931
+ /(?:const|let|var)\s+(\w+)\s*=\s*(\w+)\.listen\s*\(/,
932
+ );
933
+ if (match5) return match5[2];
934
+
935
+ // Pattern 6: app.listen( or server.listen(
936
+ const match6 = content.match(
937
+ /\b(app|server|router|handler|httpServer)\s*\.listen\s*\(/,
938
+ );
939
+ if (match6) return match6[1];
940
+
941
+ return "app";
775
942
  } catch {
776
943
  return "app";
777
944
  }
778
945
  }
779
946
 
947
+ function detectDotenv(cwd, pkg, entryPoint) {
948
+ // Check if dotenv is in dependencies
949
+ const deps = {
950
+ ...(pkg.dependencies || {}),
951
+ ...(pkg.devDependencies || {}),
952
+ };
953
+ const hasDotenvPackage = !!deps["dotenv"];
954
+
955
+ // Check if dotenv is actually being called in entry file
956
+ let hasDotenvCall = false;
957
+ if (entryPoint && fs.existsSync(entryPoint)) {
958
+ try {
959
+ const content = fs.readFileSync(entryPoint, "utf8");
960
+ hasDotenvCall =
961
+ content.includes("dotenv") ||
962
+ content.includes("require('dotenv')") ||
963
+ content.includes('require("dotenv")');
964
+ } catch {}
965
+ }
966
+
967
+ return hasDotenvPackage || hasDotenvCall;
968
+ }
969
+
780
970
  // ─── MAIN DETECT FUNCTION ────────────────────────────────────────────────────
781
971
 
782
972
  function detect(cwd) {
@@ -843,7 +1033,6 @@ function detect(cwd) {
843
1033
  const moduleSystem = detectModuleSystem(backendPkg);
844
1034
  const isTypeScript = detectTypeScript(backendDir);
845
1035
  const hasSrc = detectSrcDir(backendDir);
846
- const auth = detectAuth(backendPkg);
847
1036
  const generateTs = shouldGenerateTs(backendDir, isTypeScript);
848
1037
 
849
1038
  // ── Find frontend main file ───────────────────────────────────────────────
@@ -872,7 +1061,6 @@ function detect(cwd) {
872
1061
  isTypeScript,
873
1062
  generateTs,
874
1063
  hasSrc,
875
- auth,
876
1064
  packageManager,
877
1065
  ext: generateTs ? ".ts" : ".js",
878
1066
  // Frontend info
@@ -885,13 +1073,11 @@ function detect(cwd) {
885
1073
  if (framework.name === "next") {
886
1074
  result.next = detectNextRouter(backendDir);
887
1075
  result.nextVersion = detectNextVersion(backendPkg);
888
- if (auth.name === "next-auth") {
889
- result.nextAuthConfig = findNextAuthConfig(backendDir);
890
- }
891
1076
  }
892
1077
 
893
1078
  if (framework.name === "express") {
894
1079
  result.entryPoint = detectExpressEntry(backendDir, backendPkg);
1080
+ result.hasDotenv = detectDotenv(backendDir, backendPkg, result.entryPoint);
895
1081
  if (result.entryPoint) {
896
1082
  result.appVarName = detectAppVarName(result.entryPoint); // detect FIRST
897
1083
  result.listenCall = findListenCall(result.entryPoint, result.appVarName);
@@ -949,8 +1135,6 @@ module.exports = {
949
1135
  shouldGenerateTs,
950
1136
  detectSrcDir,
951
1137
  detectNextRouter,
952
- detectAuth,
953
- findNextAuthConfig,
954
1138
  detectPackageManager,
955
1139
  detectExistingBotVersion,
956
1140
  findFileWithContent,
@@ -959,4 +1143,7 @@ module.exports = {
959
1143
  findListenInsideCallback,
960
1144
  findCreateServer,
961
1145
  detectAppVarName,
1146
+ detectDotenv,
1147
+ parseEntryFromConfigFiles,
1148
+ scoreExpressFile,
962
1149
  };