@neat.is/core 0.4.28-dev.20260707 → 0.4.28-dev.20260708
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-A3322JYS.js → chunk-CFDPIMRP.js} +13 -9
- package/dist/chunk-CFDPIMRP.js.map +1 -0
- package/dist/{chunk-UV5WSM7M.js → chunk-I72HTUOG.js} +2 -2
- package/dist/chunk-NY5Q6NE2.js +2566 -0
- package/dist/chunk-NY5Q6NE2.js.map +1 -0
- package/dist/{chunk-QM6BMPVJ.js → chunk-O4MRDWD7.js} +125 -12
- package/dist/chunk-O4MRDWD7.js.map +1 -0
- package/dist/cli.cjs +2454 -378
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +358 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1744 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +1760 -116
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-ET5Z6KI6.js → otel-grpc-IDMIH6ZY.js} +3 -3
- package/dist/server.cjs +133 -18
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +3 -3
- package/dist/chunk-A3322JYS.js.map +0 -1
- package/dist/chunk-QM6BMPVJ.js.map +0 -1
- package/dist/chunk-XV4D7A3Z.js +0 -907
- package/dist/chunk-XV4D7A3Z.js.map +0 -1
- /package/dist/{chunk-UV5WSM7M.js.map → chunk-I72HTUOG.js.map} +0 -0
- /package/dist/{otel-grpc-ET5Z6KI6.js.map → otel-grpc-IDMIH6ZY.js.map} +0 -0
package/dist/neatd.js
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
import {
|
|
3
3
|
reconcileDaemonRecordSync,
|
|
4
4
|
startDaemon
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-NY5Q6NE2.js";
|
|
6
6
|
import {
|
|
7
7
|
listProjects,
|
|
8
8
|
registryPath
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-O4MRDWD7.js";
|
|
10
10
|
import {
|
|
11
11
|
BindAuthorityError,
|
|
12
12
|
__require
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-CFDPIMRP.js";
|
|
14
14
|
|
|
15
15
|
// src/neatd.ts
|
|
16
16
|
import { promises as fs } from "fs";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
reshapeGrpcRequest,
|
|
3
3
|
startOtelGrpcReceiver
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-I72HTUOG.js";
|
|
5
|
+
import "./chunk-CFDPIMRP.js";
|
|
6
6
|
export {
|
|
7
7
|
reshapeGrpcRequest,
|
|
8
8
|
startOtelGrpcReceiver
|
|
9
9
|
};
|
|
10
|
-
//# sourceMappingURL=otel-grpc-
|
|
10
|
+
//# sourceMappingURL=otel-grpc-IDMIH6ZY.js.map
|
package/dist/server.cjs
CHANGED
|
@@ -53,15 +53,16 @@ function mountBearerAuth(app, opts) {
|
|
|
53
53
|
if (!opts.token || opts.token.length === 0) return;
|
|
54
54
|
if (opts.trustProxy) return;
|
|
55
55
|
const expected = Buffer.from(opts.token, "utf8");
|
|
56
|
-
const
|
|
56
|
+
const exactUnauthPaths = /* @__PURE__ */ new Set([
|
|
57
|
+
...DEFAULT_UNAUTH_PATHS,
|
|
58
|
+
...opts.extraUnauthenticatedSuffixes ?? []
|
|
59
|
+
]);
|
|
57
60
|
const publicRead = opts.publicRead === true;
|
|
58
61
|
app.addHook("preHandler", (req, reply, done) => {
|
|
59
62
|
const path46 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
63
|
+
if (exactUnauthPaths.has(path46) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path46)) {
|
|
64
|
+
done();
|
|
65
|
+
return;
|
|
65
66
|
}
|
|
66
67
|
if (publicRead && PUBLIC_READ_METHODS.has(req.method)) {
|
|
67
68
|
done();
|
|
@@ -96,7 +97,7 @@ function readAuthEnv(env = process.env) {
|
|
|
96
97
|
publicRead: parseBoolEnv(env.NEAT_PUBLIC_READ)
|
|
97
98
|
};
|
|
98
99
|
}
|
|
99
|
-
var import_node_crypto, LOOPBACK_HOSTS, BindAuthorityError, PUBLIC_READ_METHODS,
|
|
100
|
+
var import_node_crypto, LOOPBACK_HOSTS, BindAuthorityError, PUBLIC_READ_METHODS, DEFAULT_UNAUTH_PATHS, PROJECT_SCOPED_UNAUTH_PATTERN;
|
|
100
101
|
var init_auth = __esm({
|
|
101
102
|
"src/auth.ts"() {
|
|
102
103
|
"use strict";
|
|
@@ -117,12 +118,15 @@ var init_auth = __esm({
|
|
|
117
118
|
}
|
|
118
119
|
};
|
|
119
120
|
PUBLIC_READ_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
|
|
120
|
-
|
|
121
|
+
DEFAULT_UNAUTH_PATHS = [
|
|
121
122
|
"/health",
|
|
122
123
|
"/healthz",
|
|
123
124
|
"/readyz",
|
|
124
125
|
"/api/config"
|
|
125
126
|
];
|
|
127
|
+
PROJECT_SCOPED_UNAUTH_PATTERN = new RegExp(
|
|
128
|
+
`^/projects/[^/]+/(?:${DEFAULT_UNAUTH_PATHS.map((p) => p.slice(1)).join("|")})$`
|
|
129
|
+
);
|
|
126
130
|
}
|
|
127
131
|
});
|
|
128
132
|
|
|
@@ -2077,6 +2081,51 @@ function computeDivergences(graph, opts = {}) {
|
|
|
2077
2081
|
});
|
|
2078
2082
|
}
|
|
2079
2083
|
|
|
2084
|
+
// src/logs-store.ts
|
|
2085
|
+
init_cjs_shims();
|
|
2086
|
+
var LOGS_STORE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
2087
|
+
var LOGS_QUERY_DEFAULT_LIMIT = 100;
|
|
2088
|
+
var LOGS_QUERY_MAX_LIMIT = 1e3;
|
|
2089
|
+
var buffers = /* @__PURE__ */ new Map();
|
|
2090
|
+
var KEY_SEP = "::";
|
|
2091
|
+
function bufferKey(projectName, source) {
|
|
2092
|
+
return `${projectName}${KEY_SEP}${source}`;
|
|
2093
|
+
}
|
|
2094
|
+
function sourcesForProject(projectName) {
|
|
2095
|
+
const prefix = `${projectName}${KEY_SEP}`;
|
|
2096
|
+
const sources = [];
|
|
2097
|
+
for (const key of buffers.keys()) {
|
|
2098
|
+
if (key.startsWith(prefix)) sources.push(key.slice(prefix.length));
|
|
2099
|
+
}
|
|
2100
|
+
return sources;
|
|
2101
|
+
}
|
|
2102
|
+
function queryLogEntries(opts) {
|
|
2103
|
+
const { projectName, source, service, since, limit } = opts;
|
|
2104
|
+
const sources = source && source.length > 0 ? source : sourcesForProject(projectName);
|
|
2105
|
+
let merged = [];
|
|
2106
|
+
for (const src of sources) {
|
|
2107
|
+
const buf = buffers.get(bufferKey(projectName, src));
|
|
2108
|
+
if (buf) merged = merged.concat(buf);
|
|
2109
|
+
}
|
|
2110
|
+
if (service) {
|
|
2111
|
+
merged = merged.filter((e) => e.serviceName === service);
|
|
2112
|
+
}
|
|
2113
|
+
if (since) {
|
|
2114
|
+
const sinceMs = Date.parse(since);
|
|
2115
|
+
if (!Number.isNaN(sinceMs)) {
|
|
2116
|
+
merged = merged.filter((e) => {
|
|
2117
|
+
const t = Date.parse(e.timestamp);
|
|
2118
|
+
return Number.isNaN(t) || t >= sinceMs;
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
merged.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp));
|
|
2123
|
+
if (typeof limit === "number" && Number.isFinite(limit) && limit >= 0) {
|
|
2124
|
+
return merged.slice(0, limit);
|
|
2125
|
+
}
|
|
2126
|
+
return merged;
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2080
2129
|
// src/policy.ts
|
|
2081
2130
|
init_cjs_shims();
|
|
2082
2131
|
var import_node_fs4 = require("fs");
|
|
@@ -3663,24 +3712,58 @@ function dedupeIncidents(events) {
|
|
|
3663
3712
|
return !hasRealFailure.has(groupKey(ev));
|
|
3664
3713
|
});
|
|
3665
3714
|
}
|
|
3715
|
+
var SnapshotValidationError = class extends Error {
|
|
3716
|
+
constructor(issues) {
|
|
3717
|
+
super(`snapshot failed validation (${issues.length} invalid ${issues.length === 1 ? "entry" : "entries"})`);
|
|
3718
|
+
this.issues = issues;
|
|
3719
|
+
this.name = "SnapshotValidationError";
|
|
3720
|
+
}
|
|
3721
|
+
issues;
|
|
3722
|
+
};
|
|
3723
|
+
function describeZodIssues(error) {
|
|
3724
|
+
return error.issues.map((issue) => issue.path.length > 0 ? `${issue.path.join(".")}: ${issue.message}` : issue.message).join("; ");
|
|
3725
|
+
}
|
|
3666
3726
|
function mergeSnapshot(graph, snapshot) {
|
|
3667
3727
|
const exported = snapshot.graph;
|
|
3728
|
+
const incomingNodes = Array.isArray(exported.nodes) ? exported.nodes : [];
|
|
3729
|
+
const incomingEdges = Array.isArray(exported.edges) ? exported.edges : [];
|
|
3730
|
+
const issues = [];
|
|
3731
|
+
const validNodes = [];
|
|
3732
|
+
const validEdges = [];
|
|
3733
|
+
for (const node of incomingNodes) {
|
|
3734
|
+
if (node.attributes === void 0) continue;
|
|
3735
|
+
const parsed = import_types4.GraphNodeSchema.safeParse(node.attributes);
|
|
3736
|
+
if (!parsed.success) {
|
|
3737
|
+
issues.push(`node "${node.key}": ${describeZodIssues(parsed.error)}`);
|
|
3738
|
+
continue;
|
|
3739
|
+
}
|
|
3740
|
+
validNodes.push({ key: node.key, attributes: parsed.data });
|
|
3741
|
+
}
|
|
3742
|
+
for (const edge of incomingEdges) {
|
|
3743
|
+
if (edge.attributes === void 0) continue;
|
|
3744
|
+
const parsed = import_types4.GraphEdgeSchema.safeParse(edge.attributes);
|
|
3745
|
+
if (!parsed.success) {
|
|
3746
|
+
const label = edge.key ?? `${edge.source}->${edge.target}`;
|
|
3747
|
+
issues.push(`edge "${label}": ${describeZodIssues(parsed.error)}`);
|
|
3748
|
+
continue;
|
|
3749
|
+
}
|
|
3750
|
+
const id = edge.key ?? parsed.data.id;
|
|
3751
|
+
validEdges.push({ key: id, source: edge.source, target: edge.target, attributes: parsed.data });
|
|
3752
|
+
}
|
|
3753
|
+
if (issues.length > 0) {
|
|
3754
|
+
throw new SnapshotValidationError(issues);
|
|
3755
|
+
}
|
|
3668
3756
|
let nodesAdded = 0;
|
|
3669
3757
|
let edgesAdded = 0;
|
|
3670
|
-
for (const node of
|
|
3758
|
+
for (const node of validNodes) {
|
|
3671
3759
|
if (graph.hasNode(node.key)) continue;
|
|
3672
|
-
if (!node.attributes) continue;
|
|
3673
3760
|
graph.addNode(node.key, node.attributes);
|
|
3674
3761
|
nodesAdded++;
|
|
3675
3762
|
}
|
|
3676
|
-
for (const edge of
|
|
3677
|
-
|
|
3678
|
-
if (!attrs) continue;
|
|
3679
|
-
const id = edge.key ?? attrs.id;
|
|
3680
|
-
if (!id) continue;
|
|
3681
|
-
if (graph.hasEdge(id)) continue;
|
|
3763
|
+
for (const edge of validEdges) {
|
|
3764
|
+
if (graph.hasEdge(edge.key)) continue;
|
|
3682
3765
|
if (!graph.hasNode(edge.source) || !graph.hasNode(edge.target)) continue;
|
|
3683
|
-
graph.addEdgeWithKey(
|
|
3766
|
+
graph.addEdgeWithKey(edge.key, edge.source, edge.target, edge.attributes);
|
|
3684
3767
|
edgesAdded++;
|
|
3685
3768
|
}
|
|
3686
3769
|
return { nodesAdded, edgesAdded };
|
|
@@ -7892,6 +7975,23 @@ function registerRoutes(scope, ctx) {
|
|
|
7892
7975
|
const sliced = ordered.slice(0, Number.isFinite(limit) && limit > 0 ? limit : 50);
|
|
7893
7976
|
return { count: sliced.length, total, events: sliced };
|
|
7894
7977
|
});
|
|
7978
|
+
scope.get("/logs", async (req, reply) => {
|
|
7979
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
7980
|
+
if (!proj) return;
|
|
7981
|
+
const rawSource = req.query.source;
|
|
7982
|
+
const sources = rawSource === void 0 ? void 0 : Array.isArray(rawSource) ? rawSource : [rawSource];
|
|
7983
|
+
const filtered = queryLogEntries({
|
|
7984
|
+
projectName: proj.name,
|
|
7985
|
+
...sources && sources.length > 0 ? { source: sources } : {},
|
|
7986
|
+
...req.query.service ? { service: req.query.service } : {},
|
|
7987
|
+
...req.query.since ? { since: req.query.since } : {}
|
|
7988
|
+
});
|
|
7989
|
+
const total = filtered.length;
|
|
7990
|
+
const limit = req.query.limit ? Number(req.query.limit) : LOGS_QUERY_DEFAULT_LIMIT;
|
|
7991
|
+
const safeLimit = Number.isFinite(limit) && limit > 0 ? Math.min(limit, LOGS_QUERY_MAX_LIMIT) : LOGS_QUERY_DEFAULT_LIMIT;
|
|
7992
|
+
const sliced = filtered.slice(0, safeLimit);
|
|
7993
|
+
return { count: sliced.length, total, logs: sliced };
|
|
7994
|
+
});
|
|
7895
7995
|
const incidentHistoryHandler = async (req, reply) => {
|
|
7896
7996
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
7897
7997
|
if (!proj) return;
|
|
@@ -7987,8 +8087,16 @@ function registerRoutes(scope, ctx) {
|
|
|
7987
8087
|
if (!against) {
|
|
7988
8088
|
return reply.code(400).send({ error: "query parameter `against` is required" });
|
|
7989
8089
|
}
|
|
8090
|
+
const targetProjectName = against === "self" ? proj.name : against;
|
|
8091
|
+
const targetProject = registry.get(targetProjectName);
|
|
8092
|
+
if (!targetProject) {
|
|
8093
|
+
return reply.code(400).send({
|
|
8094
|
+
error: "unknown snapshot id \u2014 `against` must be `self` or the name of a project this server has a snapshot for",
|
|
8095
|
+
against
|
|
8096
|
+
});
|
|
8097
|
+
}
|
|
7990
8098
|
try {
|
|
7991
|
-
const snapshot = await loadSnapshotForDiff(
|
|
8099
|
+
const snapshot = await loadSnapshotForDiff(targetProject.paths.snapshotPath);
|
|
7992
8100
|
return computeGraphDiff(proj.graph, snapshot);
|
|
7993
8101
|
} catch (err) {
|
|
7994
8102
|
return reply.code(400).send({ error: "failed to load snapshot", against, detail: err.message });
|
|
@@ -8018,6 +8126,13 @@ function registerRoutes(scope, ctx) {
|
|
|
8018
8126
|
edgeCount: proj.graph.size
|
|
8019
8127
|
};
|
|
8020
8128
|
} catch (err) {
|
|
8129
|
+
if (err instanceof SnapshotValidationError) {
|
|
8130
|
+
return reply.code(400).send({
|
|
8131
|
+
error: "snapshot merge failed",
|
|
8132
|
+
details: err.message,
|
|
8133
|
+
issues: err.issues
|
|
8134
|
+
});
|
|
8135
|
+
}
|
|
8021
8136
|
return reply.code(400).send({
|
|
8022
8137
|
error: "snapshot merge failed",
|
|
8023
8138
|
details: err.message
|