@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.
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/cluster/domain-grouping.d.ts +113 -0
- package/dist/cluster/domain-grouping.d.ts.map +1 -0
- package/dist/cluster/domain-grouping.js +277 -0
- package/dist/cluster/domain-grouping.js.map +1 -0
- package/dist/cluster/grouping-gate.d.ts +54 -0
- package/dist/cluster/grouping-gate.d.ts.map +1 -0
- package/dist/cluster/grouping-gate.js +0 -0
- package/dist/cluster/grouping-gate.js.map +1 -0
- package/dist/cluster/louvain.d.ts +88 -0
- package/dist/cluster/louvain.d.ts.map +1 -0
- package/dist/cluster/louvain.js +674 -0
- package/dist/cluster/louvain.js.map +1 -0
- package/dist/cluster/overrides.d.ts +19 -0
- package/dist/cluster/overrides.d.ts.map +1 -0
- package/dist/cluster/overrides.js +32 -0
- package/dist/cluster/overrides.js.map +1 -0
- package/dist/cluster/subsystem.d.ts +45 -0
- package/dist/cluster/subsystem.d.ts.map +1 -0
- package/dist/cluster/subsystem.js +299 -0
- package/dist/cluster/subsystem.js.map +1 -0
- package/dist/cluster/workspaces.d.ts +64 -0
- package/dist/cluster/workspaces.d.ts.map +1 -0
- package/dist/cluster/workspaces.js +739 -0
- package/dist/cluster/workspaces.js.map +1 -0
- package/dist/extract.d.ts +52 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +48 -0
- package/dist/extract.js.map +1 -0
- package/dist/framework/celery/celery.d.ts +17 -0
- package/dist/framework/celery/celery.d.ts.map +1 -0
- package/dist/framework/celery/celery.js +524 -0
- package/dist/framework/celery/celery.js.map +1 -0
- package/dist/framework/contribute-step.d.ts +38 -0
- package/dist/framework/contribute-step.d.ts.map +1 -0
- package/dist/framework/contribute-step.js +403 -0
- package/dist/framework/contribute-step.js.map +1 -0
- package/dist/framework/detect-step.d.ts +8 -0
- package/dist/framework/detect-step.d.ts.map +1 -0
- package/dist/framework/detect-step.js +54 -0
- package/dist/framework/detect-step.js.map +1 -0
- package/dist/framework/detect-util.d.ts +24 -0
- package/dist/framework/detect-util.d.ts.map +1 -0
- package/dist/framework/detect-util.js +59 -0
- package/dist/framework/detect-util.js.map +1 -0
- package/dist/framework/django/django.d.ts +22 -0
- package/dist/framework/django/django.d.ts.map +1 -0
- package/dist/framework/django/django.js +940 -0
- package/dist/framework/django/django.js.map +1 -0
- package/dist/framework/fastapi/fastapi.d.ts +27 -0
- package/dist/framework/fastapi/fastapi.d.ts.map +1 -0
- package/dist/framework/fastapi/fastapi.js +477 -0
- package/dist/framework/fastapi/fastapi.js.map +1 -0
- package/dist/framework/faststream/faststream.d.ts +19 -0
- package/dist/framework/faststream/faststream.d.ts.map +1 -0
- package/dist/framework/faststream/faststream.js +765 -0
- package/dist/framework/faststream/faststream.js.map +1 -0
- package/dist/framework/flask/flask.d.ts +17 -0
- package/dist/framework/flask/flask.d.ts.map +1 -0
- package/dist/framework/flask/flask.js +507 -0
- package/dist/framework/flask/flask.js.map +1 -0
- package/dist/framework/graphql/graphql.d.ts +17 -0
- package/dist/framework/graphql/graphql.d.ts.map +1 -0
- package/dist/framework/graphql/graphql.js +708 -0
- package/dist/framework/graphql/graphql.js.map +1 -0
- package/dist/framework/grpc/grpc.d.ts +22 -0
- package/dist/framework/grpc/grpc.d.ts.map +1 -0
- package/dist/framework/grpc/grpc.js +618 -0
- package/dist/framework/grpc/grpc.js.map +1 -0
- package/dist/framework/litestar/litestar.d.ts +17 -0
- package/dist/framework/litestar/litestar.d.ts.map +1 -0
- package/dist/framework/litestar/litestar.js +536 -0
- package/dist/framework/litestar/litestar.js.map +1 -0
- package/dist/framework/nest/nest.d.ts +19 -0
- package/dist/framework/nest/nest.d.ts.map +1 -0
- package/dist/framework/nest/nest.js +613 -0
- package/dist/framework/nest/nest.js.map +1 -0
- package/dist/framework/next/next.d.ts +22 -0
- package/dist/framework/next/next.d.ts.map +1 -0
- package/dist/framework/next/next.js +449 -0
- package/dist/framework/next/next.js.map +1 -0
- package/dist/framework/node/node.d.ts +24 -0
- package/dist/framework/node/node.d.ts.map +1 -0
- package/dist/framework/node/node.js +1009 -0
- package/dist/framework/node/node.js.map +1 -0
- package/dist/framework/orchestrator/orchestrator.d.ts +34 -0
- package/dist/framework/orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/framework/orchestrator/orchestrator.js +691 -0
- package/dist/framework/orchestrator/orchestrator.js.map +1 -0
- package/dist/framework/orm/orm.d.ts +61 -0
- package/dist/framework/orm/orm.d.ts.map +1 -0
- package/dist/framework/orm/orm.js +620 -0
- package/dist/framework/orm/orm.js.map +1 -0
- package/dist/framework/python/analyze.d.ts +38 -0
- package/dist/framework/python/analyze.d.ts.map +1 -0
- package/dist/framework/python/analyze.js +98 -0
- package/dist/framework/python/analyze.js.map +1 -0
- package/dist/framework/python/py-ast.d.ts +130 -0
- package/dist/framework/python/py-ast.d.ts.map +1 -0
- package/dist/framework/python/py-ast.js +344 -0
- package/dist/framework/python/py-ast.js.map +1 -0
- package/dist/framework/python-orm/python-orm.d.ts +19 -0
- package/dist/framework/python-orm/python-orm.d.ts.map +1 -0
- package/dist/framework/python-orm/python-orm.js +516 -0
- package/dist/framework/python-orm/python-orm.js.map +1 -0
- package/dist/framework/react-native/react-native.d.ts +35 -0
- package/dist/framework/react-native/react-native.d.ts.map +1 -0
- package/dist/framework/react-native/react-native.js +1181 -0
- package/dist/framework/react-native/react-native.js.map +1 -0
- package/dist/framework/register.d.ts +2 -0
- package/dist/framework/register.d.ts.map +1 -0
- package/dist/framework/register.js +59 -0
- package/dist/framework/register.js.map +1 -0
- package/dist/framework/registry.d.ts +31 -0
- package/dist/framework/registry.d.ts.map +1 -0
- package/dist/framework/registry.js +70 -0
- package/dist/framework/registry.js.map +1 -0
- package/dist/framework/routing/expo-router.d.ts +31 -0
- package/dist/framework/routing/expo-router.d.ts.map +1 -0
- package/dist/framework/routing/expo-router.js +356 -0
- package/dist/framework/routing/expo-router.js.map +1 -0
- package/dist/framework/routing/index.d.ts +4 -0
- package/dist/framework/routing/index.d.ts.map +1 -0
- package/dist/framework/routing/index.js +16 -0
- package/dist/framework/routing/index.js.map +1 -0
- package/dist/framework/routing/next-router.d.ts +45 -0
- package/dist/framework/routing/next-router.d.ts.map +1 -0
- package/dist/framework/routing/next-router.js +378 -0
- package/dist/framework/routing/next-router.js.map +1 -0
- package/dist/framework/routing/route-tree.d.ts +73 -0
- package/dist/framework/routing/route-tree.d.ts.map +1 -0
- package/dist/framework/routing/route-tree.js +120 -0
- package/dist/framework/routing/route-tree.js.map +1 -0
- package/dist/framework/types.d.ts +230 -0
- package/dist/framework/types.d.ts.map +1 -0
- package/dist/framework/types.js +25 -0
- package/dist/framework/types.js.map +1 -0
- package/dist/graph/cross-language.d.ts +11 -0
- package/dist/graph/cross-language.d.ts.map +1 -0
- package/dist/graph/cross-language.js +123 -0
- package/dist/graph/cross-language.js.map +1 -0
- package/dist/graph/extract.d.ts +13 -0
- package/dist/graph/extract.d.ts.map +1 -0
- package/dist/graph/extract.js +79 -0
- package/dist/graph/extract.js.map +1 -0
- package/dist/graph/file-graph.d.ts +186 -0
- package/dist/graph/file-graph.d.ts.map +1 -0
- package/dist/graph/file-graph.js +427 -0
- package/dist/graph/file-graph.js.map +1 -0
- package/dist/graph/http-callsites.d.ts +14 -0
- package/dist/graph/http-callsites.d.ts.map +1 -0
- package/dist/graph/http-callsites.js +107 -0
- package/dist/graph/http-callsites.js.map +1 -0
- package/dist/graph/incremental.d.ts +122 -0
- package/dist/graph/incremental.d.ts.map +1 -0
- package/dist/graph/incremental.js +448 -0
- package/dist/graph/incremental.js.map +1 -0
- package/dist/graph/language.d.ts +31 -0
- package/dist/graph/language.d.ts.map +1 -0
- package/dist/graph/language.js +146 -0
- package/dist/graph/language.js.map +1 -0
- package/dist/graph/noise-filter.d.ts +46 -0
- package/dist/graph/noise-filter.d.ts.map +1 -0
- package/dist/graph/noise-filter.js +199 -0
- package/dist/graph/noise-filter.js.map +1 -0
- package/dist/graph/python-adapter.d.ts +36 -0
- package/dist/graph/python-adapter.d.ts.map +1 -0
- package/dist/graph/python-adapter.js +402 -0
- package/dist/graph/python-adapter.js.map +1 -0
- package/dist/graph/python-manifest.d.ts +22 -0
- package/dist/graph/python-manifest.d.ts.map +1 -0
- package/dist/graph/python-manifest.js +137 -0
- package/dist/graph/python-manifest.js.map +1 -0
- package/dist/graph/python-stdlib.d.ts +2 -0
- package/dist/graph/python-stdlib.d.ts.map +1 -0
- package/dist/graph/python-stdlib.js +53 -0
- package/dist/graph/python-stdlib.js.map +1 -0
- package/dist/graph/ts-morph-adapter.d.ts +65 -0
- package/dist/graph/ts-morph-adapter.d.ts.map +1 -0
- package/dist/graph/ts-morph-adapter.js +265 -0
- package/dist/graph/ts-morph-adapter.js.map +1 -0
- package/dist/graph/types.d.ts +37 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +50 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/infra/aws/aws-parse.d.ts +39 -0
- package/dist/infra/aws/aws-parse.d.ts.map +1 -0
- package/dist/infra/aws/aws-parse.js +149 -0
- package/dist/infra/aws/aws-parse.js.map +1 -0
- package/dist/infra/aws/aws.d.ts +6 -0
- package/dist/infra/aws/aws.d.ts.map +1 -0
- package/dist/infra/aws/aws.js +425 -0
- package/dist/infra/aws/aws.js.map +1 -0
- package/dist/infra/azure/azure-parse.d.ts +73 -0
- package/dist/infra/azure/azure-parse.d.ts.map +1 -0
- package/dist/infra/azure/azure-parse.js +178 -0
- package/dist/infra/azure/azure-parse.js.map +1 -0
- package/dist/infra/azure/azure.d.ts +12 -0
- package/dist/infra/azure/azure.d.ts.map +1 -0
- package/dist/infra/azure/azure.js +673 -0
- package/dist/infra/azure/azure.js.map +1 -0
- package/dist/infra/cloudflare/cloudflare.d.ts +50 -0
- package/dist/infra/cloudflare/cloudflare.d.ts.map +1 -0
- package/dist/infra/cloudflare/cloudflare.js +382 -0
- package/dist/infra/cloudflare/cloudflare.js.map +1 -0
- package/dist/infra/cloudflare/wrangler-parse.d.ts +6 -0
- package/dist/infra/cloudflare/wrangler-parse.d.ts.map +1 -0
- package/dist/infra/cloudflare/wrangler-parse.js +278 -0
- package/dist/infra/cloudflare/wrangler-parse.js.map +1 -0
- package/dist/infra/compose/compose-parse.d.ts +24 -0
- package/dist/infra/compose/compose-parse.d.ts.map +1 -0
- package/dist/infra/compose/compose-parse.js +77 -0
- package/dist/infra/compose/compose-parse.js.map +1 -0
- package/dist/infra/compose/compose.d.ts +12 -0
- package/dist/infra/compose/compose.d.ts.map +1 -0
- package/dist/infra/compose/compose.js +201 -0
- package/dist/infra/compose/compose.js.map +1 -0
- package/dist/infra/convex/convex-parse.d.ts +28 -0
- package/dist/infra/convex/convex-parse.d.ts.map +1 -0
- package/dist/infra/convex/convex-parse.js +74 -0
- package/dist/infra/convex/convex-parse.js.map +1 -0
- package/dist/infra/convex/convex.d.ts +18 -0
- package/dist/infra/convex/convex.d.ts.map +1 -0
- package/dist/infra/convex/convex.js +199 -0
- package/dist/infra/convex/convex.js.map +1 -0
- package/dist/infra/digitalocean/digitalocean.d.ts +33 -0
- package/dist/infra/digitalocean/digitalocean.d.ts.map +1 -0
- package/dist/infra/digitalocean/digitalocean.js +204 -0
- package/dist/infra/digitalocean/digitalocean.js.map +1 -0
- package/dist/infra/firebase/firebase.d.ts +43 -0
- package/dist/infra/firebase/firebase.d.ts.map +1 -0
- package/dist/infra/firebase/firebase.js +271 -0
- package/dist/infra/firebase/firebase.js.map +1 -0
- package/dist/infra/fly/fly-parse.d.ts +52 -0
- package/dist/infra/fly/fly-parse.d.ts.map +1 -0
- package/dist/infra/fly/fly-parse.js +114 -0
- package/dist/infra/fly/fly-parse.js.map +1 -0
- package/dist/infra/fly/fly.d.ts +15 -0
- package/dist/infra/fly/fly.d.ts.map +1 -0
- package/dist/infra/fly/fly.js +265 -0
- package/dist/infra/fly/fly.js.map +1 -0
- package/dist/infra/gcp/gcp-parse.d.ts +24 -0
- package/dist/infra/gcp/gcp-parse.d.ts.map +1 -0
- package/dist/infra/gcp/gcp-parse.js +123 -0
- package/dist/infra/gcp/gcp-parse.js.map +1 -0
- package/dist/infra/gcp/gcp.d.ts +10 -0
- package/dist/infra/gcp/gcp.d.ts.map +1 -0
- package/dist/infra/gcp/gcp.js +502 -0
- package/dist/infra/gcp/gcp.js.map +1 -0
- package/dist/infra/heroku/heroku-parse.d.ts +33 -0
- package/dist/infra/heroku/heroku-parse.d.ts.map +1 -0
- package/dist/infra/heroku/heroku-parse.js +63 -0
- package/dist/infra/heroku/heroku-parse.js.map +1 -0
- package/dist/infra/heroku/heroku.d.ts +24 -0
- package/dist/infra/heroku/heroku.d.ts.map +1 -0
- package/dist/infra/heroku/heroku.js +253 -0
- package/dist/infra/heroku/heroku.js.map +1 -0
- package/dist/infra/image-resolve.d.ts +56 -0
- package/dist/infra/image-resolve.d.ts.map +1 -0
- package/dist/infra/image-resolve.js +229 -0
- package/dist/infra/image-resolve.js.map +1 -0
- package/dist/infra/infra-step.d.ts +39 -0
- package/dist/infra/infra-step.d.ts.map +1 -0
- package/dist/infra/infra-step.js +57 -0
- package/dist/infra/infra-step.js.map +1 -0
- package/dist/infra/k8s/index.d.ts +78 -0
- package/dist/infra/k8s/index.d.ts.map +1 -0
- package/dist/infra/k8s/index.js +251 -0
- package/dist/infra/k8s/index.js.map +1 -0
- package/dist/infra/kamal/kamal-parse.d.ts +23 -0
- package/dist/infra/kamal/kamal-parse.d.ts.map +1 -0
- package/dist/infra/kamal/kamal-parse.js +66 -0
- package/dist/infra/kamal/kamal-parse.js.map +1 -0
- package/dist/infra/kamal/kamal.d.ts +17 -0
- package/dist/infra/kamal/kamal.d.ts.map +1 -0
- package/dist/infra/kamal/kamal.js +162 -0
- package/dist/infra/kamal/kamal.js.map +1 -0
- package/dist/infra/netlify/netlify.d.ts +33 -0
- package/dist/infra/netlify/netlify.d.ts.map +1 -0
- package/dist/infra/netlify/netlify.js +247 -0
- package/dist/infra/netlify/netlify.js.map +1 -0
- package/dist/infra/opentofu/opentofu.d.ts +3 -0
- package/dist/infra/opentofu/opentofu.d.ts.map +1 -0
- package/dist/infra/opentofu/opentofu.js +157 -0
- package/dist/infra/opentofu/opentofu.js.map +1 -0
- package/dist/infra/pulumi/pulumi-parse.d.ts +60 -0
- package/dist/infra/pulumi/pulumi-parse.d.ts.map +1 -0
- package/dist/infra/pulumi/pulumi-parse.js +155 -0
- package/dist/infra/pulumi/pulumi-parse.js.map +1 -0
- package/dist/infra/pulumi/pulumi.d.ts +23 -0
- package/dist/infra/pulumi/pulumi.d.ts.map +1 -0
- package/dist/infra/pulumi/pulumi.js +260 -0
- package/dist/infra/pulumi/pulumi.js.map +1 -0
- package/dist/infra/railway/railway-parse.d.ts +54 -0
- package/dist/infra/railway/railway-parse.d.ts.map +1 -0
- package/dist/infra/railway/railway-parse.js +200 -0
- package/dist/infra/railway/railway-parse.js.map +1 -0
- package/dist/infra/railway/railway.d.ts +19 -0
- package/dist/infra/railway/railway.d.ts.map +1 -0
- package/dist/infra/railway/railway.js +397 -0
- package/dist/infra/railway/railway.js.map +1 -0
- package/dist/infra/register.d.ts +2 -0
- package/dist/infra/register.d.ts.map +1 -0
- package/dist/infra/register.js +81 -0
- package/dist/infra/register.js.map +1 -0
- package/dist/infra/registry.d.ts +64 -0
- package/dist/infra/registry.d.ts.map +1 -0
- package/dist/infra/registry.js +205 -0
- package/dist/infra/registry.js.map +1 -0
- package/dist/infra/relevance.d.ts +16 -0
- package/dist/infra/relevance.d.ts.map +1 -0
- package/dist/infra/relevance.js +132 -0
- package/dist/infra/relevance.js.map +1 -0
- package/dist/infra/render/render-parse.d.ts +76 -0
- package/dist/infra/render/render-parse.d.ts.map +1 -0
- package/dist/infra/render/render-parse.js +155 -0
- package/dist/infra/render/render-parse.js.map +1 -0
- package/dist/infra/render/render.d.ts +11 -0
- package/dist/infra/render/render.d.ts.map +1 -0
- package/dist/infra/render/render.js +303 -0
- package/dist/infra/render/render.js.map +1 -0
- package/dist/infra/sst/sst-parse.d.ts +25 -0
- package/dist/infra/sst/sst-parse.d.ts.map +1 -0
- package/dist/infra/sst/sst-parse.js +45 -0
- package/dist/infra/sst/sst-parse.js.map +1 -0
- package/dist/infra/sst/sst.d.ts +19 -0
- package/dist/infra/sst/sst.d.ts.map +1 -0
- package/dist/infra/sst/sst.js +236 -0
- package/dist/infra/sst/sst.js.map +1 -0
- package/dist/infra/supabase/supabase-parse.d.ts +34 -0
- package/dist/infra/supabase/supabase-parse.d.ts.map +1 -0
- package/dist/infra/supabase/supabase-parse.js +113 -0
- package/dist/infra/supabase/supabase-parse.js.map +1 -0
- package/dist/infra/supabase/supabase.d.ts +15 -0
- package/dist/infra/supabase/supabase.d.ts.map +1 -0
- package/dist/infra/supabase/supabase.js +198 -0
- package/dist/infra/supabase/supabase.js.map +1 -0
- package/dist/infra/terraform/hcl-parse.d.ts +34 -0
- package/dist/infra/terraform/hcl-parse.d.ts.map +1 -0
- package/dist/infra/terraform/hcl-parse.js +203 -0
- package/dist/infra/terraform/hcl-parse.js.map +1 -0
- package/dist/infra/terraform/terraform.d.ts +14 -0
- package/dist/infra/terraform/terraform.d.ts.map +1 -0
- package/dist/infra/terraform/terraform.js +264 -0
- package/dist/infra/terraform/terraform.js.map +1 -0
- package/dist/infra/types.d.ts +151 -0
- package/dist/infra/types.d.ts.map +1 -0
- package/dist/infra/types.js +14 -0
- package/dist/infra/types.js.map +1 -0
- package/dist/infra/vercel/vercel-parse.d.ts +70 -0
- package/dist/infra/vercel/vercel-parse.d.ts.map +1 -0
- package/dist/infra/vercel/vercel-parse.js +194 -0
- package/dist/infra/vercel/vercel-parse.js.map +1 -0
- package/dist/infra/vercel/vercel.d.ts +30 -0
- package/dist/infra/vercel/vercel.d.ts.map +1 -0
- package/dist/infra/vercel/vercel.js +523 -0
- package/dist/infra/vercel/vercel.js.map +1 -0
- package/dist/infra/walk.d.ts +36 -0
- package/dist/infra/walk.d.ts.map +1 -0
- package/dist/infra/walk.js +85 -0
- package/dist/infra/walk.js.map +1 -0
- package/dist/safety.d.ts +13 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +67 -0
- package/dist/safety.js.map +1 -0
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +111 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +35 -0
- package/dist/version.js.map +1 -0
- 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"}
|