@neat.is/core 0.6.3 → 0.6.4
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-PWIT35Z4.js → chunk-22X2YM5H.js} +2 -2
- package/dist/{chunk-L64CATKE.js → chunk-UCDXHLCJ.js} +82 -9
- package/dist/chunk-UCDXHLCJ.js.map +1 -0
- package/dist/cli.cjs +81 -8
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +142 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +142 -8
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +150 -8
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-L64CATKE.js.map +0 -1
- /package/dist/{chunk-PWIT35Z4.js.map → chunk-22X2YM5H.js.map} +0 -0
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
touchLastSeen,
|
|
32
32
|
upsertObservedEdge,
|
|
33
33
|
writeAtomically
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-UCDXHLCJ.js";
|
|
35
35
|
import {
|
|
36
36
|
assertBindAuthority,
|
|
37
37
|
buildOtelReceiver,
|
|
@@ -2807,4 +2807,4 @@ export {
|
|
|
2807
2807
|
resolveHost,
|
|
2808
2808
|
startDaemon
|
|
2809
2809
|
};
|
|
2810
|
-
//# sourceMappingURL=chunk-
|
|
2810
|
+
//# sourceMappingURL=chunk-22X2YM5H.js.map
|
|
@@ -1091,6 +1091,41 @@ async function writeExtractionErrors(errors, errorsPath) {
|
|
|
1091
1091
|
const lines = errors.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
1092
1092
|
await fs4.appendFile(errorsPath, lines, "utf8");
|
|
1093
1093
|
}
|
|
1094
|
+
function extractionHealthPathFor(errorsPath) {
|
|
1095
|
+
const dir = path4.dirname(errorsPath);
|
|
1096
|
+
const suffix = path4.basename(errorsPath).replace(/^errors/, "").replace(/\.ndjson$/, "");
|
|
1097
|
+
return path4.join(dir, `extraction-health${suffix}.json`);
|
|
1098
|
+
}
|
|
1099
|
+
var HEALTH_FILE_SAMPLE = 100;
|
|
1100
|
+
async function writeExtractionHealth(errors, healthPath, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
1101
|
+
const byProducer = {};
|
|
1102
|
+
for (const e of errors) byProducer[e.producer] = (byProducer[e.producer] ?? 0) + 1;
|
|
1103
|
+
const coverage = {
|
|
1104
|
+
skippedFiles: errors.length,
|
|
1105
|
+
byProducer,
|
|
1106
|
+
files: errors.slice(0, HEALTH_FILE_SAMPLE).map((e) => e.file),
|
|
1107
|
+
updatedAt: now
|
|
1108
|
+
};
|
|
1109
|
+
await fs4.mkdir(path4.dirname(healthPath), { recursive: true });
|
|
1110
|
+
await fs4.writeFile(healthPath, JSON.stringify(coverage), "utf8");
|
|
1111
|
+
}
|
|
1112
|
+
async function readExtractionHealth(healthPath) {
|
|
1113
|
+
let raw;
|
|
1114
|
+
try {
|
|
1115
|
+
raw = await fs4.readFile(healthPath, "utf8");
|
|
1116
|
+
} catch {
|
|
1117
|
+
return void 0;
|
|
1118
|
+
}
|
|
1119
|
+
try {
|
|
1120
|
+
const obj = JSON.parse(raw);
|
|
1121
|
+
if (typeof obj?.skippedFiles !== "number" || !obj.byProducer || !Array.isArray(obj.files)) {
|
|
1122
|
+
return void 0;
|
|
1123
|
+
}
|
|
1124
|
+
return obj;
|
|
1125
|
+
} catch {
|
|
1126
|
+
return void 0;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1094
1129
|
function isStrictExtractionEnabled() {
|
|
1095
1130
|
const raw = process.env.NEAT_STRICT_EXTRACTION;
|
|
1096
1131
|
return raw === "1" || raw === "true";
|
|
@@ -2060,14 +2095,16 @@ function reconcileObservedRelPath(graph, serviceName, relPath) {
|
|
|
2060
2095
|
return best ?? relPath;
|
|
2061
2096
|
}
|
|
2062
2097
|
function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
|
|
2063
|
-
const
|
|
2064
|
-
const
|
|
2098
|
+
const svcAttrs = graph.hasNode(serviceNodeId) ? graph.getNodeAttributes(serviceNodeId) : void 0;
|
|
2099
|
+
const canonicalService = svcAttrs && svcAttrs.type === NodeType4.ServiceNode && typeof svcAttrs.name === "string" ? svcAttrs.name : serviceName;
|
|
2100
|
+
const relPath = reconcileObservedRelPath(graph, canonicalService, callSite.relPath);
|
|
2101
|
+
const fileNodeId = fileId2(canonicalService, relPath);
|
|
2065
2102
|
if (!graph.hasNode(fileNodeId)) {
|
|
2066
2103
|
const language = languageForExt(relPath);
|
|
2067
2104
|
const node = {
|
|
2068
2105
|
id: fileNodeId,
|
|
2069
2106
|
type: NodeType4.FileNode,
|
|
2070
|
-
service:
|
|
2107
|
+
service: canonicalService,
|
|
2071
2108
|
path: relPath,
|
|
2072
2109
|
...language ? { language } : {},
|
|
2073
2110
|
...callSite.originalRelPath ? { originalPath: callSite.originalRelPath } : {},
|
|
@@ -7708,6 +7745,15 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
7708
7745
|
);
|
|
7709
7746
|
}
|
|
7710
7747
|
}
|
|
7748
|
+
if (opts.errorsPath) {
|
|
7749
|
+
try {
|
|
7750
|
+
await writeExtractionHealth(errorEntries, extractionHealthPathFor(opts.errorsPath));
|
|
7751
|
+
} catch (err) {
|
|
7752
|
+
console.warn(
|
|
7753
|
+
`[neat] failed to write extraction health sidecar: ${err.message}`
|
|
7754
|
+
);
|
|
7755
|
+
}
|
|
7756
|
+
}
|
|
7711
7757
|
const droppedEntries = drainDroppedExtracted();
|
|
7712
7758
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
7713
7759
|
const rejectedPath = path43.join(path43.dirname(opts.errorsPath), "rejected.ndjson");
|
|
@@ -9475,7 +9521,11 @@ function resolveProject(registry, req, reply, bootstrap, singleProject) {
|
|
|
9475
9521
|
void reply.code(503).send({ ready: false, project: name, status: "broken" });
|
|
9476
9522
|
return null;
|
|
9477
9523
|
}
|
|
9478
|
-
void reply.code(404).send({
|
|
9524
|
+
void reply.code(404).send({
|
|
9525
|
+
error: "project not found",
|
|
9526
|
+
project: name,
|
|
9527
|
+
hint: "This daemon does not host that project. GET /projects lists what it serves (see hostedHere)."
|
|
9528
|
+
});
|
|
9479
9529
|
return null;
|
|
9480
9530
|
}
|
|
9481
9531
|
return ctx;
|
|
@@ -9513,6 +9563,9 @@ function registerRoutes(scope, ctx) {
|
|
|
9513
9563
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
9514
9564
|
if (!proj) return;
|
|
9515
9565
|
const uptimeMs = Date.now() - startedAt;
|
|
9566
|
+
const coverage = await readExtractionHealth(
|
|
9567
|
+
extractionHealthPathFor(proj.paths.errorsPath)
|
|
9568
|
+
);
|
|
9516
9569
|
return {
|
|
9517
9570
|
ok: true,
|
|
9518
9571
|
project: proj.name,
|
|
@@ -9523,7 +9576,8 @@ function registerRoutes(scope, ctx) {
|
|
|
9523
9576
|
uptime: Math.floor(uptimeMs / 1e3),
|
|
9524
9577
|
nodeCount: proj.graph.order,
|
|
9525
9578
|
edgeCount: proj.graph.size,
|
|
9526
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
9579
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9580
|
+
...coverage ? { coverage } : {}
|
|
9527
9581
|
};
|
|
9528
9582
|
});
|
|
9529
9583
|
}
|
|
@@ -10165,12 +10219,17 @@ async function buildApi(opts) {
|
|
|
10165
10219
|
// The daemon is serving this project, so it's active unless its
|
|
10166
10220
|
// bootstrap broke. ('bootstrapping' still reads as active — the project
|
|
10167
10221
|
// is the one to land on; its graph route answers 503 until ready.)
|
|
10168
|
-
status: phase === "broken" ? "broken" : "active"
|
|
10222
|
+
status: phase === "broken" ? "broken" : "active",
|
|
10223
|
+
hostedHere: true
|
|
10169
10224
|
};
|
|
10170
10225
|
return [entry];
|
|
10171
10226
|
}
|
|
10172
10227
|
try {
|
|
10173
|
-
|
|
10228
|
+
const entries = await listProjects();
|
|
10229
|
+
return entries.map((entry) => ({
|
|
10230
|
+
...entry,
|
|
10231
|
+
hostedHere: registry.has(entry.name)
|
|
10232
|
+
}));
|
|
10174
10233
|
} catch (err) {
|
|
10175
10234
|
return reply.code(500).send({
|
|
10176
10235
|
error: "failed to read project registry",
|
|
@@ -10184,7 +10243,21 @@ async function buildApi(opts) {
|
|
|
10184
10243
|
if (!entry) {
|
|
10185
10244
|
return reply.code(404).send({ error: "project not found", project: req.params.project });
|
|
10186
10245
|
}
|
|
10187
|
-
|
|
10246
|
+
const hostedHere = registry.has(entry.name);
|
|
10247
|
+
if (!hostedHere) {
|
|
10248
|
+
const owner = await findDaemonByProject(entry.name).catch(() => void 0);
|
|
10249
|
+
if (owner) {
|
|
10250
|
+
return {
|
|
10251
|
+
project: { ...entry, hostedHere },
|
|
10252
|
+
servedBy: {
|
|
10253
|
+
path: owner.record.projectPath,
|
|
10254
|
+
restPort: owner.record.ports.rest,
|
|
10255
|
+
live: owner.live
|
|
10256
|
+
}
|
|
10257
|
+
};
|
|
10258
|
+
}
|
|
10259
|
+
}
|
|
10260
|
+
return { project: { ...entry, hostedHere } };
|
|
10188
10261
|
} catch (err) {
|
|
10189
10262
|
return reply.code(500).send({
|
|
10190
10263
|
error: "failed to read project registry",
|
|
@@ -10289,4 +10362,4 @@ export {
|
|
|
10289
10362
|
recordConnectorPoll,
|
|
10290
10363
|
buildApi
|
|
10291
10364
|
};
|
|
10292
|
-
//# sourceMappingURL=chunk-
|
|
10365
|
+
//# sourceMappingURL=chunk-UCDXHLCJ.js.map
|