@neat.is/core 0.7.8 → 0.7.9
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-BIY46Q6U.js → chunk-BC53SCT7.js} +36 -2
- package/dist/chunk-BC53SCT7.js.map +1 -0
- package/dist/{chunk-4GCV46AP.js → chunk-FCO5Z3RW.js} +2 -2
- package/dist/{chunk-OVRVDSUO.js → chunk-ILG3SMD5.js} +54 -4
- package/dist/{chunk-OVRVDSUO.js.map → chunk-ILG3SMD5.js.map} +1 -1
- package/dist/{chunk-LN75Z624.js → chunk-N5TPODCX.js} +69 -48
- package/dist/chunk-N5TPODCX.js.map +1 -0
- package/dist/{chunk-Y43UCVZS.js → chunk-UUYCTH2E.js} +24 -8
- package/dist/chunk-UUYCTH2E.js.map +1 -0
- package/dist/cli.cjs +136 -62
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +17 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +140 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +140 -53
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-DPSAGRUU.js → otel-grpc-CO47JRIN.js} +3 -3
- package/dist/server.cjs +124 -53
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +4 -4
- package/package.json +2 -2
- package/dist/chunk-BIY46Q6U.js.map +0 -1
- package/dist/chunk-LN75Z624.js.map +0 -1
- package/dist/chunk-Y43UCVZS.js.map +0 -1
- /package/dist/{chunk-4GCV46AP.js.map → chunk-FCO5Z3RW.js.map} +0 -0
- /package/dist/{otel-grpc-DPSAGRUU.js.map → otel-grpc-CO47JRIN.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -302,6 +302,10 @@ interface BuildOtelReceiverOptions {
|
|
|
302
302
|
onProjectSpan?: ProjectSpanHandler;
|
|
303
303
|
onProjectErrorSpanSync?: (project: string, span: ParsedSpan) => Promise<void>;
|
|
304
304
|
isProjectRegistered?: (project: string) => boolean;
|
|
305
|
+
classifyBareRoutability?: (spans: ParsedSpan[]) => {
|
|
306
|
+
rejected: number;
|
|
307
|
+
message?: string;
|
|
308
|
+
};
|
|
305
309
|
bodyLimit?: number;
|
|
306
310
|
authToken?: string;
|
|
307
311
|
trustProxy?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -302,6 +302,10 @@ interface BuildOtelReceiverOptions {
|
|
|
302
302
|
onProjectSpan?: ProjectSpanHandler;
|
|
303
303
|
onProjectErrorSpanSync?: (project: string, span: ParsedSpan) => Promise<void>;
|
|
304
304
|
isProjectRegistered?: (project: string) => boolean;
|
|
305
|
+
classifyBareRoutability?: (spans: ParsedSpan[]) => {
|
|
306
|
+
rejected: number;
|
|
307
|
+
message?: string;
|
|
308
|
+
};
|
|
305
309
|
bodyLimit?: number;
|
|
306
310
|
authToken?: string;
|
|
307
311
|
trustProxy?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
routeSpanToProject,
|
|
3
3
|
startDaemon
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ILG3SMD5.js";
|
|
5
5
|
import {
|
|
6
6
|
ProjectNameCollisionError,
|
|
7
7
|
addProject,
|
|
@@ -37,15 +37,15 @@ import {
|
|
|
37
37
|
thresholdForEdgeType,
|
|
38
38
|
touchLastSeen,
|
|
39
39
|
writeAtomically
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-N5TPODCX.js";
|
|
41
41
|
import {
|
|
42
42
|
startOtelGrpcReceiver
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-FCO5Z3RW.js";
|
|
44
44
|
import {
|
|
45
45
|
buildOtelReceiver,
|
|
46
46
|
logSpanHandler,
|
|
47
47
|
parseOtlpRequest
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-UUYCTH2E.js";
|
|
49
49
|
export {
|
|
50
50
|
ProjectNameCollisionError,
|
|
51
51
|
addProject,
|
package/dist/neatd.cjs
CHANGED
|
@@ -504,13 +504,18 @@ function loadProtobufResponseEncoder() {
|
|
|
504
504
|
);
|
|
505
505
|
return exportTraceServiceResponseType;
|
|
506
506
|
}
|
|
507
|
-
function encodeProtobufResponseBody() {
|
|
508
|
-
if (cachedProtobufResponseBody) return cachedProtobufResponseBody;
|
|
507
|
+
function encodeProtobufResponseBody(rejected, message) {
|
|
509
508
|
const Type = loadProtobufResponseEncoder();
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
509
|
+
if (!rejected) {
|
|
510
|
+
if (cachedProtobufResponseBody) return cachedProtobufResponseBody;
|
|
511
|
+
const msg2 = Type.create({});
|
|
512
|
+
cachedProtobufResponseBody = Buffer.from(Type.encode(msg2).finish());
|
|
513
|
+
return cachedProtobufResponseBody;
|
|
514
|
+
}
|
|
515
|
+
const msg = Type.fromObject({
|
|
516
|
+
partial_success: { rejected_spans: rejected, error_message: message ?? "" }
|
|
517
|
+
});
|
|
518
|
+
return Buffer.from(Type.encode(msg).finish());
|
|
514
519
|
}
|
|
515
520
|
async function decodeProtobufBody(buf) {
|
|
516
521
|
const Type = loadProtobufDecoder();
|
|
@@ -625,6 +630,13 @@ async function buildOtelReceiver(opts) {
|
|
|
625
630
|
}
|
|
626
631
|
return reply.code(200).header("content-type", "application/json").send({ partialSuccess: {} });
|
|
627
632
|
}
|
|
633
|
+
function sendOtlpPartial(reply, flavor, rejected, message) {
|
|
634
|
+
if (flavor === "protobuf") {
|
|
635
|
+
const buf = encodeProtobufResponseBody(rejected, message);
|
|
636
|
+
return reply.code(200).header("content-type", "application/x-protobuf").send(buf);
|
|
637
|
+
}
|
|
638
|
+
return reply.code(200).header("content-type", "application/json").send({ partialSuccess: { rejectedSpans: rejected, errorMessage: message } });
|
|
639
|
+
}
|
|
628
640
|
app.addContentTypeParser(
|
|
629
641
|
"application/x-protobuf",
|
|
630
642
|
{ parseAs: "buffer", bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024 },
|
|
@@ -652,6 +664,10 @@ async function buildOtelReceiver(opts) {
|
|
|
652
664
|
}
|
|
653
665
|
}
|
|
654
666
|
enqueue(spans);
|
|
667
|
+
if (opts.classifyBareRoutability) {
|
|
668
|
+
const { rejected, message } = opts.classifyBareRoutability(spans);
|
|
669
|
+
if (rejected > 0) return sendOtlpPartial(reply, result.flavor, rejected, message);
|
|
670
|
+
}
|
|
655
671
|
return sendOtlpSuccess(reply, result.flavor);
|
|
656
672
|
});
|
|
657
673
|
app.post("/projects/:project/v1/traces", async (req2, reply) => {
|
|
@@ -4828,10 +4844,15 @@ function resolveDistToSrc(absFilepath, line) {
|
|
|
4828
4844
|
}
|
|
4829
4845
|
if (!entry2) return null;
|
|
4830
4846
|
try {
|
|
4831
|
-
const
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4847
|
+
const queryLine = line !== void 0 && Number.isFinite(line) ? line : 1;
|
|
4848
|
+
let pos = entry2.consumer.originalPositionFor({ line: queryLine, column: 0 });
|
|
4849
|
+
if (!pos || !pos.source) {
|
|
4850
|
+
pos = entry2.consumer.originalPositionFor({
|
|
4851
|
+
line: queryLine,
|
|
4852
|
+
column: 0,
|
|
4853
|
+
bias: sourceMapJs.SourceMapConsumer.LEAST_UPPER_BOUND
|
|
4854
|
+
});
|
|
4855
|
+
}
|
|
4835
4856
|
if (!pos || !pos.source) return null;
|
|
4836
4857
|
const root = entry2.consumer.sourceRoot ?? "";
|
|
4837
4858
|
const resolved = import_node_path8.default.resolve(entry2.dir, root, pos.source);
|
|
@@ -4840,6 +4861,9 @@ function resolveDistToSrc(absFilepath, line) {
|
|
|
4840
4861
|
return null;
|
|
4841
4862
|
}
|
|
4842
4863
|
}
|
|
4864
|
+
function hasAdjacentSourceMap(absFilepath) {
|
|
4865
|
+
return sourceMapCache.get(absFilepath) != null;
|
|
4866
|
+
}
|
|
4843
4867
|
function callSiteFromSpan(span, serviceNode, scanPath) {
|
|
4844
4868
|
const filepath = codeFilepathOf(span.attributes);
|
|
4845
4869
|
if (filepath === void 0) return null;
|
|
@@ -4855,7 +4879,7 @@ function callSiteFromSpan(span, serviceNode, scanPath) {
|
|
|
4855
4879
|
}
|
|
4856
4880
|
const relPath = relPathForRuntimeFile(effectivePath, serviceNode, scanPath);
|
|
4857
4881
|
if (!relPath) return null;
|
|
4858
|
-
if (!resolved && abs.endsWith(".js") && relPath.startsWith("dist/") && serviceNode?.name) {
|
|
4882
|
+
if (!resolved && abs.endsWith(".js") && relPath.startsWith("dist/") && !hasAdjacentSourceMap(abs) && serviceNode?.name) {
|
|
4859
4883
|
warnNoSourceMaps(serviceNode.name);
|
|
4860
4884
|
}
|
|
4861
4885
|
const fn = codeFunctionOf(span.attributes);
|
|
@@ -5131,7 +5155,7 @@ function resolveServiceId(graph, host, env) {
|
|
|
5131
5155
|
function frontierIdFor(host) {
|
|
5132
5156
|
return (0, import_types8.frontierId)(host);
|
|
5133
5157
|
}
|
|
5134
|
-
function
|
|
5158
|
+
function resolveFusedServiceId(graph, serviceName, env) {
|
|
5135
5159
|
const id = (0, import_types8.serviceId)(serviceName, env);
|
|
5136
5160
|
if (graph.hasNode(id)) return id;
|
|
5137
5161
|
const wanted = serviceName.toLowerCase();
|
|
@@ -5141,17 +5165,21 @@ function ensureServiceNode(graph, serviceName, env) {
|
|
|
5141
5165
|
if (svc.discoveredVia === "otel") return false;
|
|
5142
5166
|
return typeof svc.name === "string" && svc.name.toLowerCase() === wanted;
|
|
5143
5167
|
});
|
|
5144
|
-
|
|
5168
|
+
return extractedId ?? id;
|
|
5169
|
+
}
|
|
5170
|
+
function ensureServiceNode(graph, serviceName, env) {
|
|
5171
|
+
const resolved = resolveFusedServiceId(graph, serviceName, env);
|
|
5172
|
+
if (graph.hasNode(resolved)) return resolved;
|
|
5145
5173
|
const node = {
|
|
5146
|
-
id,
|
|
5174
|
+
id: resolved,
|
|
5147
5175
|
type: import_types8.NodeType.ServiceNode,
|
|
5148
5176
|
name: serviceName,
|
|
5149
5177
|
language: "unknown",
|
|
5150
5178
|
discoveredVia: "otel",
|
|
5151
5179
|
...env !== "unknown" ? { env } : {}
|
|
5152
5180
|
};
|
|
5153
|
-
graph.addNode(
|
|
5154
|
-
return
|
|
5181
|
+
graph.addNode(resolved, node);
|
|
5182
|
+
return resolved;
|
|
5155
5183
|
}
|
|
5156
5184
|
function ensureInfraNode(graph, kind, name, provider) {
|
|
5157
5185
|
const id = (0, import_types8.infraId)(kind, name);
|
|
@@ -5345,7 +5373,7 @@ async function appendErrorEvent(ctx, ev) {
|
|
|
5345
5373
|
await import_node_fs7.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
5346
5374
|
}
|
|
5347
5375
|
function incidentAffectedNode(span, graph, scanPath) {
|
|
5348
|
-
const sid = (0, import_types8.serviceId)(span.service, span.env);
|
|
5376
|
+
const sid = graph ? resolveFusedServiceId(graph, span.service, span.env) : (0, import_types8.serviceId)(span.service, span.env);
|
|
5349
5377
|
const serviceNode = graph && graph.hasNode(sid) ? graph.getNodeAttributes(sid) : void 0;
|
|
5350
5378
|
const callSite = callSiteFromSpan(span, serviceNode, scanPath);
|
|
5351
5379
|
if (callSite) {
|
|
@@ -6744,7 +6772,7 @@ function disambiguate(defs) {
|
|
|
6744
6772
|
}
|
|
6745
6773
|
async function addSymbols(graph, services) {
|
|
6746
6774
|
const parsers = /* @__PURE__ */ new Map();
|
|
6747
|
-
const
|
|
6775
|
+
const parserForExt5 = (ext) => {
|
|
6748
6776
|
const grammar = GRAMMAR_BY_EXT[ext];
|
|
6749
6777
|
if (!grammar) return null;
|
|
6750
6778
|
let parser = parsers.get(ext);
|
|
@@ -6760,7 +6788,7 @@ async function addSymbols(graph, services) {
|
|
|
6760
6788
|
for (const service of services) {
|
|
6761
6789
|
const files = await loadSourceFiles(service.dir);
|
|
6762
6790
|
for (const file of files) {
|
|
6763
|
-
const parser =
|
|
6791
|
+
const parser = parserForExt5(import_node_path17.default.extname(file.path));
|
|
6764
6792
|
if (!parser) continue;
|
|
6765
6793
|
const relPath = toPosix(import_node_path17.default.relative(service.dir, file.path));
|
|
6766
6794
|
let defs;
|
|
@@ -6912,7 +6940,7 @@ function stringInner(node) {
|
|
|
6912
6940
|
}
|
|
6913
6941
|
async function addSymbolEdges(graph, services) {
|
|
6914
6942
|
const parsers = /* @__PURE__ */ new Map();
|
|
6915
|
-
const
|
|
6943
|
+
const parserForExt5 = (ext) => {
|
|
6916
6944
|
const grammar = GRAMMAR_BY_EXT[ext];
|
|
6917
6945
|
if (!grammar) return null;
|
|
6918
6946
|
let parser = parsers.get(ext);
|
|
@@ -6929,7 +6957,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
6929
6957
|
const tsPaths = await loadTsPathConfig(service.dir);
|
|
6930
6958
|
const files = await loadSourceFiles(service.dir);
|
|
6931
6959
|
for (const file of files) {
|
|
6932
|
-
const parser =
|
|
6960
|
+
const parser = parserForExt5(import_node_path18.default.extname(file.path));
|
|
6933
6961
|
if (!parser) continue;
|
|
6934
6962
|
const relPath = toPosix(import_node_path18.default.relative(service.dir, file.path));
|
|
6935
6963
|
const fileDir = import_node_path18.default.dirname(file.path);
|
|
@@ -7191,7 +7219,7 @@ function firstReferenceLines(root, wanted) {
|
|
|
7191
7219
|
}
|
|
7192
7220
|
async function addServerActions(graph, services) {
|
|
7193
7221
|
const parsers = /* @__PURE__ */ new Map();
|
|
7194
|
-
const
|
|
7222
|
+
const parserForExt5 = (ext) => {
|
|
7195
7223
|
const grammar = GRAMMAR_BY_EXT[ext];
|
|
7196
7224
|
if (!grammar) return null;
|
|
7197
7225
|
let parser = parsers.get(ext);
|
|
@@ -7214,7 +7242,7 @@ async function addServerActions(graph, services) {
|
|
|
7214
7242
|
const files = await loadSourceFiles(service.dir);
|
|
7215
7243
|
for (const file of files) {
|
|
7216
7244
|
if (isTestPath(file.path)) continue;
|
|
7217
|
-
const parser =
|
|
7245
|
+
const parser = parserForExt5(import_node_path19.default.extname(file.path));
|
|
7218
7246
|
if (!parser) continue;
|
|
7219
7247
|
const relPath = toPosix(import_node_path19.default.relative(service.dir, file.path));
|
|
7220
7248
|
let root;
|
|
@@ -7277,7 +7305,7 @@ async function addServerActions(graph, services) {
|
|
|
7277
7305
|
}
|
|
7278
7306
|
for (const file of files) {
|
|
7279
7307
|
if (isTestPath(file.path)) continue;
|
|
7280
|
-
const parser =
|
|
7308
|
+
const parser = parserForExt5(import_node_path19.default.extname(file.path));
|
|
7281
7309
|
if (!parser) continue;
|
|
7282
7310
|
const relPath = toPosix(import_node_path19.default.relative(service.dir, file.path));
|
|
7283
7311
|
const fileDir = import_node_path19.default.dirname(file.path);
|
|
@@ -8241,6 +8269,7 @@ init_cjs_shims();
|
|
|
8241
8269
|
var import_node_path30 = __toESM(require("path"), 1);
|
|
8242
8270
|
var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
|
|
8243
8271
|
var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
|
|
8272
|
+
var import_tree_sitter_typescript2 = __toESM(require("tree-sitter-typescript"), 1);
|
|
8244
8273
|
var import_tree_sitter_python3 = __toESM(require("tree-sitter-python"), 1);
|
|
8245
8274
|
var import_types20 = require("@neat.is/types");
|
|
8246
8275
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
@@ -8291,19 +8320,27 @@ function callsFromSource(source, parser, knownHosts) {
|
|
|
8291
8320
|
}
|
|
8292
8321
|
return out;
|
|
8293
8322
|
}
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8323
|
+
var GRAMMAR_BY_EXT2 = {
|
|
8324
|
+
".ts": import_tree_sitter_typescript2.default.typescript,
|
|
8325
|
+
".tsx": import_tree_sitter_typescript2.default.tsx,
|
|
8326
|
+
".js": import_tree_sitter_javascript4.default,
|
|
8327
|
+
".jsx": import_tree_sitter_javascript4.default,
|
|
8328
|
+
".mjs": import_tree_sitter_javascript4.default,
|
|
8329
|
+
".cjs": import_tree_sitter_javascript4.default,
|
|
8330
|
+
".py": import_tree_sitter_python3.default
|
|
8331
|
+
};
|
|
8332
|
+
function parserForExt(ext, cache) {
|
|
8333
|
+
const grammar = GRAMMAR_BY_EXT2[ext] ?? import_tree_sitter_javascript4.default;
|
|
8334
|
+
let parser = cache.get(grammar);
|
|
8335
|
+
if (!parser) {
|
|
8336
|
+
parser = new import_tree_sitter6.default();
|
|
8337
|
+
parser.setLanguage(grammar);
|
|
8338
|
+
cache.set(grammar, parser);
|
|
8339
|
+
}
|
|
8340
|
+
return parser;
|
|
8303
8341
|
}
|
|
8304
8342
|
async function addHttpCallEdges(graph, services) {
|
|
8305
|
-
const
|
|
8306
|
-
const pyParser = makePyParser3();
|
|
8343
|
+
const parserCache = /* @__PURE__ */ new Map();
|
|
8307
8344
|
const { knownHosts, hostToNodeId } = buildServiceHostIndex(services);
|
|
8308
8345
|
let nodesAdded = 0;
|
|
8309
8346
|
let edgesAdded = 0;
|
|
@@ -8312,7 +8349,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
8312
8349
|
const seen = /* @__PURE__ */ new Set();
|
|
8313
8350
|
for (const file of files) {
|
|
8314
8351
|
if (isTestPath(file.path)) continue;
|
|
8315
|
-
const parser = import_node_path30.default.extname(file.path)
|
|
8352
|
+
const parser = parserForExt(import_node_path30.default.extname(file.path), parserCache);
|
|
8316
8353
|
let sites;
|
|
8317
8354
|
try {
|
|
8318
8355
|
sites = callsFromSource(file.content, parser, knownHosts);
|
|
@@ -8385,7 +8422,7 @@ function parseSource5(parser, source) {
|
|
|
8385
8422
|
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK5)
|
|
8386
8423
|
);
|
|
8387
8424
|
}
|
|
8388
|
-
function
|
|
8425
|
+
function makeJsParser3() {
|
|
8389
8426
|
const p = new import_tree_sitter7.default();
|
|
8390
8427
|
p.setLanguage(import_tree_sitter_javascript5.default);
|
|
8391
8428
|
return p;
|
|
@@ -8563,7 +8600,7 @@ function findRoute(entries, method, normalizedPath) {
|
|
|
8563
8600
|
);
|
|
8564
8601
|
}
|
|
8565
8602
|
async function addRouteCallEdges(graph, services) {
|
|
8566
|
-
const jsParser =
|
|
8603
|
+
const jsParser = makeJsParser3();
|
|
8567
8604
|
const { knownHosts, hostToNodeId } = buildServiceHostIndex(services);
|
|
8568
8605
|
const routeIndex = buildRouteIndex(graph);
|
|
8569
8606
|
if (routeIndex.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
@@ -8955,7 +8992,7 @@ var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"),
|
|
|
8955
8992
|
var import_types27 = require("@neat.is/types");
|
|
8956
8993
|
var FIRESTORE_CLIENT_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])firebase\/firestore['"`]/;
|
|
8957
8994
|
var FIRESTORE_ADMIN_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])firebase-admin(?:\/firestore)?['"`]/;
|
|
8958
|
-
function
|
|
8995
|
+
function parserForExt2(ext) {
|
|
8959
8996
|
const p = new import_tree_sitter8.default();
|
|
8960
8997
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript6.default);
|
|
8961
8998
|
return p;
|
|
@@ -9120,7 +9157,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9120
9157
|
const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(file.content);
|
|
9121
9158
|
if (!hasClient && !hasAdmin) return [];
|
|
9122
9159
|
const fileSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
|
|
9123
|
-
const tree = parseSource3(
|
|
9160
|
+
const tree = parseSource3(parserForExt2(import_node_path37.default.extname(file.path)), file.content);
|
|
9124
9161
|
const clientVars = firestoreClientVars(tree.rootNode);
|
|
9125
9162
|
const collLine = /* @__PURE__ */ new Map();
|
|
9126
9163
|
const writes = /* @__PURE__ */ new Map();
|
|
@@ -9537,7 +9574,7 @@ var import_tree_sitter_python4 = __toESM(require("tree-sitter-python"), 1);
|
|
|
9537
9574
|
var import_types29 = require("@neat.is/types");
|
|
9538
9575
|
var SQLALCHEMY_IMPORT_RE = /(?:from|import)\s+(?:flask_sqlalchemy|sqlalchemy)\b/;
|
|
9539
9576
|
var PARSE_CHUNK6 = 16384;
|
|
9540
|
-
function
|
|
9577
|
+
function makePyParser3() {
|
|
9541
9578
|
const p = new import_tree_sitter9.default();
|
|
9542
9579
|
p.setLanguage(import_tree_sitter_python4.default);
|
|
9543
9580
|
return p;
|
|
@@ -9644,7 +9681,7 @@ function foreignKeyParentTable(call) {
|
|
|
9644
9681
|
}
|
|
9645
9682
|
function sqlalchemyForeignKeys(file, serviceDir) {
|
|
9646
9683
|
if (!SQLALCHEMY_IMPORT_RE.test(file.content)) return [];
|
|
9647
|
-
const tree = parseSource6(
|
|
9684
|
+
const tree = parseSource6(makePyParser3(), file.content);
|
|
9648
9685
|
const out = [];
|
|
9649
9686
|
const seen = /* @__PURE__ */ new Set();
|
|
9650
9687
|
walk3(tree.rootNode, (node) => {
|
|
@@ -9681,7 +9718,7 @@ function sqlalchemyForeignKeys(file, serviceDir) {
|
|
|
9681
9718
|
}
|
|
9682
9719
|
function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
9683
9720
|
if (!SQLALCHEMY_IMPORT_RE.test(file.content)) return [];
|
|
9684
|
-
const tree = parseSource6(
|
|
9721
|
+
const tree = parseSource6(makePyParser3(), file.content);
|
|
9685
9722
|
const out = [];
|
|
9686
9723
|
const seen = /* @__PURE__ */ new Set();
|
|
9687
9724
|
const push = (name, line, columns) => {
|
|
@@ -9733,7 +9770,7 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
|
9733
9770
|
function buildSqlalchemyModelRegistry(files) {
|
|
9734
9771
|
const table = /* @__PURE__ */ new Map();
|
|
9735
9772
|
const ambiguous = /* @__PURE__ */ new Set();
|
|
9736
|
-
const parser =
|
|
9773
|
+
const parser = makePyParser3();
|
|
9737
9774
|
for (const file of files) {
|
|
9738
9775
|
if (!SQLALCHEMY_IMPORT_RE.test(file.content)) continue;
|
|
9739
9776
|
const tree = parseSource6(parser, file.content);
|
|
@@ -9782,7 +9819,7 @@ function importsModelName(content, name) {
|
|
|
9782
9819
|
function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
9783
9820
|
const registry = buildSqlalchemyModelRegistry(files);
|
|
9784
9821
|
if (registry.size === 0) return [];
|
|
9785
|
-
const parser =
|
|
9822
|
+
const parser = makePyParser3();
|
|
9786
9823
|
const out = [];
|
|
9787
9824
|
const seen = /* @__PURE__ */ new Set();
|
|
9788
9825
|
for (const file of files) {
|
|
@@ -9820,7 +9857,7 @@ var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
|
|
|
9820
9857
|
var import_types30 = require("@neat.is/types");
|
|
9821
9858
|
var DJANGO_IMPORT_RE = /(?:from|import)\s+django\b/;
|
|
9822
9859
|
var PARSE_CHUNK7 = 16384;
|
|
9823
|
-
function
|
|
9860
|
+
function makePyParser4() {
|
|
9824
9861
|
const p = new import_tree_sitter10.default();
|
|
9825
9862
|
p.setLanguage(import_tree_sitter_python5.default);
|
|
9826
9863
|
return p;
|
|
@@ -9881,7 +9918,7 @@ function readMeta(body) {
|
|
|
9881
9918
|
}
|
|
9882
9919
|
function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
9883
9920
|
if (!DJANGO_IMPORT_RE.test(file.content)) return [];
|
|
9884
|
-
const tree = parseSource7(
|
|
9921
|
+
const tree = parseSource7(makePyParser4(), file.content);
|
|
9885
9922
|
const out = [];
|
|
9886
9923
|
const seen = /* @__PURE__ */ new Set();
|
|
9887
9924
|
const defaultAppLabel = import_node_path40.default.basename(import_node_path40.default.dirname(file.path));
|
|
@@ -9916,7 +9953,7 @@ var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"),
|
|
|
9916
9953
|
var import_types31 = require("@neat.is/types");
|
|
9917
9954
|
var DRIZZLE_IMPORT_RE = /drizzle-orm/;
|
|
9918
9955
|
var TABLE_BUILDERS = /* @__PURE__ */ new Set(["pgTable", "mysqlTable", "sqliteTable"]);
|
|
9919
|
-
function
|
|
9956
|
+
function parserForExt3(ext) {
|
|
9920
9957
|
const p = new import_tree_sitter11.default();
|
|
9921
9958
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript7.default);
|
|
9922
9959
|
return p;
|
|
@@ -9988,7 +10025,7 @@ function columnsFromObject(obj) {
|
|
|
9988
10025
|
}
|
|
9989
10026
|
function drizzleEndpointsFromFile(file, serviceDir) {
|
|
9990
10027
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
9991
|
-
const tree = parseSource3(
|
|
10028
|
+
const tree = parseSource3(parserForExt3(import_node_path41.default.extname(file.path)), file.content);
|
|
9992
10029
|
const out = [];
|
|
9993
10030
|
const seen = /* @__PURE__ */ new Set();
|
|
9994
10031
|
const walk9 = (node) => {
|
|
@@ -10077,7 +10114,7 @@ function referencesTargetVar(call) {
|
|
|
10077
10114
|
}
|
|
10078
10115
|
function drizzleForeignKeys(file, serviceDir) {
|
|
10079
10116
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
10080
|
-
const tree = parseSource3(
|
|
10117
|
+
const tree = parseSource3(parserForExt3(import_node_path41.default.extname(file.path)), file.content);
|
|
10081
10118
|
const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
|
|
10082
10119
|
const out = [];
|
|
10083
10120
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -12784,7 +12821,7 @@ var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"),
|
|
|
12784
12821
|
var import_types47 = require("@neat.is/types");
|
|
12785
12822
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
12786
12823
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
12787
|
-
function
|
|
12824
|
+
function parserForExt4(ext) {
|
|
12788
12825
|
const p = new import_tree_sitter16.default();
|
|
12789
12826
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
12790
12827
|
return p;
|
|
@@ -12873,7 +12910,7 @@ function topLevelSchemas(root) {
|
|
|
12873
12910
|
}
|
|
12874
12911
|
function zodShapesFromFile(file, serviceDir) {
|
|
12875
12912
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
12876
|
-
const tree = parseSource3(
|
|
12913
|
+
const tree = parseSource3(parserForExt4(import_node_path57.default.extname(file.path)), file.content);
|
|
12877
12914
|
const out = [];
|
|
12878
12915
|
const seen = /* @__PURE__ */ new Set();
|
|
12879
12916
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -18839,6 +18876,19 @@ async function startDaemon(opts = {}) {
|
|
|
18839
18876
|
let otlpAddress = "";
|
|
18840
18877
|
let daemonRecord = null;
|
|
18841
18878
|
if (bind) {
|
|
18879
|
+
let bareSpanIsRoutable2 = function(serviceName) {
|
|
18880
|
+
if (singleProject) {
|
|
18881
|
+
const slot = slots.get(singleProject);
|
|
18882
|
+
if (!slot) {
|
|
18883
|
+
return !serviceName || serviceNameMatchesProject(serviceName, singleProject);
|
|
18884
|
+
}
|
|
18885
|
+
return spanBelongsToSingleProject(slot.graph, singleProject, serviceName);
|
|
18886
|
+
}
|
|
18887
|
+
const entries = [...slots.values()].map((s) => s.entry);
|
|
18888
|
+
const target = routeSpanToProject(serviceName, entries);
|
|
18889
|
+
return slots.has(target) || slots.has(DEFAULT_PROJECT);
|
|
18890
|
+
};
|
|
18891
|
+
var bareSpanIsRoutable = bareSpanIsRoutable2;
|
|
18842
18892
|
const auth = readAuthEnv();
|
|
18843
18893
|
const host = resolveHost(opts, Boolean(auth.authToken));
|
|
18844
18894
|
const restPort = resolveRestPort(opts);
|
|
@@ -18936,6 +18986,20 @@ async function startDaemon(opts = {}) {
|
|
|
18936
18986
|
const liveEntries = await listProjects().catch(() => []);
|
|
18937
18987
|
let slot = slots.get(project);
|
|
18938
18988
|
if (!slot) {
|
|
18989
|
+
if (singleProject && project === singleProject) {
|
|
18990
|
+
slot = await tryRecoverSlot({
|
|
18991
|
+
name: singleProject,
|
|
18992
|
+
path: singleProjectPath,
|
|
18993
|
+
registeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18994
|
+
languages: [],
|
|
18995
|
+
status: "active"
|
|
18996
|
+
});
|
|
18997
|
+
if (!slot || slot.status !== "active") {
|
|
18998
|
+
warnDroppedSpan(singleProject, slot?.errorReason ?? "unknown");
|
|
18999
|
+
return null;
|
|
19000
|
+
}
|
|
19001
|
+
return slot;
|
|
19002
|
+
}
|
|
18939
19003
|
await recordUnroutedSpan(serviceName, traceId);
|
|
18940
19004
|
return null;
|
|
18941
19005
|
}
|
|
@@ -19002,7 +19066,30 @@ async function startDaemon(opts = {}) {
|
|
|
19002
19066
|
// host, rather than accepting it and dropping the batch. `slots` covers
|
|
19003
19067
|
// active/recovering projects, `bootstrapStatus` the ones still
|
|
19004
19068
|
// extracting; a foreign or wrong-cased project name matches neither.
|
|
19005
|
-
|
|
19069
|
+
// A single-project daemon owns exactly one project by definition, so its
|
|
19070
|
+
// own name always counts as registered even before loadAll populates the
|
|
19071
|
+
// slot — otherwise a scoped span arriving during cold-start would 404 and
|
|
19072
|
+
// be lost (OTLP does not retry 4xx). resolveSlotByName then builds it (#879).
|
|
19073
|
+
isProjectRegistered: (project) => slots.has(project) || bootstrapStatus.has(project) || singleProject !== void 0 && project === singleProject,
|
|
19074
|
+
// #881 — the bare `/v1/traces` route replies before the span is routed
|
|
19075
|
+
// (off the queue), so tell the receiver, per batch, how many spans will
|
|
19076
|
+
// land on no project. It keeps the 200 but reports those as
|
|
19077
|
+
// partialSuccess.rejectedSpans instead of an empty partialSuccess that an
|
|
19078
|
+
// exporter reads as full acceptance. Pure — the drop + unrouted-ledger
|
|
19079
|
+
// write still happen on the async onSpan path.
|
|
19080
|
+
classifyBareRoutability: (spans) => {
|
|
19081
|
+
let rejected = 0;
|
|
19082
|
+
for (const span of spans) {
|
|
19083
|
+
if (!bareSpanIsRoutable2(span.service)) rejected++;
|
|
19084
|
+
}
|
|
19085
|
+
if (rejected === 0) return { rejected: 0 };
|
|
19086
|
+
const noun = rejected === 1 ? "span" : "spans";
|
|
19087
|
+
const verb = rejected === 1 ? "was" : "were";
|
|
19088
|
+
return {
|
|
19089
|
+
rejected,
|
|
19090
|
+
message: `${rejected} ${noun} matched no project on this daemon and ${verb} dropped. Export to /projects/<project>/v1/traces, or check the exporter's service.name.`
|
|
19091
|
+
};
|
|
19092
|
+
}
|
|
19006
19093
|
});
|
|
19007
19094
|
otlpAddress = await listenSteppingOtlp(otlpApp, otlpPort, host);
|
|
19008
19095
|
console.log(`neatd: OTLP listening on ${otlpAddress}/v1/traces`);
|