@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
package/dist/cli.cjs
CHANGED
|
@@ -2329,6 +2329,41 @@ async function writeExtractionErrors(errors, errorsPath) {
|
|
|
2329
2329
|
const lines = errors.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
2330
2330
|
await import_node_fs5.promises.appendFile(errorsPath, lines, "utf8");
|
|
2331
2331
|
}
|
|
2332
|
+
function extractionHealthPathFor(errorsPath) {
|
|
2333
|
+
const dir = import_node_path5.default.dirname(errorsPath);
|
|
2334
|
+
const suffix = import_node_path5.default.basename(errorsPath).replace(/^errors/, "").replace(/\.ndjson$/, "");
|
|
2335
|
+
return import_node_path5.default.join(dir, `extraction-health${suffix}.json`);
|
|
2336
|
+
}
|
|
2337
|
+
var HEALTH_FILE_SAMPLE = 100;
|
|
2338
|
+
async function writeExtractionHealth(errors, healthPath, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
2339
|
+
const byProducer = {};
|
|
2340
|
+
for (const e of errors) byProducer[e.producer] = (byProducer[e.producer] ?? 0) + 1;
|
|
2341
|
+
const coverage = {
|
|
2342
|
+
skippedFiles: errors.length,
|
|
2343
|
+
byProducer,
|
|
2344
|
+
files: errors.slice(0, HEALTH_FILE_SAMPLE).map((e) => e.file),
|
|
2345
|
+
updatedAt: now
|
|
2346
|
+
};
|
|
2347
|
+
await import_node_fs5.promises.mkdir(import_node_path5.default.dirname(healthPath), { recursive: true });
|
|
2348
|
+
await import_node_fs5.promises.writeFile(healthPath, JSON.stringify(coverage), "utf8");
|
|
2349
|
+
}
|
|
2350
|
+
async function readExtractionHealth(healthPath) {
|
|
2351
|
+
let raw;
|
|
2352
|
+
try {
|
|
2353
|
+
raw = await import_node_fs5.promises.readFile(healthPath, "utf8");
|
|
2354
|
+
} catch {
|
|
2355
|
+
return void 0;
|
|
2356
|
+
}
|
|
2357
|
+
try {
|
|
2358
|
+
const obj = JSON.parse(raw);
|
|
2359
|
+
if (typeof obj?.skippedFiles !== "number" || !obj.byProducer || !Array.isArray(obj.files)) {
|
|
2360
|
+
return void 0;
|
|
2361
|
+
}
|
|
2362
|
+
return obj;
|
|
2363
|
+
} catch {
|
|
2364
|
+
return void 0;
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2332
2367
|
function isStrictExtractionEnabled() {
|
|
2333
2368
|
const raw = process.env.NEAT_STRICT_EXTRACTION;
|
|
2334
2369
|
return raw === "1" || raw === "true";
|
|
@@ -3292,14 +3327,16 @@ function reconcileObservedRelPath(graph, serviceName, relPath) {
|
|
|
3292
3327
|
return best ?? relPath;
|
|
3293
3328
|
}
|
|
3294
3329
|
function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
|
|
3295
|
-
const
|
|
3296
|
-
const
|
|
3330
|
+
const svcAttrs = graph.hasNode(serviceNodeId) ? graph.getNodeAttributes(serviceNodeId) : void 0;
|
|
3331
|
+
const canonicalService = svcAttrs && svcAttrs.type === import_types6.NodeType.ServiceNode && typeof svcAttrs.name === "string" ? svcAttrs.name : serviceName;
|
|
3332
|
+
const relPath = reconcileObservedRelPath(graph, canonicalService, callSite.relPath);
|
|
3333
|
+
const fileNodeId = (0, import_types6.fileId)(canonicalService, relPath);
|
|
3297
3334
|
if (!graph.hasNode(fileNodeId)) {
|
|
3298
3335
|
const language = languageForExt(relPath);
|
|
3299
3336
|
const node = {
|
|
3300
3337
|
id: fileNodeId,
|
|
3301
3338
|
type: import_types6.NodeType.FileNode,
|
|
3302
|
-
service:
|
|
3339
|
+
service: canonicalService,
|
|
3303
3340
|
path: relPath,
|
|
3304
3341
|
...language ? { language } : {},
|
|
3305
3342
|
...callSite.originalRelPath ? { originalPath: callSite.originalRelPath } : {},
|
|
@@ -8424,6 +8461,15 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
8424
8461
|
);
|
|
8425
8462
|
}
|
|
8426
8463
|
}
|
|
8464
|
+
if (opts.errorsPath) {
|
|
8465
|
+
try {
|
|
8466
|
+
await writeExtractionHealth(errorEntries, extractionHealthPathFor(opts.errorsPath));
|
|
8467
|
+
} catch (err) {
|
|
8468
|
+
console.warn(
|
|
8469
|
+
`[neat] failed to write extraction health sidecar: ${err.message}`
|
|
8470
|
+
);
|
|
8471
|
+
}
|
|
8472
|
+
}
|
|
8427
8473
|
const droppedEntries = drainDroppedExtracted();
|
|
8428
8474
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
8429
8475
|
const rejectedPath = import_node_path44.default.join(import_node_path44.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
@@ -10320,7 +10366,11 @@ function resolveProject(registry, req, reply, bootstrap, singleProject) {
|
|
|
10320
10366
|
void reply.code(503).send({ ready: false, project: name, status: "broken" });
|
|
10321
10367
|
return null;
|
|
10322
10368
|
}
|
|
10323
|
-
void reply.code(404).send({
|
|
10369
|
+
void reply.code(404).send({
|
|
10370
|
+
error: "project not found",
|
|
10371
|
+
project: name,
|
|
10372
|
+
hint: "This daemon does not host that project. GET /projects lists what it serves (see hostedHere)."
|
|
10373
|
+
});
|
|
10324
10374
|
return null;
|
|
10325
10375
|
}
|
|
10326
10376
|
return ctx;
|
|
@@ -10358,6 +10408,9 @@ function registerRoutes(scope, ctx) {
|
|
|
10358
10408
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
10359
10409
|
if (!proj) return;
|
|
10360
10410
|
const uptimeMs = Date.now() - startedAt;
|
|
10411
|
+
const coverage = await readExtractionHealth(
|
|
10412
|
+
extractionHealthPathFor(proj.paths.errorsPath)
|
|
10413
|
+
);
|
|
10361
10414
|
return {
|
|
10362
10415
|
ok: true,
|
|
10363
10416
|
project: proj.name,
|
|
@@ -10368,7 +10421,8 @@ function registerRoutes(scope, ctx) {
|
|
|
10368
10421
|
uptime: Math.floor(uptimeMs / 1e3),
|
|
10369
10422
|
nodeCount: proj.graph.order,
|
|
10370
10423
|
edgeCount: proj.graph.size,
|
|
10371
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
10424
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10425
|
+
...coverage ? { coverage } : {}
|
|
10372
10426
|
};
|
|
10373
10427
|
});
|
|
10374
10428
|
}
|
|
@@ -11010,12 +11064,17 @@ async function buildApi(opts) {
|
|
|
11010
11064
|
// The daemon is serving this project, so it's active unless its
|
|
11011
11065
|
// bootstrap broke. ('bootstrapping' still reads as active — the project
|
|
11012
11066
|
// is the one to land on; its graph route answers 503 until ready.)
|
|
11013
|
-
status: phase === "broken" ? "broken" : "active"
|
|
11067
|
+
status: phase === "broken" ? "broken" : "active",
|
|
11068
|
+
hostedHere: true
|
|
11014
11069
|
};
|
|
11015
11070
|
return [entry2];
|
|
11016
11071
|
}
|
|
11017
11072
|
try {
|
|
11018
|
-
|
|
11073
|
+
const entries = await listProjects();
|
|
11074
|
+
return entries.map((entry2) => ({
|
|
11075
|
+
...entry2,
|
|
11076
|
+
hostedHere: registry.has(entry2.name)
|
|
11077
|
+
}));
|
|
11019
11078
|
} catch (err) {
|
|
11020
11079
|
return reply.code(500).send({
|
|
11021
11080
|
error: "failed to read project registry",
|
|
@@ -11029,7 +11088,21 @@ async function buildApi(opts) {
|
|
|
11029
11088
|
if (!entry2) {
|
|
11030
11089
|
return reply.code(404).send({ error: "project not found", project: req.params.project });
|
|
11031
11090
|
}
|
|
11032
|
-
|
|
11091
|
+
const hostedHere = registry.has(entry2.name);
|
|
11092
|
+
if (!hostedHere) {
|
|
11093
|
+
const owner = await findDaemonByProject(entry2.name).catch(() => void 0);
|
|
11094
|
+
if (owner) {
|
|
11095
|
+
return {
|
|
11096
|
+
project: { ...entry2, hostedHere },
|
|
11097
|
+
servedBy: {
|
|
11098
|
+
path: owner.record.projectPath,
|
|
11099
|
+
restPort: owner.record.ports.rest,
|
|
11100
|
+
live: owner.live
|
|
11101
|
+
}
|
|
11102
|
+
};
|
|
11103
|
+
}
|
|
11104
|
+
}
|
|
11105
|
+
return { project: { ...entry2, hostedHere } };
|
|
11033
11106
|
} catch (err) {
|
|
11034
11107
|
return reply.code(500).send({
|
|
11035
11108
|
error: "failed to read project registry",
|