@launchsecure/launch-kit 0.0.23 → 0.0.25

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.
Files changed (60) hide show
  1. package/dist/deck-client/assets/{_baseUniq-DsfOm3t_.js → _baseUniq-2gclQXo7.js} +1 -1
  2. package/dist/deck-client/assets/{arc-NJuvkBv1.js → arc-DcMY5Wm0.js} +1 -1
  3. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-BgrcgZs0.js → architectureDiagram-Q4EWVU46-B8iirmmJ.js} +1 -1
  4. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-C3XoLi15.js → blockDiagram-DXYQGD6D-B4JBLjmJ.js} +1 -1
  5. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-FX2PjLfb.js → c4Diagram-AHTNJAMY-CojrJAk8.js} +1 -1
  6. package/dist/deck-client/assets/channel-ERh5jKXV.js +1 -0
  7. package/dist/deck-client/assets/{chunk-4BX2VUAB-D0aqsJV0.js → chunk-4BX2VUAB-Bmb_BMDo.js} +1 -1
  8. package/dist/deck-client/assets/{chunk-4TB4RGXK-7qRCCAgK.js → chunk-4TB4RGXK-CumBy8qe.js} +1 -1
  9. package/dist/deck-client/assets/{chunk-55IACEB6-DfHG-iqb.js → chunk-55IACEB6-Ka8Hb1wD.js} +1 -1
  10. package/dist/deck-client/assets/{chunk-EDXVE4YY-DrR52j3B.js → chunk-EDXVE4YY-B3sIPiQo.js} +1 -1
  11. package/dist/deck-client/assets/{chunk-FMBD7UC4-D5KSGATB.js → chunk-FMBD7UC4-C1tYkaqu.js} +1 -1
  12. package/dist/deck-client/assets/{chunk-OYMX7WX6-M7hsLRNU.js → chunk-OYMX7WX6-D7Wacbky.js} +1 -1
  13. package/dist/deck-client/assets/{chunk-QZHKN3VN-1ynAWO2m.js → chunk-QZHKN3VN-ChXI0vO3.js} +1 -1
  14. package/dist/deck-client/assets/{chunk-YZCP3GAM-S2-nGw3D.js → chunk-YZCP3GAM-BXhiqf8u.js} +1 -1
  15. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CMi1Gaev.js +1 -0
  16. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CMi1Gaev.js +1 -0
  17. package/dist/deck-client/assets/clone-DfWhlD4X.js +1 -0
  18. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-BcMwozS2.js → cose-bilkent-S5V4N54A-Bqp3p68D.js} +1 -1
  19. package/dist/deck-client/assets/{dagre-KV5264BT-DtKMhl_1.js → dagre-KV5264BT-BS-rtyhZ.js} +1 -1
  20. package/dist/deck-client/assets/{diagram-5BDNPKRD-1plH69us.js → diagram-5BDNPKRD-BIrj9YGI.js} +1 -1
  21. package/dist/deck-client/assets/{diagram-G4DWMVQ6-D_o-BHO3.js → diagram-G4DWMVQ6-noHWPIg4.js} +1 -1
  22. package/dist/deck-client/assets/{diagram-MMDJMWI5-ClZ1LIx6.js → diagram-MMDJMWI5-C2qHxvqV.js} +1 -1
  23. package/dist/deck-client/assets/{diagram-TYMM5635-B8dKHfRh.js → diagram-TYMM5635-BytnGQr-.js} +1 -1
  24. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-CY2aCH7-.js → erDiagram-SMLLAGMA-BfK5m2YQ.js} +1 -1
  25. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-DZZWHti8.js → flowDiagram-DWJPFMVM-Cq925G1Z.js} +1 -1
  26. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-OwGGa6Lu.js → ganttDiagram-T4ZO3ILL-DhhHPAmj.js} +1 -1
  27. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-GKyWD4Qt.js → gitGraphDiagram-UUTBAWPF-B3Lc0h9q.js} +1 -1
  28. package/dist/deck-client/assets/{graph-CORzYQdB.js → graph-RTawgVWm.js} +1 -1
  29. package/dist/deck-client/assets/{index-hiIpM7EP.js → index-BfIfJXmS.js} +3 -3
  30. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-DmgqJCcF.js → infoDiagram-42DDH7IO-BlR584kX.js} +1 -1
  31. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-D-1v7knu.js → ishikawaDiagram-UXIWVN3A-DygKoNGY.js} +1 -1
  32. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-CYrGQE7b.js → journeyDiagram-VCZTEJTY-BnaiYp9N.js} +1 -1
  33. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-BJFDWiH-.js → kanban-definition-6JOO6SKY-BQBUBzJC.js} +1 -1
  34. package/dist/deck-client/assets/{layout-BTFFcaxF.js → layout-DeZ8HI1T.js} +1 -1
  35. package/dist/deck-client/assets/{linear-DAbl6COS.js → linear-C6roLi_9.js} +1 -1
  36. package/dist/deck-client/assets/{min-oWHBrFBm.js → min-CbUksbuI.js} +1 -1
  37. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-BTCB0VLO.js → mindmap-definition-QFDTVHPH-iNxV62yN.js} +1 -1
  38. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-CUZChWNA.js → pieDiagram-DEJITSTG-DHVA0jaG.js} +1 -1
  39. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-4M1Um_e4.js → quadrantDiagram-34T5L4WZ-DBeKKLUQ.js} +1 -1
  40. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-DLzQZ0B3.js → requirementDiagram-MS252O5E-CBwITx7p.js} +1 -1
  41. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-DcNgzV3E.js → sankeyDiagram-XADWPNL6-BtE-1YTU.js} +1 -1
  42. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-CAcI2vC9.js → sequenceDiagram-FGHM5R23-DN96yPP2.js} +1 -1
  43. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-CntjTTm5.js → stateDiagram-FHFEXIEX-VUkKC2uJ.js} +1 -1
  44. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CA0IjulK.js +1 -0
  45. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-D8zrit4U.js → timeline-definition-GMOUNBTQ-oUeZhRns.js} +1 -1
  46. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-C4SuFPgo.js → vennDiagram-DHZGUBPP-D87fK90n.js} +1 -1
  47. package/dist/deck-client/assets/wardley-RL74JXVD-DYbYcpDp.js +162 -0
  48. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-kj73r6f-.js → wardleyDiagram-NUSXRM2D-Ca_i0QRA.js} +1 -1
  49. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CC_d_Ey3.js → xychartDiagram-5P7HB3ND-CUOJVIvq.js} +1 -1
  50. package/dist/deck-client/index.html +1 -1
  51. package/dist/server/chart-serve.js +368 -27
  52. package/dist/server/cli.js +368 -27
  53. package/dist/server/graph-mcp-entry.js +368 -27
  54. package/package.json +1 -1
  55. package/dist/deck-client/assets/channel-ChQjD1T1.js +0 -1
  56. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-B_9iqK1S.js +0 -1
  57. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-B_9iqK1S.js +0 -1
  58. package/dist/deck-client/assets/clone-BYt1AMfz.js +0 -1
  59. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-YiaphOU_.js +0 -1
  60. package/dist/deck-client/assets/wardley-RL74JXVD-B3F-Olcq.js +0 -162
@@ -175,6 +175,7 @@ function walkWithIgnore(dir, exts, opts = {}) {
175
175
  const skip = opts.extraIgnore ? /* @__PURE__ */ new Set([...DEFAULT_IGNORE_DIRS, ...opts.extraIgnore]) : DEFAULT_IGNORE_DIRS;
176
176
  for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
177
177
  if (entry.isDirectory()) {
178
+ if (entry.name.startsWith(".")) continue;
178
179
  if (skip.has(entry.name)) continue;
179
180
  results.push(...walkWithIgnore((0, import_node_path3.join)(dir, entry.name), exts, opts));
180
181
  } else if (exts.includes((0, import_node_path3.extname)(entry.name))) {
@@ -191,15 +192,9 @@ var init_walk = __esm({
191
192
  import_node_path3 = require("node:path");
192
193
  DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
193
194
  "node_modules",
194
- ".git",
195
- ".next",
196
- ".launchsecure",
197
- ".claude",
198
195
  "dist",
199
196
  "build",
200
197
  "out",
201
- ".turbo",
202
- ".vercel",
203
198
  "coverage"
204
199
  ]);
205
200
  }
@@ -404,11 +399,14 @@ var init_resolve_paths = __esm({
404
399
  var ts_extractor_exports = {};
405
400
  __export(ts_extractor_exports, {
406
401
  classifyFile: () => classifyFile,
402
+ classifyRouteAgainstMiddleware: () => classifyRouteAgainstMiddleware,
407
403
  createQuery: () => createQuery,
408
404
  extractAuthWrappersTS: () => extractAuthWrappersTS,
409
405
  extractDbCallsTS: () => extractDbCallsTS,
410
406
  extractDeep: () => extractDeep,
407
+ extractMiddlewareAuthTS: () => extractMiddlewareAuthTS,
411
408
  initTreeSitter: () => initTreeSitter,
409
+ middlewarePatternToRegex: () => middlewarePatternToRegex,
412
410
  parseCodeTS: () => parseCodeTS,
413
411
  parseFileTS: () => parseFileTS,
414
412
  setExtractorConfig: () => setExtractorConfig
@@ -802,6 +800,180 @@ function extractAuthWrappersTS(absPath) {
802
800
  }
803
801
  return wrappers;
804
802
  }
803
+ function inferIntentFromName(name) {
804
+ for (const re of EXEMPT_NAME_PATTERNS) {
805
+ if (re.test(name)) return { intent: "exempt", hint: `name "${name}" matches /${re.source}/` };
806
+ }
807
+ for (const re of PROTECT_NAME_PATTERNS) {
808
+ if (re.test(name)) return { intent: "protect", hint: `name "${name}" matches /${re.source}/` };
809
+ }
810
+ return { intent: "ambiguous", hint: `name "${name}" has no exempt/protect signal` };
811
+ }
812
+ function looksLikeRoutePattern(s) {
813
+ return s.startsWith("/") && !s.startsWith("//");
814
+ }
815
+ function collectStringsFromArray(arrNode) {
816
+ const out = [];
817
+ for (const child of arrNode.children) {
818
+ if (child.type !== "string") continue;
819
+ const frag = childOfType(child, "string_fragment");
820
+ if (frag) out.push(frag.text);
821
+ }
822
+ return out;
823
+ }
824
+ function findArrayInValue(valueNode) {
825
+ if (!valueNode) return null;
826
+ if (valueNode.type === "array") return valueNode;
827
+ if (valueNode.type === "call_expression") {
828
+ const args = childOfType(valueNode, "arguments");
829
+ if (!args) return null;
830
+ for (const c of args.children) {
831
+ if (c.type === "array") return c;
832
+ }
833
+ }
834
+ return null;
835
+ }
836
+ function extractMatcherFromDeclarator(decl) {
837
+ const nameNode = childOfType(decl, "identifier");
838
+ if (!nameNode) return null;
839
+ let valueNode;
840
+ for (const c of decl.children) {
841
+ if (c.type === "identifier" || c.type === "=" || c.type === "type_annotation") continue;
842
+ valueNode = c;
843
+ }
844
+ const arr = findArrayInValue(valueNode);
845
+ if (!arr) return null;
846
+ const strings = collectStringsFromArray(arr);
847
+ const routes = strings.filter(looksLikeRoutePattern);
848
+ if (routes.length === 0) return null;
849
+ const { intent, hint } = inferIntentFromName(nameNode.text);
850
+ return { name: nameNode.text, patterns: routes, intent, hint };
851
+ }
852
+ function extractMatchersFromObject(objNode) {
853
+ const out = [];
854
+ for (const pair of childrenOfType(objNode, "pair")) {
855
+ const key = childOfType(pair, "property_identifier");
856
+ if (!key) continue;
857
+ const arr = pair.children.find((c) => c.type === "array");
858
+ if (!arr) continue;
859
+ const routes = collectStringsFromArray(arr).filter(looksLikeRoutePattern);
860
+ if (routes.length === 0) continue;
861
+ const { intent, hint } = inferIntentFromName(key.text);
862
+ out.push({ name: key.text, patterns: routes, intent, hint });
863
+ }
864
+ return out;
865
+ }
866
+ function detectFallthroughProtect(root) {
867
+ const text = root.text;
868
+ const signals = [
869
+ /\bauth\.protect\s*\(/,
870
+ /\bauth\(\)\.protect\s*\(/,
871
+ /\bredirect\s*\(\s*['"`]\/(sign-?in|log-?in|auth)/i,
872
+ /\bNextResponse\.redirect\s*\(/,
873
+ /\bthrow\s+new\s+\w*Unauthorized/i
874
+ ];
875
+ return signals.some((re) => re.test(text));
876
+ }
877
+ function extractMiddlewareAuthTS(absPath) {
878
+ if (!require("node:fs").existsSync(absPath)) return null;
879
+ const tree = parseSource(absPath);
880
+ const root = tree.rootNode;
881
+ const matchers = [];
882
+ for (const stmt of root.children) {
883
+ if (stmt.type !== "lexical_declaration" && stmt.type !== "variable_declaration") continue;
884
+ for (const decl of childrenOfType(stmt, "variable_declarator")) {
885
+ const m = extractMatcherFromDeclarator(decl);
886
+ if (m) matchers.push(m);
887
+ let valueNode;
888
+ for (const c of decl.children) {
889
+ if (c.type === "identifier" || c.type === "=" || c.type === "type_annotation") continue;
890
+ valueNode = c;
891
+ }
892
+ if (valueNode?.type === "object") {
893
+ for (const inner of extractMatchersFromObject(valueNode)) matchers.push(inner);
894
+ }
895
+ }
896
+ }
897
+ for (const stmt of root.children) {
898
+ if (stmt.type !== "export_statement") continue;
899
+ const decl = childOfType(stmt, "lexical_declaration") ?? childOfType(stmt, "variable_declaration");
900
+ if (!decl) continue;
901
+ for (const d of childrenOfType(decl, "variable_declarator")) {
902
+ let valueNode;
903
+ for (const c of d.children) {
904
+ if (c.type === "identifier" || c.type === "=" || c.type === "type_annotation") continue;
905
+ valueNode = c;
906
+ }
907
+ if (valueNode?.type === "object") {
908
+ for (const inner of extractMatchersFromObject(valueNode)) matchers.push(inner);
909
+ }
910
+ const m = extractMatcherFromDeclarator(d);
911
+ if (m && !matchers.some((x) => x.name === m.name && x.patterns.join() === m.patterns.join())) {
912
+ matchers.push(m);
913
+ }
914
+ }
915
+ }
916
+ return {
917
+ file: absPath,
918
+ matchers,
919
+ hasFallthroughProtect: detectFallthroughProtect(root)
920
+ };
921
+ }
922
+ function middlewarePatternToRegex(pattern) {
923
+ if (/\(\?\!/.test(pattern)) return null;
924
+ if (pattern.startsWith("(")) return null;
925
+ let src = "^";
926
+ let i = 0;
927
+ while (i < pattern.length) {
928
+ const ch = pattern[i];
929
+ if (ch === "(" && pattern.slice(i, i + 4) === "(.*)") {
930
+ src += ".*";
931
+ i += 4;
932
+ continue;
933
+ }
934
+ if (ch === ":") {
935
+ i++;
936
+ while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) i++;
937
+ src += "[^/]+";
938
+ continue;
939
+ }
940
+ if (ch === "*") {
941
+ i++;
942
+ while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) i++;
943
+ if (pattern[i] === "?") {
944
+ i++;
945
+ src += ".*";
946
+ continue;
947
+ }
948
+ src += ".+";
949
+ continue;
950
+ }
951
+ if (/[.\\+?^${}()|[\]]/.test(ch)) {
952
+ src += "\\" + ch;
953
+ i++;
954
+ continue;
955
+ }
956
+ src += ch;
957
+ i++;
958
+ }
959
+ src += "$";
960
+ try {
961
+ return new RegExp(src);
962
+ } catch {
963
+ return null;
964
+ }
965
+ }
966
+ function classifyRouteAgainstMiddleware(routePath, info) {
967
+ for (const m of info.matchers) {
968
+ if (m.intent === "ambiguous") continue;
969
+ for (const pat of m.patterns) {
970
+ const re = middlewarePatternToRegex(pat);
971
+ if (!re) continue;
972
+ if (re.test(routePath)) return { intent: m.intent, matcher: m.name, pattern: pat };
973
+ }
974
+ }
975
+ return null;
976
+ }
805
977
  function trunc(s, max = 120) {
806
978
  return s.length > max ? s.slice(0, max) + "..." : s;
807
979
  }
@@ -958,7 +1130,7 @@ function extractDeep(absPath) {
958
1130
  }
959
1131
  return { elements, stateVars, conditions, variables, responses, params };
960
1132
  }
961
- var import_node_fs5, import_node_path5, tsxLanguage, parserInstance, initPromise, initialized, queriesDir, queryCache, PRISMA_MUTATION_METHODS_BUILTIN, SUPABASE_MUTATION_METHODS_BUILTIN, DB_IDENTIFIERS_FALLBACK, extraDbIdentifiers, extraMutationMethods, INLINE_AUTH_IMPORTS;
1133
+ var import_node_fs5, import_node_path5, tsxLanguage, parserInstance, initPromise, initialized, queriesDir, queryCache, PRISMA_MUTATION_METHODS_BUILTIN, SUPABASE_MUTATION_METHODS_BUILTIN, DB_IDENTIFIERS_FALLBACK, extraDbIdentifiers, extraMutationMethods, INLINE_AUTH_IMPORTS, EXEMPT_NAME_PATTERNS, PROTECT_NAME_PATTERNS;
962
1134
  var init_ts_extractor = __esm({
963
1135
  "src/server/graph/core/ts-extractor.ts"() {
964
1136
  "use strict";
@@ -997,6 +1169,29 @@ var init_ts_extractor = __esm({
997
1169
  { module: /^@auth\//, helpers: ["auth"] },
998
1170
  { module: /^@supabase\/auth-helpers/, helpers: ["createServerClient"] }
999
1171
  ];
1172
+ EXEMPT_NAME_PATTERNS = [
1173
+ /^is_?public/i,
1174
+ /^public_?routes?/i,
1175
+ /^public_?paths?/i,
1176
+ /^whitelist/i,
1177
+ /^allowlist/i,
1178
+ /^unauthenticated/i,
1179
+ /^anonymous/i,
1180
+ /^guest/i,
1181
+ /^skip_?auth/i,
1182
+ /^bypass/i
1183
+ ];
1184
+ PROTECT_NAME_PATTERNS = [
1185
+ /^is_?protected/i,
1186
+ /^protected_?routes?/i,
1187
+ /^protected_?paths?/i,
1188
+ /^require_?auth/i,
1189
+ /^auth_?required/i,
1190
+ /^private_?routes?/i,
1191
+ /^is_?admin/i,
1192
+ /^admin_?routes?/i,
1193
+ /^secured/i
1194
+ ];
1000
1195
  }
1001
1196
  });
1002
1197
 
@@ -1540,43 +1735,169 @@ function generate(rootDir) {
1540
1735
  nodeIdSet.add(externalId);
1541
1736
  uiEdges.push(...edgesFromThis);
1542
1737
  }
1738
+ const tablesByFile = /* @__PURE__ */ new Map();
1739
+ const allDbNodes = [...apiNodes, ...uiNodes];
1740
+ for (const node of allDbNodes) {
1741
+ const calls = node._dbCalls;
1742
+ if (!calls || calls.length === 0) continue;
1743
+ const map = /* @__PURE__ */ new Map();
1744
+ for (const c of calls) {
1745
+ const key = `${c.kind}:${c.model}:${c.isMutation ? "m" : "r"}`;
1746
+ if (!map.has(key)) {
1747
+ map.set(key, { model: c.model, method: c.method, isMutation: c.isMutation, kind: c.kind, via: [] });
1748
+ }
1749
+ }
1750
+ tablesByFile.set(node.id, map);
1751
+ }
1752
+ const reverseRuntimeImports = /* @__PURE__ */ new Map();
1753
+ for (const edge of uiEdges) {
1754
+ if (edge.type !== "imports" && edge.type !== "renders") continue;
1755
+ if (!reverseRuntimeImports.has(edge.target)) {
1756
+ reverseRuntimeImports.set(edge.target, /* @__PURE__ */ new Set());
1757
+ }
1758
+ reverseRuntimeImports.get(edge.target).add(edge.source);
1759
+ }
1760
+ let changed = true;
1761
+ let iterations = 0;
1762
+ while (changed && iterations < 50) {
1763
+ changed = false;
1764
+ iterations++;
1765
+ for (const [target, tableMap] of [...tablesByFile]) {
1766
+ const importers = reverseRuntimeImports.get(target);
1767
+ if (!importers) continue;
1768
+ for (const importer of importers) {
1769
+ if (importer === target) continue;
1770
+ let importerMap = tablesByFile.get(importer);
1771
+ if (!importerMap) {
1772
+ importerMap = /* @__PURE__ */ new Map();
1773
+ tablesByFile.set(importer, importerMap);
1774
+ }
1775
+ for (const [key, call] of tableMap) {
1776
+ if (importerMap.has(key)) continue;
1777
+ importerMap.set(key, {
1778
+ model: call.model,
1779
+ method: null,
1780
+ isMutation: call.isMutation,
1781
+ kind: call.kind,
1782
+ via: [...call.via, target]
1783
+ });
1784
+ changed = true;
1785
+ }
1786
+ }
1787
+ }
1788
+ }
1789
+ for (const node of apiNodes) {
1790
+ const map = tablesByFile.get(node.id);
1791
+ if (!map) continue;
1792
+ node.db_models = [...new Set([...map.values()].map((c) => c.model))];
1793
+ node.db_operations = [...new Set(
1794
+ [...map.values()].filter((c) => c.via.length === 0 && c.method).map((c) => `${c.model}.${c.method}`)
1795
+ )];
1796
+ node.mutates = [...map.values()].some((c) => c.isMutation);
1797
+ }
1543
1798
  const apiCrossRefs = [];
1544
1799
  for (const node of apiNodes) {
1545
- const dbCalls = node._dbCalls;
1546
- if (!dbCalls) continue;
1547
- const seenModels = /* @__PURE__ */ new Set();
1548
- for (const call of dbCalls) {
1800
+ const map = tablesByFile.get(node.id);
1801
+ if (!map) {
1802
+ delete node._dbCalls;
1803
+ continue;
1804
+ }
1805
+ const seenTargets = /* @__PURE__ */ new Set();
1806
+ for (const call of map.values()) {
1549
1807
  const target = call.kind === "sql" ? call.model : camelToPascal(call.model);
1550
- if (seenModels.has(target)) continue;
1551
- seenModels.add(target);
1552
- apiCrossRefs.push({
1808
+ if (seenTargets.has(target)) continue;
1809
+ seenTargets.add(target);
1810
+ const isTransitive = call.via.length > 0;
1811
+ const ref = {
1553
1812
  source: node.id,
1554
1813
  target,
1555
- type: call.isMutation ? "mutates" : "reads",
1814
+ type: call.isMutation ? isTransitive ? "mutates_via" : "mutates" : isTransitive ? "reads_via" : "reads",
1556
1815
  layer: "db"
1557
- });
1816
+ };
1817
+ if (isTransitive) ref.via = call.via;
1818
+ apiCrossRefs.push(ref);
1558
1819
  }
1559
1820
  delete node._dbCalls;
1560
1821
  }
1561
1822
  const uiCrossRefs = [];
1562
1823
  for (const node of uiNodes) {
1563
- const dbCalls = node._dbCalls;
1564
- if (!dbCalls) continue;
1565
- const seenModels = /* @__PURE__ */ new Set();
1566
- for (const call of dbCalls) {
1824
+ const map = tablesByFile.get(node.id);
1825
+ if (!map) {
1826
+ if (node._dbCalls) delete node._dbCalls;
1827
+ continue;
1828
+ }
1829
+ const seenTargets = /* @__PURE__ */ new Set();
1830
+ for (const call of map.values()) {
1567
1831
  const target = call.kind === "sql" ? call.model : camelToPascal(call.model);
1568
- if (seenModels.has(target)) continue;
1569
- seenModels.add(target);
1570
- uiCrossRefs.push({
1832
+ if (seenTargets.has(target)) continue;
1833
+ seenTargets.add(target);
1834
+ const isTransitive = call.via.length > 0;
1835
+ const ref = {
1571
1836
  source: node.id,
1572
1837
  target,
1573
- type: call.isMutation ? "mutates" : "reads",
1838
+ type: call.isMutation ? isTransitive ? "mutates_via" : "mutates" : isTransitive ? "reads_via" : "reads",
1574
1839
  layer: "db"
1575
- });
1840
+ };
1841
+ if (isTransitive) ref.via = call.via;
1842
+ uiCrossRefs.push(ref);
1576
1843
  }
1577
- delete node._dbCalls;
1844
+ if (node._dbCalls) delete node._dbCalls;
1578
1845
  }
1579
1846
  uiCrossRefs.sort((a, b) => a.source.localeCompare(b.source) || a.target.localeCompare(b.target));
1847
+ const middlewareInfos = [];
1848
+ for (const conv of paths.conventionFiles) {
1849
+ if (!/middleware\.tsx?$/.test(conv)) continue;
1850
+ try {
1851
+ const info = extractMiddlewareAuthTS(conv);
1852
+ if (info && info.matchers.length > 0) middlewareInfos.push(info);
1853
+ } catch {
1854
+ }
1855
+ }
1856
+ if (middlewareInfos.length > 0) {
1857
+ let setAuth2 = function(node, newTags, replaceAll) {
1858
+ const existing = node.auth ?? [];
1859
+ const meaningful = existing.filter((a) => a !== "public");
1860
+ const merged = replaceAll ? newTags : [.../* @__PURE__ */ new Set([...newTags, ...meaningful])];
1861
+ node.auth = merged.length > 0 ? merged : ["public"];
1862
+ }, applyMiddleware2 = function(node, routePath) {
1863
+ let resolved = null;
1864
+ let label = "";
1865
+ let hasAnyExemptMatcher = false;
1866
+ let hasAnyFallthrough = false;
1867
+ for (const info of middlewareInfos) {
1868
+ if (info.hasFallthroughProtect) hasAnyFallthrough = true;
1869
+ if (info.matchers.some((m) => m.intent === "exempt")) hasAnyExemptMatcher = true;
1870
+ const c = classifyRouteAgainstMiddleware(routePath, info);
1871
+ if (!c) continue;
1872
+ if (!resolved) {
1873
+ resolved = c.intent;
1874
+ label = c.matcher;
1875
+ }
1876
+ }
1877
+ if (resolved === "exempt") {
1878
+ setAuth2(node, ["public"], true);
1879
+ return;
1880
+ }
1881
+ if (resolved === "protect") {
1882
+ setAuth2(node, [`middleware:${label}`], false);
1883
+ return;
1884
+ }
1885
+ if (hasAnyExemptMatcher && hasAnyFallthrough) {
1886
+ setAuth2(node, ["middleware-protected"], false);
1887
+ }
1888
+ };
1889
+ var setAuth = setAuth2, applyMiddleware = applyMiddleware2;
1890
+ for (const node of apiNodes) {
1891
+ const routePath = node.path;
1892
+ if (!routePath) continue;
1893
+ applyMiddleware2(node, routePath);
1894
+ }
1895
+ for (const node of uiNodes) {
1896
+ const route = node.route;
1897
+ if (!route) continue;
1898
+ applyMiddleware2(node, route);
1899
+ }
1900
+ }
1580
1901
  const apiNodeIds = new Set(apiNodes.map((n) => n.id));
1581
1902
  const apiEdges = [];
1582
1903
  const uiOnlyEdges = [];
@@ -3536,7 +3857,7 @@ var init_static_ref_scanner = __esm({
3536
3857
  },
3537
3858
  generate(rootDir, layerOutputs) {
3538
3859
  const staticOutput = layerOutputs.get("static");
3539
- if (!staticOutput || staticOutput.nodes.length === 0) {
3860
+ if (!staticOutput || !Array.isArray(staticOutput.nodes) || staticOutput.nodes.length === 0) {
3540
3861
  return { cross_refs: [], flagged_edges: [], warnings: [] };
3541
3862
  }
3542
3863
  const valueLookup = /* @__PURE__ */ new Map();
@@ -4535,6 +4856,26 @@ async function generateGraph(rootDir, layer) {
4535
4856
  invalidateCache(filePath);
4536
4857
  invalidateTaggedCache(rootDir, result.layer);
4537
4858
  }
4859
+ if (!layer) {
4860
+ const producedLayers = new Set(results.map((r) => r.layer));
4861
+ try {
4862
+ for (const f of (0, import_node_fs16.readdirSync)(dir)) {
4863
+ if (!f.endsWith(".json") || f === "tags.json") continue;
4864
+ const layerName = f.replace(/\.json$/, "");
4865
+ if (producedLayers.has(layerName)) continue;
4866
+ const orphan = (0, import_node_path17.join)(dir, f);
4867
+ try {
4868
+ (0, import_node_fs16.unlinkSync)(orphan);
4869
+ invalidateCache(orphan);
4870
+ invalidateTaggedCache(rootDir, layerName);
4871
+ process.stderr.write(`[launch-chart] removed orphan layer file: ${f} (no parser produced ${layerName} this run)
4872
+ `);
4873
+ } catch {
4874
+ }
4875
+ }
4876
+ } catch {
4877
+ }
4878
+ }
4538
4879
  return results;
4539
4880
  }
4540
4881
  var import_node_fs16, import_node_path17, GRAPHS_DIR2, graphCache, taggedCache;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launchsecure/launch-kit",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "description": "LaunchSecure toolkit — launch-pod (pipeline), launch-chart (project graph MCP), launch-deck (visual playground MCP).",
5
5
  "license": "MIT",
6
6
  "author": "LaunchSecure - AutomateWithUs",
@@ -1 +0,0 @@
1
- import{aq as o,ar as n}from"./index-hiIpM7EP.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-7qRCCAgK.js";import{_ as i}from"./index-hiIpM7EP.js";import"./chunk-FMBD7UC4-D5KSGATB.js";import"./chunk-YZCP3GAM-S2-nGw3D.js";import"./chunk-55IACEB6-DfHG-iqb.js";import"./chunk-EDXVE4YY-DrR52j3B.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-7qRCCAgK.js";import{_ as i}from"./index-hiIpM7EP.js";import"./chunk-FMBD7UC4-D5KSGATB.js";import"./chunk-YZCP3GAM-S2-nGw3D.js";import"./chunk-55IACEB6-DfHG-iqb.js";import"./chunk-EDXVE4YY-DrR52j3B.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
@@ -1 +0,0 @@
1
- import{b as r}from"./graph-CORzYQdB.js";var e=4;function a(o){return r(o,e)}export{a as c};
@@ -1 +0,0 @@
1
- import{s as t,b as r,a,S as s}from"./chunk-OYMX7WX6-M7hsLRNU.js";import{_ as i}from"./index-hiIpM7EP.js";import"./chunk-55IACEB6-DfHG-iqb.js";import"./chunk-EDXVE4YY-DrR52j3B.js";var l={parser:a,get db(){return new s(2)},renderer:r,styles:t,init:i(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},"init")};export{l as diagram};