@neat.is/core 0.5.0 → 0.5.1-dev.20260719

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  routeSpanToProject,
3
3
  startDaemon
4
- } from "./chunk-5MGHWP6R.js";
4
+ } from "./chunk-O4PCNQFG.js";
5
5
  import {
6
6
  ProjectNameCollisionError,
7
7
  addProject,
@@ -37,7 +37,7 @@ import {
37
37
  thresholdForEdgeType,
38
38
  touchLastSeen,
39
39
  writeAtomically
40
- } from "./chunk-QQDZSIY3.js";
40
+ } from "./chunk-BI3XKGVG.js";
41
41
  import {
42
42
  startOtelGrpcReceiver
43
43
  } from "./chunk-I72HTUOG.js";
package/dist/neatd.cjs CHANGED
@@ -2627,6 +2627,7 @@ function ensureFrontierNode(graph, host, ts) {
2627
2627
  }
2628
2628
  function upsertObservedEdge(graph, type, source, target, ts, isError = false, evidence) {
2629
2629
  if (!graph.hasNode(source) || !graph.hasNode(target)) return null;
2630
+ const grain = source.startsWith("file:") ? "file" : "service";
2630
2631
  const id = makeObservedEdgeId(type, source, target);
2631
2632
  if (graph.hasEdge(id)) {
2632
2633
  const existing = graph.getEdgeAttributes(id);
@@ -2643,7 +2644,9 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
2643
2644
  lastObserved: ts,
2644
2645
  callCount: newSpanCount,
2645
2646
  signal: newSignal,
2646
- confidence: (0, import_types3.confidenceForObservedSignal)(newSignal)
2647
+ confidence: (0, import_types3.confidenceForObservedSignal)(newSignal),
2648
+ grain
2649
+ // backfills legacy edges that predate ADR-142
2647
2650
  };
2648
2651
  graph.replaceEdgeAttributes(id, updated);
2649
2652
  return { edge: updated, created: false };
@@ -2663,6 +2666,7 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
2663
2666
  lastObserved: ts,
2664
2667
  callCount: 1,
2665
2668
  signal,
2669
+ grain,
2666
2670
  // Call-site evidence from span code.* semconv (file-awareness.md §4 + §6).
2667
2671
  // Only set when code.filepath was present on the span — never fabricated.
2668
2672
  ...evidence ? { evidence } : {}
@@ -4746,6 +4750,15 @@ async function parse4(serviceDir) {
4746
4750
  const config = parseConnectionString(urlMatch[1]);
4747
4751
  if (config) return [{ ...config, sourceFile: filePath }];
4748
4752
  }
4753
+ const urlEnvMatch = content.match(
4754
+ /(?:url|connectionString)\s*:\s*process\.env(?:\.([A-Za-z_$][\w$]*)|\[\s*['"]([^'"]+)['"]\s*\])/
4755
+ );
4756
+ if (urlEnvMatch) {
4757
+ const varName = urlEnvMatch[1] ?? urlEnvMatch[2];
4758
+ const resolved = varName ? await resolveEnvVar(serviceDir, varName) : null;
4759
+ const config = resolved ? parseConnectionString(resolved) : null;
4760
+ if (config) return [{ ...config, sourceFile: filePath }];
4761
+ }
4749
4762
  const hostMatch = content.match(/host\s*:\s*['"`]([^'"`]+)['"`]/);
4750
4763
  if (hostMatch) {
4751
4764
  const portMatch = content.match(/port\s*:\s*(\d+)/);
@@ -4799,6 +4812,15 @@ async function parse5(serviceDir) {
4799
4812
  const config = parseConnectionString(urlMatch[1]);
4800
4813
  if (config) return [{ ...config, sourceFile: filePath }];
4801
4814
  }
4815
+ const urlEnvMatch = content.match(
4816
+ /connection\s*:\s*process\.env(?:\.([A-Za-z_$][\w$]*)|\[\s*['"]([^'"]+)['"]\s*\])/
4817
+ );
4818
+ if (urlEnvMatch) {
4819
+ const varName = urlEnvMatch[1] ?? urlEnvMatch[2];
4820
+ const resolved = varName ? await resolveEnvVar(serviceDir, varName) : null;
4821
+ const config = resolved ? parseConnectionString(resolved) : null;
4822
+ if (config) return [{ ...config, sourceFile: filePath }];
4823
+ }
4802
4824
  const host = content.match(/host\s*:\s*['"`]([^'"`]+)['"`]/)?.[1];
4803
4825
  if (host) {
4804
4826
  const port = content.match(/port\s*:\s*(\d+)/)?.[1];
@@ -6347,6 +6369,16 @@ function constructorMatchesImport(name, ctx) {
6347
6369
  if (name === "createClient") return ctx.hasSupabaseJs;
6348
6370
  return ctx.hasSupabaseSsr;
6349
6371
  }
6372
+ var SUPABASE_CLIENT_ASSIGN_RE = /(?:const|let|var)\s+(\w+)\s*=\s*(?:await\s+)?(createClient|createServerClient|createBrowserClient)\s*\(/g;
6373
+ function supabaseClientVars(content, ctx) {
6374
+ const vars = /* @__PURE__ */ new Set();
6375
+ SUPABASE_CLIENT_ASSIGN_RE.lastIndex = 0;
6376
+ let m;
6377
+ while ((m = SUPABASE_CLIENT_ASSIGN_RE.exec(content)) !== null) {
6378
+ if (constructorMatchesImport(m[2], ctx)) vars.add(m[1]);
6379
+ }
6380
+ return vars;
6381
+ }
6350
6382
  function supabaseEndpointsFromFile(file, serviceDir) {
6351
6383
  const ctx = readImports2(file.content);
6352
6384
  if (!ctx.hasSupabaseJs && !ctx.hasSupabaseSsr) return [];
@@ -6379,6 +6411,34 @@ function supabaseEndpointsFromFile(file, serviceDir) {
6379
6411
  }
6380
6412
  });
6381
6413
  }
6414
+ const clientVars = supabaseClientVars(file.content, ctx);
6415
+ for (const clientVar of clientVars) {
6416
+ const accessRe = new RegExp(
6417
+ `\\b${clientVar}\\s*\\.\\s*(from|rpc)\\s*\\(\\s*['"\`]([\\w.-]+)['"\`]`,
6418
+ "g"
6419
+ );
6420
+ let am;
6421
+ while ((am = accessRe.exec(file.content)) !== null) {
6422
+ const kind = am[1] === "rpc" ? "supabase-rpc" : "supabase-table";
6423
+ const resource = am[2];
6424
+ const key = `${kind}/${resource}`;
6425
+ if (seen.has(key)) continue;
6426
+ seen.add(key);
6427
+ const line = lineOf(file.content, am[0]);
6428
+ out.push({
6429
+ infraId: (0, import_types19.infraId)(kind, resource),
6430
+ name: resource,
6431
+ kind,
6432
+ edgeType: "CALLS",
6433
+ confidenceKind: "verified-call-site",
6434
+ evidence: {
6435
+ file: import_node_path30.default.relative(serviceDir, file.path),
6436
+ line,
6437
+ snippet: snippet(file.content, line)
6438
+ }
6439
+ });
6440
+ }
6441
+ }
6382
6442
  return out;
6383
6443
  }
6384
6444
 
@@ -9558,7 +9618,30 @@ init_otel();
9558
9618
 
9559
9619
  // src/connectors/index.ts
9560
9620
  init_cjs_shims();
9621
+ var import_types34 = require("@neat.is/types");
9561
9622
  var NO_ENV = "unknown";
9623
+ function staticCallSiteFor(graph, serviceName, targetNodeId) {
9624
+ if (!graph.hasNode(targetNodeId)) return void 0;
9625
+ const sites = [];
9626
+ for (const edgeId of graph.inboundEdges(targetNodeId)) {
9627
+ const edge = graph.getEdgeAttributes(edgeId);
9628
+ if (edge.provenance !== import_types34.Provenance.EXTRACTED) continue;
9629
+ const parsed = (0, import_types34.parseFileId)(edge.source);
9630
+ if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
9631
+ const site = { relPath: edge.evidence.file };
9632
+ if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
9633
+ sites.push(site);
9634
+ }
9635
+ return sites.length === 1 ? sites[0] : void 0;
9636
+ }
9637
+ function routeCallSiteFor(graph, targetNodeId) {
9638
+ if (!graph.hasNode(targetNodeId)) return void 0;
9639
+ const attrs = graph.getNodeAttributes(targetNodeId);
9640
+ if (attrs.type !== import_types34.NodeType.RouteNode || !attrs.path) return void 0;
9641
+ const site = { relPath: attrs.path };
9642
+ if (attrs.line !== void 0) site.line = attrs.line;
9643
+ return site;
9644
+ }
9562
9645
  async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
9563
9646
  const signals = await connector.poll(ctx);
9564
9647
  let edgesCreated = 0;
@@ -9575,7 +9658,7 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
9575
9658
  ensureInfraNode(graph, kind, name, provider);
9576
9659
  }
9577
9660
  const serviceNodeId = ensureServiceNode(graph, resolved.serviceName, NO_ENV);
9578
- const callSite = signal.callSite ? { relPath: signal.callSite.file, line: signal.callSite.line } : void 0;
9661
+ const callSite = signal.callSite ? { relPath: signal.callSite.file, line: signal.callSite.line } : routeCallSiteFor(graph, resolved.targetNodeId) ?? staticCallSiteFor(graph, resolved.serviceName, resolved.targetNodeId);
9579
9662
  const sourceId = callSite ? ensureObservedFileNode(graph, resolved.serviceName, serviceNodeId, callSite) : serviceNodeId;
9580
9663
  const evidence = callSite ? {
9581
9664
  file: reconcileObservedRelPath(graph, resolved.serviceName, callSite.relPath),
@@ -10126,19 +10209,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
10126
10209
 
10127
10210
  // src/connectors/supabase/resolve.ts
10128
10211
  init_cjs_shims();
10129
- var import_types35 = require("@neat.is/types");
10212
+ var import_types36 = require("@neat.is/types");
10130
10213
  function createSupabaseResolveTarget(graph, config) {
10131
10214
  return (signal, _ctx) => {
10132
10215
  if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
10133
10216
  return null;
10134
10217
  }
10135
- const subResourceId = (0, import_types35.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
10218
+ const subResourceId = (0, import_types36.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
10136
10219
  if (graph.hasNode(subResourceId)) {
10137
- return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types35.EdgeType.CALLS };
10220
+ return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types36.EdgeType.CALLS };
10221
+ }
10222
+ const bareResourceId = (0, import_types36.infraId)(signal.targetKind, signal.targetName);
10223
+ if (graph.hasNode(bareResourceId)) {
10224
+ return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types36.EdgeType.CALLS };
10138
10225
  }
10139
- const projectLevelId = (0, import_types35.infraId)("supabase", config.nodeRef);
10226
+ const projectLevelId = (0, import_types36.infraId)("supabase", config.nodeRef);
10140
10227
  if (graph.hasNode(projectLevelId)) {
10141
- return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types35.EdgeType.CALLS };
10228
+ return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types36.EdgeType.CALLS };
10142
10229
  }
10143
10230
  return null;
10144
10231
  };
@@ -10231,7 +10318,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
10231
10318
 
10232
10319
  // src/connectors/railway/index.ts
10233
10320
  init_cjs_shims();
10234
- var import_types39 = require("@neat.is/types");
10321
+ var import_types40 = require("@neat.is/types");
10235
10322
 
10236
10323
  // src/connectors/railway/client.ts
10237
10324
  init_cjs_shims();
@@ -10357,7 +10444,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
10357
10444
  const out = [];
10358
10445
  graph.forEachNode((_id, attrs) => {
10359
10446
  const node = attrs;
10360
- if (node.type !== import_types39.NodeType.RouteNode) return;
10447
+ if (node.type !== import_types40.NodeType.RouteNode) return;
10361
10448
  const route = attrs;
10362
10449
  if (route.service !== serviceName) return;
10363
10450
  out.push({
@@ -10453,12 +10540,12 @@ function createRailwayResolveTarget(config) {
10453
10540
  const serviceName = config.serviceNameById[config.serviceId];
10454
10541
  if (!serviceName) return null;
10455
10542
  if (signal.targetKind === ROUTE_TARGET_KIND) {
10456
- return { targetNodeId: signal.targetName, serviceName, edgeType: import_types39.EdgeType.CALLS };
10543
+ return { targetNodeId: signal.targetName, serviceName, edgeType: import_types40.EdgeType.CALLS };
10457
10544
  }
10458
10545
  if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
10459
10546
  const peerName = config.serviceNameById[signal.targetName];
10460
10547
  if (!peerName) return null;
10461
- return { targetNodeId: (0, import_types39.serviceId)(peerName), serviceName, edgeType: import_types39.EdgeType.CONNECTS_TO };
10548
+ return { targetNodeId: (0, import_types40.serviceId)(peerName), serviceName, edgeType: import_types40.EdgeType.CONNECTS_TO };
10462
10549
  }
10463
10550
  return null;
10464
10551
  };
@@ -10645,7 +10732,7 @@ function mapLogEntriesToSignals(entries) {
10645
10732
 
10646
10733
  // src/connectors/firebase/resolve.ts
10647
10734
  init_cjs_shims();
10648
- var import_types40 = require("@neat.is/types");
10735
+ var import_types41 = require("@neat.is/types");
10649
10736
  function neatServiceNameFor(resourceType, resourceName, serviceMap) {
10650
10737
  switch (resourceType) {
10651
10738
  case "cloud_function":
@@ -10660,7 +10747,7 @@ function routeEntriesFor(graph, serviceName) {
10660
10747
  const entries = [];
10661
10748
  graph.forEachNode((_id, attrs) => {
10662
10749
  const node = attrs;
10663
- if (node.type !== import_types40.NodeType.RouteNode) return;
10750
+ if (node.type !== import_types41.NodeType.RouteNode) return;
10664
10751
  const route = attrs;
10665
10752
  if (route.service !== serviceName) return;
10666
10753
  entries.push({
@@ -10692,7 +10779,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
10692
10779
  return {
10693
10780
  targetNodeId: match.routeNodeId,
10694
10781
  serviceName,
10695
- edgeType: import_types40.EdgeType.CALLS
10782
+ edgeType: import_types41.EdgeType.CALLS
10696
10783
  };
10697
10784
  };
10698
10785
  }
@@ -10719,7 +10806,7 @@ init_cjs_shims();
10719
10806
 
10720
10807
  // src/connectors/cloudflare/connector.ts
10721
10808
  init_cjs_shims();
10722
- var import_types42 = require("@neat.is/types");
10809
+ var import_types43 = require("@neat.is/types");
10723
10810
 
10724
10811
  // src/connectors/cloudflare/client.ts
10725
10812
  init_cjs_shims();
@@ -10880,7 +10967,7 @@ function findTaggedWorkerFileNode(graph, workerName) {
10880
10967
  graph.forEachNode((id, attrs) => {
10881
10968
  if (found) return;
10882
10969
  const a = attrs;
10883
- if (a.type === import_types42.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
10970
+ if (a.type === import_types43.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
10884
10971
  found = id;
10885
10972
  }
10886
10973
  });
@@ -10892,7 +10979,7 @@ function findMatchingRouteNode(graph, serviceName, method, path53) {
10892
10979
  graph.forEachNode((id, attrs) => {
10893
10980
  if (found) return;
10894
10981
  const a = attrs;
10895
- if (a.type !== import_types42.NodeType.RouteNode || a.service !== serviceName) return;
10982
+ if (a.type !== import_types43.NodeType.RouteNode || a.service !== serviceName) return;
10896
10983
  if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
10897
10984
  const routeMethod = (a.method ?? "").toUpperCase();
10898
10985
  if (routeMethod !== "ALL" && routeMethod !== method) return;
@@ -10911,11 +10998,11 @@ function createCloudflareResolveTarget(config, graph) {
10911
10998
  };
10912
10999
  const mapping = config.workers?.[scriptName];
10913
11000
  if (mapping) {
10914
- const wholeFileId = (0, import_types42.fileId)(mapping.service, mapping.entryFile);
11001
+ const wholeFileId = (0, import_types43.fileId)(mapping.service, mapping.entryFile);
10915
11002
  return {
10916
11003
  targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
10917
11004
  serviceName: mapping.service,
10918
- edgeType: import_types42.EdgeType.CALLS
11005
+ edgeType: import_types43.EdgeType.CALLS
10919
11006
  };
10920
11007
  }
10921
11008
  const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
@@ -10924,13 +11011,13 @@ function createCloudflareResolveTarget(config, graph) {
10924
11011
  return {
10925
11012
  targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
10926
11013
  serviceName: fileNode.service,
10927
- edgeType: import_types42.EdgeType.CALLS
11014
+ edgeType: import_types43.EdgeType.CALLS
10928
11015
  };
10929
11016
  }
10930
11017
  return {
10931
- targetNodeId: (0, import_types42.infraId)("cloudflare-worker", scriptName),
11018
+ targetNodeId: (0, import_types43.infraId)("cloudflare-worker", scriptName),
10932
11019
  serviceName: scriptName,
10933
- edgeType: import_types42.EdgeType.CALLS,
11020
+ edgeType: import_types43.EdgeType.CALLS,
10934
11021
  ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
10935
11022
  };
10936
11023
  };
@@ -11189,7 +11276,7 @@ function unroutedErrorsPath(neatHome4) {
11189
11276
  }
11190
11277
 
11191
11278
  // src/daemon.ts
11192
- var import_types45 = require("@neat.is/types");
11279
+ var import_types46 = require("@neat.is/types");
11193
11280
  function daemonJsonPath(scanPath) {
11194
11281
  return import_node_path50.default.join(scanPath, "neat-out", "daemon.json");
11195
11282
  }
@@ -11324,7 +11411,7 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
11324
11411
  if (!serviceName) return true;
11325
11412
  if (serviceNameMatchesProject(serviceName, project)) return true;
11326
11413
  return graph.someNode(
11327
- (_id, attrs) => attrs.type === import_types45.NodeType.ServiceNode && attrs.name === serviceName
11414
+ (_id, attrs) => attrs.type === import_types46.NodeType.ServiceNode && attrs.name === serviceName
11328
11415
  );
11329
11416
  }
11330
11417
  async function bootstrapProject(entry2, connectors = [], neatHome4) {