@backthread/extractor 0.1.0

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 (379) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/cluster/domain-grouping.d.ts +113 -0
  4. package/dist/cluster/domain-grouping.d.ts.map +1 -0
  5. package/dist/cluster/domain-grouping.js +277 -0
  6. package/dist/cluster/domain-grouping.js.map +1 -0
  7. package/dist/cluster/grouping-gate.d.ts +54 -0
  8. package/dist/cluster/grouping-gate.d.ts.map +1 -0
  9. package/dist/cluster/grouping-gate.js +0 -0
  10. package/dist/cluster/grouping-gate.js.map +1 -0
  11. package/dist/cluster/louvain.d.ts +88 -0
  12. package/dist/cluster/louvain.d.ts.map +1 -0
  13. package/dist/cluster/louvain.js +674 -0
  14. package/dist/cluster/louvain.js.map +1 -0
  15. package/dist/cluster/overrides.d.ts +19 -0
  16. package/dist/cluster/overrides.d.ts.map +1 -0
  17. package/dist/cluster/overrides.js +32 -0
  18. package/dist/cluster/overrides.js.map +1 -0
  19. package/dist/cluster/subsystem.d.ts +45 -0
  20. package/dist/cluster/subsystem.d.ts.map +1 -0
  21. package/dist/cluster/subsystem.js +299 -0
  22. package/dist/cluster/subsystem.js.map +1 -0
  23. package/dist/cluster/workspaces.d.ts +64 -0
  24. package/dist/cluster/workspaces.d.ts.map +1 -0
  25. package/dist/cluster/workspaces.js +739 -0
  26. package/dist/cluster/workspaces.js.map +1 -0
  27. package/dist/extract.d.ts +52 -0
  28. package/dist/extract.d.ts.map +1 -0
  29. package/dist/extract.js +48 -0
  30. package/dist/extract.js.map +1 -0
  31. package/dist/framework/celery/celery.d.ts +17 -0
  32. package/dist/framework/celery/celery.d.ts.map +1 -0
  33. package/dist/framework/celery/celery.js +524 -0
  34. package/dist/framework/celery/celery.js.map +1 -0
  35. package/dist/framework/contribute-step.d.ts +38 -0
  36. package/dist/framework/contribute-step.d.ts.map +1 -0
  37. package/dist/framework/contribute-step.js +403 -0
  38. package/dist/framework/contribute-step.js.map +1 -0
  39. package/dist/framework/detect-step.d.ts +8 -0
  40. package/dist/framework/detect-step.d.ts.map +1 -0
  41. package/dist/framework/detect-step.js +54 -0
  42. package/dist/framework/detect-step.js.map +1 -0
  43. package/dist/framework/detect-util.d.ts +24 -0
  44. package/dist/framework/detect-util.d.ts.map +1 -0
  45. package/dist/framework/detect-util.js +59 -0
  46. package/dist/framework/detect-util.js.map +1 -0
  47. package/dist/framework/django/django.d.ts +22 -0
  48. package/dist/framework/django/django.d.ts.map +1 -0
  49. package/dist/framework/django/django.js +940 -0
  50. package/dist/framework/django/django.js.map +1 -0
  51. package/dist/framework/fastapi/fastapi.d.ts +27 -0
  52. package/dist/framework/fastapi/fastapi.d.ts.map +1 -0
  53. package/dist/framework/fastapi/fastapi.js +477 -0
  54. package/dist/framework/fastapi/fastapi.js.map +1 -0
  55. package/dist/framework/faststream/faststream.d.ts +19 -0
  56. package/dist/framework/faststream/faststream.d.ts.map +1 -0
  57. package/dist/framework/faststream/faststream.js +765 -0
  58. package/dist/framework/faststream/faststream.js.map +1 -0
  59. package/dist/framework/flask/flask.d.ts +17 -0
  60. package/dist/framework/flask/flask.d.ts.map +1 -0
  61. package/dist/framework/flask/flask.js +507 -0
  62. package/dist/framework/flask/flask.js.map +1 -0
  63. package/dist/framework/graphql/graphql.d.ts +17 -0
  64. package/dist/framework/graphql/graphql.d.ts.map +1 -0
  65. package/dist/framework/graphql/graphql.js +708 -0
  66. package/dist/framework/graphql/graphql.js.map +1 -0
  67. package/dist/framework/grpc/grpc.d.ts +22 -0
  68. package/dist/framework/grpc/grpc.d.ts.map +1 -0
  69. package/dist/framework/grpc/grpc.js +618 -0
  70. package/dist/framework/grpc/grpc.js.map +1 -0
  71. package/dist/framework/litestar/litestar.d.ts +17 -0
  72. package/dist/framework/litestar/litestar.d.ts.map +1 -0
  73. package/dist/framework/litestar/litestar.js +536 -0
  74. package/dist/framework/litestar/litestar.js.map +1 -0
  75. package/dist/framework/nest/nest.d.ts +19 -0
  76. package/dist/framework/nest/nest.d.ts.map +1 -0
  77. package/dist/framework/nest/nest.js +613 -0
  78. package/dist/framework/nest/nest.js.map +1 -0
  79. package/dist/framework/next/next.d.ts +22 -0
  80. package/dist/framework/next/next.d.ts.map +1 -0
  81. package/dist/framework/next/next.js +449 -0
  82. package/dist/framework/next/next.js.map +1 -0
  83. package/dist/framework/node/node.d.ts +24 -0
  84. package/dist/framework/node/node.d.ts.map +1 -0
  85. package/dist/framework/node/node.js +1009 -0
  86. package/dist/framework/node/node.js.map +1 -0
  87. package/dist/framework/orchestrator/orchestrator.d.ts +34 -0
  88. package/dist/framework/orchestrator/orchestrator.d.ts.map +1 -0
  89. package/dist/framework/orchestrator/orchestrator.js +691 -0
  90. package/dist/framework/orchestrator/orchestrator.js.map +1 -0
  91. package/dist/framework/orm/orm.d.ts +61 -0
  92. package/dist/framework/orm/orm.d.ts.map +1 -0
  93. package/dist/framework/orm/orm.js +620 -0
  94. package/dist/framework/orm/orm.js.map +1 -0
  95. package/dist/framework/python/analyze.d.ts +38 -0
  96. package/dist/framework/python/analyze.d.ts.map +1 -0
  97. package/dist/framework/python/analyze.js +98 -0
  98. package/dist/framework/python/analyze.js.map +1 -0
  99. package/dist/framework/python/py-ast.d.ts +130 -0
  100. package/dist/framework/python/py-ast.d.ts.map +1 -0
  101. package/dist/framework/python/py-ast.js +344 -0
  102. package/dist/framework/python/py-ast.js.map +1 -0
  103. package/dist/framework/python-orm/python-orm.d.ts +19 -0
  104. package/dist/framework/python-orm/python-orm.d.ts.map +1 -0
  105. package/dist/framework/python-orm/python-orm.js +516 -0
  106. package/dist/framework/python-orm/python-orm.js.map +1 -0
  107. package/dist/framework/react-native/react-native.d.ts +35 -0
  108. package/dist/framework/react-native/react-native.d.ts.map +1 -0
  109. package/dist/framework/react-native/react-native.js +1181 -0
  110. package/dist/framework/react-native/react-native.js.map +1 -0
  111. package/dist/framework/register.d.ts +2 -0
  112. package/dist/framework/register.d.ts.map +1 -0
  113. package/dist/framework/register.js +59 -0
  114. package/dist/framework/register.js.map +1 -0
  115. package/dist/framework/registry.d.ts +31 -0
  116. package/dist/framework/registry.d.ts.map +1 -0
  117. package/dist/framework/registry.js +70 -0
  118. package/dist/framework/registry.js.map +1 -0
  119. package/dist/framework/routing/expo-router.d.ts +31 -0
  120. package/dist/framework/routing/expo-router.d.ts.map +1 -0
  121. package/dist/framework/routing/expo-router.js +356 -0
  122. package/dist/framework/routing/expo-router.js.map +1 -0
  123. package/dist/framework/routing/index.d.ts +4 -0
  124. package/dist/framework/routing/index.d.ts.map +1 -0
  125. package/dist/framework/routing/index.js +16 -0
  126. package/dist/framework/routing/index.js.map +1 -0
  127. package/dist/framework/routing/next-router.d.ts +45 -0
  128. package/dist/framework/routing/next-router.d.ts.map +1 -0
  129. package/dist/framework/routing/next-router.js +378 -0
  130. package/dist/framework/routing/next-router.js.map +1 -0
  131. package/dist/framework/routing/route-tree.d.ts +73 -0
  132. package/dist/framework/routing/route-tree.d.ts.map +1 -0
  133. package/dist/framework/routing/route-tree.js +120 -0
  134. package/dist/framework/routing/route-tree.js.map +1 -0
  135. package/dist/framework/types.d.ts +230 -0
  136. package/dist/framework/types.d.ts.map +1 -0
  137. package/dist/framework/types.js +25 -0
  138. package/dist/framework/types.js.map +1 -0
  139. package/dist/graph/cross-language.d.ts +11 -0
  140. package/dist/graph/cross-language.d.ts.map +1 -0
  141. package/dist/graph/cross-language.js +123 -0
  142. package/dist/graph/cross-language.js.map +1 -0
  143. package/dist/graph/extract.d.ts +13 -0
  144. package/dist/graph/extract.d.ts.map +1 -0
  145. package/dist/graph/extract.js +79 -0
  146. package/dist/graph/extract.js.map +1 -0
  147. package/dist/graph/file-graph.d.ts +186 -0
  148. package/dist/graph/file-graph.d.ts.map +1 -0
  149. package/dist/graph/file-graph.js +427 -0
  150. package/dist/graph/file-graph.js.map +1 -0
  151. package/dist/graph/http-callsites.d.ts +14 -0
  152. package/dist/graph/http-callsites.d.ts.map +1 -0
  153. package/dist/graph/http-callsites.js +107 -0
  154. package/dist/graph/http-callsites.js.map +1 -0
  155. package/dist/graph/incremental.d.ts +122 -0
  156. package/dist/graph/incremental.d.ts.map +1 -0
  157. package/dist/graph/incremental.js +448 -0
  158. package/dist/graph/incremental.js.map +1 -0
  159. package/dist/graph/language.d.ts +31 -0
  160. package/dist/graph/language.d.ts.map +1 -0
  161. package/dist/graph/language.js +146 -0
  162. package/dist/graph/language.js.map +1 -0
  163. package/dist/graph/noise-filter.d.ts +46 -0
  164. package/dist/graph/noise-filter.d.ts.map +1 -0
  165. package/dist/graph/noise-filter.js +199 -0
  166. package/dist/graph/noise-filter.js.map +1 -0
  167. package/dist/graph/python-adapter.d.ts +36 -0
  168. package/dist/graph/python-adapter.d.ts.map +1 -0
  169. package/dist/graph/python-adapter.js +402 -0
  170. package/dist/graph/python-adapter.js.map +1 -0
  171. package/dist/graph/python-manifest.d.ts +22 -0
  172. package/dist/graph/python-manifest.d.ts.map +1 -0
  173. package/dist/graph/python-manifest.js +137 -0
  174. package/dist/graph/python-manifest.js.map +1 -0
  175. package/dist/graph/python-stdlib.d.ts +2 -0
  176. package/dist/graph/python-stdlib.d.ts.map +1 -0
  177. package/dist/graph/python-stdlib.js +53 -0
  178. package/dist/graph/python-stdlib.js.map +1 -0
  179. package/dist/graph/ts-morph-adapter.d.ts +65 -0
  180. package/dist/graph/ts-morph-adapter.d.ts.map +1 -0
  181. package/dist/graph/ts-morph-adapter.js +265 -0
  182. package/dist/graph/ts-morph-adapter.js.map +1 -0
  183. package/dist/graph/types.d.ts +37 -0
  184. package/dist/graph/types.d.ts.map +1 -0
  185. package/dist/graph/types.js +50 -0
  186. package/dist/graph/types.js.map +1 -0
  187. package/dist/index.d.ts +45 -0
  188. package/dist/index.d.ts.map +1 -0
  189. package/dist/index.js +51 -0
  190. package/dist/index.js.map +1 -0
  191. package/dist/infra/aws/aws-parse.d.ts +39 -0
  192. package/dist/infra/aws/aws-parse.d.ts.map +1 -0
  193. package/dist/infra/aws/aws-parse.js +149 -0
  194. package/dist/infra/aws/aws-parse.js.map +1 -0
  195. package/dist/infra/aws/aws.d.ts +6 -0
  196. package/dist/infra/aws/aws.d.ts.map +1 -0
  197. package/dist/infra/aws/aws.js +425 -0
  198. package/dist/infra/aws/aws.js.map +1 -0
  199. package/dist/infra/azure/azure-parse.d.ts +73 -0
  200. package/dist/infra/azure/azure-parse.d.ts.map +1 -0
  201. package/dist/infra/azure/azure-parse.js +178 -0
  202. package/dist/infra/azure/azure-parse.js.map +1 -0
  203. package/dist/infra/azure/azure.d.ts +12 -0
  204. package/dist/infra/azure/azure.d.ts.map +1 -0
  205. package/dist/infra/azure/azure.js +673 -0
  206. package/dist/infra/azure/azure.js.map +1 -0
  207. package/dist/infra/cloudflare/cloudflare.d.ts +50 -0
  208. package/dist/infra/cloudflare/cloudflare.d.ts.map +1 -0
  209. package/dist/infra/cloudflare/cloudflare.js +382 -0
  210. package/dist/infra/cloudflare/cloudflare.js.map +1 -0
  211. package/dist/infra/cloudflare/wrangler-parse.d.ts +6 -0
  212. package/dist/infra/cloudflare/wrangler-parse.d.ts.map +1 -0
  213. package/dist/infra/cloudflare/wrangler-parse.js +278 -0
  214. package/dist/infra/cloudflare/wrangler-parse.js.map +1 -0
  215. package/dist/infra/compose/compose-parse.d.ts +24 -0
  216. package/dist/infra/compose/compose-parse.d.ts.map +1 -0
  217. package/dist/infra/compose/compose-parse.js +77 -0
  218. package/dist/infra/compose/compose-parse.js.map +1 -0
  219. package/dist/infra/compose/compose.d.ts +12 -0
  220. package/dist/infra/compose/compose.d.ts.map +1 -0
  221. package/dist/infra/compose/compose.js +201 -0
  222. package/dist/infra/compose/compose.js.map +1 -0
  223. package/dist/infra/convex/convex-parse.d.ts +28 -0
  224. package/dist/infra/convex/convex-parse.d.ts.map +1 -0
  225. package/dist/infra/convex/convex-parse.js +74 -0
  226. package/dist/infra/convex/convex-parse.js.map +1 -0
  227. package/dist/infra/convex/convex.d.ts +18 -0
  228. package/dist/infra/convex/convex.d.ts.map +1 -0
  229. package/dist/infra/convex/convex.js +199 -0
  230. package/dist/infra/convex/convex.js.map +1 -0
  231. package/dist/infra/digitalocean/digitalocean.d.ts +33 -0
  232. package/dist/infra/digitalocean/digitalocean.d.ts.map +1 -0
  233. package/dist/infra/digitalocean/digitalocean.js +204 -0
  234. package/dist/infra/digitalocean/digitalocean.js.map +1 -0
  235. package/dist/infra/firebase/firebase.d.ts +43 -0
  236. package/dist/infra/firebase/firebase.d.ts.map +1 -0
  237. package/dist/infra/firebase/firebase.js +271 -0
  238. package/dist/infra/firebase/firebase.js.map +1 -0
  239. package/dist/infra/fly/fly-parse.d.ts +52 -0
  240. package/dist/infra/fly/fly-parse.d.ts.map +1 -0
  241. package/dist/infra/fly/fly-parse.js +114 -0
  242. package/dist/infra/fly/fly-parse.js.map +1 -0
  243. package/dist/infra/fly/fly.d.ts +15 -0
  244. package/dist/infra/fly/fly.d.ts.map +1 -0
  245. package/dist/infra/fly/fly.js +265 -0
  246. package/dist/infra/fly/fly.js.map +1 -0
  247. package/dist/infra/gcp/gcp-parse.d.ts +24 -0
  248. package/dist/infra/gcp/gcp-parse.d.ts.map +1 -0
  249. package/dist/infra/gcp/gcp-parse.js +123 -0
  250. package/dist/infra/gcp/gcp-parse.js.map +1 -0
  251. package/dist/infra/gcp/gcp.d.ts +10 -0
  252. package/dist/infra/gcp/gcp.d.ts.map +1 -0
  253. package/dist/infra/gcp/gcp.js +502 -0
  254. package/dist/infra/gcp/gcp.js.map +1 -0
  255. package/dist/infra/heroku/heroku-parse.d.ts +33 -0
  256. package/dist/infra/heroku/heroku-parse.d.ts.map +1 -0
  257. package/dist/infra/heroku/heroku-parse.js +63 -0
  258. package/dist/infra/heroku/heroku-parse.js.map +1 -0
  259. package/dist/infra/heroku/heroku.d.ts +24 -0
  260. package/dist/infra/heroku/heroku.d.ts.map +1 -0
  261. package/dist/infra/heroku/heroku.js +253 -0
  262. package/dist/infra/heroku/heroku.js.map +1 -0
  263. package/dist/infra/image-resolve.d.ts +56 -0
  264. package/dist/infra/image-resolve.d.ts.map +1 -0
  265. package/dist/infra/image-resolve.js +229 -0
  266. package/dist/infra/image-resolve.js.map +1 -0
  267. package/dist/infra/infra-step.d.ts +39 -0
  268. package/dist/infra/infra-step.d.ts.map +1 -0
  269. package/dist/infra/infra-step.js +57 -0
  270. package/dist/infra/infra-step.js.map +1 -0
  271. package/dist/infra/k8s/index.d.ts +78 -0
  272. package/dist/infra/k8s/index.d.ts.map +1 -0
  273. package/dist/infra/k8s/index.js +251 -0
  274. package/dist/infra/k8s/index.js.map +1 -0
  275. package/dist/infra/kamal/kamal-parse.d.ts +23 -0
  276. package/dist/infra/kamal/kamal-parse.d.ts.map +1 -0
  277. package/dist/infra/kamal/kamal-parse.js +66 -0
  278. package/dist/infra/kamal/kamal-parse.js.map +1 -0
  279. package/dist/infra/kamal/kamal.d.ts +17 -0
  280. package/dist/infra/kamal/kamal.d.ts.map +1 -0
  281. package/dist/infra/kamal/kamal.js +162 -0
  282. package/dist/infra/kamal/kamal.js.map +1 -0
  283. package/dist/infra/netlify/netlify.d.ts +33 -0
  284. package/dist/infra/netlify/netlify.d.ts.map +1 -0
  285. package/dist/infra/netlify/netlify.js +247 -0
  286. package/dist/infra/netlify/netlify.js.map +1 -0
  287. package/dist/infra/opentofu/opentofu.d.ts +3 -0
  288. package/dist/infra/opentofu/opentofu.d.ts.map +1 -0
  289. package/dist/infra/opentofu/opentofu.js +157 -0
  290. package/dist/infra/opentofu/opentofu.js.map +1 -0
  291. package/dist/infra/pulumi/pulumi-parse.d.ts +60 -0
  292. package/dist/infra/pulumi/pulumi-parse.d.ts.map +1 -0
  293. package/dist/infra/pulumi/pulumi-parse.js +155 -0
  294. package/dist/infra/pulumi/pulumi-parse.js.map +1 -0
  295. package/dist/infra/pulumi/pulumi.d.ts +23 -0
  296. package/dist/infra/pulumi/pulumi.d.ts.map +1 -0
  297. package/dist/infra/pulumi/pulumi.js +260 -0
  298. package/dist/infra/pulumi/pulumi.js.map +1 -0
  299. package/dist/infra/railway/railway-parse.d.ts +54 -0
  300. package/dist/infra/railway/railway-parse.d.ts.map +1 -0
  301. package/dist/infra/railway/railway-parse.js +200 -0
  302. package/dist/infra/railway/railway-parse.js.map +1 -0
  303. package/dist/infra/railway/railway.d.ts +19 -0
  304. package/dist/infra/railway/railway.d.ts.map +1 -0
  305. package/dist/infra/railway/railway.js +397 -0
  306. package/dist/infra/railway/railway.js.map +1 -0
  307. package/dist/infra/register.d.ts +2 -0
  308. package/dist/infra/register.d.ts.map +1 -0
  309. package/dist/infra/register.js +81 -0
  310. package/dist/infra/register.js.map +1 -0
  311. package/dist/infra/registry.d.ts +64 -0
  312. package/dist/infra/registry.d.ts.map +1 -0
  313. package/dist/infra/registry.js +205 -0
  314. package/dist/infra/registry.js.map +1 -0
  315. package/dist/infra/relevance.d.ts +16 -0
  316. package/dist/infra/relevance.d.ts.map +1 -0
  317. package/dist/infra/relevance.js +132 -0
  318. package/dist/infra/relevance.js.map +1 -0
  319. package/dist/infra/render/render-parse.d.ts +76 -0
  320. package/dist/infra/render/render-parse.d.ts.map +1 -0
  321. package/dist/infra/render/render-parse.js +155 -0
  322. package/dist/infra/render/render-parse.js.map +1 -0
  323. package/dist/infra/render/render.d.ts +11 -0
  324. package/dist/infra/render/render.d.ts.map +1 -0
  325. package/dist/infra/render/render.js +303 -0
  326. package/dist/infra/render/render.js.map +1 -0
  327. package/dist/infra/sst/sst-parse.d.ts +25 -0
  328. package/dist/infra/sst/sst-parse.d.ts.map +1 -0
  329. package/dist/infra/sst/sst-parse.js +45 -0
  330. package/dist/infra/sst/sst-parse.js.map +1 -0
  331. package/dist/infra/sst/sst.d.ts +19 -0
  332. package/dist/infra/sst/sst.d.ts.map +1 -0
  333. package/dist/infra/sst/sst.js +236 -0
  334. package/dist/infra/sst/sst.js.map +1 -0
  335. package/dist/infra/supabase/supabase-parse.d.ts +34 -0
  336. package/dist/infra/supabase/supabase-parse.d.ts.map +1 -0
  337. package/dist/infra/supabase/supabase-parse.js +113 -0
  338. package/dist/infra/supabase/supabase-parse.js.map +1 -0
  339. package/dist/infra/supabase/supabase.d.ts +15 -0
  340. package/dist/infra/supabase/supabase.d.ts.map +1 -0
  341. package/dist/infra/supabase/supabase.js +198 -0
  342. package/dist/infra/supabase/supabase.js.map +1 -0
  343. package/dist/infra/terraform/hcl-parse.d.ts +34 -0
  344. package/dist/infra/terraform/hcl-parse.d.ts.map +1 -0
  345. package/dist/infra/terraform/hcl-parse.js +203 -0
  346. package/dist/infra/terraform/hcl-parse.js.map +1 -0
  347. package/dist/infra/terraform/terraform.d.ts +14 -0
  348. package/dist/infra/terraform/terraform.d.ts.map +1 -0
  349. package/dist/infra/terraform/terraform.js +264 -0
  350. package/dist/infra/terraform/terraform.js.map +1 -0
  351. package/dist/infra/types.d.ts +151 -0
  352. package/dist/infra/types.d.ts.map +1 -0
  353. package/dist/infra/types.js +14 -0
  354. package/dist/infra/types.js.map +1 -0
  355. package/dist/infra/vercel/vercel-parse.d.ts +70 -0
  356. package/dist/infra/vercel/vercel-parse.d.ts.map +1 -0
  357. package/dist/infra/vercel/vercel-parse.js +194 -0
  358. package/dist/infra/vercel/vercel-parse.js.map +1 -0
  359. package/dist/infra/vercel/vercel.d.ts +30 -0
  360. package/dist/infra/vercel/vercel.d.ts.map +1 -0
  361. package/dist/infra/vercel/vercel.js +523 -0
  362. package/dist/infra/vercel/vercel.js.map +1 -0
  363. package/dist/infra/walk.d.ts +36 -0
  364. package/dist/infra/walk.d.ts.map +1 -0
  365. package/dist/infra/walk.js +85 -0
  366. package/dist/infra/walk.js.map +1 -0
  367. package/dist/safety.d.ts +13 -0
  368. package/dist/safety.d.ts.map +1 -0
  369. package/dist/safety.js +67 -0
  370. package/dist/safety.js.map +1 -0
  371. package/dist/types.d.ts +47 -0
  372. package/dist/types.d.ts.map +1 -0
  373. package/dist/types.js +111 -0
  374. package/dist/types.js.map +1 -0
  375. package/dist/version.d.ts +2 -0
  376. package/dist/version.d.ts.map +1 -0
  377. package/dist/version.js +35 -0
  378. package/dist/version.js.map +1 -0
  379. package/package.json +65 -0
@@ -0,0 +1,24 @@
1
+ import type { InfraAdapter, InfraGraph } from '../types.js';
2
+ export interface HerokuInputs {
3
+ procfileEntries: Array<{
4
+ processType: string;
5
+ command: string;
6
+ }>;
7
+ appJson: {
8
+ name?: string;
9
+ addons: Array<{
10
+ slug: string;
11
+ plan?: string;
12
+ }>;
13
+ env: Record<string, unknown>;
14
+ formation: Record<string, unknown>;
15
+ } | null;
16
+ hasHerokuYml: boolean;
17
+ }
18
+ /**
19
+ * Pure graph builder — takes pre-parsed Heroku config objects and emits an
20
+ * InfraGraph. Separated from fs IO for unit-testing without a real repo dir.
21
+ */
22
+ export declare function buildHerokuGraph(inputs: HerokuInputs, root: string): InfraGraph;
23
+ export declare const herokuAdapter: InfraAdapter;
24
+ //# sourceMappingURL=heroku.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heroku.d.ts","sourceRoot":"","sources":["../../../src/infra/heroku/heroku.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,YAAY,EAAa,UAAU,EAAa,MAAM,aAAa,CAAC;AA+IlF,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;IACpJ,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CA0E/E;AAKD,eAAO,MAAM,aAAa,EAAE,YAsC3B,CAAC"}
@@ -0,0 +1,253 @@
1
+ // the Heroku InfraAdapter (v0).
2
+ //
3
+ // Surfaces the PaaS deployment topology from Procfile + app.json. Emits:
4
+ // - One `worker` node per Procfile process type (web/worker/release/clock/custom)
5
+ // - One node per app.json addon, kind decided by a static slug map
6
+ // - `stores-in` edges (dyno → datastore addon)
7
+ // - `calls` edges (dyno → external-api addon)
8
+ //
9
+ // Everything is `declared` provenance: the files literally name the dyno type
10
+ // and the addon slug. No LLM, no inference → classificationsNeeded: [].
11
+ //
12
+ // heroku.yml (Docker-based deploys) is DEFERRED — it is YAML, and there is no
13
+ // YAML parser available in this dependency-free adapter. Presence of
14
+ // heroku.yml is used in detect() only. Parsing is tracked for .
15
+ //
16
+ // PaaS tight static model: an addon slug literally names the managed service,
17
+ // so the kind decision is made by a static slug→kind map here rather than
18
+ // delegating to the LLM classifier. Unknown slugs fall back to `external-api`
19
+ // (a named managed service you don't own) — declared, not classified.
20
+ import { readFileSync, existsSync } from 'node:fs';
21
+ import { join } from 'node:path';
22
+ import { parseProcfile, parseAppJson } from './heroku-parse.js';
23
+ /**
24
+ * Extract the root slug from an addon slug that may carry a plan suffix
25
+ * (e.g. 'heroku-postgresql:mini' → 'heroku-postgresql').
26
+ */
27
+ function rootSlug(slug) {
28
+ return slug.split(':')[0].toLowerCase().trim();
29
+ }
30
+ const SLUG_MAP = {
31
+ // Relational / Postgres
32
+ 'heroku-postgresql': { kind: 'datastore', label: 'Heroku Postgres' },
33
+ 'jawsdb': { kind: 'datastore', label: 'JawsDB MySQL' },
34
+ 'jawsdb-maria': { kind: 'datastore', label: 'JawsDB MariaDB' },
35
+ 'cleardb': { kind: 'datastore', label: 'ClearDB MySQL' },
36
+ 'xeround': { kind: 'datastore', label: 'Xeround' },
37
+ // Redis / Memcache
38
+ 'heroku-redis': { kind: 'datastore', label: 'Heroku Redis' },
39
+ 'rediscloud': { kind: 'datastore', label: 'Redis Cloud' },
40
+ 'redistogo': { kind: 'datastore', label: 'RedisToGo' },
41
+ 'memcachier': { kind: 'datastore', label: 'MemCachier' },
42
+ 'memcachedcloud': { kind: 'datastore', label: 'Memcached Cloud' },
43
+ // Search / Time-series
44
+ 'searchbox': { kind: 'datastore', label: 'SearchBox (Elasticsearch)' },
45
+ 'bonsai': { kind: 'datastore', label: 'Bonsai (Elasticsearch)' },
46
+ 'algoliasearch': { kind: 'external-api', label: 'Algolia' },
47
+ // Messaging / Email
48
+ 'sendgrid': { kind: 'external-api', label: 'SendGrid' },
49
+ 'mailgun': { kind: 'external-api', label: 'Mailgun' },
50
+ 'mandrill': { kind: 'external-api', label: 'Mandrill' },
51
+ 'postmark': { kind: 'external-api', label: 'Postmark' },
52
+ 'sparkpost': { kind: 'external-api', label: 'SparkPost' },
53
+ // SMS / telephony
54
+ 'twilio': { kind: 'external-api', label: 'Twilio' },
55
+ // Payments
56
+ 'stripe': { kind: 'external-api', label: 'Stripe' },
57
+ // Monitoring / logging
58
+ 'papertrail': { kind: 'external-api', label: 'Papertrail' },
59
+ 'logentries': { kind: 'external-api', label: 'Logentries' },
60
+ 'librato': { kind: 'external-api', label: 'Librato' },
61
+ 'new-relic': { kind: 'external-api', label: 'New Relic' },
62
+ 'rollbar': { kind: 'external-api', label: 'Rollbar' },
63
+ 'sentry': { kind: 'external-api', label: 'Sentry' },
64
+ 'scout': { kind: 'external-api', label: 'Scout APM' },
65
+ 'airbrake': { kind: 'external-api', label: 'Airbrake' },
66
+ 'honeybadger': { kind: 'external-api', label: 'Honeybadger' },
67
+ // Queuing / jobs
68
+ 'cloudamqp': { kind: 'queue', label: 'CloudAMQP' },
69
+ 'rabbitmq-bigwig': { kind: 'queue', label: 'RabbitMQ Bigwig' },
70
+ 'iron-mq': { kind: 'queue', label: 'IronMQ' },
71
+ // Storage / CDN
72
+ 'cloudinary': { kind: 'external-api', label: 'Cloudinary' },
73
+ 'bucketeer': { kind: 'datastore', label: 'Bucketeer (S3)' },
74
+ // Auth
75
+ 'auth0': { kind: 'external-api', label: 'Auth0' },
76
+ 'stormpath': { kind: 'external-api', label: 'Stormpath' },
77
+ // Scheduled jobs helpers
78
+ 'scheduler': { kind: 'external-api', label: 'Heroku Scheduler' },
79
+ 'heroku-scheduler': { kind: 'external-api', label: 'Heroku Scheduler' },
80
+ };
81
+ function lookupAddon(slug) {
82
+ const root = rootSlug(slug);
83
+ return (SLUG_MAP[root] ?? {
84
+ kind: 'external-api',
85
+ label: slug, // use the raw slug as label for unknown addons
86
+ });
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // Source-root resolution.
90
+ //
91
+ // A Heroku app builds the whole repo (or a monorepo sub-dir) into one slug; the
92
+ // dynos all run process types from that single slug, so every dyno shares ONE
93
+ // source root. The only honest sub-root signal is the monorepo-buildpack base
94
+ // dir, declared in app.json `env` as `APP_BASE` (heroku-buildpack-monorepo) or
95
+ // `PROJECT_PATH`. With that → the dynos' code lives under that sub-dir. Without
96
+ // it the app sits at the repo root, which is a catch-all: we emit NO source root
97
+ // (the deployment consumer drops an empty root anyway, and a bare repo root must
98
+ // never swallow sibling units) → the code honestly stays "Other".
99
+ /** Normalize a repo-relative path: backslashes→/, collapse `.`/`./`, strip trailing `/`. */
100
+ function normalizeRoot(p) {
101
+ return p.replace(/\\/g, '/').replace(/^\.(?:\/|$)/, '').replace(/\/+$/, '');
102
+ }
103
+ /** Read an app.json env value, which may be a bare string or `{ value: string }`. */
104
+ function envValue(v) {
105
+ if (typeof v === 'string')
106
+ return v || undefined;
107
+ if (v && typeof v === 'object' && !Array.isArray(v)) {
108
+ const val = v.value;
109
+ return typeof val === 'string' && val ? val : undefined;
110
+ }
111
+ return undefined;
112
+ }
113
+ /**
114
+ * The repo-relative source root shared by every dyno: the monorepo-buildpack
115
+ * base dir from app.json env (`APP_BASE` / `PROJECT_PATH`), or '' (→ no source
116
+ * root) for a root-level app.
117
+ */
118
+ function appSourceRoot(appJson) {
119
+ if (!appJson)
120
+ return '';
121
+ for (const key of ['APP_BASE', 'PROJECT_PATH']) {
122
+ const raw = envValue(appJson.env[key]);
123
+ if (raw)
124
+ return normalizeRoot(raw);
125
+ }
126
+ return '';
127
+ }
128
+ // ---------------------------------------------------------------------------
129
+ // Node-id helpers — adapter-local natural keys.
130
+ const dynoId = (processType) => `dyno:${processType}`;
131
+ const addonId = (slug) => `addon:${rootSlug(slug)}`;
132
+ // ---------------------------------------------------------------------------
133
+ // Detection helpers.
134
+ const HEROKU_FILES = ['Procfile', 'app.json', 'heroku.yml'];
135
+ function detectHeroku(repoDir) {
136
+ return HEROKU_FILES.some((f) => existsSync(join(repoDir, f)));
137
+ }
138
+ /**
139
+ * Pure graph builder — takes pre-parsed Heroku config objects and emits an
140
+ * InfraGraph. Separated from fs IO for unit-testing without a real repo dir.
141
+ */
142
+ export function buildHerokuGraph(inputs, root) {
143
+ const { procfileEntries, appJson } = inputs;
144
+ const nodes = new Map();
145
+ const edges = [];
146
+ const addNode = (n) => {
147
+ if (!nodes.has(n.id))
148
+ nodes.set(n.id, n);
149
+ };
150
+ // ---- Dynos (one `worker` node per Procfile process type) ----------------
151
+ // every dyno shares the app's single source root (the monorepo base
152
+ // dir, or none for a root-level app).
153
+ const srcRoot = appSourceRoot(appJson);
154
+ for (const { processType, command } of procfileEntries) {
155
+ addNode({
156
+ id: dynoId(processType),
157
+ label: `${processType} dyno`,
158
+ kind: 'worker',
159
+ provenance: 'declared',
160
+ metadata: { processType, command },
161
+ ...(srcRoot ? { sourceRoots: [srcRoot] } : {}),
162
+ });
163
+ }
164
+ // ---- Addons (from app.json) -----------------------------------------------
165
+ const addonMetas = [];
166
+ if (appJson) {
167
+ for (const { slug, plan } of appJson.addons) {
168
+ if (!slug)
169
+ continue;
170
+ const meta = lookupAddon(slug);
171
+ const id = addonId(slug);
172
+ const node = {
173
+ id,
174
+ label: meta.label,
175
+ kind: meta.kind,
176
+ provenance: 'declared',
177
+ metadata: { provider: 'heroku', slug: rootSlug(slug), ...(plan ? { plan } : {}) },
178
+ };
179
+ addNode(node);
180
+ addonMetas.push({ id, meta, slug });
181
+ }
182
+ }
183
+ // ---- Edges: each dyno → each addon, verb by addon kind -------------------
184
+ // Only emit edges when we have dynos (Procfile present).
185
+ // Edge verb follows the 8-verb taxonomy:
186
+ // datastore → stores-in
187
+ // queue → publishes (can't distinguish producer/consumer from Procfile alone)
188
+ // external-api / other → calls
189
+ if (procfileEntries.length > 0) {
190
+ for (const { processType } of procfileEntries) {
191
+ const srcId = dynoId(processType);
192
+ for (const { id: targetId, meta } of addonMetas) {
193
+ let kind;
194
+ if (meta.kind === 'datastore') {
195
+ kind = 'stores-in';
196
+ }
197
+ else if (meta.kind === 'queue') {
198
+ kind = 'publishes';
199
+ }
200
+ else {
201
+ kind = 'calls';
202
+ }
203
+ edges.push({ source: srcId, target: targetId, kind });
204
+ }
205
+ }
206
+ }
207
+ return {
208
+ root,
209
+ adapter: 'heroku',
210
+ nodes: [...nodes.values()],
211
+ edges,
212
+ classificationsNeeded: [], // all declared via static slug map
213
+ };
214
+ }
215
+ // ---------------------------------------------------------------------------
216
+ // Adapter.
217
+ export const herokuAdapter = {
218
+ name: 'heroku',
219
+ async detect(repoDir) {
220
+ return detectHeroku(repoDir);
221
+ },
222
+ async extract(repoDir) {
223
+ // -- Procfile --
224
+ let procfileEntries = [];
225
+ const procfilePath = join(repoDir, 'Procfile');
226
+ if (existsSync(procfilePath)) {
227
+ try {
228
+ procfileEntries = parseProcfile(readFileSync(procfilePath, 'utf8'));
229
+ }
230
+ catch (err) {
231
+ console.warn(` [heroku] skipping unparseable ${procfilePath}: ${err.message}`);
232
+ }
233
+ }
234
+ // -- app.json --
235
+ let appJson = null;
236
+ const appJsonPath = join(repoDir, 'app.json');
237
+ if (existsSync(appJsonPath)) {
238
+ try {
239
+ appJson = parseAppJson(readFileSync(appJsonPath, 'utf8'));
240
+ }
241
+ catch (err) {
242
+ console.warn(` [heroku] skipping unparseable ${appJsonPath}: ${err.message}`);
243
+ }
244
+ }
245
+ // -- heroku.yml (presence check only — YAML parsing deferred) --
246
+ const hasHerokuYml = existsSync(join(repoDir, 'heroku.yml'));
247
+ if (hasHerokuYml) {
248
+ console.warn(' [heroku] heroku.yml detected but YAML parsing is deferred in v0 — skipping content extraction');
249
+ }
250
+ return buildHerokuGraph({ procfileEntries, appJson, hasHerokuYml }, repoDir);
251
+ },
252
+ };
253
+ //# sourceMappingURL=heroku.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heroku.js","sourceRoot":"","sources":["../../../src/infra/heroku/heroku.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /** An in-repo Dockerfile and its inferred build-context dir (the source root). */
2
+ export interface DockerfileEntry {
3
+ /** Repo-relative path to the Dockerfile (provenance). */
4
+ dockerfile: string;
5
+ /** Repo-relative build-context dir = the source root ('' = repo root). */
6
+ context: string;
7
+ }
8
+ /** An explicit "this image ref is built from this context" pairing. */
9
+ export interface ImagePairing {
10
+ /** The image ref this pairing builds (e.g. a compose service's `image:`). */
11
+ image: string;
12
+ /** Repo-relative build-context dir = the source root ('' = repo root). */
13
+ context: string;
14
+ }
15
+ /** Everything the pure resolver needs: the repo's Dockerfiles + known pairings. */
16
+ export interface DockerfileIndex {
17
+ dockerfiles: DockerfileEntry[];
18
+ pairings: ImagePairing[];
19
+ }
20
+ export interface ParsedImageRef {
21
+ /** Registry host (`ghcr.io`, `123.dkr.ecr…`), or undefined for the default registry. */
22
+ registry?: string;
23
+ /** Repository path WITHOUT the registry (`acme/api`, `postgres`). */
24
+ repository: string;
25
+ /** Last path segment of the repository — the "base name" (`api`, `postgres`, `web`). */
26
+ name: string;
27
+ /** True iff the repository has no `/` after the registry — a Docker official-library image. */
28
+ officialLibrary: boolean;
29
+ }
30
+ /** Parse an image ref into its parts. Tolerant: never throws, best-effort. */
31
+ export declare function parseImageRef(ref: string): ParsedImageRef;
32
+ /**
33
+ * Is this image ref a PULLED public image (so it must NOT match a local
34
+ * Dockerfile heuristically)? True when it's a Docker official-library image
35
+ * (no org segment, e.g. `postgres:15`, `redis`) OR its base name carries a
36
+ * well-known data-store / message-bus / base-image token.
37
+ */
38
+ export declare function isLikelyExternalImage(ref: string): boolean;
39
+ /**
40
+ * Resolve an image ref to the repo-relative source-root dir(s) that build it,
41
+ * using only the injected index (no fs). Returns [] when unresolvable — the
42
+ * caller then emits NO `sourceRoots` (honest "Other"). Never returns the repo
43
+ * root ('') — that would be a catch-all swallowing sibling units.
44
+ *
45
+ * Deterministic: contexts are de-duped and sorted; ties at a signal degrade to
46
+ * [] rather than an arbitrary pick.
47
+ */
48
+ export declare function resolveImageToSourceRoots(imageRef: string, index: DockerfileIndex): string[];
49
+ /**
50
+ * Walk `repoDir` into a DockerfileIndex: every in-repo Dockerfile (context =
51
+ * its own dir, the docker-build convention) + every compose service that
52
+ * declares BOTH `build:` and `image:` as an explicit image→context pairing.
53
+ * Bounded + error-tolerant (shared walk.ts). Deterministic (sorted).
54
+ */
55
+ export declare function buildDockerfileIndex(repoDir: string): DockerfileIndex;
56
+ //# sourceMappingURL=image-resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-resolve.d.ts","sourceRoot":"","sources":["../../src/infra/image-resolve.ts"],"names":[],"mappings":"AA6CA,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AA2CD,MAAM,WAAW,cAAc;IAC7B,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAuBzD;AAuBD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAK1D;AAwBD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,EAAE,CA2B5F;AAgBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CA2BrE"}
@@ -0,0 +1,229 @@
1
+ // shared image→source resolver (Phase 0 of , seam #2).
2
+ //
3
+ // Tier-1/2 adapters (compose, Vercel, Fly, Render, Railway, Heroku) point at a
4
+ // SOURCE dir, so `sourceRoots` falls out cleanly. Tier-3 adapters (k8s,
5
+ // Terraform, Pulumi, AWS/GCP/Azure-native) reference a PRE-BUILT image
6
+ // (`image: myorg/api:1.2`) — there's no source dir in the config. This resolver
7
+ // is the shared bridge: given an image ref + an index of the repo's in-repo
8
+ // Dockerfiles (and any explicit image→context pairings the compose adapter
9
+ // already knows), it answers "which repo dir builds this image?" → that
10
+ // Dockerfile's build context = the source root the Tier-3 adapter emits.
11
+ //
12
+ // Hard rules:
13
+ // * Deterministic, NO LLM.
14
+ // * Graceful degradation — an image that resolves to no in-repo Dockerfile
15
+ // returns []; the adapter then emits NO `sourceRoots` and that unit's code
16
+ // honestly stays in "Other (not deployed)." NEVER guess.
17
+ // * Never a repo-root catch-all — a context that resolves to '' (the whole
18
+ // repo) is dropped, so it can't swallow sibling deploy units.
19
+ // * Pure core (`resolveImageToSourceRoots`) takes an injected index — no fs —
20
+ // so it's unit-testable, mirroring the netlify/compose builder split. The
21
+ // thin fs wrapper (`buildDockerfileIndex`) walks the repo.
22
+ //
23
+ // Matching signals, in priority order (best-effort, first hit wins):
24
+ // 1. An explicit image→context PAIRING (a compose service that declares BOTH
25
+ // `build:` and `image:` is the authoritative "this image is built here").
26
+ // 2. NAME-CONVENTION: the image's base name (`acme/api:1` → `api`) equals a
27
+ // Dockerfile build-context dir's last path segment. Exactly one match wins;
28
+ // ambiguous (≥2) → honest [] (never guess).
29
+ // 3. SINGLE-CONTEXT repo: exactly one Dockerfile build context in the whole
30
+ // repo → the obvious context (guarded by the external-image exclusion so a
31
+ // pulled `postgres:15` never grabs your one Dockerfile).
32
+ //
33
+ // Pulled public images (official-library `postgres:15`, known data/queue/base
34
+ // images) are excluded from the heuristic signals (2 + 3) — they run no code of
35
+ // yours. An explicit pairing (signal 1) still wins for them, because the repo
36
+ // literally said it builds that tag.
37
+ import { readFileSync } from 'node:fs';
38
+ import { relative } from 'node:path';
39
+ import { findFiles } from './walk.js';
40
+ import { parseComposeConfig } from './compose/compose-parse.js';
41
+ // ---------------------------------------------------------------------------
42
+ // Path helpers (repo-relative, normalized) — same idiom as netlify.ts/compose.ts.
43
+ /** Normalize a repo-relative path: backslashes→/, collapse a bare `.`/leading `./`,
44
+ * strip trailing `/`. A lone `.` (the repo root) normalizes to '' so it's dropped. */
45
+ function normalizeRoot(p) {
46
+ return p.replace(/\\/g, '/').replace(/^\.(?:\/|$)/, '').replace(/\/+$/, '');
47
+ }
48
+ /** The repo-relative directory of a repo-relative file path ('' = repo root). */
49
+ function dirOf(relPath) {
50
+ const i = relPath.lastIndexOf('/');
51
+ return i === -1 ? '' : relPath.slice(0, i);
52
+ }
53
+ /** Resolve `rel` (may contain `./`/`../`) against repo-relative `baseDir` → normalized. */
54
+ function resolveRel(baseDir, rel) {
55
+ const parts = (baseDir ? baseDir.split('/') : []).concat(rel.split('/'));
56
+ const out = [];
57
+ for (const p of parts) {
58
+ if (p === '' || p === '.')
59
+ continue;
60
+ if (p === '..')
61
+ out.pop();
62
+ else
63
+ out.push(p);
64
+ }
65
+ return out.join('/');
66
+ }
67
+ /** The last path segment of a repo-relative dir ('' for the repo root). */
68
+ function lastSegment(dir) {
69
+ const norm = normalizeRoot(dir);
70
+ if (!norm)
71
+ return '';
72
+ const i = norm.lastIndexOf('/');
73
+ return i === -1 ? norm : norm.slice(i + 1);
74
+ }
75
+ /** Parse an image ref into its parts. Tolerant: never throws, best-effort. */
76
+ export function parseImageRef(ref) {
77
+ let s = ref.trim();
78
+ // Strip a digest (`@sha256:…`) then a tag (the last `:` AFTER the last `/`,
79
+ // so a registry `host:port` isn't mistaken for a tag).
80
+ const at = s.indexOf('@');
81
+ if (at !== -1)
82
+ s = s.slice(0, at);
83
+ const lastSlash = s.lastIndexOf('/');
84
+ const lastColon = s.lastIndexOf(':');
85
+ if (lastColon > lastSlash)
86
+ s = s.slice(0, lastColon);
87
+ // The first segment is a registry iff it looks like a host (`.`/`:` or localhost).
88
+ const segs = s.split('/').filter((x) => x.length > 0);
89
+ let registry;
90
+ if (segs.length > 1) {
91
+ const first = segs[0];
92
+ if (first.includes('.') || first.includes(':') || first === 'localhost') {
93
+ registry = first;
94
+ segs.shift();
95
+ }
96
+ }
97
+ const repository = segs.join('/');
98
+ const name = segs.length ? segs[segs.length - 1] : repository;
99
+ return { registry, repository, name, officialLibrary: segs.length === 1 };
100
+ }
101
+ // ---------------------------------------------------------------------------
102
+ // Pulled-public-image exclusion. These run no code of yours, so the heuristic
103
+ // signals (name-convention + single-context) must never grab a local Dockerfile
104
+ // for them. Reuses the compose data/queue token lists + common base images.
105
+ const DATASTORE_TOKENS = [
106
+ 'postgres', 'postgis', 'mysql', 'mariadb', 'mongo', 'redis', 'valkey', 'keydb',
107
+ 'memcached', 'elasticsearch', 'opensearch', 'clickhouse', 'cassandra', 'scylla',
108
+ 'cockroach', 'influxdb', 'neo4j', 'couchdb', 'rethinkdb', 'minio', 'timescale',
109
+ ];
110
+ const QUEUE_TOKENS = [
111
+ 'rabbitmq', 'kafka', 'redpanda', 'nats', 'zookeeper', 'activemq', 'pulsar',
112
+ 'mosquitto', 'emqx',
113
+ ];
114
+ // Common public base / sidecar / tooling images that are pulled, never built here.
115
+ const PUBLIC_IMAGE_TOKENS = [
116
+ 'nginx', 'httpd', 'caddy', 'traefik', 'envoy', 'haproxy', 'busybox', 'alpine',
117
+ 'ubuntu', 'debian', 'node', 'python', 'golang', 'openjdk', 'ruby', 'php',
118
+ 'registry', 'grafana', 'prometheus', 'pause', 'consul', 'vault', 'jaeger',
119
+ ];
120
+ /**
121
+ * Is this image ref a PULLED public image (so it must NOT match a local
122
+ * Dockerfile heuristically)? True when it's a Docker official-library image
123
+ * (no org segment, e.g. `postgres:15`, `redis`) OR its base name carries a
124
+ * well-known data-store / message-bus / base-image token.
125
+ */
126
+ export function isLikelyExternalImage(ref) {
127
+ const { name, officialLibrary } = parseImageRef(ref);
128
+ if (officialLibrary)
129
+ return true;
130
+ const base = name.toLowerCase();
131
+ return [...DATASTORE_TOKENS, ...QUEUE_TOKENS, ...PUBLIC_IMAGE_TOKENS].some((t) => base.includes(t));
132
+ }
133
+ /**
134
+ * Do two image refs name the same image? Matches on the repository path
135
+ * (registry + tag ignored — a k8s manifest's `ghcr.io/acme/api:prod` and a
136
+ * compose `acme/api` are the same image), with a base-name fallback for when
137
+ * one side qualifies the org and the other doesn't.
138
+ */
139
+ function imageRefsMatch(a, b) {
140
+ const pa = parseImageRef(a);
141
+ const pb = parseImageRef(b);
142
+ if (pa.repository && pa.repository === pb.repository)
143
+ return true;
144
+ // Fallback: same base name ONLY when exactly one side is org-qualified and the
145
+ // other isn't — the genuine "registry/org-qualified ref vs an unqualified
146
+ // compose tag" case (e.g. `ghcr.io/acme/api` or ECR `…/api` vs compose `api`).
147
+ // Requiring `officialLibrary` to DIFFER means two distinct org-qualified refs
148
+ // (`acme/api` vs `other/api`) never collide on base name alone, and two bare
149
+ // names (`postgres` vs `postgres`) already matched on repository above.
150
+ return pa.name.length > 0 && pa.name === pb.name && pa.officialLibrary !== pb.officialLibrary;
151
+ }
152
+ // ---------------------------------------------------------------------------
153
+ // The pure resolver.
154
+ /**
155
+ * Resolve an image ref to the repo-relative source-root dir(s) that build it,
156
+ * using only the injected index (no fs). Returns [] when unresolvable — the
157
+ * caller then emits NO `sourceRoots` (honest "Other"). Never returns the repo
158
+ * root ('') — that would be a catch-all swallowing sibling units.
159
+ *
160
+ * Deterministic: contexts are de-duped and sorted; ties at a signal degrade to
161
+ * [] rather than an arbitrary pick.
162
+ */
163
+ export function resolveImageToSourceRoots(imageRef, index) {
164
+ if (!imageRef || !imageRef.trim())
165
+ return [];
166
+ // Signal 1 — explicit pairing (authoritative; wins even for external-looking
167
+ // names, because the repo literally declared it builds that tag).
168
+ const paired = uniqSorted(index.pairings.filter((p) => imageRefsMatch(imageRef, p.image)).map((p) => normalizeRoot(p.context)));
169
+ if (paired.length)
170
+ return paired;
171
+ // Heuristic signals (2 + 3) never fire for a pulled public image.
172
+ if (isLikelyExternalImage(imageRef))
173
+ return [];
174
+ const contexts = uniqSorted(index.dockerfiles.map((d) => normalizeRoot(d.context)));
175
+ // Signal 2 — name-convention: image base name === a context's last segment.
176
+ const { name } = parseImageRef(imageRef);
177
+ if (name) {
178
+ const byName = contexts.filter((c) => lastSegment(c) === name);
179
+ if (byName.length === 1)
180
+ return byName;
181
+ if (byName.length > 1)
182
+ return []; // ambiguous → never guess
183
+ }
184
+ // Signal 3 — single-context repo: the one Dockerfile context is the obvious one.
185
+ if (contexts.length === 1)
186
+ return contexts;
187
+ return [];
188
+ }
189
+ /** De-dupe, drop the empty (repo-root) context, and sort for determinism. */
190
+ function uniqSorted(roots) {
191
+ return [...new Set(roots.filter((r) => r.length > 0))].sort();
192
+ }
193
+ // ---------------------------------------------------------------------------
194
+ // fs wrapper — walk the repo into a DockerfileIndex (the thin impure shell).
195
+ // `Dockerfile`, `Dockerfile.prod`, `api.Dockerfile`, but NOT `.dockerignore`.
196
+ const DOCKERFILE_RE = /^Dockerfile(\.[A-Za-z0-9_.-]+)?$|\.Dockerfile$/;
197
+ // Compose-file basename (matches compose.ts) — the authoritative pairing source.
198
+ const COMPOSE_RE = /^(docker-compose|compose)(\.[A-Za-z0-9_-]+)?\.ya?ml$/i;
199
+ /**
200
+ * Walk `repoDir` into a DockerfileIndex: every in-repo Dockerfile (context =
201
+ * its own dir, the docker-build convention) + every compose service that
202
+ * declares BOTH `build:` and `image:` as an explicit image→context pairing.
203
+ * Bounded + error-tolerant (shared walk.ts). Deterministic (sorted).
204
+ */
205
+ export function buildDockerfileIndex(repoDir) {
206
+ const rel = (abs) => (relative(repoDir, abs) || abs).split('\\').join('/');
207
+ const dockerfiles = findFiles(repoDir, (_abs, e) => DOCKERFILE_RE.test(e.name)).map((abs) => {
208
+ const file = rel(abs);
209
+ return { dockerfile: file, context: dirOf(file) };
210
+ });
211
+ const pairings = [];
212
+ for (const abs of findFiles(repoDir, (_a, e) => COMPOSE_RE.test(e.name), { maxDepth: 5 })) {
213
+ let config;
214
+ try {
215
+ config = parseComposeConfig(readFileSync(abs, 'utf8'));
216
+ }
217
+ catch {
218
+ continue; // a malformed compose file shouldn't sink the index
219
+ }
220
+ const composeDir = dirOf(rel(abs));
221
+ for (const svc of config.services) {
222
+ if (svc.build && svc.image) {
223
+ pairings.push({ image: svc.image, context: resolveRel(composeDir, svc.build.context) });
224
+ }
225
+ }
226
+ }
227
+ return { dockerfiles, pairings };
228
+ }
229
+ //# sourceMappingURL=image-resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-resolve.js","sourceRoot":"","sources":["../../src/infra/image-resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { MergedInfraGraph } from './types.js';
2
+ import type { InfraModuleKind } from '../types.js';
3
+ /** A (provider, resourceType) pair an injected classifier must resolve. */
4
+ export interface ResourceTypeRef {
5
+ provider: string;
6
+ resourceType: string;
7
+ }
8
+ /** The classifier's verdict for one ref. */
9
+ export interface ResourceTypeResult {
10
+ provider: string;
11
+ resourceType: string;
12
+ nodeKind: InfraModuleKind;
13
+ }
14
+ /**
15
+ * Host-injected resolver for open-ended IaC resource types. Pure packages never
16
+ * ship one; the container/CLI passes a closure that calls the LLM classifier and
17
+ * accumulates cost in its own ledger. Deterministic dedupe happens here, before
18
+ * the callback, so the closure sees unique refs only.
19
+ */
20
+ export type ResourceTypeClassifier = (refs: ResourceTypeRef[]) => Promise<ResourceTypeResult[]>;
21
+ export interface InfraStepResult {
22
+ graph: MergedInfraGraph;
23
+ counts: {
24
+ nodes: number;
25
+ edges: number;
26
+ classified: number;
27
+ };
28
+ }
29
+ export declare function extractInfra(args: {
30
+ repoDir: string;
31
+ /**
32
+ * Optional host-injected classifier for open-ended IaC resource types. Omit
33
+ * (e.g. offline / --no-llm) to skip classification: deterministic adapter
34
+ * nodes still land; any classification-pending node keeps its adapter-emitted
35
+ * placeholder kind.
36
+ */
37
+ classifyResourceTypes?: ResourceTypeClassifier;
38
+ }): Promise<InfraStepResult>;
39
+ //# sourceMappingURL=infra-step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infra-step.d.ts","sourceRoot":"","sources":["../../src/infra/infra-step.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,4CAA4C;AAC5C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG,CACnC,IAAI,EAAE,eAAe,EAAE,KACpB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;AAEnC,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,sBAAsB,CAAC;CAChD,GAAG,OAAO,CAAC,eAAe,CAAC,CAoC3B"}