@launchsecure/launch-kit 0.0.18 → 0.0.19
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/dist/chart-client/assets/index-C8ANseEa.js +441 -0
- package/dist/chart-client/index.html +1 -1
- package/dist/deck-client/assets/{_baseUniq-2gclQXo7.js → _baseUniq-DsfOm3t_.js} +1 -1
- package/dist/deck-client/assets/{arc-DcMY5Wm0.js → arc-NJuvkBv1.js} +1 -1
- package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-B8iirmmJ.js → architectureDiagram-Q4EWVU46-BgrcgZs0.js} +1 -1
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-B4JBLjmJ.js → blockDiagram-DXYQGD6D-C3XoLi15.js} +1 -1
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-CojrJAk8.js → c4Diagram-AHTNJAMY-FX2PjLfb.js} +1 -1
- package/dist/deck-client/assets/channel-ChQjD1T1.js +1 -0
- package/dist/deck-client/assets/{chunk-4BX2VUAB-Bmb_BMDo.js → chunk-4BX2VUAB-D0aqsJV0.js} +1 -1
- package/dist/deck-client/assets/{chunk-4TB4RGXK-CumBy8qe.js → chunk-4TB4RGXK-7qRCCAgK.js} +1 -1
- package/dist/deck-client/assets/{chunk-55IACEB6-Ka8Hb1wD.js → chunk-55IACEB6-DfHG-iqb.js} +1 -1
- package/dist/deck-client/assets/{chunk-EDXVE4YY-B3sIPiQo.js → chunk-EDXVE4YY-DrR52j3B.js} +1 -1
- package/dist/deck-client/assets/{chunk-FMBD7UC4-C1tYkaqu.js → chunk-FMBD7UC4-D5KSGATB.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-D7Wacbky.js → chunk-OYMX7WX6-M7hsLRNU.js} +1 -1
- package/dist/deck-client/assets/{chunk-QZHKN3VN-ChXI0vO3.js → chunk-QZHKN3VN-1ynAWO2m.js} +1 -1
- package/dist/deck-client/assets/{chunk-YZCP3GAM-BXhiqf8u.js → chunk-YZCP3GAM-S2-nGw3D.js} +1 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-B_9iqK1S.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-B_9iqK1S.js +1 -0
- package/dist/deck-client/assets/clone-BYt1AMfz.js +1 -0
- package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-Bqp3p68D.js → cose-bilkent-S5V4N54A-BcMwozS2.js} +1 -1
- package/dist/deck-client/assets/{dagre-KV5264BT-BS-rtyhZ.js → dagre-KV5264BT-DtKMhl_1.js} +1 -1
- package/dist/deck-client/assets/{diagram-5BDNPKRD-BIrj9YGI.js → diagram-5BDNPKRD-1plH69us.js} +1 -1
- package/dist/deck-client/assets/{diagram-G4DWMVQ6-noHWPIg4.js → diagram-G4DWMVQ6-D_o-BHO3.js} +1 -1
- package/dist/deck-client/assets/{diagram-MMDJMWI5-C2qHxvqV.js → diagram-MMDJMWI5-ClZ1LIx6.js} +1 -1
- package/dist/deck-client/assets/{diagram-TYMM5635-BytnGQr-.js → diagram-TYMM5635-B8dKHfRh.js} +1 -1
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-BfK5m2YQ.js → erDiagram-SMLLAGMA-CY2aCH7-.js} +1 -1
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-Cq925G1Z.js → flowDiagram-DWJPFMVM-DZZWHti8.js} +1 -1
- package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-DhhHPAmj.js → ganttDiagram-T4ZO3ILL-OwGGa6Lu.js} +1 -1
- package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-B3Lc0h9q.js → gitGraphDiagram-UUTBAWPF-GKyWD4Qt.js} +1 -1
- package/dist/deck-client/assets/{graph-RTawgVWm.js → graph-CORzYQdB.js} +1 -1
- package/dist/deck-client/assets/{index-BfIfJXmS.js → index-hiIpM7EP.js} +3 -3
- package/dist/deck-client/assets/{infoDiagram-42DDH7IO-BlR584kX.js → infoDiagram-42DDH7IO-DmgqJCcF.js} +1 -1
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DygKoNGY.js → ishikawaDiagram-UXIWVN3A-D-1v7knu.js} +1 -1
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-BnaiYp9N.js → journeyDiagram-VCZTEJTY-CYrGQE7b.js} +1 -1
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-BQBUBzJC.js → kanban-definition-6JOO6SKY-BJFDWiH-.js} +1 -1
- package/dist/deck-client/assets/{layout-DeZ8HI1T.js → layout-BTFFcaxF.js} +1 -1
- package/dist/deck-client/assets/{linear-C6roLi_9.js → linear-DAbl6COS.js} +1 -1
- package/dist/deck-client/assets/{min-CbUksbuI.js → min-oWHBrFBm.js} +1 -1
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-iNxV62yN.js → mindmap-definition-QFDTVHPH-BTCB0VLO.js} +1 -1
- package/dist/deck-client/assets/{pieDiagram-DEJITSTG-DHVA0jaG.js → pieDiagram-DEJITSTG-CUZChWNA.js} +1 -1
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-DBeKKLUQ.js → quadrantDiagram-34T5L4WZ-4M1Um_e4.js} +1 -1
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-CBwITx7p.js → requirementDiagram-MS252O5E-DLzQZ0B3.js} +1 -1
- package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BtE-1YTU.js → sankeyDiagram-XADWPNL6-DcNgzV3E.js} +1 -1
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-DN96yPP2.js → sequenceDiagram-FGHM5R23-CAcI2vC9.js} +1 -1
- package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-VUkKC2uJ.js → stateDiagram-FHFEXIEX-CntjTTm5.js} +1 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-YiaphOU_.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-oUeZhRns.js → timeline-definition-GMOUNBTQ-D8zrit4U.js} +1 -1
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-D87fK90n.js → vennDiagram-DHZGUBPP-C4SuFPgo.js} +1 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-B3F-Olcq.js +162 -0
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-Ca_i0QRA.js → wardleyDiagram-NUSXRM2D-kj73r6f-.js} +1 -1
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CUOJVIvq.js → xychartDiagram-5P7HB3ND-CC_d_Ey3.js} +1 -1
- package/dist/deck-client/index.html +1 -1
- package/dist/server/chart-serve.js +392 -169
- package/dist/server/cli.js +384 -168
- package/dist/server/council-entry.js +0 -0
- package/dist/server/deck-server/deck-mcp-entry.js +0 -0
- package/dist/server/fb-wizard.js +0 -0
- package/dist/server/graph-mcp-entry.js +430 -206
- package/dist/server/server/cli.js +0 -0
- package/dist/server/server/fb-wizard.js +0 -0
- package/dist/server/server/graph-mcp-entry.js +0 -0
- package/package.json +18 -17
- package/dist/chart-client/assets/index-D7x8nz-H.js +0 -441
- package/dist/deck-client/assets/channel-ERh5jKXV.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CMi1Gaev.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CMi1Gaev.js +0 -1
- package/dist/deck-client/assets/clone-DfWhlD4X.js +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CA0IjulK.js +0 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-DYbYcpDp.js +0 -162
|
@@ -602,19 +602,19 @@ __export(chart_serve_exports, {
|
|
|
602
602
|
module.exports = __toCommonJS(chart_serve_exports);
|
|
603
603
|
var import_node_http = __toESM(require("node:http"));
|
|
604
604
|
var import_node_fs18 = __toESM(require("node:fs"));
|
|
605
|
-
var
|
|
605
|
+
var import_node_path19 = __toESM(require("node:path"));
|
|
606
606
|
|
|
607
607
|
// src/server/graph/index.ts
|
|
608
608
|
var import_node_fs15 = require("node:fs");
|
|
609
|
-
var
|
|
609
|
+
var import_node_path16 = require("node:path");
|
|
610
610
|
|
|
611
611
|
// src/server/graph/core/graph-builder.ts
|
|
612
612
|
var import_node_fs12 = require("node:fs");
|
|
613
|
-
var
|
|
613
|
+
var import_node_path12 = require("node:path");
|
|
614
614
|
init_config();
|
|
615
615
|
|
|
616
616
|
// src/server/graph/core/parser-registry.ts
|
|
617
|
-
var
|
|
617
|
+
var import_node_path11 = require("node:path");
|
|
618
618
|
|
|
619
619
|
// src/server/graph/parsers/ts/typescript-project.ts
|
|
620
620
|
var import_node_fs5 = require("node:fs");
|
|
@@ -622,35 +622,12 @@ var import_node_path5 = require("node:path");
|
|
|
622
622
|
init_config();
|
|
623
623
|
|
|
624
624
|
// src/server/graph/core/resolve-paths.ts
|
|
625
|
-
var import_node_fs2 = require("node:fs");
|
|
626
|
-
var import_node_path2 = require("node:path");
|
|
627
|
-
function detectDbDir(rootDir, config) {
|
|
628
|
-
if (config.paths?.dbDir) return (0, import_node_path2.join)(rootDir, config.paths.dbDir);
|
|
629
|
-
const prismaDir = (0, import_node_path2.join)(rootDir, "prisma");
|
|
630
|
-
if ((0, import_node_fs2.existsSync)(prismaDir)) return prismaDir;
|
|
631
|
-
return null;
|
|
632
|
-
}
|
|
633
|
-
function resolveProjectPaths(rootDir, config) {
|
|
634
|
-
const dbDir = detectDbDir(rootDir, config);
|
|
635
|
-
if (config.paths?.appDir) {
|
|
636
|
-
const appDir = (0, import_node_path2.join)(rootDir, config.paths.appDir);
|
|
637
|
-
const srcDir = config.paths.srcDir ? (0, import_node_path2.join)(rootDir, config.paths.srcDir) : (0, import_node_path2.dirname)(appDir);
|
|
638
|
-
return { srcDir, appDir, apiDir: (0, import_node_path2.join)(appDir, "api"), dbDir };
|
|
639
|
-
}
|
|
640
|
-
const srcApp = (0, import_node_path2.join)(rootDir, "src", "app");
|
|
641
|
-
if ((0, import_node_fs2.existsSync)(srcApp)) {
|
|
642
|
-
return { srcDir: (0, import_node_path2.join)(rootDir, "src"), appDir: srcApp, apiDir: (0, import_node_path2.join)(srcApp, "api"), dbDir };
|
|
643
|
-
}
|
|
644
|
-
const rootApp = (0, import_node_path2.join)(rootDir, "app");
|
|
645
|
-
if ((0, import_node_fs2.existsSync)(rootApp)) {
|
|
646
|
-
return { srcDir: rootDir, appDir: rootApp, apiDir: (0, import_node_path2.join)(rootApp, "api"), dbDir };
|
|
647
|
-
}
|
|
648
|
-
return null;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// src/server/graph/core/walk.ts
|
|
652
625
|
var import_node_fs3 = require("node:fs");
|
|
653
626
|
var import_node_path3 = require("node:path");
|
|
627
|
+
|
|
628
|
+
// src/server/graph/core/walk.ts
|
|
629
|
+
var import_node_fs2 = require("node:fs");
|
|
630
|
+
var import_node_path2 = require("node:path");
|
|
654
631
|
var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
655
632
|
"node_modules",
|
|
656
633
|
".git",
|
|
@@ -666,12 +643,12 @@ var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
|
666
643
|
]);
|
|
667
644
|
function walk(dir, exts) {
|
|
668
645
|
const results = [];
|
|
669
|
-
if (!(0,
|
|
670
|
-
for (const entry of (0,
|
|
671
|
-
const full = (0,
|
|
646
|
+
if (!(0, import_node_fs2.existsSync)(dir)) return results;
|
|
647
|
+
for (const entry of (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true })) {
|
|
648
|
+
const full = (0, import_node_path2.join)(dir, entry.name);
|
|
672
649
|
if (entry.isDirectory()) {
|
|
673
650
|
results.push(...walk(full, exts));
|
|
674
|
-
} else if (exts.includes((0,
|
|
651
|
+
} else if (exts.includes((0, import_node_path2.extname)(entry.name))) {
|
|
675
652
|
results.push(full);
|
|
676
653
|
}
|
|
677
654
|
}
|
|
@@ -679,19 +656,205 @@ function walk(dir, exts) {
|
|
|
679
656
|
}
|
|
680
657
|
function walkWithIgnore(dir, exts, opts = {}) {
|
|
681
658
|
const results = [];
|
|
682
|
-
if (!(0,
|
|
659
|
+
if (!(0, import_node_fs2.existsSync)(dir)) return results;
|
|
683
660
|
const skip = opts.extraIgnore ? /* @__PURE__ */ new Set([...DEFAULT_IGNORE_DIRS, ...opts.extraIgnore]) : DEFAULT_IGNORE_DIRS;
|
|
684
|
-
for (const entry of (0,
|
|
661
|
+
for (const entry of (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true })) {
|
|
685
662
|
if (entry.isDirectory()) {
|
|
686
663
|
if (skip.has(entry.name)) continue;
|
|
687
|
-
results.push(...walkWithIgnore((0,
|
|
688
|
-
} else if (exts.includes((0,
|
|
689
|
-
results.push((0,
|
|
664
|
+
results.push(...walkWithIgnore((0, import_node_path2.join)(dir, entry.name), exts, opts));
|
|
665
|
+
} else if (exts.includes((0, import_node_path2.extname)(entry.name))) {
|
|
666
|
+
results.push((0, import_node_path2.join)(dir, entry.name));
|
|
690
667
|
}
|
|
691
668
|
}
|
|
692
669
|
return results;
|
|
693
670
|
}
|
|
694
671
|
|
|
672
|
+
// src/server/graph/core/resolve-paths.ts
|
|
673
|
+
function hasSqlFiles(dir) {
|
|
674
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return false;
|
|
675
|
+
try {
|
|
676
|
+
return (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true }).some(
|
|
677
|
+
(e) => e.isFile() && e.name.endsWith(".sql")
|
|
678
|
+
);
|
|
679
|
+
} catch {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function hasNestedMigrationSql(dir) {
|
|
684
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return false;
|
|
685
|
+
try {
|
|
686
|
+
return (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true }).some(
|
|
687
|
+
(e) => e.isDirectory() && (0, import_node_fs3.existsSync)((0, import_node_path3.join)(dir, e.name, "migration.sql"))
|
|
688
|
+
);
|
|
689
|
+
} catch {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function resolveDbFromDir(dir) {
|
|
694
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return { kind: "none", schemaPath: null, migrationsDir: null };
|
|
695
|
+
const schemaPath = (0, import_node_path3.join)(dir, "schema.prisma");
|
|
696
|
+
if ((0, import_node_fs3.existsSync)(schemaPath)) {
|
|
697
|
+
const migrationsDir2 = (0, import_node_path3.join)(dir, "migrations");
|
|
698
|
+
return {
|
|
699
|
+
kind: "prisma",
|
|
700
|
+
schemaPath,
|
|
701
|
+
migrationsDir: (0, import_node_fs3.existsSync)(migrationsDir2) ? migrationsDir2 : null
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
const migrationsDir = (0, import_node_path3.join)(dir, "migrations");
|
|
705
|
+
if (hasSqlFiles(migrationsDir) || hasNestedMigrationSql(migrationsDir)) {
|
|
706
|
+
return { kind: "sql-migrations", migrationsDir, schemaPath: null };
|
|
707
|
+
}
|
|
708
|
+
if (hasSqlFiles(dir) || hasNestedMigrationSql(dir)) {
|
|
709
|
+
return { kind: "sql-migrations", migrationsDir: dir, schemaPath: null };
|
|
710
|
+
}
|
|
711
|
+
return { kind: "none", schemaPath: null, migrationsDir: null };
|
|
712
|
+
}
|
|
713
|
+
function detectDbConfig(rootDir, config) {
|
|
714
|
+
if (config.paths?.dbDir) {
|
|
715
|
+
return resolveDbFromDir((0, import_node_path3.join)(rootDir, config.paths.dbDir));
|
|
716
|
+
}
|
|
717
|
+
const candidates = ["prisma", "supabase", "drizzle", (0, import_node_path3.join)("db", "migrations"), "migrations"];
|
|
718
|
+
for (const c of candidates) {
|
|
719
|
+
const dir = (0, import_node_path3.join)(rootDir, c);
|
|
720
|
+
const resolved = resolveDbFromDir(dir);
|
|
721
|
+
if (resolved.kind !== "none") return resolved;
|
|
722
|
+
}
|
|
723
|
+
return { kind: "none", schemaPath: null, migrationsDir: null };
|
|
724
|
+
}
|
|
725
|
+
function detectDbDir(rootDir, config, dbConfig) {
|
|
726
|
+
if (config.paths?.dbDir) return (0, import_node_path3.join)(rootDir, config.paths.dbDir);
|
|
727
|
+
if (dbConfig.kind === "prisma") return (0, import_node_path3.dirname)(dbConfig.schemaPath);
|
|
728
|
+
if (dbConfig.kind === "sql-migrations") return dbConfig.migrationsDir;
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
var NON_SOURCE_DIRS = /* @__PURE__ */ new Set([
|
|
732
|
+
...DEFAULT_IGNORE_DIRS,
|
|
733
|
+
// DB conventions (handled by db parsers)
|
|
734
|
+
"prisma",
|
|
735
|
+
"supabase",
|
|
736
|
+
"drizzle",
|
|
737
|
+
"migrations",
|
|
738
|
+
// Web assets
|
|
739
|
+
"public",
|
|
740
|
+
"static",
|
|
741
|
+
"assets",
|
|
742
|
+
// Docs
|
|
743
|
+
"docs",
|
|
744
|
+
"documentation",
|
|
745
|
+
// Test dirs (project tests aren't part of the structural graph)
|
|
746
|
+
"tests",
|
|
747
|
+
"__tests__",
|
|
748
|
+
"e2e",
|
|
749
|
+
"playwright",
|
|
750
|
+
"cypress",
|
|
751
|
+
// Monorepo workspace roots — separate graph projects per .launchchart.json
|
|
752
|
+
"packages",
|
|
753
|
+
"apps",
|
|
754
|
+
"services",
|
|
755
|
+
"libs"
|
|
756
|
+
]);
|
|
757
|
+
function dirHasTSFiles(dir) {
|
|
758
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return false;
|
|
759
|
+
try {
|
|
760
|
+
const stack = [dir];
|
|
761
|
+
while (stack.length > 0) {
|
|
762
|
+
const cur = stack.pop();
|
|
763
|
+
const entries = (0, import_node_fs3.readdirSync)(cur, { withFileTypes: true });
|
|
764
|
+
for (const e of entries) {
|
|
765
|
+
if (e.isFile() && (e.name.endsWith(".ts") || e.name.endsWith(".tsx"))) return true;
|
|
766
|
+
if (e.isDirectory() && !e.name.startsWith(".") && !DEFAULT_IGNORE_DIRS.has(e.name)) {
|
|
767
|
+
stack.push((0, import_node_path3.join)(cur, e.name));
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
} catch {
|
|
772
|
+
}
|
|
773
|
+
return false;
|
|
774
|
+
}
|
|
775
|
+
function collectCodeBearingChildren(dir, extraSkip) {
|
|
776
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return [];
|
|
777
|
+
const out = [];
|
|
778
|
+
try {
|
|
779
|
+
for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
|
|
780
|
+
if (!entry.isDirectory()) continue;
|
|
781
|
+
if (entry.name.startsWith(".")) continue;
|
|
782
|
+
if (NON_SOURCE_DIRS.has(entry.name)) continue;
|
|
783
|
+
if (extraSkip?.has(entry.name)) continue;
|
|
784
|
+
const full = (0, import_node_path3.join)(dir, entry.name);
|
|
785
|
+
if (dirHasTSFiles(full)) out.push(full);
|
|
786
|
+
}
|
|
787
|
+
} catch {
|
|
788
|
+
}
|
|
789
|
+
return out;
|
|
790
|
+
}
|
|
791
|
+
function detectSrcRoots(rootDir, srcDir, appDir, config) {
|
|
792
|
+
if (config.paths?.srcRoots && config.paths.srcRoots.length > 0) {
|
|
793
|
+
const roots2 = /* @__PURE__ */ new Set();
|
|
794
|
+
roots2.add(appDir);
|
|
795
|
+
for (const r of config.paths.srcRoots) {
|
|
796
|
+
const abs = (0, import_node_path3.isAbsolute)(r) ? r : (0, import_node_path3.resolve)(rootDir, r);
|
|
797
|
+
roots2.add(abs);
|
|
798
|
+
}
|
|
799
|
+
return [...roots2];
|
|
800
|
+
}
|
|
801
|
+
const roots = /* @__PURE__ */ new Set();
|
|
802
|
+
roots.add(appDir);
|
|
803
|
+
for (const c of collectCodeBearingChildren(srcDir)) roots.add(c);
|
|
804
|
+
if (srcDir !== rootDir) {
|
|
805
|
+
const skipSrcWrapper = /* @__PURE__ */ new Set([(0, import_node_path3.basename)(srcDir)]);
|
|
806
|
+
for (const c of collectCodeBearingChildren(rootDir, skipSrcWrapper)) roots.add(c);
|
|
807
|
+
}
|
|
808
|
+
return [...roots];
|
|
809
|
+
}
|
|
810
|
+
var CONVENTION_NAMES = ["middleware.ts", "middleware.tsx", "instrumentation.ts", "instrumentation.tsx"];
|
|
811
|
+
function detectConventionFiles(rootDir, srcDir) {
|
|
812
|
+
const out = [];
|
|
813
|
+
const seen = /* @__PURE__ */ new Set();
|
|
814
|
+
const dirs = srcDir === rootDir ? [rootDir] : [srcDir, rootDir];
|
|
815
|
+
for (const dir of dirs) {
|
|
816
|
+
for (const name of CONVENTION_NAMES) {
|
|
817
|
+
const full = (0, import_node_path3.join)(dir, name);
|
|
818
|
+
if (!seen.has(full) && (0, import_node_fs3.existsSync)(full)) {
|
|
819
|
+
try {
|
|
820
|
+
if ((0, import_node_fs3.statSync)(full).isFile()) {
|
|
821
|
+
seen.add(full);
|
|
822
|
+
out.push(full);
|
|
823
|
+
}
|
|
824
|
+
} catch {
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return out;
|
|
830
|
+
}
|
|
831
|
+
function resolveProjectPaths(rootDir, config) {
|
|
832
|
+
let srcDir;
|
|
833
|
+
let appDir;
|
|
834
|
+
if (config.paths?.appDir) {
|
|
835
|
+
appDir = (0, import_node_path3.join)(rootDir, config.paths.appDir);
|
|
836
|
+
srcDir = config.paths.srcDir ? (0, import_node_path3.join)(rootDir, config.paths.srcDir) : (0, import_node_path3.dirname)(appDir);
|
|
837
|
+
} else {
|
|
838
|
+
const srcApp = (0, import_node_path3.join)(rootDir, "src", "app");
|
|
839
|
+
const rootApp = (0, import_node_path3.join)(rootDir, "app");
|
|
840
|
+
if ((0, import_node_fs3.existsSync)(srcApp)) {
|
|
841
|
+
srcDir = (0, import_node_path3.join)(rootDir, "src");
|
|
842
|
+
appDir = srcApp;
|
|
843
|
+
} else if ((0, import_node_fs3.existsSync)(rootApp)) {
|
|
844
|
+
srcDir = rootDir;
|
|
845
|
+
appDir = rootApp;
|
|
846
|
+
} else {
|
|
847
|
+
return null;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
const apiDir = (0, import_node_path3.join)(appDir, "api");
|
|
851
|
+
const dbConfig = detectDbConfig(rootDir, config);
|
|
852
|
+
const dbDir = detectDbDir(rootDir, config, dbConfig);
|
|
853
|
+
const srcRoots = detectSrcRoots(rootDir, srcDir, appDir, config);
|
|
854
|
+
const conventionFiles = detectConventionFiles(rootDir, srcDir);
|
|
855
|
+
return { srcDir, appDir, apiDir, dbDir, srcRoots, conventionFiles, dbConfig };
|
|
856
|
+
}
|
|
857
|
+
|
|
695
858
|
// src/server/graph/parsers/ts/typescript-project.ts
|
|
696
859
|
init_ts_extractor();
|
|
697
860
|
var HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]);
|
|
@@ -708,8 +871,12 @@ var CLASSIFICATION_TO_LAYER = {
|
|
|
708
871
|
"mcp-tool": "ui",
|
|
709
872
|
external: "ui"
|
|
710
873
|
};
|
|
711
|
-
function toNodeId(srcDir, absPath) {
|
|
712
|
-
|
|
874
|
+
function toNodeId(srcDir, rootDir, absPath) {
|
|
875
|
+
const relFromSrc = (0, import_node_path5.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
876
|
+
if (relFromSrc.startsWith("..")) {
|
|
877
|
+
return (0, import_node_path5.relative)(rootDir, absPath).replace(/\\/g, "/");
|
|
878
|
+
}
|
|
879
|
+
return relFromSrc;
|
|
713
880
|
}
|
|
714
881
|
function resolveImport(srcDir, specifier) {
|
|
715
882
|
if (!specifier.startsWith("@/")) return null;
|
|
@@ -799,12 +966,13 @@ function extractRoute(id) {
|
|
|
799
966
|
function nameFromFilename(absPath) {
|
|
800
967
|
return (0, import_node_path5.basename)(absPath, (0, import_node_path5.extname)(absPath)).replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^(\w)/, (_, c) => c.toUpperCase());
|
|
801
968
|
}
|
|
802
|
-
function
|
|
803
|
-
let route = "/" + (0, import_node_path5.relative)(
|
|
969
|
+
function filePathToAppRoute(appDir, absPath) {
|
|
970
|
+
let route = ("/" + (0, import_node_path5.relative)(appDir, absPath).replace(/\\/g, "/")).replace(/\/route\.tsx?$/, "");
|
|
971
|
+
route = route.replace(/\/\([^)]+\)/g, "");
|
|
972
|
+
route = route.replace(/\[\.\.\.([^\]]+)\]/g, "*$1");
|
|
804
973
|
route = route.replace(/\[([^\]]+)\]/g, ":$1");
|
|
805
974
|
route = route.replace(/\/+/g, "/");
|
|
806
|
-
|
|
807
|
-
return "/api" + route;
|
|
975
|
+
return route === "" ? "/" : route;
|
|
808
976
|
}
|
|
809
977
|
function camelToPascal(s) {
|
|
810
978
|
if (!s) return s;
|
|
@@ -889,7 +1057,7 @@ function matchRouteToPage(route, routeToNodeId) {
|
|
|
889
1057
|
if (routeToNodeId.has(normalized)) return routeToNodeId.get(normalized);
|
|
890
1058
|
return null;
|
|
891
1059
|
}
|
|
892
|
-
function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps, routeToNodeId) {
|
|
1060
|
+
function extractEdges(srcDir, rootDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps, routeToNodeId) {
|
|
893
1061
|
const edges = [];
|
|
894
1062
|
const flagged = [];
|
|
895
1063
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -917,7 +1085,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
|
|
|
917
1085
|
for (const name of names) {
|
|
918
1086
|
const targetAbs = barrelMap.get(name);
|
|
919
1087
|
if (targetAbs) {
|
|
920
|
-
const targetId = toNodeId(srcDir, targetAbs);
|
|
1088
|
+
const targetId = toNodeId(srcDir, rootDir, targetAbs);
|
|
921
1089
|
if (nodeIdSet.has(targetId)) {
|
|
922
1090
|
if (!byTarget.has(targetId)) byTarget.set(targetId, []);
|
|
923
1091
|
byTarget.get(targetId).push(name);
|
|
@@ -931,7 +1099,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
|
|
|
931
1099
|
} else {
|
|
932
1100
|
const resolved = resolveImport(srcDir, specifier);
|
|
933
1101
|
if (resolved) {
|
|
934
|
-
const targetId = toNodeId(srcDir, resolved);
|
|
1102
|
+
const targetId = toNodeId(srcDir, rootDir, resolved);
|
|
935
1103
|
if (nodeIdSet.has(targetId) && !targetId.endsWith("/index.ts") && !targetId.endsWith("/index.tsx")) {
|
|
936
1104
|
addEdge(targetId, edgeTypeFor(isTypeOnly, names));
|
|
937
1105
|
}
|
|
@@ -940,7 +1108,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
|
|
|
940
1108
|
} else if (specifier.startsWith(".")) {
|
|
941
1109
|
const resolved = resolveRelativeImport(absPath, specifier);
|
|
942
1110
|
if (resolved) {
|
|
943
|
-
const targetId = toNodeId(srcDir, resolved);
|
|
1111
|
+
const targetId = toNodeId(srcDir, rootDir, resolved);
|
|
944
1112
|
if (nodeIdSet.has(targetId) && !targetId.endsWith("/index.ts") && !targetId.endsWith("/index.tsx")) {
|
|
945
1113
|
addEdge(targetId, edgeTypeFor(isTypeOnly, names));
|
|
946
1114
|
}
|
|
@@ -992,13 +1160,22 @@ function generate(rootDir) {
|
|
|
992
1160
|
const config = loadConfig(rootDir);
|
|
993
1161
|
const paths = resolveProjectPaths(rootDir, config);
|
|
994
1162
|
const srcDir = paths.srcDir;
|
|
995
|
-
const
|
|
996
|
-
const
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1163
|
+
const allDiscovered = [];
|
|
1164
|
+
const discoveredSet = /* @__PURE__ */ new Set();
|
|
1165
|
+
for (const root of paths.srcRoots) {
|
|
1166
|
+
for (const f of walk(root, [".tsx", ".ts"])) {
|
|
1167
|
+
if (!discoveredSet.has(f)) {
|
|
1168
|
+
discoveredSet.add(f);
|
|
1169
|
+
allDiscovered.push(f);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
for (const conv of paths.conventionFiles) {
|
|
1174
|
+
if (!discoveredSet.has(conv)) {
|
|
1175
|
+
discoveredSet.add(conv);
|
|
1176
|
+
allDiscovered.push(conv);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1002
1179
|
const parsedByPath = /* @__PURE__ */ new Map();
|
|
1003
1180
|
for (const absPath of allDiscovered) {
|
|
1004
1181
|
parsedByPath.set(absPath, parseFileTS(absPath));
|
|
@@ -1010,7 +1187,7 @@ function generate(rootDir) {
|
|
|
1010
1187
|
const routeToNodeId = /* @__PURE__ */ new Map();
|
|
1011
1188
|
const fileSet = allDiscovered.filter((f) => !(0, import_node_path5.basename)(f).startsWith("index."));
|
|
1012
1189
|
for (const absPath of fileSet) {
|
|
1013
|
-
const id = toNodeId(srcDir, absPath);
|
|
1190
|
+
const id = toNodeId(srcDir, rootDir, absPath);
|
|
1014
1191
|
const type = classifyType(absPath, id);
|
|
1015
1192
|
if (type === "test" || type === "story") continue;
|
|
1016
1193
|
const parsed = parsedByPath.get(absPath);
|
|
@@ -1025,7 +1202,7 @@ function generate(rootDir) {
|
|
|
1025
1202
|
const dbCalls = extractDbCallsTS(absPath);
|
|
1026
1203
|
const authWrappers = extractAuthWrappersTS(absPath);
|
|
1027
1204
|
const deep = extractDeep(absPath);
|
|
1028
|
-
const routePath = (
|
|
1205
|
+
const routePath = filePathToAppRoute(paths.appDir, absPath);
|
|
1029
1206
|
const mutations = dbCalls.filter((c) => c.isMutation);
|
|
1030
1207
|
const mutates = mutations.length > 0;
|
|
1031
1208
|
const authStrategy = [...authWrappers];
|
|
@@ -1069,11 +1246,12 @@ function generate(rootDir) {
|
|
|
1069
1246
|
const uiEdges = [];
|
|
1070
1247
|
const uiFlagged = [];
|
|
1071
1248
|
for (const absPath of fileSet) {
|
|
1072
|
-
const id = toNodeId(srcDir, absPath);
|
|
1249
|
+
const id = toNodeId(srcDir, rootDir, absPath);
|
|
1073
1250
|
if (!nodeIdSet.has(id)) continue;
|
|
1074
1251
|
const parsed = parsedByPath.get(absPath);
|
|
1075
1252
|
const { edges, flagged } = extractEdges(
|
|
1076
1253
|
srcDir,
|
|
1254
|
+
rootDir,
|
|
1077
1255
|
absPath,
|
|
1078
1256
|
id,
|
|
1079
1257
|
parsed,
|
|
@@ -1086,7 +1264,7 @@ function generate(rootDir) {
|
|
|
1086
1264
|
}
|
|
1087
1265
|
const fetchCallEntries = [];
|
|
1088
1266
|
for (const absPath of fileSet) {
|
|
1089
|
-
const sourceId = toNodeId(srcDir, absPath);
|
|
1267
|
+
const sourceId = toNodeId(srcDir, rootDir, absPath);
|
|
1090
1268
|
if (!nodeIdSet.has(sourceId)) continue;
|
|
1091
1269
|
const parsed = parsedByPath.get(absPath);
|
|
1092
1270
|
if (parsed.fetchCalls.length === 0) continue;
|
|
@@ -1125,7 +1303,7 @@ function generate(rootDir) {
|
|
|
1125
1303
|
for (const name of names) {
|
|
1126
1304
|
const targetAbs = barrelMap.get(name);
|
|
1127
1305
|
if (!targetAbs) continue;
|
|
1128
|
-
const targetId2 = toNodeId(srcDir, targetAbs);
|
|
1306
|
+
const targetId2 = toNodeId(srcDir, rootDir, targetAbs);
|
|
1129
1307
|
if (!nodeIdSet.has(targetId2)) continue;
|
|
1130
1308
|
const key2 = `${externalId}\u2192${targetId2}`;
|
|
1131
1309
|
if (seen.has(key2)) continue;
|
|
@@ -1139,7 +1317,7 @@ function generate(rootDir) {
|
|
|
1139
1317
|
resolved = resolveRelativeImport(absPath, specifier);
|
|
1140
1318
|
}
|
|
1141
1319
|
if (!resolved) continue;
|
|
1142
|
-
const targetId = toNodeId(srcDir, resolved);
|
|
1320
|
+
const targetId = toNodeId(srcDir, rootDir, resolved);
|
|
1143
1321
|
if (!nodeIdSet.has(targetId)) continue;
|
|
1144
1322
|
if (targetId.endsWith("/index.ts") || targetId.endsWith("/index.tsx")) continue;
|
|
1145
1323
|
const key = `${externalId}\u2192${targetId}`;
|
|
@@ -1317,7 +1495,7 @@ var typescriptProjectParser = {
|
|
|
1317
1495
|
|
|
1318
1496
|
// src/server/graph/parsers/db/prisma-schema.ts
|
|
1319
1497
|
var import_node_fs6 = require("node:fs");
|
|
1320
|
-
|
|
1498
|
+
init_config();
|
|
1321
1499
|
function parseModels(content) {
|
|
1322
1500
|
const nodes = [];
|
|
1323
1501
|
const relations = [];
|
|
@@ -1408,10 +1586,24 @@ function parseEnums(content) {
|
|
|
1408
1586
|
return nodes;
|
|
1409
1587
|
}
|
|
1410
1588
|
function detect2(rootDir) {
|
|
1411
|
-
|
|
1589
|
+
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
1590
|
+
return paths?.dbConfig.kind === "prisma" && (0, import_node_fs6.existsSync)(paths.dbConfig.schemaPath);
|
|
1412
1591
|
}
|
|
1413
1592
|
function generate2(rootDir) {
|
|
1414
|
-
const
|
|
1593
|
+
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
1594
|
+
if (paths.dbConfig.kind !== "prisma") {
|
|
1595
|
+
return {
|
|
1596
|
+
metadata: { generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), layer: "db", source: "none" },
|
|
1597
|
+
nodes: [],
|
|
1598
|
+
edges: [],
|
|
1599
|
+
cross_refs: [],
|
|
1600
|
+
contradictions: [],
|
|
1601
|
+
warnings: [],
|
|
1602
|
+
flagged_edges: [],
|
|
1603
|
+
patterns: { total_tables: 0, total_enums: 0, total_relations: 0 }
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
const schemaPath = paths.dbConfig.schemaPath;
|
|
1415
1607
|
const content = (0, import_node_fs6.readFileSync)(schemaPath, "utf-8");
|
|
1416
1608
|
const { nodes: modelNodes, relations } = parseModels(content);
|
|
1417
1609
|
const enumNodes = parseEnums(content);
|
|
@@ -1432,7 +1624,7 @@ function generate2(rootDir) {
|
|
|
1432
1624
|
metadata: {
|
|
1433
1625
|
generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
1434
1626
|
scope: "prisma-schema",
|
|
1435
|
-
source:
|
|
1627
|
+
source: schemaPath,
|
|
1436
1628
|
provider: "postgresql",
|
|
1437
1629
|
layer: "db",
|
|
1438
1630
|
total_models: modelNodes.length,
|
|
@@ -1470,7 +1662,8 @@ var prismaSchemaParser = {
|
|
|
1470
1662
|
|
|
1471
1663
|
// src/server/graph/parsers/db/sql-migrations.ts
|
|
1472
1664
|
var import_node_fs7 = require("node:fs");
|
|
1473
|
-
var
|
|
1665
|
+
var import_node_path6 = require("node:path");
|
|
1666
|
+
init_config();
|
|
1474
1667
|
var PG_TO_PRISMA = {
|
|
1475
1668
|
"TEXT": "String",
|
|
1476
1669
|
"VARCHAR": "String",
|
|
@@ -1619,19 +1812,29 @@ function parseUniqueIndex(sql, state) {
|
|
|
1619
1812
|
state.uniqueIndexes.get(m[1]).add(m[2]);
|
|
1620
1813
|
}
|
|
1621
1814
|
}
|
|
1622
|
-
function
|
|
1623
|
-
|
|
1815
|
+
function discoverMigrationFiles(migrationsDir) {
|
|
1816
|
+
if (!(0, import_node_fs7.existsSync)(migrationsDir)) return [];
|
|
1817
|
+
const out = [];
|
|
1818
|
+
const entries = (0, import_node_fs7.readdirSync)(migrationsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
1819
|
+
for (const entry of entries) {
|
|
1820
|
+
if (entry.isDirectory()) {
|
|
1821
|
+
const sqlPath = (0, import_node_path6.join)(migrationsDir, entry.name, "migration.sql");
|
|
1822
|
+
if ((0, import_node_fs7.existsSync)(sqlPath)) out.push(sqlPath);
|
|
1823
|
+
} else if (entry.isFile() && entry.name.endsWith(".sql")) {
|
|
1824
|
+
out.push((0, import_node_path6.join)(migrationsDir, entry.name));
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
return out;
|
|
1828
|
+
}
|
|
1829
|
+
function parseMigrations(migrationsDir) {
|
|
1624
1830
|
const state = {
|
|
1625
1831
|
tables: /* @__PURE__ */ new Map(),
|
|
1626
1832
|
enums: /* @__PURE__ */ new Map(),
|
|
1627
1833
|
fks: [],
|
|
1628
1834
|
uniqueIndexes: /* @__PURE__ */ new Map()
|
|
1629
1835
|
};
|
|
1630
|
-
if (!
|
|
1631
|
-
const
|
|
1632
|
-
for (const dir of dirs) {
|
|
1633
|
-
const sqlPath = (0, import_node_path7.join)(migrationsDir, dir, "migration.sql");
|
|
1634
|
-
if (!(0, import_node_fs7.existsSync)(sqlPath)) continue;
|
|
1836
|
+
if (!migrationsDir) return state;
|
|
1837
|
+
for (const sqlPath of discoverMigrationFiles(migrationsDir)) {
|
|
1635
1838
|
const sql = (0, import_node_fs7.readFileSync)(sqlPath, "utf-8");
|
|
1636
1839
|
parseCreateEnum(sql, state);
|
|
1637
1840
|
parseCreateTable(sql, state);
|
|
@@ -1642,9 +1845,8 @@ function parseMigrations(rootDir) {
|
|
|
1642
1845
|
}
|
|
1643
1846
|
return state;
|
|
1644
1847
|
}
|
|
1645
|
-
function loadPrismaState(
|
|
1646
|
-
|
|
1647
|
-
if (!(0, import_node_fs7.existsSync)(schemaPath)) return null;
|
|
1848
|
+
function loadPrismaState(schemaPath) {
|
|
1849
|
+
if (!schemaPath || !(0, import_node_fs7.existsSync)(schemaPath)) return null;
|
|
1648
1850
|
const content = (0, import_node_fs7.readFileSync)(schemaPath, "utf-8");
|
|
1649
1851
|
const tables = /* @__PURE__ */ new Map();
|
|
1650
1852
|
const enums = /* @__PURE__ */ new Map();
|
|
@@ -1809,14 +2011,28 @@ function verify(sqlState, prisma) {
|
|
|
1809
2011
|
}
|
|
1810
2012
|
return { contradictions, flaggedEdges };
|
|
1811
2013
|
}
|
|
2014
|
+
function migrationsDirFor(rootDir) {
|
|
2015
|
+
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
2016
|
+
if (!paths) return null;
|
|
2017
|
+
if (paths.dbConfig.kind === "prisma" || paths.dbConfig.kind === "sql-migrations") {
|
|
2018
|
+
return paths.dbConfig.migrationsDir;
|
|
2019
|
+
}
|
|
2020
|
+
return null;
|
|
2021
|
+
}
|
|
2022
|
+
function schemaPathFor(rootDir) {
|
|
2023
|
+
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
2024
|
+
if (!paths) return null;
|
|
2025
|
+
return paths.dbConfig.kind === "prisma" ? paths.dbConfig.schemaPath : null;
|
|
2026
|
+
}
|
|
1812
2027
|
function detect3(rootDir) {
|
|
1813
|
-
const
|
|
1814
|
-
if (!
|
|
1815
|
-
return (
|
|
2028
|
+
const dir = migrationsDirFor(rootDir);
|
|
2029
|
+
if (!dir) return false;
|
|
2030
|
+
return discoverMigrationFiles(dir).length > 0;
|
|
1816
2031
|
}
|
|
1817
2032
|
function generate3(rootDir) {
|
|
1818
|
-
const
|
|
1819
|
-
const
|
|
2033
|
+
const migrationsDir = migrationsDirFor(rootDir);
|
|
2034
|
+
const sqlState = parseMigrations(migrationsDir);
|
|
2035
|
+
const prisma = loadPrismaState(schemaPathFor(rootDir));
|
|
1820
2036
|
const prismaTableIds = prisma ? new Set(prisma.tables.keys()) : /* @__PURE__ */ new Set();
|
|
1821
2037
|
const prismaEnumIds = prisma ? new Set(prisma.enums.keys()) : /* @__PURE__ */ new Set();
|
|
1822
2038
|
const nodes = [];
|
|
@@ -1862,7 +2078,7 @@ function generate3(rootDir) {
|
|
|
1862
2078
|
metadata: {
|
|
1863
2079
|
generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
1864
2080
|
scope: "sql-migrations",
|
|
1865
|
-
source: "
|
|
2081
|
+
source: migrationsDir ?? "none",
|
|
1866
2082
|
layer: "db",
|
|
1867
2083
|
sql_tables: sqlState.tables.size,
|
|
1868
2084
|
sql_enums: sqlState.enums.size,
|
|
@@ -2101,31 +2317,31 @@ var fetchResolverParser = {
|
|
|
2101
2317
|
|
|
2102
2318
|
// src/server/graph/parsers/crosslayer/api-annotations.ts
|
|
2103
2319
|
var import_node_fs8 = require("node:fs");
|
|
2104
|
-
var
|
|
2320
|
+
var import_node_path7 = require("node:path");
|
|
2105
2321
|
var API_ANNOTATION_RE = /@api\s+(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\/\S+)/g;
|
|
2106
2322
|
function walk2(dir, exts) {
|
|
2107
2323
|
if (!(0, import_node_fs8.existsSync)(dir)) return [];
|
|
2108
2324
|
const results = [];
|
|
2109
2325
|
for (const entry of (0, import_node_fs8.readdirSync)(dir, { withFileTypes: true })) {
|
|
2110
2326
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
2111
|
-
const full = (0,
|
|
2327
|
+
const full = (0, import_node_path7.join)(dir, entry.name);
|
|
2112
2328
|
if (entry.isDirectory()) {
|
|
2113
2329
|
results.push(...walk2(full, exts));
|
|
2114
|
-
} else if (exts.includes((0,
|
|
2330
|
+
} else if (exts.includes((0, import_node_path7.extname)(entry.name))) {
|
|
2115
2331
|
results.push(full);
|
|
2116
2332
|
}
|
|
2117
2333
|
}
|
|
2118
2334
|
return results;
|
|
2119
2335
|
}
|
|
2120
2336
|
function toNodeId2(srcDir, absPath) {
|
|
2121
|
-
return (0,
|
|
2337
|
+
return (0, import_node_path7.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
2122
2338
|
}
|
|
2123
2339
|
var apiAnnotationsParser = {
|
|
2124
2340
|
id: "api-annotations",
|
|
2125
2341
|
layer: "crosslayer",
|
|
2126
2342
|
concern: "api-binding",
|
|
2127
2343
|
detect(rootDir) {
|
|
2128
|
-
return (0, import_node_fs8.existsSync)((0,
|
|
2344
|
+
return (0, import_node_fs8.existsSync)((0, import_node_path7.join)(rootDir, "src"));
|
|
2129
2345
|
},
|
|
2130
2346
|
generate(rootDir, layerOutputs) {
|
|
2131
2347
|
const apiOutput = layerOutputs.get("api");
|
|
@@ -2136,7 +2352,7 @@ var apiAnnotationsParser = {
|
|
|
2136
2352
|
const uiNodeIds = new Set(uiOutput?.nodes.map((n) => n.id) ?? []);
|
|
2137
2353
|
const apiRoutes = loadApiRoutesFromOutput(apiOutput);
|
|
2138
2354
|
const apiPathMap = buildApiPathMap(apiRoutes);
|
|
2139
|
-
const srcDir = (0,
|
|
2355
|
+
const srcDir = (0, import_node_path7.join)(rootDir, "src");
|
|
2140
2356
|
const files = walk2(srcDir, [".ts", ".tsx"]);
|
|
2141
2357
|
const crossRefs = [];
|
|
2142
2358
|
const flaggedEdges = [];
|
|
@@ -2187,7 +2403,7 @@ var apiAnnotationsParser = {
|
|
|
2187
2403
|
|
|
2188
2404
|
// src/server/graph/parsers/crosslayer/url-literal-scanner.ts
|
|
2189
2405
|
var import_node_fs9 = require("node:fs");
|
|
2190
|
-
var
|
|
2406
|
+
var import_node_path8 = require("node:path");
|
|
2191
2407
|
init_config();
|
|
2192
2408
|
var URL_LITERAL_RE = /['"`](\/api\/[^'"`\s]+?)['"`]/g;
|
|
2193
2409
|
function walk3(dir, exts) {
|
|
@@ -2195,17 +2411,17 @@ function walk3(dir, exts) {
|
|
|
2195
2411
|
const results = [];
|
|
2196
2412
|
for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
|
|
2197
2413
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
2198
|
-
const full = (0,
|
|
2414
|
+
const full = (0, import_node_path8.join)(dir, entry.name);
|
|
2199
2415
|
if (entry.isDirectory()) {
|
|
2200
2416
|
results.push(...walk3(full, exts));
|
|
2201
|
-
} else if (exts.includes((0,
|
|
2417
|
+
} else if (exts.includes((0, import_node_path8.extname)(entry.name))) {
|
|
2202
2418
|
results.push(full);
|
|
2203
2419
|
}
|
|
2204
2420
|
}
|
|
2205
2421
|
return results;
|
|
2206
2422
|
}
|
|
2207
2423
|
function toNodeId3(srcDir, absPath) {
|
|
2208
|
-
return (0,
|
|
2424
|
+
return (0, import_node_path8.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
2209
2425
|
}
|
|
2210
2426
|
var urlLiteralScannerParser = {
|
|
2211
2427
|
id: "url-literal-scanner",
|
|
@@ -2226,7 +2442,7 @@ var urlLiteralScannerParser = {
|
|
|
2226
2442
|
const apiPathMap = buildApiPathMap(apiRoutes);
|
|
2227
2443
|
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
2228
2444
|
const srcDir = paths.srcDir;
|
|
2229
|
-
const clientDir = (0,
|
|
2445
|
+
const clientDir = (0, import_node_path8.join)(srcDir, "client");
|
|
2230
2446
|
const files = [
|
|
2231
2447
|
...walk3(clientDir, [".ts", ".tsx"]),
|
|
2232
2448
|
...walk3(paths.appDir, [".ts", ".tsx"])
|
|
@@ -2268,7 +2484,7 @@ var urlLiteralScannerParser = {
|
|
|
2268
2484
|
|
|
2269
2485
|
// src/server/graph/parsers/static/static-values.ts
|
|
2270
2486
|
var import_node_fs10 = require("node:fs");
|
|
2271
|
-
var
|
|
2487
|
+
var import_node_path9 = require("node:path");
|
|
2272
2488
|
var parseCode = null;
|
|
2273
2489
|
function tryLoadTreeSitter() {
|
|
2274
2490
|
if (parseCode) return true;
|
|
@@ -2301,8 +2517,8 @@ function extractEnumValues(rootDir) {
|
|
|
2301
2517
|
const nodes = [];
|
|
2302
2518
|
const edges = [];
|
|
2303
2519
|
const schemaPaths = [
|
|
2304
|
-
(0,
|
|
2305
|
-
(0,
|
|
2520
|
+
(0, import_node_path9.join)(rootDir, "prisma", "schema.prisma"),
|
|
2521
|
+
(0, import_node_path9.join)(rootDir, "prisma", "schema")
|
|
2306
2522
|
];
|
|
2307
2523
|
let content = "";
|
|
2308
2524
|
for (const p of schemaPaths) {
|
|
@@ -2313,7 +2529,7 @@ function extractEnumValues(rootDir) {
|
|
|
2313
2529
|
content = (0, import_node_fs10.readFileSync)(p, "utf-8");
|
|
2314
2530
|
} else if (stat.isDirectory()) {
|
|
2315
2531
|
const files = (0, import_node_fs10.readdirSync)(p).filter((f) => f.endsWith(".prisma"));
|
|
2316
|
-
content = files.map((f) => (0, import_node_fs10.readFileSync)((0,
|
|
2532
|
+
content = files.map((f) => (0, import_node_fs10.readFileSync)((0, import_node_path9.join)(p, f), "utf-8")).join("\n");
|
|
2317
2533
|
}
|
|
2318
2534
|
} catch {
|
|
2319
2535
|
continue;
|
|
@@ -2469,14 +2685,14 @@ function extractSeedData(rootDir) {
|
|
|
2469
2685
|
const nodes = [];
|
|
2470
2686
|
const edges = [];
|
|
2471
2687
|
const seedFiles = [
|
|
2472
|
-
(0,
|
|
2473
|
-
(0,
|
|
2474
|
-
(0,
|
|
2688
|
+
(0, import_node_path9.join)(rootDir, "prisma", "seed.ts"),
|
|
2689
|
+
(0, import_node_path9.join)(rootDir, "prisma", "seed.js"),
|
|
2690
|
+
(0, import_node_path9.join)(rootDir, "src", "server", "lib", "system-tags.ts")
|
|
2475
2691
|
].filter(import_node_fs10.existsSync);
|
|
2476
2692
|
const useTreeSitter = tryLoadTreeSitter();
|
|
2477
2693
|
for (const filePath of seedFiles) {
|
|
2478
2694
|
const content = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
|
|
2479
|
-
const relPath = (0,
|
|
2695
|
+
const relPath = (0, import_node_path9.relative)(rootDir, filePath);
|
|
2480
2696
|
const seeded = detectSeededArrays(content, relPath);
|
|
2481
2697
|
let astRoot = null;
|
|
2482
2698
|
if (useTreeSitter && parseCode) {
|
|
@@ -2574,7 +2790,7 @@ function walkDir(dir, exts) {
|
|
|
2574
2790
|
const results = [];
|
|
2575
2791
|
for (const entry of (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true })) {
|
|
2576
2792
|
if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist") continue;
|
|
2577
|
-
const full = (0,
|
|
2793
|
+
const full = (0, import_node_path9.join)(dir, entry.name);
|
|
2578
2794
|
if (entry.isDirectory()) results.push(...walkDir(full, exts));
|
|
2579
2795
|
else if (exts.some((ext) => entry.name.endsWith(ext))) results.push(full);
|
|
2580
2796
|
}
|
|
@@ -2582,11 +2798,11 @@ function walkDir(dir, exts) {
|
|
|
2582
2798
|
}
|
|
2583
2799
|
function extractConstants(rootDir) {
|
|
2584
2800
|
const nodes = [];
|
|
2585
|
-
const srcDir = (0,
|
|
2801
|
+
const srcDir = (0, import_node_path9.join)(rootDir, "src");
|
|
2586
2802
|
if (!(0, import_node_fs10.existsSync)(srcDir)) return { nodes };
|
|
2587
2803
|
for (const filePath of walkDir(srcDir, [".ts", ".tsx"])) {
|
|
2588
2804
|
const content = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
|
|
2589
|
-
const relPath = (0,
|
|
2805
|
+
const relPath = (0, import_node_path9.relative)(rootDir, filePath);
|
|
2590
2806
|
const constArrayRe = /export\s+const\s+([A-Z][A-Z_0-9]+)\s*(?::[^=]+)?\s*=\s*\[/g;
|
|
2591
2807
|
let cm;
|
|
2592
2808
|
while ((cm = constArrayRe.exec(content)) !== null) {
|
|
@@ -2619,7 +2835,7 @@ function extractConstants(rootDir) {
|
|
|
2619
2835
|
return { nodes };
|
|
2620
2836
|
}
|
|
2621
2837
|
function detect4(rootDir) {
|
|
2622
|
-
return (0, import_node_fs10.existsSync)((0,
|
|
2838
|
+
return (0, import_node_fs10.existsSync)((0, import_node_path9.join)(rootDir, "prisma", "schema.prisma")) || (0, import_node_fs10.existsSync)((0, import_node_path9.join)(rootDir, "prisma", "seed.ts"));
|
|
2623
2839
|
}
|
|
2624
2840
|
function generate4(rootDir) {
|
|
2625
2841
|
const enumResult = extractEnumValues(rootDir);
|
|
@@ -2695,7 +2911,7 @@ var staticValuesParser = {
|
|
|
2695
2911
|
|
|
2696
2912
|
// src/server/graph/parsers/crosslayer/static-ref-scanner.ts
|
|
2697
2913
|
var import_node_fs11 = require("node:fs");
|
|
2698
|
-
var
|
|
2914
|
+
var import_node_path10 = require("node:path");
|
|
2699
2915
|
init_config();
|
|
2700
2916
|
var MIN_VALUE_LENGTH = 4;
|
|
2701
2917
|
var SKIP_VALUES = /* @__PURE__ */ new Set([
|
|
@@ -2839,11 +3055,11 @@ var staticRefScannerParser = {
|
|
|
2839
3055
|
if (!paths) return { cross_refs: [], flagged_edges: [], warnings: [] };
|
|
2840
3056
|
const srcDir = paths.srcDir;
|
|
2841
3057
|
const files = [
|
|
2842
|
-
...walkWithIgnore((0,
|
|
3058
|
+
...walkWithIgnore((0, import_node_path10.join)(srcDir, "client"), [".ts", ".tsx"]),
|
|
2843
3059
|
...walkWithIgnore(paths.appDir, [".ts", ".tsx"]),
|
|
2844
|
-
...walkWithIgnore((0,
|
|
2845
|
-
...walkWithIgnore((0,
|
|
2846
|
-
...walkWithIgnore((0,
|
|
3060
|
+
...walkWithIgnore((0, import_node_path10.join)(srcDir, "server"), [".ts", ".tsx"]),
|
|
3061
|
+
...walkWithIgnore((0, import_node_path10.join)(srcDir, "lib"), [".ts", ".tsx"]),
|
|
3062
|
+
...walkWithIgnore((0, import_node_path10.join)(srcDir, "config"), [".ts", ".tsx"])
|
|
2847
3063
|
];
|
|
2848
3064
|
const uiOutput = layerOutputs.get("ui");
|
|
2849
3065
|
const apiOutput = layerOutputs.get("api");
|
|
@@ -2861,7 +3077,7 @@ var staticRefScannerParser = {
|
|
|
2861
3077
|
const seen = /* @__PURE__ */ new Set();
|
|
2862
3078
|
let filesScanned = 0;
|
|
2863
3079
|
for (const absPath of files) {
|
|
2864
|
-
const sourceId = (0,
|
|
3080
|
+
const sourceId = (0, import_node_path10.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
2865
3081
|
const sourceLayer = uiNodeIds.has(sourceId) ? "ui" : apiNodeIds.has(sourceId) ? "api" : null;
|
|
2866
3082
|
if (!sourceLayer) continue;
|
|
2867
3083
|
const content = (0, import_node_fs11.readFileSync)(absPath, "utf-8");
|
|
@@ -2980,7 +3196,7 @@ function registerBuiltins(registry, disabled) {
|
|
|
2980
3196
|
function loadCustomParsers(registry, config, rootDir, disabled) {
|
|
2981
3197
|
for (const entry of config.parsers?.custom ?? []) {
|
|
2982
3198
|
try {
|
|
2983
|
-
const absPath = (0,
|
|
3199
|
+
const absPath = (0, import_node_path11.resolve)(rootDir, entry.path);
|
|
2984
3200
|
const mod = require(absPath);
|
|
2985
3201
|
const parser = "default" in mod ? mod.default : mod;
|
|
2986
3202
|
if (disabled.has(parser.id)) continue;
|
|
@@ -3110,7 +3326,7 @@ function applyCrossLayerResults(uiOutput, results) {
|
|
|
3110
3326
|
|
|
3111
3327
|
// src/server/graph/core/graph-builder.ts
|
|
3112
3328
|
function readGraphFromDisk(rootDir, layer) {
|
|
3113
|
-
const filePath = (0,
|
|
3329
|
+
const filePath = (0, import_node_path12.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
|
|
3114
3330
|
if (!(0, import_node_fs12.existsSync)(filePath)) return null;
|
|
3115
3331
|
try {
|
|
3116
3332
|
return JSON.parse((0, import_node_fs12.readFileSync)(filePath, "utf-8"));
|
|
@@ -3214,11 +3430,11 @@ function generateAll(rootDir) {
|
|
|
3214
3430
|
init_config();
|
|
3215
3431
|
|
|
3216
3432
|
// src/server/graph/core/tagger-registry.ts
|
|
3217
|
-
var
|
|
3433
|
+
var import_node_path14 = require("node:path");
|
|
3218
3434
|
|
|
3219
3435
|
// src/server/graph/taggers/module-tagger.ts
|
|
3220
3436
|
var import_node_fs13 = require("node:fs");
|
|
3221
|
-
var
|
|
3437
|
+
var import_node_path13 = require("node:path");
|
|
3222
3438
|
function matchGlob(pattern, id) {
|
|
3223
3439
|
const patParts = pattern.split("/");
|
|
3224
3440
|
const idParts = id.split("/");
|
|
@@ -3251,13 +3467,13 @@ function detectConventionDirs(rootDir, extraConventionDirs = []) {
|
|
|
3251
3467
|
const conventionDirs = [...CONVENTION_DIRS_BUILTIN, ...extraConventionDirs];
|
|
3252
3468
|
const searchDirs = [
|
|
3253
3469
|
rootDir,
|
|
3254
|
-
(0,
|
|
3255
|
-
(0,
|
|
3256
|
-
(0,
|
|
3470
|
+
(0, import_node_path13.join)(rootDir, "src"),
|
|
3471
|
+
(0, import_node_path13.join)(rootDir, "app"),
|
|
3472
|
+
(0, import_node_path13.join)(rootDir, "lib")
|
|
3257
3473
|
];
|
|
3258
3474
|
for (const base of searchDirs) {
|
|
3259
3475
|
for (const convention of conventionDirs) {
|
|
3260
|
-
const dir = (0,
|
|
3476
|
+
const dir = (0, import_node_path13.join)(base, convention);
|
|
3261
3477
|
if (!(0, import_node_fs13.existsSync)(dir)) continue;
|
|
3262
3478
|
try {
|
|
3263
3479
|
const stat = (0, import_node_fs13.statSync)(dir);
|
|
@@ -3556,7 +3772,7 @@ function loadCustomTaggers(registry, config, rootDir, disabled) {
|
|
|
3556
3772
|
for (const entry of config.taggers?.custom ?? []) {
|
|
3557
3773
|
if (disabled.has(entry.id)) continue;
|
|
3558
3774
|
try {
|
|
3559
|
-
const absPath = (0,
|
|
3775
|
+
const absPath = (0, import_node_path14.resolve)(rootDir, entry.path);
|
|
3560
3776
|
const mod = require(absPath);
|
|
3561
3777
|
const tagger = "default" in mod ? mod.default : mod;
|
|
3562
3778
|
const override = config.taggers?.trackUntagged?.[tagger.id];
|
|
@@ -3580,12 +3796,12 @@ function createTaggerRegistry(config, rootDir) {
|
|
|
3580
3796
|
|
|
3581
3797
|
// src/server/graph/core/tag-store.ts
|
|
3582
3798
|
var import_node_fs14 = require("node:fs");
|
|
3583
|
-
var
|
|
3799
|
+
var import_node_path15 = require("node:path");
|
|
3584
3800
|
var TAGS_FILENAME = "tags.json";
|
|
3585
3801
|
var GRAPHS_DIR = ".launchsecure/graphs";
|
|
3586
3802
|
var tagCache = /* @__PURE__ */ new Map();
|
|
3587
3803
|
function tagsFilePath(rootDir) {
|
|
3588
|
-
return (0,
|
|
3804
|
+
return (0, import_node_path15.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
|
|
3589
3805
|
}
|
|
3590
3806
|
function readTagStore(rootDir) {
|
|
3591
3807
|
const filePath = tagsFilePath(rootDir);
|
|
@@ -3606,7 +3822,7 @@ function readTagStore(rootDir) {
|
|
|
3606
3822
|
}
|
|
3607
3823
|
function writeTagStore(rootDir, store) {
|
|
3608
3824
|
const filePath = tagsFilePath(rootDir);
|
|
3609
|
-
const dir = (0,
|
|
3825
|
+
const dir = (0, import_node_path15.dirname)(filePath);
|
|
3610
3826
|
(0, import_node_fs14.mkdirSync)(dir, { recursive: true });
|
|
3611
3827
|
const cleaned = {};
|
|
3612
3828
|
for (const [nodeId, tags] of Object.entries(store)) {
|
|
@@ -3637,20 +3853,20 @@ function removeTag(rootDir, nodeId, key) {
|
|
|
3637
3853
|
init_ts_extractor();
|
|
3638
3854
|
var GRAPHS_DIR2 = ".launchsecure/graphs";
|
|
3639
3855
|
function getAvailableLayers(rootDir) {
|
|
3640
|
-
const dir = (0,
|
|
3856
|
+
const dir = (0, import_node_path16.join)(rootDir, GRAPHS_DIR2);
|
|
3641
3857
|
if (!(0, import_node_fs15.existsSync)(dir)) return [];
|
|
3642
3858
|
return (0, import_node_fs15.readdirSync)(dir).filter((f) => f.endsWith(".json") && f !== "tags.json").map((f) => f.replace(".json", ""));
|
|
3643
3859
|
}
|
|
3644
3860
|
var graphCache = /* @__PURE__ */ new Map();
|
|
3645
3861
|
var taggedCache = /* @__PURE__ */ new Map();
|
|
3646
3862
|
function graphsDir(rootDir) {
|
|
3647
|
-
return (0,
|
|
3863
|
+
return (0, import_node_path16.join)(rootDir, GRAPHS_DIR2);
|
|
3648
3864
|
}
|
|
3649
3865
|
function graphFilePath(rootDir, layer) {
|
|
3650
|
-
return (0,
|
|
3866
|
+
return (0, import_node_path16.join)(graphsDir(rootDir), `${layer}.json`);
|
|
3651
3867
|
}
|
|
3652
3868
|
function tagsFilePath2(rootDir) {
|
|
3653
|
-
return (0,
|
|
3869
|
+
return (0, import_node_path16.join)(graphsDir(rootDir), "tags.json");
|
|
3654
3870
|
}
|
|
3655
3871
|
function getMtimeMs(filePath) {
|
|
3656
3872
|
if (!(0, import_node_fs15.existsSync)(filePath)) return 0;
|
|
@@ -3751,15 +3967,15 @@ async function generateGraph(rootDir, layer) {
|
|
|
3751
3967
|
var import_node_child_process = require("node:child_process");
|
|
3752
3968
|
var import_node_fs16 = require("node:fs");
|
|
3753
3969
|
var import_node_os = require("node:os");
|
|
3754
|
-
var
|
|
3970
|
+
var import_node_path17 = require("node:path");
|
|
3755
3971
|
function lockDir(projectRoot) {
|
|
3756
3972
|
if (projectRoot) {
|
|
3757
|
-
return (0,
|
|
3973
|
+
return (0, import_node_path17.join)(projectRoot, ".launchsecure");
|
|
3758
3974
|
}
|
|
3759
|
-
return (0,
|
|
3975
|
+
return (0, import_node_path17.join)((0, import_node_os.homedir)(), ".launchsecure");
|
|
3760
3976
|
}
|
|
3761
3977
|
function lockPath(projectRoot) {
|
|
3762
|
-
return (0,
|
|
3978
|
+
return (0, import_node_path17.join)(lockDir(projectRoot), "launch-chart.lock");
|
|
3763
3979
|
}
|
|
3764
3980
|
var _activeProjectRoot;
|
|
3765
3981
|
function readLock(projectRoot) {
|
|
@@ -3844,9 +4060,9 @@ init_config();
|
|
|
3844
4060
|
|
|
3845
4061
|
// src/server/graph/core/audit-core.ts
|
|
3846
4062
|
var import_node_fs17 = require("node:fs");
|
|
3847
|
-
var
|
|
4063
|
+
var import_node_path18 = require("node:path");
|
|
3848
4064
|
function readGraphFile(rootDir, layer) {
|
|
3849
|
-
const filePath = (0,
|
|
4065
|
+
const filePath = (0, import_node_path18.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
|
|
3850
4066
|
if (!(0, import_node_fs17.existsSync)(filePath)) return null;
|
|
3851
4067
|
try {
|
|
3852
4068
|
return JSON.parse((0, import_node_fs17.readFileSync)(filePath, "utf-8"));
|
|
@@ -3893,7 +4109,7 @@ function checkUnprotectedRoutes(rootDir) {
|
|
|
3893
4109
|
const api = readGraphFile(rootDir, "api");
|
|
3894
4110
|
const staticGraph = readGraphFile(rootDir, "static");
|
|
3895
4111
|
if (!api) return buildReport("api", "unprotected_routes", findings);
|
|
3896
|
-
const routePermsPath = (0,
|
|
4112
|
+
const routePermsPath = (0, import_node_path18.join)(rootDir, "src", "config", "route-permissions.ts");
|
|
3897
4113
|
let routePermsContent = "";
|
|
3898
4114
|
if ((0, import_node_fs17.existsSync)(routePermsPath)) {
|
|
3899
4115
|
routePermsContent = (0, import_node_fs17.readFileSync)(routePermsPath, "utf-8");
|
|
@@ -3973,7 +4189,7 @@ function checkUnenforcedPermissions(rootDir) {
|
|
|
3973
4189
|
const staticGraph = readGraphFile(rootDir, "static");
|
|
3974
4190
|
if (!staticGraph) return buildReport("static", "unenforced_permissions", findings);
|
|
3975
4191
|
const permissions = staticGraph.nodes.filter((n) => n.type === "seed_permission").map((n) => ({ id: n.id, key: n.value, name: n.name }));
|
|
3976
|
-
const routePermsPath = (0,
|
|
4192
|
+
const routePermsPath = (0, import_node_path18.join)(rootDir, "src", "config", "route-permissions.ts");
|
|
3977
4193
|
let routePermsContent = "";
|
|
3978
4194
|
if ((0, import_node_fs17.existsSync)(routePermsPath)) {
|
|
3979
4195
|
routePermsContent = (0, import_node_fs17.readFileSync)(routePermsPath, "utf-8");
|
|
@@ -4006,7 +4222,7 @@ function checkHardcodedValues(rootDir) {
|
|
|
4006
4222
|
const seen = /* @__PURE__ */ new Set();
|
|
4007
4223
|
for (const node of api.nodes) {
|
|
4008
4224
|
if (node.type !== "endpoint") continue;
|
|
4009
|
-
const filePath = (0,
|
|
4225
|
+
const filePath = (0, import_node_path18.join)(rootDir, "src", node.id);
|
|
4010
4226
|
if (!(0, import_node_fs17.existsSync)(filePath)) continue;
|
|
4011
4227
|
const content = (0, import_node_fs17.readFileSync)(filePath, "utf-8");
|
|
4012
4228
|
let m;
|
|
@@ -4138,16 +4354,16 @@ var MIME_TYPES = {
|
|
|
4138
4354
|
function findProjectRoot(startDir) {
|
|
4139
4355
|
let dir = startDir;
|
|
4140
4356
|
for (let i = 0; i < 8; i++) {
|
|
4141
|
-
const graphsDir2 =
|
|
4142
|
-
if (import_node_fs18.default.existsSync(
|
|
4143
|
-
const parent =
|
|
4357
|
+
const graphsDir2 = import_node_path19.default.join(dir, ".launchsecure", "graphs");
|
|
4358
|
+
if (import_node_fs18.default.existsSync(import_node_path19.default.join(graphsDir2, "ui.json")) || import_node_fs18.default.existsSync(import_node_path19.default.join(graphsDir2, "api.json")) || import_node_fs18.default.existsSync(import_node_path19.default.join(graphsDir2, "db.json"))) return dir;
|
|
4359
|
+
const parent = import_node_path19.default.dirname(dir);
|
|
4144
4360
|
if (parent === dir) break;
|
|
4145
4361
|
dir = parent;
|
|
4146
4362
|
}
|
|
4147
4363
|
dir = startDir;
|
|
4148
4364
|
for (let i = 0; i < 8; i++) {
|
|
4149
|
-
if (import_node_fs18.default.existsSync(
|
|
4150
|
-
const parent =
|
|
4365
|
+
if (import_node_fs18.default.existsSync(import_node_path19.default.join(dir, ".git"))) return dir;
|
|
4366
|
+
const parent = import_node_path19.default.dirname(dir);
|
|
4151
4367
|
if (parent === dir) break;
|
|
4152
4368
|
dir = parent;
|
|
4153
4369
|
}
|
|
@@ -4156,7 +4372,7 @@ function findProjectRoot(startDir) {
|
|
|
4156
4372
|
function resolveRequestRoot(url, monorepoRoot, projects) {
|
|
4157
4373
|
const projectParam = url.searchParams.get("project");
|
|
4158
4374
|
if (!projectParam || projects.length === 0) return monorepoRoot;
|
|
4159
|
-
const resolved =
|
|
4375
|
+
const resolved = import_node_path19.default.resolve(monorepoRoot, projectParam);
|
|
4160
4376
|
if (!resolved.startsWith(monorepoRoot)) {
|
|
4161
4377
|
throw new Error("Project path outside monorepo root");
|
|
4162
4378
|
}
|
|
@@ -4208,14 +4424,14 @@ async function buildMergedGraph(root) {
|
|
|
4208
4424
|
}
|
|
4209
4425
|
function serveStatic(res, filePath) {
|
|
4210
4426
|
if (!import_node_fs18.default.existsSync(filePath) || !import_node_fs18.default.statSync(filePath).isFile()) return false;
|
|
4211
|
-
const ext =
|
|
4427
|
+
const ext = import_node_path19.default.extname(filePath).toLowerCase();
|
|
4212
4428
|
const mime = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
4213
4429
|
res.writeHead(200, { "Content-Type": mime, "Cache-Control": "no-cache" });
|
|
4214
4430
|
import_node_fs18.default.createReadStream(filePath).pipe(res);
|
|
4215
4431
|
return true;
|
|
4216
4432
|
}
|
|
4217
4433
|
function serveIndex(res, clientDir) {
|
|
4218
|
-
const indexPath =
|
|
4434
|
+
const indexPath = import_node_path19.default.join(clientDir, "index.html");
|
|
4219
4435
|
if (!import_node_fs18.default.existsSync(indexPath)) {
|
|
4220
4436
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
4221
4437
|
res.end(`LaunchChart client bundle not found at ${clientDir}. Run 'npm run build:chart-client'.`);
|
|
@@ -4224,14 +4440,14 @@ function serveIndex(res, clientDir) {
|
|
|
4224
4440
|
serveStatic(res, indexPath);
|
|
4225
4441
|
}
|
|
4226
4442
|
function tryListen(server, port) {
|
|
4227
|
-
return new Promise((
|
|
4443
|
+
return new Promise((resolve4, reject) => {
|
|
4228
4444
|
const onError = (err) => {
|
|
4229
4445
|
server.off("listening", onListening);
|
|
4230
4446
|
reject(err);
|
|
4231
4447
|
};
|
|
4232
4448
|
const onListening = () => {
|
|
4233
4449
|
server.off("error", onError);
|
|
4234
|
-
|
|
4450
|
+
resolve4(port);
|
|
4235
4451
|
};
|
|
4236
4452
|
server.once("error", onError);
|
|
4237
4453
|
server.once("listening", onListening);
|
|
@@ -4268,7 +4484,7 @@ async function startChartServer(opts = {}) {
|
|
|
4268
4484
|
}
|
|
4269
4485
|
return { port: existing.port, url: existing.url };
|
|
4270
4486
|
}
|
|
4271
|
-
const clientDir = opts.clientDir ??
|
|
4487
|
+
const clientDir = opts.clientDir ?? import_node_path19.default.join(__dirname, "..", "chart-client");
|
|
4272
4488
|
const rootConfig = loadConfig(projectRoot);
|
|
4273
4489
|
const projects = rootConfig.projects ?? [];
|
|
4274
4490
|
const server = import_node_http.default.createServer((req, res) => {
|
|
@@ -4284,11 +4500,11 @@ async function startChartServer(opts = {}) {
|
|
|
4284
4500
|
}
|
|
4285
4501
|
if (req.method === "GET" && url2.pathname === "/api/projects") {
|
|
4286
4502
|
const projectList = projects.length > 0 ? projects.map((p) => {
|
|
4287
|
-
const absRoot =
|
|
4288
|
-
const hasGraphs = import_node_fs18.default.existsSync(
|
|
4289
|
-
const hasNextConfig = import_node_fs18.default.existsSync(
|
|
4503
|
+
const absRoot = import_node_path19.default.resolve(projectRoot, p.root);
|
|
4504
|
+
const hasGraphs = import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, ".launchsecure", "graphs"));
|
|
4505
|
+
const hasNextConfig = import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, "next.config.ts")) || import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, "next.config.js")) || import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, "next.config.mjs"));
|
|
4290
4506
|
return { name: p.name, root: p.root, hasGraphs, hasNextConfig };
|
|
4291
|
-
}) : [{ name:
|
|
4507
|
+
}) : [{ name: import_node_path19.default.basename(projectRoot), root: ".", hasGraphs: import_node_fs18.default.existsSync(import_node_path19.default.join(projectRoot, ".launchsecure", "graphs")), hasNextConfig: true }];
|
|
4292
4508
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4293
4509
|
res.end(JSON.stringify({ projects: projectList, monorepoRoot: projectRoot }));
|
|
4294
4510
|
return;
|
|
@@ -4334,18 +4550,18 @@ async function startChartServer(opts = {}) {
|
|
|
4334
4550
|
}
|
|
4335
4551
|
if (req.method === "GET" && url2.pathname === "/api/file-content") {
|
|
4336
4552
|
const relPath = url2.searchParams.get("path");
|
|
4337
|
-
if (!relPath || relPath.includes("..") ||
|
|
4553
|
+
if (!relPath || relPath.includes("..") || import_node_path19.default.isAbsolute(relPath)) {
|
|
4338
4554
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
4339
4555
|
res.end(JSON.stringify({ error: "Invalid path" }));
|
|
4340
4556
|
return;
|
|
4341
4557
|
}
|
|
4342
|
-
const filePath =
|
|
4558
|
+
const filePath = import_node_path19.default.join(reqRoot, relPath);
|
|
4343
4559
|
if (!filePath.startsWith(reqRoot) || !import_node_fs18.default.existsSync(filePath) || !import_node_fs18.default.statSync(filePath).isFile()) {
|
|
4344
4560
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
4345
4561
|
res.end(JSON.stringify({ error: "File not found" }));
|
|
4346
4562
|
return;
|
|
4347
4563
|
}
|
|
4348
|
-
const ext =
|
|
4564
|
+
const ext = import_node_path19.default.extname(filePath).toLowerCase();
|
|
4349
4565
|
const langMap = { ".ts": "typescript", ".tsx": "tsx", ".js": "javascript", ".jsx": "jsx", ".prisma": "prisma", ".json": "json", ".css": "css" };
|
|
4350
4566
|
const content = import_node_fs18.default.readFileSync(filePath, "utf-8");
|
|
4351
4567
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -4389,7 +4605,7 @@ async function startChartServer(opts = {}) {
|
|
|
4389
4605
|
req.on("end", () => {
|
|
4390
4606
|
try {
|
|
4391
4607
|
const newConfig = JSON.parse(body);
|
|
4392
|
-
const configPath =
|
|
4608
|
+
const configPath = import_node_path19.default.join(reqRoot, ".launchchart.json");
|
|
4393
4609
|
import_node_fs18.default.writeFileSync(configPath, JSON.stringify(newConfig, null, 2) + "\n", "utf-8");
|
|
4394
4610
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4395
4611
|
res.end(JSON.stringify({ ok: true }));
|
|
@@ -4423,7 +4639,7 @@ async function startChartServer(opts = {}) {
|
|
|
4423
4639
|
const taggerConfig = JSON.parse(body);
|
|
4424
4640
|
const config2 = loadConfig(reqRoot);
|
|
4425
4641
|
config2.taggers = taggerConfig;
|
|
4426
|
-
const configPath =
|
|
4642
|
+
const configPath = import_node_path19.default.join(reqRoot, ".launchchart.json");
|
|
4427
4643
|
import_node_fs18.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
4428
4644
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4429
4645
|
res.end(JSON.stringify({ ok: true }));
|
|
@@ -4491,16 +4707,23 @@ async function startChartServer(opts = {}) {
|
|
|
4491
4707
|
const paths = resolveProjectPaths(reqRoot, config2);
|
|
4492
4708
|
const overrides = {
|
|
4493
4709
|
appDir: !!config2.paths?.appDir,
|
|
4494
|
-
dbDir: !!config2.paths?.dbDir
|
|
4710
|
+
dbDir: !!config2.paths?.dbDir,
|
|
4711
|
+
srcRoots: !!(config2.paths?.srcRoots && config2.paths.srcRoots.length > 0)
|
|
4495
4712
|
};
|
|
4713
|
+
const relFromRoot = (abs) => import_node_path19.default.relative(reqRoot, abs) || ".";
|
|
4496
4714
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4497
4715
|
res.end(JSON.stringify({
|
|
4498
4716
|
projectRoot: reqRoot,
|
|
4499
4717
|
detected: paths ? {
|
|
4500
|
-
srcDir:
|
|
4501
|
-
appDir:
|
|
4502
|
-
apiDir:
|
|
4503
|
-
dbDir: paths.dbDir ?
|
|
4718
|
+
srcDir: relFromRoot(paths.srcDir),
|
|
4719
|
+
appDir: relFromRoot(paths.appDir),
|
|
4720
|
+
apiDir: relFromRoot(paths.apiDir),
|
|
4721
|
+
dbDir: paths.dbDir ? relFromRoot(paths.dbDir) : null,
|
|
4722
|
+
dbKind: paths.dbConfig.kind,
|
|
4723
|
+
dbSchemaPath: paths.dbConfig.schemaPath ? relFromRoot(paths.dbConfig.schemaPath) : null,
|
|
4724
|
+
dbMigrationsDir: paths.dbConfig.migrationsDir ? relFromRoot(paths.dbConfig.migrationsDir) : null,
|
|
4725
|
+
srcRoots: paths.srcRoots.map(relFromRoot),
|
|
4726
|
+
conventionFiles: paths.conventionFiles.map(relFromRoot)
|
|
4504
4727
|
} : null,
|
|
4505
4728
|
overrides,
|
|
4506
4729
|
isOverride: overrides.appDir
|
|
@@ -4509,8 +4732,8 @@ async function startChartServer(opts = {}) {
|
|
|
4509
4732
|
}
|
|
4510
4733
|
if (req.method === "GET" && url2.pathname === "/api/browse-dir") {
|
|
4511
4734
|
const browsePath = url2.searchParams.get("path") || projectRoot;
|
|
4512
|
-
const abs =
|
|
4513
|
-
const twoUp =
|
|
4735
|
+
const abs = import_node_path19.default.resolve(browsePath);
|
|
4736
|
+
const twoUp = import_node_path19.default.resolve(projectRoot, "..", "..");
|
|
4514
4737
|
if (!abs.startsWith(twoUp)) {
|
|
4515
4738
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
4516
4739
|
res.end(JSON.stringify({ ok: false, error: "Path outside allowed range" }));
|
|
@@ -4519,9 +4742,9 @@ async function startChartServer(opts = {}) {
|
|
|
4519
4742
|
try {
|
|
4520
4743
|
const entries = import_node_fs18.default.readdirSync(abs, { withFileTypes: true });
|
|
4521
4744
|
const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "node_modules" && e.name !== "dist" && e.name !== ".next").map((e) => e.name).sort();
|
|
4522
|
-
const parent = abs !== twoUp ?
|
|
4745
|
+
const parent = abs !== twoUp ? import_node_path19.default.dirname(abs) : null;
|
|
4523
4746
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4524
|
-
res.end(JSON.stringify({ current: abs, parent, dirs, relative:
|
|
4747
|
+
res.end(JSON.stringify({ current: abs, parent, dirs, relative: import_node_path19.default.relative(projectRoot, abs) || "." }));
|
|
4525
4748
|
} catch (err) {
|
|
4526
4749
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
4527
4750
|
res.end(JSON.stringify({ ok: false, error: String(err) }));
|
|
@@ -4547,7 +4770,7 @@ async function startChartServer(opts = {}) {
|
|
|
4547
4770
|
const { projects: newProjects } = JSON.parse(body);
|
|
4548
4771
|
const config2 = loadConfig(projectRoot);
|
|
4549
4772
|
config2.projects = newProjects.length > 0 ? newProjects : void 0;
|
|
4550
|
-
const configPath =
|
|
4773
|
+
const configPath = import_node_path19.default.join(projectRoot, ".launchchart.json");
|
|
4551
4774
|
import_node_fs18.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
4552
4775
|
projects.length = 0;
|
|
4553
4776
|
if (config2.projects) projects.push(...config2.projects);
|
|
@@ -4561,7 +4784,7 @@ async function startChartServer(opts = {}) {
|
|
|
4561
4784
|
return;
|
|
4562
4785
|
}
|
|
4563
4786
|
if (url2.pathname !== "/") {
|
|
4564
|
-
const staticPath =
|
|
4787
|
+
const staticPath = import_node_path19.default.join(clientDir, url2.pathname);
|
|
4565
4788
|
if (serveStatic(res, staticPath)) return;
|
|
4566
4789
|
}
|
|
4567
4790
|
serveIndex(res, clientDir);
|