@neat.is/core 0.5.2 → 0.5.4-dev.20260721
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/{chunk-I72HTUOG.js → chunk-4RU3AAOI.js} +2 -2
- package/dist/{chunk-CFDPIMRP.js → chunk-I4NZ7PSN.js} +3 -2
- package/dist/chunk-I4NZ7PSN.js.map +1 -0
- package/dist/{chunk-BI3XKGVG.js → chunk-PEFX3DBR.js} +473 -127
- package/dist/chunk-PEFX3DBR.js.map +1 -0
- package/dist/{chunk-DPEPI2N6.js → chunk-VR73QNJD.js} +293 -22
- package/dist/chunk-VR73QNJD.js.map +1 -0
- package/dist/cli.cjs +1371 -479
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +343 -75
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +879 -310
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +888 -319
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-IDMIH6ZY.js → otel-grpc-TEGOXE6T.js} +3 -3
- package/dist/server.cjs +553 -192
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-BI3XKGVG.js.map +0 -1
- package/dist/chunk-CFDPIMRP.js.map +0 -1
- package/dist/chunk-DPEPI2N6.js.map +0 -1
- /package/dist/{chunk-I72HTUOG.js.map → chunk-4RU3AAOI.js.map} +0 -0
- /package/dist/{otel-grpc-IDMIH6ZY.js.map → otel-grpc-TEGOXE6T.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mountBearerAuth,
|
|
3
3
|
readAuthEnv
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-I4NZ7PSN.js";
|
|
5
5
|
|
|
6
6
|
// src/graph.ts
|
|
7
7
|
import GraphDefault from "graphology";
|
|
@@ -456,19 +456,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
456
456
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
457
457
|
let best = { path: [start], edges: [] };
|
|
458
458
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
459
|
-
function step(node,
|
|
460
|
-
if (
|
|
461
|
-
best = { path: [...
|
|
459
|
+
function step(node, path48, edges) {
|
|
460
|
+
if (path48.length > best.path.length) {
|
|
461
|
+
best = { path: [...path48], edges: [...edges] };
|
|
462
462
|
}
|
|
463
|
-
if (
|
|
463
|
+
if (path48.length - 1 >= maxDepth) return;
|
|
464
464
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
465
465
|
for (const [srcId, edge] of incoming) {
|
|
466
466
|
if (visited.has(srcId)) continue;
|
|
467
467
|
visited.add(srcId);
|
|
468
|
-
|
|
468
|
+
path48.push(srcId);
|
|
469
469
|
edges.push(edge);
|
|
470
|
-
step(srcId,
|
|
471
|
-
|
|
470
|
+
step(srcId, path48, edges);
|
|
471
|
+
path48.pop();
|
|
472
472
|
edges.pop();
|
|
473
473
|
visited.delete(srcId);
|
|
474
474
|
}
|
|
@@ -662,26 +662,26 @@ function dominantFailingCall(graph, serviceId5, visited) {
|
|
|
662
662
|
return best;
|
|
663
663
|
}
|
|
664
664
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
665
|
-
const
|
|
665
|
+
const path48 = [originServiceId];
|
|
666
666
|
const edges = [];
|
|
667
667
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
668
668
|
let current = originServiceId;
|
|
669
669
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
670
670
|
const hop = dominantFailingCall(graph, current, visited);
|
|
671
671
|
if (!hop) break;
|
|
672
|
-
|
|
672
|
+
path48.push(hop.nextService);
|
|
673
673
|
edges.push(hop.edge);
|
|
674
674
|
visited.add(hop.nextService);
|
|
675
675
|
current = hop.nextService;
|
|
676
676
|
}
|
|
677
677
|
if (edges.length === 0) return null;
|
|
678
|
-
return { path:
|
|
678
|
+
return { path: path48, edges, culprit: current };
|
|
679
679
|
}
|
|
680
680
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
681
681
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
682
682
|
if (!chain) return null;
|
|
683
683
|
const culprit = chain.culprit;
|
|
684
|
-
const
|
|
684
|
+
const path48 = [...chain.path];
|
|
685
685
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
686
686
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
687
687
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -689,14 +689,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
689
689
|
if (loc) {
|
|
690
690
|
let rootCauseNode = culprit;
|
|
691
691
|
if (loc.fileNode) {
|
|
692
|
-
|
|
692
|
+
path48.push(loc.fileNode);
|
|
693
693
|
edgeProvenances.push(Provenance.OBSERVED);
|
|
694
694
|
rootCauseNode = loc.fileNode;
|
|
695
695
|
}
|
|
696
696
|
return RootCauseResultSchema.parse({
|
|
697
697
|
rootCauseNode,
|
|
698
698
|
rootCauseReason: loc.rootCauseReason,
|
|
699
|
-
traversalPath:
|
|
699
|
+
traversalPath: path48,
|
|
700
700
|
edgeProvenances,
|
|
701
701
|
confidence,
|
|
702
702
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -708,7 +708,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
708
708
|
return RootCauseResultSchema.parse({
|
|
709
709
|
rootCauseNode: culprit,
|
|
710
710
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
711
|
-
traversalPath:
|
|
711
|
+
traversalPath: path48,
|
|
712
712
|
edgeProvenances,
|
|
713
713
|
confidence,
|
|
714
714
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2229,6 +2229,18 @@ async function handleSpan(ctx, span) {
|
|
|
2229
2229
|
callSiteEvidence
|
|
2230
2230
|
);
|
|
2231
2231
|
if (result) affectedNode = targetId;
|
|
2232
|
+
if (span.dbSystem === "mongodb" && span.dbCollection) {
|
|
2233
|
+
const collectionId = ensureInfraNode(ctx.graph, "mongodb-collection", span.dbCollection, "self");
|
|
2234
|
+
upsertObservedEdge(
|
|
2235
|
+
ctx.graph,
|
|
2236
|
+
EdgeType3.CALLS,
|
|
2237
|
+
observedSource(),
|
|
2238
|
+
collectionId,
|
|
2239
|
+
ts,
|
|
2240
|
+
isError,
|
|
2241
|
+
callSiteEvidence
|
|
2242
|
+
);
|
|
2243
|
+
}
|
|
2232
2244
|
}
|
|
2233
2245
|
} else if (span.messagingSystem && span.messagingDestination && spanMintsMessagingEdge(span.kind)) {
|
|
2234
2246
|
const targetId = ensureMessagingDestinationNode(
|
|
@@ -3990,14 +4002,21 @@ function engineFromImage(image) {
|
|
|
3990
4002
|
// src/extract/databases/dotenv.ts
|
|
3991
4003
|
var CONNECTION_KEYS = /* @__PURE__ */ new Set([
|
|
3992
4004
|
"DATABASE_URL",
|
|
4005
|
+
"DATABASE_URI",
|
|
3993
4006
|
"DB_URL",
|
|
4007
|
+
"DB_URI",
|
|
3994
4008
|
"POSTGRES_URL",
|
|
4009
|
+
"POSTGRES_URI",
|
|
3995
4010
|
"POSTGRESQL_URL",
|
|
4011
|
+
"POSTGRESQL_URI",
|
|
3996
4012
|
"MYSQL_URL",
|
|
4013
|
+
"MYSQL_URI",
|
|
4014
|
+
"MONGODB_URL",
|
|
3997
4015
|
"MONGODB_URI",
|
|
3998
4016
|
"MONGO_URL",
|
|
3999
4017
|
"MONGO_URI",
|
|
4000
|
-
"REDIS_URL"
|
|
4018
|
+
"REDIS_URL",
|
|
4019
|
+
"REDIS_URI"
|
|
4001
4020
|
]);
|
|
4002
4021
|
function parseDotenvLine(line) {
|
|
4003
4022
|
const trimmed = line.trim();
|
|
@@ -5819,6 +5838,301 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
5819
5838
|
return out;
|
|
5820
5839
|
}
|
|
5821
5840
|
|
|
5841
|
+
// src/extract/calls/mongoose.ts
|
|
5842
|
+
import path31 from "path";
|
|
5843
|
+
import { infraId as infraId7 } from "@neat.is/types";
|
|
5844
|
+
var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
|
|
5845
|
+
var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
|
|
5846
|
+
var PLURALIZE_DISABLED_RE = /\bpluralize\s*\(\s*(?:null|false)\s*\)/;
|
|
5847
|
+
var UNCOUNTABLES = /* @__PURE__ */ new Set([
|
|
5848
|
+
"advice",
|
|
5849
|
+
"energy",
|
|
5850
|
+
"excretion",
|
|
5851
|
+
"digestion",
|
|
5852
|
+
"cooperation",
|
|
5853
|
+
"health",
|
|
5854
|
+
"justice",
|
|
5855
|
+
"labour",
|
|
5856
|
+
"machinery",
|
|
5857
|
+
"equipment",
|
|
5858
|
+
"information",
|
|
5859
|
+
"pollution",
|
|
5860
|
+
"sewage",
|
|
5861
|
+
"paper",
|
|
5862
|
+
"money",
|
|
5863
|
+
"species",
|
|
5864
|
+
"series",
|
|
5865
|
+
"rain",
|
|
5866
|
+
"rice",
|
|
5867
|
+
"fish",
|
|
5868
|
+
"sheep",
|
|
5869
|
+
"moose",
|
|
5870
|
+
"deer",
|
|
5871
|
+
"news",
|
|
5872
|
+
"expertise",
|
|
5873
|
+
"status",
|
|
5874
|
+
"media"
|
|
5875
|
+
]);
|
|
5876
|
+
var PLURALIZE_RULES = [
|
|
5877
|
+
[/human$/gi, "humans"],
|
|
5878
|
+
[/(m)an$/gi, "$1en"],
|
|
5879
|
+
[/(pe)rson$/gi, "$1ople"],
|
|
5880
|
+
[/(child)$/gi, "$1ren"],
|
|
5881
|
+
[/^(ox)$/gi, "$1en"],
|
|
5882
|
+
[/(ax|test)is$/gi, "$1es"],
|
|
5883
|
+
[/(octop|vir)us$/gi, "$1i"],
|
|
5884
|
+
[/(alias|status)$/gi, "$1es"],
|
|
5885
|
+
[/(bu)s$/gi, "$1ses"],
|
|
5886
|
+
[/(buffal|tomat|potat)o$/gi, "$1oes"],
|
|
5887
|
+
[/([ti])um$/gi, "$1a"],
|
|
5888
|
+
[/sis$/gi, "ses"],
|
|
5889
|
+
[/(?:([^f])fe|([lr])f)$/gi, "$1$2ves"],
|
|
5890
|
+
[/(hive)$/gi, "$1s"],
|
|
5891
|
+
[/([^aeiouy]|qu)y$/gi, "$1ies"],
|
|
5892
|
+
[/(x|ch|ss|sh)$/gi, "$1es"],
|
|
5893
|
+
[/(matr|vert|ind)ix|ex$/gi, "$1ices"],
|
|
5894
|
+
[/([m|l])ouse$/gi, "$1ice"],
|
|
5895
|
+
[/(kn|w|l)ife$/gi, "$1ives"],
|
|
5896
|
+
[/(quiz)$/gi, "$1zes"],
|
|
5897
|
+
[/s$/gi, "s"],
|
|
5898
|
+
[/([^a-z])$/, "$1"],
|
|
5899
|
+
[/$/gi, "s"]
|
|
5900
|
+
];
|
|
5901
|
+
function pluralizeCollection(name) {
|
|
5902
|
+
const str = name.toLowerCase();
|
|
5903
|
+
if (UNCOUNTABLES.has(str)) return str;
|
|
5904
|
+
for (const [re, repl] of PLURALIZE_RULES) {
|
|
5905
|
+
if (str.match(re)) return str.replace(re, repl);
|
|
5906
|
+
}
|
|
5907
|
+
return str;
|
|
5908
|
+
}
|
|
5909
|
+
var MODEL_METHODS = [
|
|
5910
|
+
"find",
|
|
5911
|
+
"findOne",
|
|
5912
|
+
"findById",
|
|
5913
|
+
"findByIdAndUpdate",
|
|
5914
|
+
"findByIdAndDelete",
|
|
5915
|
+
"findOneAndUpdate",
|
|
5916
|
+
"findOneAndDelete",
|
|
5917
|
+
"findOneAndReplace",
|
|
5918
|
+
"countDocuments",
|
|
5919
|
+
"estimatedDocumentCount",
|
|
5920
|
+
"distinct",
|
|
5921
|
+
"aggregate",
|
|
5922
|
+
"exists",
|
|
5923
|
+
"where",
|
|
5924
|
+
"populate",
|
|
5925
|
+
"watch",
|
|
5926
|
+
"hydrate",
|
|
5927
|
+
"create",
|
|
5928
|
+
"insertMany",
|
|
5929
|
+
"insertOne",
|
|
5930
|
+
"updateOne",
|
|
5931
|
+
"updateMany",
|
|
5932
|
+
"replaceOne",
|
|
5933
|
+
"deleteOne",
|
|
5934
|
+
"deleteMany",
|
|
5935
|
+
"bulkWrite",
|
|
5936
|
+
"bulkSave",
|
|
5937
|
+
"save",
|
|
5938
|
+
// pre-v7, removed in current mongoose but present in older codebases:
|
|
5939
|
+
"count",
|
|
5940
|
+
"update",
|
|
5941
|
+
"remove",
|
|
5942
|
+
"findOneAndRemove",
|
|
5943
|
+
"findByIdAndRemove"
|
|
5944
|
+
];
|
|
5945
|
+
var MODEL_METHODS_ALT = MODEL_METHODS.join("|");
|
|
5946
|
+
function schemaCollectionVars(content) {
|
|
5947
|
+
const out = /* @__PURE__ */ new Map();
|
|
5948
|
+
const re = /(?:const|let|var)\s+(\w+)\s*=\s*new\s+(?:mongoose\s*\.\s*)?Schema\s*\(/g;
|
|
5949
|
+
let m;
|
|
5950
|
+
while ((m = re.exec(content)) !== null) {
|
|
5951
|
+
const windowText = content.slice(m.index, m.index + 2e3);
|
|
5952
|
+
const opt = /\bcollection\s*:\s*['"`]([\w.-]+)['"`]/.exec(windowText);
|
|
5953
|
+
if (opt) out.set(m[1], opt[1]);
|
|
5954
|
+
}
|
|
5955
|
+
return out;
|
|
5956
|
+
}
|
|
5957
|
+
function resolveModel(modelName, rest, schemaColl, pluralizeOn) {
|
|
5958
|
+
const trimmed = rest.trim();
|
|
5959
|
+
const literalThird = /,\s*['"`]([\w.-]+)['"`]\s*$/.exec(trimmed);
|
|
5960
|
+
if (literalThird) return { name: literalThird[1], kind: "mongodb-collection" };
|
|
5961
|
+
const firstIdent = /^([A-Za-z_$][\w$]*)/.exec(trimmed)?.[1];
|
|
5962
|
+
if (firstIdent && schemaColl.has(firstIdent)) {
|
|
5963
|
+
return { name: schemaColl.get(firstIdent), kind: "mongodb-collection" };
|
|
5964
|
+
}
|
|
5965
|
+
if (/,\s*[A-Za-z_$][\w$]*\s*$/.test(trimmed)) {
|
|
5966
|
+
return { name: modelName, kind: "mongodb-model" };
|
|
5967
|
+
}
|
|
5968
|
+
return { name: pluralizeOn ? pluralizeCollection(modelName) : modelName, kind: "mongodb-collection" };
|
|
5969
|
+
}
|
|
5970
|
+
function collectModelDefs(content, pluralizeOn) {
|
|
5971
|
+
const schemaColl = schemaCollectionVars(content);
|
|
5972
|
+
const out = [];
|
|
5973
|
+
const re = /(?:(?:const|let|var)\s+(\w+)\s*=\s*)?(?:await\s+)?(?:\b\w+\s*\.\s*)?\bmodel\s*\(\s*['"`]([\w$]+)['"`]\s*(?:,\s*([\s\S]{0,300}?))?\)/g;
|
|
5974
|
+
let m;
|
|
5975
|
+
while ((m = re.exec(content)) !== null) {
|
|
5976
|
+
out.push({
|
|
5977
|
+
modelName: m[2],
|
|
5978
|
+
varName: m[1] ?? null,
|
|
5979
|
+
resolved: resolveModel(m[2], m[3] ?? "", schemaColl, pluralizeOn),
|
|
5980
|
+
matchText: m[0]
|
|
5981
|
+
});
|
|
5982
|
+
}
|
|
5983
|
+
return out;
|
|
5984
|
+
}
|
|
5985
|
+
function endpoint(r, file, serviceDir, matchText) {
|
|
5986
|
+
const line = lineOf(file.content, matchText);
|
|
5987
|
+
return {
|
|
5988
|
+
infraId: infraId7(r.kind, r.name),
|
|
5989
|
+
name: r.name,
|
|
5990
|
+
kind: r.kind,
|
|
5991
|
+
edgeType: "CALLS",
|
|
5992
|
+
confidenceKind: "verified-call-site",
|
|
5993
|
+
evidence: { file: path31.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
5994
|
+
};
|
|
5995
|
+
}
|
|
5996
|
+
function mongooseEndpointsFromFile(file, serviceDir) {
|
|
5997
|
+
const hasMongoose = MONGOOSE_IMPORT_RE.test(file.content);
|
|
5998
|
+
const hasMongodb = MONGODB_IMPORT_RE.test(file.content);
|
|
5999
|
+
if (!hasMongoose && !hasMongodb) return [];
|
|
6000
|
+
const content = file.content;
|
|
6001
|
+
const out = [];
|
|
6002
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6003
|
+
const push = (r, matchText) => {
|
|
6004
|
+
const key = `${r.kind}/${r.name}`;
|
|
6005
|
+
if (seen.has(key)) return;
|
|
6006
|
+
seen.add(key);
|
|
6007
|
+
out.push(endpoint(r, file, serviceDir, matchText));
|
|
6008
|
+
};
|
|
6009
|
+
if (hasMongoose) {
|
|
6010
|
+
const pluralizeOn = !PLURALIZE_DISABLED_RE.test(content);
|
|
6011
|
+
for (const def of collectModelDefs(content, pluralizeOn)) push(def.resolved, def.matchText);
|
|
6012
|
+
}
|
|
6013
|
+
const collRe = /\.\s*collection\s*\(\s*['"`]([\w.$-]+)['"`]\s*\)/g;
|
|
6014
|
+
let c;
|
|
6015
|
+
while ((c = collRe.exec(content)) !== null) {
|
|
6016
|
+
push({ name: c[1], kind: "mongodb-collection" }, c[0]);
|
|
6017
|
+
}
|
|
6018
|
+
return out;
|
|
6019
|
+
}
|
|
6020
|
+
function parseDestructure(inner, specifier, out) {
|
|
6021
|
+
for (const raw of inner.split(",")) {
|
|
6022
|
+
const part = raw.trim();
|
|
6023
|
+
if (!part) continue;
|
|
6024
|
+
const asM = /^(\w+)\s+as\s+(\w+)$/.exec(part);
|
|
6025
|
+
const colonM = /^(\w+)\s*:\s*(\w+)$/.exec(part);
|
|
6026
|
+
if (asM) out.push({ local: asM[2], kind: "named", exportName: asM[1], specifier });
|
|
6027
|
+
else if (colonM) out.push({ local: colonM[2], kind: "named", exportName: colonM[1], specifier });
|
|
6028
|
+
else {
|
|
6029
|
+
const id = /^(\w+)$/.exec(part);
|
|
6030
|
+
if (id) out.push({ local: id[1], kind: "named", exportName: id[1], specifier });
|
|
6031
|
+
}
|
|
6032
|
+
}
|
|
6033
|
+
}
|
|
6034
|
+
function parseImportBindings(content) {
|
|
6035
|
+
const out = [];
|
|
6036
|
+
const esm = /import\s+([^;'"`\n]+?)\s+from\s*['"`]([^'"`]+)['"`]/g;
|
|
6037
|
+
let m;
|
|
6038
|
+
while ((m = esm.exec(content)) !== null) {
|
|
6039
|
+
const clause = m[1].trim();
|
|
6040
|
+
const spec = m[2];
|
|
6041
|
+
const ns = /^\*\s+as\s+(\w+)$/.exec(clause);
|
|
6042
|
+
if (ns) {
|
|
6043
|
+
out.push({ local: ns[1], kind: "namespace", specifier: spec });
|
|
6044
|
+
continue;
|
|
6045
|
+
}
|
|
6046
|
+
const named = /\{([^}]*)\}/.exec(clause);
|
|
6047
|
+
if (named) parseDestructure(named[1], spec, out);
|
|
6048
|
+
const def = /^(\w+)\s*(?:,|$)/.exec(clause);
|
|
6049
|
+
if (def && !clause.startsWith("{")) out.push({ local: def[1], kind: "default", specifier: spec });
|
|
6050
|
+
}
|
|
6051
|
+
const cjs = /(?:const|let|var)\s+(\{[^}]*\}|\w+)\s*=\s*require\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
6052
|
+
while ((m = cjs.exec(content)) !== null) {
|
|
6053
|
+
const lhs = m[1];
|
|
6054
|
+
const spec = m[2];
|
|
6055
|
+
if (lhs.startsWith("{")) parseDestructure(lhs.slice(1, -1), spec, out);
|
|
6056
|
+
else out.push({ local: lhs, kind: "whole", specifier: spec });
|
|
6057
|
+
}
|
|
6058
|
+
return out;
|
|
6059
|
+
}
|
|
6060
|
+
function fileExportsOf(content, pluralizeOn) {
|
|
6061
|
+
const defs = collectModelDefs(content, pluralizeOn).filter((d) => d.resolved.kind === "mongodb-collection");
|
|
6062
|
+
if (defs.length === 0) return null;
|
|
6063
|
+
const byVar = /* @__PURE__ */ new Map();
|
|
6064
|
+
for (const d of defs) if (d.varName) byVar.set(d.varName, d.resolved.name);
|
|
6065
|
+
const byName = new Map(byVar);
|
|
6066
|
+
let def;
|
|
6067
|
+
const named = /(?:module\.exports|export\s+default)\s*=\s*(\w+)\b/.exec(content);
|
|
6068
|
+
if (named && byVar.has(named[1])) def = byVar.get(named[1]);
|
|
6069
|
+
if (!def) {
|
|
6070
|
+
const inline = /(?:module\.exports|export\s+default)\s*=\s*(?:await\s+)?(?:\w+\s*\.\s*)?model\s*\(\s*['"`]([\w$]+)['"`]/.exec(content);
|
|
6071
|
+
if (inline) def = pluralizeOn ? pluralizeCollection(inline[1]) : inline[1];
|
|
6072
|
+
}
|
|
6073
|
+
if (!def && byVar.size === 1) def = [...byVar.values()][0];
|
|
6074
|
+
return { byName, ...def ? { default: def } : {} };
|
|
6075
|
+
}
|
|
6076
|
+
async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
6077
|
+
const mongooseFiles = files.filter((f) => MONGOOSE_IMPORT_RE.test(f.content));
|
|
6078
|
+
if (mongooseFiles.length === 0) return [];
|
|
6079
|
+
const pluralizeOn = !files.some((f) => PLURALIZE_DISABLED_RE.test(f.content));
|
|
6080
|
+
const registry = /* @__PURE__ */ new Map();
|
|
6081
|
+
for (const f of mongooseFiles) {
|
|
6082
|
+
const fx = fileExportsOf(f.content, pluralizeOn);
|
|
6083
|
+
if (fx) registry.set(toPosix2(path31.relative(serviceDir, f.path)), fx);
|
|
6084
|
+
}
|
|
6085
|
+
if (registry.size === 0) return [];
|
|
6086
|
+
const out = [];
|
|
6087
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6088
|
+
for (const f of files) {
|
|
6089
|
+
const bindings = parseImportBindings(f.content);
|
|
6090
|
+
if (bindings.length === 0) continue;
|
|
6091
|
+
const directColl = /* @__PURE__ */ new Map();
|
|
6092
|
+
const nsExports = /* @__PURE__ */ new Map();
|
|
6093
|
+
for (const b of bindings) {
|
|
6094
|
+
const resolvedRel = await resolveJsImport(b.specifier, path31.dirname(f.path), serviceDir, null);
|
|
6095
|
+
if (!resolvedRel) continue;
|
|
6096
|
+
const fx = registry.get(resolvedRel);
|
|
6097
|
+
if (!fx) continue;
|
|
6098
|
+
if (b.kind === "named" && b.exportName) {
|
|
6099
|
+
const coll = fx.byName.get(b.exportName);
|
|
6100
|
+
if (coll) directColl.set(b.local, coll);
|
|
6101
|
+
} else if (b.kind === "default") {
|
|
6102
|
+
if (fx.default) directColl.set(b.local, fx.default);
|
|
6103
|
+
} else {
|
|
6104
|
+
if (fx.default) directColl.set(b.local, fx.default);
|
|
6105
|
+
nsExports.set(b.local, fx);
|
|
6106
|
+
}
|
|
6107
|
+
}
|
|
6108
|
+
if (directColl.size === 0 && nsExports.size === 0) continue;
|
|
6109
|
+
const localDefs = new Set(
|
|
6110
|
+
collectModelDefs(f.content, pluralizeOn).map((d) => d.varName).filter((v) => v !== null)
|
|
6111
|
+
);
|
|
6112
|
+
const emit = (collection, matchText) => {
|
|
6113
|
+
const key = `${f.path}::${collection}`;
|
|
6114
|
+
if (seen.has(key)) return;
|
|
6115
|
+
seen.add(key);
|
|
6116
|
+
out.push(endpoint({ name: collection, kind: "mongodb-collection" }, f, serviceDir, matchText));
|
|
6117
|
+
};
|
|
6118
|
+
for (const [local, collection] of directColl) {
|
|
6119
|
+
if (localDefs.has(local)) continue;
|
|
6120
|
+
const qre = new RegExp(`\\b${local}\\s*\\.\\s*(?:${MODEL_METHODS_ALT})\\s*\\(`, "g");
|
|
6121
|
+
let qm;
|
|
6122
|
+
while ((qm = qre.exec(f.content)) !== null) emit(collection, qm[0]);
|
|
6123
|
+
}
|
|
6124
|
+
for (const [local, fx] of nsExports) {
|
|
6125
|
+
const qre = new RegExp(`\\b${local}\\s*\\.\\s*(\\w+)\\s*\\.\\s*(?:${MODEL_METHODS_ALT})\\s*\\(`, "g");
|
|
6126
|
+
let qm;
|
|
6127
|
+
while ((qm = qre.exec(f.content)) !== null) {
|
|
6128
|
+
const coll = fx.byName.get(qm[1]);
|
|
6129
|
+
if (coll) emit(coll, qm[0]);
|
|
6130
|
+
}
|
|
6131
|
+
}
|
|
6132
|
+
}
|
|
6133
|
+
return out;
|
|
6134
|
+
}
|
|
6135
|
+
|
|
5822
6136
|
// src/extract/calls/index.ts
|
|
5823
6137
|
function edgeTypeFromEndpoint(ep) {
|
|
5824
6138
|
switch (ep.edgeType) {
|
|
@@ -5839,16 +6153,20 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
5839
6153
|
for (const service of services) {
|
|
5840
6154
|
const files = await loadSourceFiles(service.dir);
|
|
5841
6155
|
const endpoints = [];
|
|
6156
|
+
const maskedFiles = [];
|
|
5842
6157
|
for (const file of files) {
|
|
5843
6158
|
if (isTestPath(file.path)) continue;
|
|
5844
6159
|
const masked = maskCommentsInSource(file.content);
|
|
5845
6160
|
const maskedFile = { path: file.path, content: masked };
|
|
6161
|
+
maskedFiles.push(maskedFile);
|
|
5846
6162
|
endpoints.push(...kafkaEndpointsFromFile(maskedFile, service.dir));
|
|
5847
6163
|
endpoints.push(...redisEndpointsFromFile(maskedFile, service.dir));
|
|
5848
6164
|
endpoints.push(...awsEndpointsFromFile(maskedFile, service.dir));
|
|
5849
6165
|
endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir));
|
|
5850
6166
|
endpoints.push(...supabaseEndpointsFromFile(maskedFile, service.dir));
|
|
6167
|
+
endpoints.push(...mongooseEndpointsFromFile(maskedFile, service.dir));
|
|
5851
6168
|
}
|
|
6169
|
+
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
5852
6170
|
if (endpoints.length === 0) continue;
|
|
5853
6171
|
const seenEdges = /* @__PURE__ */ new Set();
|
|
5854
6172
|
for (const ep of endpoints) {
|
|
@@ -5919,14 +6237,14 @@ async function addCallEdges(graph, services) {
|
|
|
5919
6237
|
}
|
|
5920
6238
|
|
|
5921
6239
|
// src/extract/infra/docker-compose.ts
|
|
5922
|
-
import
|
|
6240
|
+
import path32 from "path";
|
|
5923
6241
|
import { EdgeType as EdgeType13, Provenance as Provenance13, confidenceForExtracted as confidenceForExtracted11 } from "@neat.is/types";
|
|
5924
6242
|
|
|
5925
6243
|
// src/extract/infra/shared.ts
|
|
5926
|
-
import { NodeType as NodeType13, Provenance as Provenance12, confidenceForExtracted as confidenceForExtracted10, infraId as
|
|
6244
|
+
import { NodeType as NodeType13, Provenance as Provenance12, confidenceForExtracted as confidenceForExtracted10, infraId as infraId8 } from "@neat.is/types";
|
|
5927
6245
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
5928
6246
|
return {
|
|
5929
|
-
id:
|
|
6247
|
+
id: infraId8(kind, name),
|
|
5930
6248
|
type: NodeType13.InfraNode,
|
|
5931
6249
|
name,
|
|
5932
6250
|
provider,
|
|
@@ -5989,7 +6307,7 @@ function dependsOnList(value) {
|
|
|
5989
6307
|
}
|
|
5990
6308
|
function serviceNameToServiceNode(name, services) {
|
|
5991
6309
|
for (const s of services) {
|
|
5992
|
-
if (s.node.name === name ||
|
|
6310
|
+
if (s.node.name === name || path32.basename(s.dir) === name) return s.node.id;
|
|
5993
6311
|
}
|
|
5994
6312
|
return null;
|
|
5995
6313
|
}
|
|
@@ -5998,7 +6316,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
5998
6316
|
let edgesAdded = 0;
|
|
5999
6317
|
let composePath = null;
|
|
6000
6318
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
6001
|
-
const abs =
|
|
6319
|
+
const abs = path32.join(scanPath, name);
|
|
6002
6320
|
if (await exists(abs)) {
|
|
6003
6321
|
composePath = abs;
|
|
6004
6322
|
break;
|
|
@@ -6011,13 +6329,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
6011
6329
|
} catch (err) {
|
|
6012
6330
|
recordExtractionError(
|
|
6013
6331
|
"infra docker-compose",
|
|
6014
|
-
|
|
6332
|
+
path32.relative(scanPath, composePath),
|
|
6015
6333
|
err
|
|
6016
6334
|
);
|
|
6017
6335
|
return { nodesAdded, edgesAdded };
|
|
6018
6336
|
}
|
|
6019
6337
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
6020
|
-
const evidenceFile =
|
|
6338
|
+
const evidenceFile = path32.relative(scanPath, composePath).split(path32.sep).join("/");
|
|
6021
6339
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
6022
6340
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
6023
6341
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -6058,7 +6376,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
6058
6376
|
}
|
|
6059
6377
|
|
|
6060
6378
|
// src/extract/infra/dockerfile.ts
|
|
6061
|
-
import
|
|
6379
|
+
import path33 from "path";
|
|
6062
6380
|
import { promises as fs16 } from "fs";
|
|
6063
6381
|
import { EdgeType as EdgeType14, Provenance as Provenance14, confidenceForExtracted as confidenceForExtracted12 } from "@neat.is/types";
|
|
6064
6382
|
function readDockerfile(content) {
|
|
@@ -6089,7 +6407,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6089
6407
|
let nodesAdded = 0;
|
|
6090
6408
|
let edgesAdded = 0;
|
|
6091
6409
|
for (const service of services) {
|
|
6092
|
-
const dockerfilePath =
|
|
6410
|
+
const dockerfilePath = path33.join(service.dir, "Dockerfile");
|
|
6093
6411
|
if (!await exists(dockerfilePath)) continue;
|
|
6094
6412
|
let content;
|
|
6095
6413
|
try {
|
|
@@ -6097,7 +6415,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6097
6415
|
} catch (err) {
|
|
6098
6416
|
recordExtractionError(
|
|
6099
6417
|
"infra dockerfile",
|
|
6100
|
-
|
|
6418
|
+
path33.relative(scanPath, dockerfilePath),
|
|
6101
6419
|
err
|
|
6102
6420
|
);
|
|
6103
6421
|
continue;
|
|
@@ -6109,8 +6427,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6109
6427
|
graph.addNode(node.id, node);
|
|
6110
6428
|
nodesAdded++;
|
|
6111
6429
|
}
|
|
6112
|
-
const relDockerfile = toPosix2(
|
|
6113
|
-
const evidenceFile = toPosix2(
|
|
6430
|
+
const relDockerfile = toPosix2(path33.relative(service.dir, dockerfilePath));
|
|
6431
|
+
const evidenceFile = toPosix2(path33.relative(scanPath, dockerfilePath));
|
|
6114
6432
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
6115
6433
|
graph,
|
|
6116
6434
|
service.pkg.name,
|
|
@@ -6162,7 +6480,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6162
6480
|
|
|
6163
6481
|
// src/extract/infra/terraform.ts
|
|
6164
6482
|
import { promises as fs17 } from "fs";
|
|
6165
|
-
import
|
|
6483
|
+
import path34 from "path";
|
|
6166
6484
|
import { EdgeType as EdgeType15, Provenance as Provenance15, confidenceForExtracted as confidenceForExtracted13 } from "@neat.is/types";
|
|
6167
6485
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
6168
6486
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
@@ -6173,11 +6491,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
6173
6491
|
for (const entry of entries) {
|
|
6174
6492
|
if (entry.isDirectory()) {
|
|
6175
6493
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
6176
|
-
const child =
|
|
6494
|
+
const child = path34.join(start, entry.name);
|
|
6177
6495
|
if (await isPythonVenvDir(child)) continue;
|
|
6178
6496
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
6179
6497
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
6180
|
-
out.push(
|
|
6498
|
+
out.push(path34.join(start, entry.name));
|
|
6181
6499
|
}
|
|
6182
6500
|
}
|
|
6183
6501
|
return out;
|
|
@@ -6209,7 +6527,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
6209
6527
|
const files = await walkTfFiles(scanPath);
|
|
6210
6528
|
for (const file of files) {
|
|
6211
6529
|
const content = await fs17.readFile(file, "utf8");
|
|
6212
|
-
const evidenceFile = toPosix2(
|
|
6530
|
+
const evidenceFile = toPosix2(path34.relative(scanPath, file));
|
|
6213
6531
|
const resources = [];
|
|
6214
6532
|
const byKey = /* @__PURE__ */ new Map();
|
|
6215
6533
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -6266,7 +6584,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
6266
6584
|
|
|
6267
6585
|
// src/extract/infra/k8s.ts
|
|
6268
6586
|
import { promises as fs18 } from "fs";
|
|
6269
|
-
import
|
|
6587
|
+
import path35 from "path";
|
|
6270
6588
|
import { parseAllDocuments as parseAllDocuments2 } from "yaml";
|
|
6271
6589
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
6272
6590
|
Service: "k8s-service",
|
|
@@ -6284,11 +6602,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
6284
6602
|
for (const entry of entries) {
|
|
6285
6603
|
if (entry.isDirectory()) {
|
|
6286
6604
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
6287
|
-
const child =
|
|
6605
|
+
const child = path35.join(start, entry.name);
|
|
6288
6606
|
if (await isPythonVenvDir(child)) continue;
|
|
6289
6607
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
6290
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
6291
|
-
out.push(
|
|
6608
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path35.extname(entry.name))) {
|
|
6609
|
+
out.push(path35.join(start, entry.name));
|
|
6292
6610
|
}
|
|
6293
6611
|
}
|
|
6294
6612
|
return out;
|
|
@@ -6321,13 +6639,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
6321
6639
|
|
|
6322
6640
|
// src/extract/infra/cloudflare.ts
|
|
6323
6641
|
import { promises as fs19 } from "fs";
|
|
6324
|
-
import
|
|
6642
|
+
import path36 from "path";
|
|
6325
6643
|
import { parse as parseToml2 } from "smol-toml";
|
|
6326
6644
|
import { EdgeType as EdgeType16, Provenance as Provenance16, confidenceForExtracted as confidenceForExtracted14 } from "@neat.is/types";
|
|
6327
6645
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
6328
6646
|
async function readWranglerConfig(dir) {
|
|
6329
6647
|
for (const filename of WRANGLER_FILENAMES) {
|
|
6330
|
-
const abs =
|
|
6648
|
+
const abs = path36.join(dir, filename);
|
|
6331
6649
|
if (!await exists(abs)) continue;
|
|
6332
6650
|
const raw = await fs19.readFile(abs, "utf8");
|
|
6333
6651
|
const config = filename === "wrangler.toml" ? parseToml2(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -6390,11 +6708,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
6390
6708
|
try {
|
|
6391
6709
|
read = await readWranglerConfig(service.dir);
|
|
6392
6710
|
} catch (err) {
|
|
6393
|
-
recordExtractionError("infra cloudflare",
|
|
6711
|
+
recordExtractionError("infra cloudflare", path36.relative(scanPath, service.dir), err);
|
|
6394
6712
|
continue;
|
|
6395
6713
|
}
|
|
6396
6714
|
if (!read || !read.config.name) continue;
|
|
6397
|
-
const evidenceFile = toPosix2(
|
|
6715
|
+
const evidenceFile = toPosix2(path36.relative(scanPath, path36.join(service.dir, read.relFile)));
|
|
6398
6716
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
6399
6717
|
}
|
|
6400
6718
|
for (const worker of discovered) {
|
|
@@ -6406,7 +6724,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
6406
6724
|
}
|
|
6407
6725
|
let anchorId = service.node.id;
|
|
6408
6726
|
if (config.main) {
|
|
6409
|
-
const entryRelPath = toPosix2(
|
|
6727
|
+
const entryRelPath = toPosix2(path36.normalize(config.main));
|
|
6410
6728
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
6411
6729
|
graph,
|
|
6412
6730
|
service.pkg.name,
|
|
@@ -6553,12 +6871,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
6553
6871
|
|
|
6554
6872
|
// src/extract/infra/vercel.ts
|
|
6555
6873
|
import { promises as fs20 } from "fs";
|
|
6556
|
-
import
|
|
6874
|
+
import path37 from "path";
|
|
6557
6875
|
import { EdgeType as EdgeType17 } from "@neat.is/types";
|
|
6558
6876
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
6559
6877
|
async function readVercelConfig(dir) {
|
|
6560
6878
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
6561
|
-
const abs =
|
|
6879
|
+
const abs = path37.join(dir, filename);
|
|
6562
6880
|
if (!await exists(abs)) continue;
|
|
6563
6881
|
const raw = await fs20.readFile(abs, "utf8");
|
|
6564
6882
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -6567,7 +6885,7 @@ async function readVercelConfig(dir) {
|
|
|
6567
6885
|
return null;
|
|
6568
6886
|
}
|
|
6569
6887
|
async function readLinkedProjectName(dir) {
|
|
6570
|
-
const abs =
|
|
6888
|
+
const abs = path37.join(dir, ".vercel", "project.json");
|
|
6571
6889
|
if (!await exists(abs)) return void 0;
|
|
6572
6890
|
const parsed = JSON.parse(await fs20.readFile(abs, "utf8"));
|
|
6573
6891
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -6585,7 +6903,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
6585
6903
|
read = await readVercelConfig(service.dir);
|
|
6586
6904
|
projectName = await readLinkedProjectName(service.dir);
|
|
6587
6905
|
} catch (err) {
|
|
6588
|
-
recordExtractionError("infra vercel",
|
|
6906
|
+
recordExtractionError("infra vercel", path37.relative(scanPath, service.dir), err);
|
|
6589
6907
|
continue;
|
|
6590
6908
|
}
|
|
6591
6909
|
if (!read && !projectName) continue;
|
|
@@ -6601,7 +6919,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
6601
6919
|
const anchorId = service.node.id;
|
|
6602
6920
|
if (!read) continue;
|
|
6603
6921
|
const { config, relFile, raw } = read;
|
|
6604
|
-
const evidenceFile = toPosix2(
|
|
6922
|
+
const evidenceFile = toPosix2(path37.relative(scanPath, path37.join(service.dir, relFile)));
|
|
6605
6923
|
const add = (edgeType, kind, name) => {
|
|
6606
6924
|
if (!name) return;
|
|
6607
6925
|
const result = emitPlatformResourceEdge(
|
|
@@ -6630,13 +6948,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
6630
6948
|
|
|
6631
6949
|
// src/extract/infra/railway.ts
|
|
6632
6950
|
import { promises as fs21 } from "fs";
|
|
6633
|
-
import
|
|
6951
|
+
import path38 from "path";
|
|
6634
6952
|
import { parse as parseToml3 } from "smol-toml";
|
|
6635
6953
|
import { EdgeType as EdgeType18 } from "@neat.is/types";
|
|
6636
6954
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
6637
6955
|
async function readRailwayConfig(dir) {
|
|
6638
6956
|
for (const filename of RAILWAY_FILENAMES) {
|
|
6639
|
-
const abs =
|
|
6957
|
+
const abs = path38.join(dir, filename);
|
|
6640
6958
|
if (!await exists(abs)) continue;
|
|
6641
6959
|
const raw = await fs21.readFile(abs, "utf8");
|
|
6642
6960
|
const config = filename === "railway.toml" ? parseToml3(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -6652,7 +6970,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
6652
6970
|
try {
|
|
6653
6971
|
read = await readRailwayConfig(service.dir);
|
|
6654
6972
|
} catch (err) {
|
|
6655
|
-
recordExtractionError("infra railway",
|
|
6973
|
+
recordExtractionError("infra railway", path38.relative(scanPath, service.dir), err);
|
|
6656
6974
|
continue;
|
|
6657
6975
|
}
|
|
6658
6976
|
if (!read) continue;
|
|
@@ -6662,7 +6980,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
6662
6980
|
}
|
|
6663
6981
|
const anchorId = service.node.id;
|
|
6664
6982
|
const { config, relFile, raw } = read;
|
|
6665
|
-
const evidenceFile = toPosix2(
|
|
6983
|
+
const evidenceFile = toPosix2(path38.relative(scanPath, path38.join(service.dir, relFile)));
|
|
6666
6984
|
const add = (edgeType, kind, name) => {
|
|
6667
6985
|
if (!name) return;
|
|
6668
6986
|
const result = emitPlatformResourceEdge(
|
|
@@ -6687,12 +7005,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
6687
7005
|
|
|
6688
7006
|
// src/extract/infra/supabase.ts
|
|
6689
7007
|
import { promises as fs22 } from "fs";
|
|
6690
|
-
import
|
|
7008
|
+
import path39 from "path";
|
|
6691
7009
|
import { parse as parseToml4 } from "smol-toml";
|
|
6692
7010
|
import { EdgeType as EdgeType19 } from "@neat.is/types";
|
|
6693
7011
|
async function readSupabaseConfig(dir) {
|
|
6694
|
-
const relFile =
|
|
6695
|
-
const abs =
|
|
7012
|
+
const relFile = path39.join("supabase", "config.toml");
|
|
7013
|
+
const abs = path39.join(dir, relFile);
|
|
6696
7014
|
if (!await exists(abs)) return null;
|
|
6697
7015
|
const raw = await fs22.readFile(abs, "utf8");
|
|
6698
7016
|
const config = parseToml4(raw);
|
|
@@ -6706,7 +7024,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
6706
7024
|
try {
|
|
6707
7025
|
read = await readSupabaseConfig(service.dir);
|
|
6708
7026
|
} catch (err) {
|
|
6709
|
-
recordExtractionError("infra supabase",
|
|
7027
|
+
recordExtractionError("infra supabase", path39.relative(scanPath, service.dir), err);
|
|
6710
7028
|
continue;
|
|
6711
7029
|
}
|
|
6712
7030
|
if (!read) continue;
|
|
@@ -6721,7 +7039,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
6721
7039
|
});
|
|
6722
7040
|
}
|
|
6723
7041
|
const anchorId = service.node.id;
|
|
6724
|
-
const evidenceFile = toPosix2(
|
|
7042
|
+
const evidenceFile = toPosix2(path39.relative(scanPath, path39.join(service.dir, relFile)));
|
|
6725
7043
|
const add = (edgeType, kind, name) => {
|
|
6726
7044
|
if (!name) return;
|
|
6727
7045
|
const result = emitPlatformResourceEdge(
|
|
@@ -6762,11 +7080,11 @@ async function addInfra(graph, scanPath, services) {
|
|
|
6762
7080
|
}
|
|
6763
7081
|
|
|
6764
7082
|
// src/extract/index.ts
|
|
6765
|
-
import
|
|
7083
|
+
import path41 from "path";
|
|
6766
7084
|
|
|
6767
7085
|
// src/extract/retire.ts
|
|
6768
7086
|
import { existsSync as existsSync2 } from "fs";
|
|
6769
|
-
import
|
|
7087
|
+
import path40 from "path";
|
|
6770
7088
|
import { NodeType as NodeType14, Provenance as Provenance17 } from "@neat.is/types";
|
|
6771
7089
|
function dropOrphanedFileNodes(graph) {
|
|
6772
7090
|
const orphans = [];
|
|
@@ -6800,11 +7118,11 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
6800
7118
|
if (edge.provenance !== Provenance17.EXTRACTED) return;
|
|
6801
7119
|
const evidenceFile = edge.evidence?.file;
|
|
6802
7120
|
if (!evidenceFile) return;
|
|
6803
|
-
if (
|
|
7121
|
+
if (path40.isAbsolute(evidenceFile)) {
|
|
6804
7122
|
if (!existsSync2(evidenceFile)) toDrop.push(id);
|
|
6805
7123
|
return;
|
|
6806
7124
|
}
|
|
6807
|
-
const found = bases.some((base) => existsSync2(
|
|
7125
|
+
const found = bases.some((base) => existsSync2(path40.join(base, evidenceFile)));
|
|
6808
7126
|
if (!found) toDrop.push(id);
|
|
6809
7127
|
});
|
|
6810
7128
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -6846,7 +7164,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
6846
7164
|
}
|
|
6847
7165
|
const droppedEntries = drainDroppedExtracted();
|
|
6848
7166
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
6849
|
-
const rejectedPath =
|
|
7167
|
+
const rejectedPath = path41.join(path41.dirname(opts.errorsPath), "rejected.ndjson");
|
|
6850
7168
|
try {
|
|
6851
7169
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
6852
7170
|
} catch (err) {
|
|
@@ -7164,7 +7482,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
7164
7482
|
|
|
7165
7483
|
// src/persist.ts
|
|
7166
7484
|
import { promises as fs23 } from "fs";
|
|
7167
|
-
import
|
|
7485
|
+
import path42 from "path";
|
|
7168
7486
|
import { Provenance as Provenance19, observedEdgeId as observedEdgeId2 } from "@neat.is/types";
|
|
7169
7487
|
var SCHEMA_VERSION = 4;
|
|
7170
7488
|
function migrateV1ToV2(payload) {
|
|
@@ -7201,7 +7519,7 @@ function migrateV2ToV3(payload) {
|
|
|
7201
7519
|
return { ...payload, schemaVersion: 3 };
|
|
7202
7520
|
}
|
|
7203
7521
|
async function ensureDir(filePath) {
|
|
7204
|
-
await fs23.mkdir(
|
|
7522
|
+
await fs23.mkdir(path42.dirname(filePath), { recursive: true });
|
|
7205
7523
|
}
|
|
7206
7524
|
async function saveGraphToDisk(graph, outPath) {
|
|
7207
7525
|
await ensureDir(outPath);
|
|
@@ -7357,23 +7675,23 @@ function canonicalJson(value) {
|
|
|
7357
7675
|
}
|
|
7358
7676
|
|
|
7359
7677
|
// src/projects.ts
|
|
7360
|
-
import
|
|
7678
|
+
import path43 from "path";
|
|
7361
7679
|
function pathsForProject(project, baseDir) {
|
|
7362
7680
|
if (project === DEFAULT_PROJECT) {
|
|
7363
7681
|
return {
|
|
7364
|
-
snapshotPath:
|
|
7365
|
-
errorsPath:
|
|
7366
|
-
staleEventsPath:
|
|
7367
|
-
embeddingsCachePath:
|
|
7368
|
-
policyViolationsPath:
|
|
7682
|
+
snapshotPath: path43.join(baseDir, "graph.json"),
|
|
7683
|
+
errorsPath: path43.join(baseDir, "errors.ndjson"),
|
|
7684
|
+
staleEventsPath: path43.join(baseDir, "stale-events.ndjson"),
|
|
7685
|
+
embeddingsCachePath: path43.join(baseDir, "embeddings.json"),
|
|
7686
|
+
policyViolationsPath: path43.join(baseDir, "policy-violations.ndjson")
|
|
7369
7687
|
};
|
|
7370
7688
|
}
|
|
7371
7689
|
return {
|
|
7372
|
-
snapshotPath:
|
|
7373
|
-
errorsPath:
|
|
7374
|
-
staleEventsPath:
|
|
7375
|
-
embeddingsCachePath:
|
|
7376
|
-
policyViolationsPath:
|
|
7690
|
+
snapshotPath: path43.join(baseDir, `${project}.json`),
|
|
7691
|
+
errorsPath: path43.join(baseDir, `errors.${project}.ndjson`),
|
|
7692
|
+
staleEventsPath: path43.join(baseDir, `stale-events.${project}.ndjson`),
|
|
7693
|
+
embeddingsCachePath: path43.join(baseDir, `embeddings.${project}.json`),
|
|
7694
|
+
policyViolationsPath: path43.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
7377
7695
|
};
|
|
7378
7696
|
}
|
|
7379
7697
|
var Projects = class {
|
|
@@ -7414,7 +7732,7 @@ function parseExtraProjects(raw) {
|
|
|
7414
7732
|
// src/registry.ts
|
|
7415
7733
|
import { promises as fs25 } from "fs";
|
|
7416
7734
|
import os2 from "os";
|
|
7417
|
-
import
|
|
7735
|
+
import path44 from "path";
|
|
7418
7736
|
import {
|
|
7419
7737
|
RegistryFileSchema
|
|
7420
7738
|
} from "@neat.is/types";
|
|
@@ -7422,20 +7740,20 @@ var LOCK_TIMEOUT_MS = 5e3;
|
|
|
7422
7740
|
var LOCK_RETRY_MS = 50;
|
|
7423
7741
|
function neatHome() {
|
|
7424
7742
|
const override = process.env.NEAT_HOME;
|
|
7425
|
-
if (override && override.length > 0) return
|
|
7426
|
-
return
|
|
7743
|
+
if (override && override.length > 0) return path44.resolve(override);
|
|
7744
|
+
return path44.join(os2.homedir(), ".neat");
|
|
7427
7745
|
}
|
|
7428
7746
|
function registryPath() {
|
|
7429
|
-
return
|
|
7747
|
+
return path44.join(neatHome(), "projects.json");
|
|
7430
7748
|
}
|
|
7431
7749
|
function registryLockPath() {
|
|
7432
|
-
return
|
|
7750
|
+
return path44.join(neatHome(), "projects.json.lock");
|
|
7433
7751
|
}
|
|
7434
7752
|
function daemonPidPath() {
|
|
7435
|
-
return
|
|
7753
|
+
return path44.join(neatHome(), "neatd.pid");
|
|
7436
7754
|
}
|
|
7437
7755
|
function daemonsDir() {
|
|
7438
|
-
return
|
|
7756
|
+
return path44.join(neatHome(), "daemons");
|
|
7439
7757
|
}
|
|
7440
7758
|
function isFiniteInt(v) {
|
|
7441
7759
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -7476,7 +7794,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
7476
7794
|
const out = [];
|
|
7477
7795
|
for (const name of names) {
|
|
7478
7796
|
if (!name.endsWith(".json")) continue;
|
|
7479
|
-
const file =
|
|
7797
|
+
const file = path44.join(dir, name);
|
|
7480
7798
|
let raw;
|
|
7481
7799
|
try {
|
|
7482
7800
|
raw = await fs25.readFile(file, "utf8");
|
|
@@ -7597,7 +7915,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
7597
7915
|
}
|
|
7598
7916
|
}
|
|
7599
7917
|
async function normalizeProjectPath(input) {
|
|
7600
|
-
const resolved =
|
|
7918
|
+
const resolved = path44.resolve(input);
|
|
7601
7919
|
try {
|
|
7602
7920
|
return await fs25.realpath(resolved);
|
|
7603
7921
|
} catch {
|
|
@@ -7605,7 +7923,7 @@ async function normalizeProjectPath(input) {
|
|
|
7605
7923
|
}
|
|
7606
7924
|
}
|
|
7607
7925
|
async function writeAtomically(target, contents) {
|
|
7608
|
-
await fs25.mkdir(
|
|
7926
|
+
await fs25.mkdir(path44.dirname(target), { recursive: true });
|
|
7609
7927
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
7610
7928
|
const fd = await fs25.open(tmp, "w");
|
|
7611
7929
|
try {
|
|
@@ -7618,7 +7936,7 @@ async function writeAtomically(target, contents) {
|
|
|
7618
7936
|
}
|
|
7619
7937
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
7620
7938
|
const deadline = Date.now() + timeoutMs;
|
|
7621
|
-
await fs25.mkdir(
|
|
7939
|
+
await fs25.mkdir(path44.dirname(lockPath), { recursive: true });
|
|
7622
7940
|
let probedHolder = false;
|
|
7623
7941
|
while (true) {
|
|
7624
7942
|
try {
|
|
@@ -7814,13 +8132,13 @@ import { DivergenceTypeSchema, PoliciesCheckBodySchema, PolicySeveritySchema } f
|
|
|
7814
8132
|
|
|
7815
8133
|
// src/extend/index.ts
|
|
7816
8134
|
import { promises as fs27 } from "fs";
|
|
7817
|
-
import
|
|
8135
|
+
import path46 from "path";
|
|
7818
8136
|
import os3 from "os";
|
|
7819
8137
|
import { resolve as registryResolve, list as registryList } from "@neat.is/instrumentation-registry";
|
|
7820
8138
|
|
|
7821
8139
|
// src/installers/package-manager.ts
|
|
7822
8140
|
import { promises as fs26 } from "fs";
|
|
7823
|
-
import
|
|
8141
|
+
import path45 from "path";
|
|
7824
8142
|
import { spawn } from "child_process";
|
|
7825
8143
|
var LOCKFILE_PRIORITY = [
|
|
7826
8144
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -7842,22 +8160,22 @@ async function exists2(p) {
|
|
|
7842
8160
|
}
|
|
7843
8161
|
}
|
|
7844
8162
|
async function detectPackageManager(serviceDir) {
|
|
7845
|
-
let dir =
|
|
8163
|
+
let dir = path45.resolve(serviceDir);
|
|
7846
8164
|
const stops = /* @__PURE__ */ new Set();
|
|
7847
8165
|
for (let i = 0; i < 64; i++) {
|
|
7848
8166
|
if (stops.has(dir)) break;
|
|
7849
8167
|
stops.add(dir);
|
|
7850
8168
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
7851
|
-
const lockPath =
|
|
8169
|
+
const lockPath = path45.join(dir, candidate.lockfile);
|
|
7852
8170
|
if (await exists2(lockPath)) {
|
|
7853
8171
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
7854
8172
|
}
|
|
7855
8173
|
}
|
|
7856
|
-
const parent =
|
|
8174
|
+
const parent = path45.dirname(dir);
|
|
7857
8175
|
if (parent === dir) break;
|
|
7858
8176
|
dir = parent;
|
|
7859
8177
|
}
|
|
7860
|
-
return { pm: "npm", cwd:
|
|
8178
|
+
return { pm: "npm", cwd: path45.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
7861
8179
|
}
|
|
7862
8180
|
async function runPackageManagerInstall(cmd) {
|
|
7863
8181
|
return new Promise((resolve) => {
|
|
@@ -7906,22 +8224,53 @@ async function fileExists2(p) {
|
|
|
7906
8224
|
}
|
|
7907
8225
|
}
|
|
7908
8226
|
async function readPackageJson(scanPath) {
|
|
7909
|
-
const pkgPath =
|
|
8227
|
+
const pkgPath = path46.join(scanPath, "package.json");
|
|
7910
8228
|
const raw = await fs27.readFile(pkgPath, "utf8");
|
|
7911
8229
|
return JSON.parse(raw);
|
|
7912
8230
|
}
|
|
8231
|
+
var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
8232
|
+
"node_modules",
|
|
8233
|
+
"dist",
|
|
8234
|
+
"build",
|
|
8235
|
+
"out",
|
|
8236
|
+
"coverage",
|
|
8237
|
+
"neat-out"
|
|
8238
|
+
]);
|
|
7913
8239
|
async function findHookFiles(scanPath) {
|
|
7914
|
-
const
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
8240
|
+
const found = [];
|
|
8241
|
+
const walk3 = async (dir) => {
|
|
8242
|
+
const entries = await fs27.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
8243
|
+
for (const entry of entries) {
|
|
8244
|
+
if (entry.isDirectory()) {
|
|
8245
|
+
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
8246
|
+
await walk3(path46.join(dir, entry.name));
|
|
8247
|
+
} else if (entry.isFile()) {
|
|
8248
|
+
if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
|
|
8249
|
+
const rel = path46.relative(scanPath, path46.join(dir, entry.name));
|
|
8250
|
+
found.push(rel.split(path46.sep).join("/"));
|
|
8251
|
+
}
|
|
8252
|
+
}
|
|
8253
|
+
}
|
|
8254
|
+
};
|
|
8255
|
+
await walk3(scanPath);
|
|
8256
|
+
return found.sort();
|
|
8257
|
+
}
|
|
8258
|
+
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
8259
|
+
let fallback = null;
|
|
8260
|
+
for (const file of hookFiles) {
|
|
8261
|
+
const content = await fs27.readFile(path46.join(scanPath, file), "utf8");
|
|
8262
|
+
const patched = splicedContent(content, snippet2);
|
|
8263
|
+
if (patched !== null) return { file, content, patched };
|
|
8264
|
+
if (fallback === null) fallback = { file, content };
|
|
8265
|
+
}
|
|
8266
|
+
return { file: fallback.file, content: fallback.content, patched: null };
|
|
7918
8267
|
}
|
|
7919
8268
|
function extendLogPath() {
|
|
7920
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
8269
|
+
return process.env.NEAT_EXTEND_LOG ?? path46.join(os3.homedir(), ".neat", "extend-log.ndjson");
|
|
7921
8270
|
}
|
|
7922
8271
|
async function appendExtendLog(entry) {
|
|
7923
8272
|
const logPath = extendLogPath();
|
|
7924
|
-
await fs27.mkdir(
|
|
8273
|
+
await fs27.mkdir(path46.dirname(logPath), { recursive: true });
|
|
7925
8274
|
await fs27.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
7926
8275
|
}
|
|
7927
8276
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -7980,7 +8329,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
7980
8329
|
}
|
|
7981
8330
|
async function describeProjectInstrumentation(ctx) {
|
|
7982
8331
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
7983
|
-
const envNeat = await fileExists2(
|
|
8332
|
+
const envNeat = await fileExists2(path46.join(ctx.scanPath, ".env.neat"));
|
|
7984
8333
|
const registryInstrPackages = new Set(
|
|
7985
8334
|
registryList().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
7986
8335
|
);
|
|
@@ -8002,16 +8351,22 @@ async function applyExtension(ctx, args, options) {
|
|
|
8002
8351
|
);
|
|
8003
8352
|
}
|
|
8004
8353
|
for (const file of hookFiles) {
|
|
8005
|
-
const content = await fs27.readFile(
|
|
8354
|
+
const content = await fs27.readFile(path46.join(ctx.scanPath, file), "utf8");
|
|
8006
8355
|
if (content.includes(args.registration_snippet)) {
|
|
8007
8356
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
8008
8357
|
}
|
|
8009
8358
|
}
|
|
8010
|
-
const
|
|
8011
|
-
|
|
8359
|
+
const primary = await pickPrimaryHookFile(ctx.scanPath, hookFiles, args.registration_snippet);
|
|
8360
|
+
if (primary.patched === null) {
|
|
8361
|
+
throw new Error(
|
|
8362
|
+
`Could not find instrumentation insertion point in ${hookFiles.join(", ")}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
8363
|
+
);
|
|
8364
|
+
}
|
|
8365
|
+
const primaryFile = primary.file;
|
|
8366
|
+
const primaryPath = path46.join(ctx.scanPath, primaryFile);
|
|
8012
8367
|
const filesTouched = [];
|
|
8013
8368
|
const depsAdded = [];
|
|
8014
|
-
const pkgPath =
|
|
8369
|
+
const pkgPath = path46.join(ctx.scanPath, "package.json");
|
|
8015
8370
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
8016
8371
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
8017
8372
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -8019,14 +8374,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
8019
8374
|
filesTouched.push("package.json");
|
|
8020
8375
|
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
8021
8376
|
}
|
|
8022
|
-
|
|
8023
|
-
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
8024
|
-
if (!patched) {
|
|
8025
|
-
throw new Error(
|
|
8026
|
-
`Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
8027
|
-
);
|
|
8028
|
-
}
|
|
8029
|
-
await fs27.writeFile(primaryPath, patched, "utf8");
|
|
8377
|
+
await fs27.writeFile(primaryPath, primary.patched, "utf8");
|
|
8030
8378
|
filesTouched.push(primaryFile);
|
|
8031
8379
|
const cmd = await detectPackageManager(ctx.scanPath);
|
|
8032
8380
|
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
@@ -8057,7 +8405,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
8057
8405
|
};
|
|
8058
8406
|
}
|
|
8059
8407
|
for (const file of hookFiles) {
|
|
8060
|
-
const content = await fs27.readFile(
|
|
8408
|
+
const content = await fs27.readFile(path46.join(ctx.scanPath, file), "utf8");
|
|
8061
8409
|
if (content.includes(args.registration_snippet)) {
|
|
8062
8410
|
return {
|
|
8063
8411
|
library: args.library,
|
|
@@ -8068,7 +8416,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
8068
8416
|
};
|
|
8069
8417
|
}
|
|
8070
8418
|
}
|
|
8071
|
-
const
|
|
8419
|
+
const primary = await pickPrimaryHookFile(ctx.scanPath, hookFiles, args.registration_snippet);
|
|
8072
8420
|
const filesTouched = [];
|
|
8073
8421
|
const depsToAdd = [];
|
|
8074
8422
|
let packageJsonPatch = {};
|
|
@@ -8079,10 +8427,8 @@ async function dryRunExtension(ctx, args) {
|
|
|
8079
8427
|
depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
|
|
8080
8428
|
filesTouched.push("package.json");
|
|
8081
8429
|
}
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
if (patched) {
|
|
8085
|
-
filesTouched.push(primaryFile);
|
|
8430
|
+
if (primary.patched !== null) {
|
|
8431
|
+
filesTouched.push(primary.file);
|
|
8086
8432
|
templatePatch = `+ ${args.registration_snippet}`;
|
|
8087
8433
|
} else {
|
|
8088
8434
|
templatePatch = "Could not find insertion point in hook file.";
|
|
@@ -8100,7 +8446,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
8100
8446
|
if (!match) {
|
|
8101
8447
|
return { undone: false, message: "no apply found for library" };
|
|
8102
8448
|
}
|
|
8103
|
-
const pkgPath =
|
|
8449
|
+
const pkgPath = path46.join(ctx.scanPath, "package.json");
|
|
8104
8450
|
if (await fileExists2(pkgPath)) {
|
|
8105
8451
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
8106
8452
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -8111,7 +8457,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
8111
8457
|
}
|
|
8112
8458
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
8113
8459
|
for (const file of hookFiles) {
|
|
8114
|
-
const filePath =
|
|
8460
|
+
const filePath = path46.join(ctx.scanPath, file);
|
|
8115
8461
|
const content = await fs27.readFile(filePath, "utf8");
|
|
8116
8462
|
if (content.includes(match.registration_snippet)) {
|
|
8117
8463
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -8226,7 +8572,7 @@ data: ${JSON.stringify(envelope.payload)}
|
|
|
8226
8572
|
|
|
8227
8573
|
// src/connectors-config.ts
|
|
8228
8574
|
import os4 from "os";
|
|
8229
|
-
import
|
|
8575
|
+
import path47 from "path";
|
|
8230
8576
|
import { promises as fs28 } from "fs";
|
|
8231
8577
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
8232
8578
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -8241,11 +8587,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
8241
8587
|
};
|
|
8242
8588
|
function neatHome2() {
|
|
8243
8589
|
const override = process.env.NEAT_HOME;
|
|
8244
|
-
if (override && override.length > 0) return
|
|
8245
|
-
return
|
|
8590
|
+
if (override && override.length > 0) return path47.resolve(override);
|
|
8591
|
+
return path47.join(os4.homedir(), ".neat");
|
|
8246
8592
|
}
|
|
8247
8593
|
function connectorsConfigPath(home = neatHome2()) {
|
|
8248
|
-
return
|
|
8594
|
+
return path47.join(home, "connectors.json");
|
|
8249
8595
|
}
|
|
8250
8596
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
8251
8597
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -8376,7 +8722,7 @@ function connectorMatchesProject(entry, project) {
|
|
|
8376
8722
|
var CONNECTORS_LOCK_TIMEOUT_MS = 5e3;
|
|
8377
8723
|
var CONNECTORS_LOCK_RETRY_MS = 50;
|
|
8378
8724
|
function connectorsConfigLockPath(home = neatHome2()) {
|
|
8379
|
-
return
|
|
8725
|
+
return path47.join(home, "connectors.json.lock");
|
|
8380
8726
|
}
|
|
8381
8727
|
function isEnvRef(value) {
|
|
8382
8728
|
return value.length > 1 && value.startsWith("$");
|
|
@@ -8389,7 +8735,7 @@ function redactCredentialRef(ref) {
|
|
|
8389
8735
|
return out;
|
|
8390
8736
|
}
|
|
8391
8737
|
async function writeConfigAtomically0600(file, contents) {
|
|
8392
|
-
await fs28.mkdir(
|
|
8738
|
+
await fs28.mkdir(path47.dirname(file), { recursive: true });
|
|
8393
8739
|
const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
8394
8740
|
const fd = await fs28.open(tmp, "w", 384);
|
|
8395
8741
|
try {
|
|
@@ -8403,7 +8749,7 @@ async function writeConfigAtomically0600(file, contents) {
|
|
|
8403
8749
|
}
|
|
8404
8750
|
async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEOUT_MS) {
|
|
8405
8751
|
const deadline = Date.now() + timeoutMs;
|
|
8406
|
-
await fs28.mkdir(
|
|
8752
|
+
await fs28.mkdir(path47.dirname(lockPath), { recursive: true });
|
|
8407
8753
|
for (; ; ) {
|
|
8408
8754
|
try {
|
|
8409
8755
|
const fd = await fs28.open(lockPath, "wx");
|
|
@@ -9149,7 +9495,7 @@ function registerRoutes(scope, ctx) {
|
|
|
9149
9495
|
});
|
|
9150
9496
|
}
|
|
9151
9497
|
async function buildApi(opts) {
|
|
9152
|
-
const app = Fastify({ logger: false });
|
|
9498
|
+
const app = Fastify({ logger: false, routerOptions: { maxParamLength: 1024 } });
|
|
9153
9499
|
await app.register(cors, { origin: true });
|
|
9154
9500
|
const env = readAuthEnv();
|
|
9155
9501
|
const authToken = opts.authToken ?? env.authToken;
|
|
@@ -9361,4 +9707,4 @@ export {
|
|
|
9361
9707
|
recordConnectorPoll,
|
|
9362
9708
|
buildApi
|
|
9363
9709
|
};
|
|
9364
|
-
//# sourceMappingURL=chunk-
|
|
9710
|
+
//# sourceMappingURL=chunk-PEFX3DBR.js.map
|