@neat.is/core 0.9.1 → 0.9.2-dev.20260822

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/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  routeSpanToProject,
3
3
  startDaemon
4
- } from "./chunk-YKQB622D.js";
4
+ } from "./chunk-L4SZIIER.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-UN7VFA4H.js";
40
+ } from "./chunk-RQQUI3NQ.js";
41
41
  import {
42
42
  startOtelGrpcReceiver
43
- } from "./chunk-FCO5Z3RW.js";
43
+ } from "./chunk-ERE47MCR.js";
44
44
  import {
45
45
  buildOtelReceiver,
46
46
  logSpanHandler,
47
47
  parseOtlpRequest
48
- } from "./chunk-UUYCTH2E.js";
48
+ } from "./chunk-GDGUY4T6.js";
49
49
  export {
50
50
  ProjectNameCollisionError,
51
51
  addProject,
package/dist/neatd.cjs CHANGED
@@ -526,11 +526,42 @@ async function decodeProtobufBody(buf) {
526
526
  const { reshapeGrpcRequest: reshapeGrpcRequest2 } = await Promise.resolve().then(() => (init_otel_grpc(), otel_grpc_exports));
527
527
  return reshapeGrpcRequest2(decoded);
528
528
  }
529
+ function decompressorForEncoding(encoding) {
530
+ switch (encoding) {
531
+ case "gzip":
532
+ case "x-gzip":
533
+ return import_node_zlib.default.createGunzip();
534
+ case "deflate":
535
+ return import_node_zlib.default.createInflate();
536
+ default:
537
+ return null;
538
+ }
539
+ }
529
540
  async function buildOtelReceiver(opts) {
530
541
  const app = (0, import_fastify.default)({
531
542
  logger: false,
532
543
  bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024
533
544
  });
545
+ app.addHook("preParsing", (req2, _reply, payload, done) => {
546
+ const encoding = (req2.headers["content-encoding"] ?? "").toString().trim().toLowerCase();
547
+ if (encoding === "" || encoding === "identity") {
548
+ done(null, payload);
549
+ return;
550
+ }
551
+ const decompressor = decompressorForEncoding(encoding);
552
+ if (!decompressor) {
553
+ done(null, payload);
554
+ return;
555
+ }
556
+ const tracked = decompressor;
557
+ tracked.receivedEncodedLength = 0;
558
+ payload.on("data", (chunk) => {
559
+ tracked.receivedEncodedLength = (tracked.receivedEncodedLength ?? 0) + chunk.length;
560
+ });
561
+ payload.on("error", (err) => decompressor.destroy(err));
562
+ payload.pipe(decompressor);
563
+ done(null, decompressor);
564
+ });
534
565
  const REJECT_WARN_INTERVAL_MS = 6e4;
535
566
  let lastRejectWarnAt = 0;
536
567
  const warnRejectedOtlp = () => {
@@ -728,13 +759,14 @@ async function listenSteppingOtlp(app, requestedPort, host) {
728
759
  }
729
760
  }
730
761
  }
731
- var import_node_path53, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
762
+ var import_node_path53, import_node_url2, import_node_zlib, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
732
763
  var init_otel = __esm({
733
764
  "src/otel.ts"() {
734
765
  "use strict";
735
766
  init_cjs_shims();
736
767
  import_node_path53 = __toESM(require("path"), 1);
737
768
  import_node_url2 = require("url");
769
+ import_node_zlib = __toESM(require("zlib"), 1);
738
770
  import_fastify = __toESM(require("fastify"), 1);
739
771
  import_protobufjs = __toESM(require("protobufjs"), 1);
740
772
  init_auth();
@@ -5485,6 +5517,14 @@ function grpcStatusCodeFromAttrs(attrs) {
5485
5517
  }
5486
5518
  return void 0;
5487
5519
  }
5520
+ function spanRecordsError(span) {
5521
+ if (span.statusCode === 2) return true;
5522
+ const grpc2 = grpcStatusCodeFromAttrs(span.attributes);
5523
+ if (grpc2 !== void 0 && grpc2 !== 0) return true;
5524
+ const httpStatus = httpResponseStatusFromAttrs(span.attributes);
5525
+ if (httpStatus !== void 0 && httpStatus >= 500) return true;
5526
+ return false;
5527
+ }
5488
5528
  function nonHttpFailureMessageFromAttrs(attrs) {
5489
5529
  const grpc2 = grpcStatusCodeFromAttrs(attrs);
5490
5530
  if (grpc2 !== void 0 && grpc2 !== 0) {
@@ -6283,6 +6323,21 @@ async function recordExceptionIncident(ctx, span, ts) {
6283
6323
  };
6284
6324
  await appendErrorEvent(ctx, ev);
6285
6325
  }
6326
+ async function recordGrpcFailureIncident(ctx, span, ts) {
6327
+ const attrs = sanitizeAttributes(span.attributes);
6328
+ const ev = {
6329
+ id: `${span.traceId}:${span.spanId}`,
6330
+ timestamp: ts,
6331
+ service: span.service,
6332
+ traceId: span.traceId,
6333
+ spanId: span.spanId,
6334
+ errorType: "grpc-failure",
6335
+ errorMessage: incidentMessage(span),
6336
+ ...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
6337
+ affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath)
6338
+ };
6339
+ await appendErrorEvent(ctx, ev);
6340
+ }
6286
6341
  async function advance4xxBurst(ctx, span, affectedNode, ts, nowMs, status2) {
6287
6342
  const { threshold, windowMs } = loadIncidentThresholdsFromEnv();
6288
6343
  if (!ctx.burstState) ctx.burstState = /* @__PURE__ */ new Map();
@@ -6353,7 +6408,7 @@ async function handleSpan(ctx, span) {
6353
6408
  warnUnidentifiedSpan(ctx.project ?? DEFAULT_PROJECT);
6354
6409
  }
6355
6410
  const sourceId = ensureServiceNode(ctx.graph, span.service, env);
6356
- const isError = span.statusCode === 2;
6411
+ const isError = spanRecordsError(span);
6357
6412
  const durationMs = span.durationNanos > 0n && !spanIsStreaming(span) ? Number(span.durationNanos) / 1e6 : void 0;
6358
6413
  const sourceServiceNode = ctx.graph.getNodeAttributes(sourceId);
6359
6414
  const callSite = callSiteFromSpan(span, sourceServiceNode, ctx.scanPath);
@@ -6589,10 +6644,13 @@ async function handleSpan(ctx, span) {
6589
6644
  }
6590
6645
  if (span.statusCode !== 2) {
6591
6646
  const status2 = httpResponseStatus(span);
6647
+ const grpcStatus = grpcStatusCodeFromAttrs(span.attributes);
6592
6648
  if (span.exception) {
6593
6649
  await recordExceptionIncident(ctx, span, ts);
6594
6650
  } else if (status2 !== void 0 && status2 >= 500) {
6595
6651
  await recordFailingResponseIncident(ctx, span, sourceId, ts, status2, 1);
6652
+ } else if (grpcStatus !== void 0 && grpcStatus !== 0) {
6653
+ await recordGrpcFailureIncident(ctx, span, ts);
6596
6654
  } else if (status2 !== void 0 && status2 >= 400 && spanMintsObservedEdge(span.kind)) {
6597
6655
  await advance4xxBurst(ctx, span, sourceId, ts, nowMs, status2);
6598
6656
  }