@neat.is/core 0.2.5
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/compat.json +120 -0
- package/dist/chunk-6JT6L2OV.js +164 -0
- package/dist/chunk-6JT6L2OV.js.map +1 -0
- package/dist/chunk-6SFEITLJ.js +3371 -0
- package/dist/chunk-6SFEITLJ.js.map +1 -0
- package/dist/chunk-I5IMCXRO.js +325 -0
- package/dist/chunk-I5IMCXRO.js.map +1 -0
- package/dist/chunk-T2U4U256.js +462 -0
- package/dist/chunk-T2U4U256.js.map +1 -0
- package/dist/chunk-WX55TLUT.js +184 -0
- package/dist/chunk-WX55TLUT.js.map +1 -0
- package/dist/chunk-XOOCA5T7.js +290 -0
- package/dist/chunk-XOOCA5T7.js.map +1 -0
- package/dist/cli.cjs +5754 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +36 -0
- package/dist/cli.d.ts +36 -0
- package/dist/cli.js +1175 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +4552 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +408 -0
- package/dist/index.d.ts +408 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/neatd.cjs +3070 -0
- package/dist/neatd.cjs.map +1 -0
- package/dist/neatd.d.cts +1 -0
- package/dist/neatd.d.ts +1 -0
- package/dist/neatd.js +114 -0
- package/dist/neatd.js.map +1 -0
- package/dist/otel-grpc-B4XBSI4W.js +9 -0
- package/dist/otel-grpc-B4XBSI4W.js.map +1 -0
- package/dist/server.cjs +4499 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +2 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +97 -0
- package/dist/server.js.map +1 -0
- package/package.json +77 -0
- package/proto/opentelemetry/proto/collector/trace/v1/trace_service.proto +31 -0
- package/proto/opentelemetry/proto/common/v1/common.proto +46 -0
- package/proto/opentelemetry/proto/resource/v1/resource.proto +19 -0
- package/proto/opentelemetry/proto/trace/v1/trace.proto +93 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
// src/otel-grpc.ts
|
|
2
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3
|
+
import path2 from "path";
|
|
4
|
+
import * as grpc from "@grpc/grpc-js";
|
|
5
|
+
import * as protoLoader from "@grpc/proto-loader";
|
|
6
|
+
|
|
7
|
+
// src/otel.ts
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
import Fastify from "fastify";
|
|
11
|
+
import protobuf from "protobufjs";
|
|
12
|
+
function extractExceptionFromEvents(events) {
|
|
13
|
+
if (!events) return void 0;
|
|
14
|
+
for (const ev of events) {
|
|
15
|
+
if (ev.name !== "exception") continue;
|
|
16
|
+
const attrs = attrsToRecord(ev.attributes);
|
|
17
|
+
const out = {};
|
|
18
|
+
const t = attrs["exception.type"];
|
|
19
|
+
const m = attrs["exception.message"];
|
|
20
|
+
const s = attrs["exception.stacktrace"];
|
|
21
|
+
if (typeof t === "string") out.type = t;
|
|
22
|
+
if (typeof m === "string") out.message = m;
|
|
23
|
+
if (typeof s === "string") out.stacktrace = s;
|
|
24
|
+
if (out.type || out.message || out.stacktrace) return out;
|
|
25
|
+
}
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
function flattenAttribute(v) {
|
|
29
|
+
if (!v) return null;
|
|
30
|
+
if (v.stringValue !== void 0) return v.stringValue;
|
|
31
|
+
if (v.boolValue !== void 0) return v.boolValue;
|
|
32
|
+
if (v.intValue !== void 0) {
|
|
33
|
+
return typeof v.intValue === "string" ? Number(v.intValue) : v.intValue;
|
|
34
|
+
}
|
|
35
|
+
if (v.doubleValue !== void 0) return v.doubleValue;
|
|
36
|
+
if (v.arrayValue?.values) {
|
|
37
|
+
return v.arrayValue.values.map((x) => flattenAttribute(x));
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function attrsToRecord(attrs) {
|
|
42
|
+
const out = {};
|
|
43
|
+
if (!attrs) return out;
|
|
44
|
+
for (const kv of attrs) {
|
|
45
|
+
if (kv.key) out[kv.key] = flattenAttribute(kv.value);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
function durationNanos(start, end) {
|
|
50
|
+
if (!start || !end) return 0n;
|
|
51
|
+
try {
|
|
52
|
+
return BigInt(end) - BigInt(start);
|
|
53
|
+
} catch {
|
|
54
|
+
return 0n;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function isoFromUnixNano(nanos) {
|
|
58
|
+
if (!nanos || nanos === "0") return void 0;
|
|
59
|
+
try {
|
|
60
|
+
const ms = Number(BigInt(nanos) / 1000000n);
|
|
61
|
+
if (!Number.isFinite(ms)) return void 0;
|
|
62
|
+
return new Date(ms).toISOString();
|
|
63
|
+
} catch {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function parseOtlpRequest(body) {
|
|
68
|
+
const out = [];
|
|
69
|
+
for (const rs of body.resourceSpans ?? []) {
|
|
70
|
+
const resourceAttrs = attrsToRecord(rs.resource?.attributes);
|
|
71
|
+
const service = typeof resourceAttrs["service.name"] === "string" ? resourceAttrs["service.name"] : "unknown";
|
|
72
|
+
for (const ss of rs.scopeSpans ?? []) {
|
|
73
|
+
for (const span of ss.spans ?? []) {
|
|
74
|
+
const attrs = attrsToRecord(span.attributes);
|
|
75
|
+
const parsed = {
|
|
76
|
+
service,
|
|
77
|
+
traceId: span.traceId ?? "",
|
|
78
|
+
spanId: span.spanId ?? "",
|
|
79
|
+
parentSpanId: span.parentSpanId || void 0,
|
|
80
|
+
name: span.name ?? "",
|
|
81
|
+
kind: span.kind,
|
|
82
|
+
startTimeUnixNano: span.startTimeUnixNano ?? "0",
|
|
83
|
+
endTimeUnixNano: span.endTimeUnixNano ?? "0",
|
|
84
|
+
startTimeIso: isoFromUnixNano(span.startTimeUnixNano),
|
|
85
|
+
durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),
|
|
86
|
+
attributes: attrs,
|
|
87
|
+
dbSystem: typeof attrs["db.system"] === "string" ? attrs["db.system"] : void 0,
|
|
88
|
+
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
89
|
+
statusCode: span.status?.code,
|
|
90
|
+
errorMessage: span.status?.message,
|
|
91
|
+
exception: extractExceptionFromEvents(span.events)
|
|
92
|
+
};
|
|
93
|
+
out.push(parsed);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
var exportTraceServiceRequestType = null;
|
|
100
|
+
function loadProtobufDecoder() {
|
|
101
|
+
if (exportTraceServiceRequestType) return exportTraceServiceRequestType;
|
|
102
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
103
|
+
const protoRoot = path.resolve(here, "..", "proto");
|
|
104
|
+
const root = new protobuf.Root();
|
|
105
|
+
root.resolvePath = (_origin, target) => path.resolve(protoRoot, target);
|
|
106
|
+
root.loadSync(
|
|
107
|
+
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
108
|
+
{ keepCase: true }
|
|
109
|
+
);
|
|
110
|
+
exportTraceServiceRequestType = root.lookupType(
|
|
111
|
+
"opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest"
|
|
112
|
+
);
|
|
113
|
+
return exportTraceServiceRequestType;
|
|
114
|
+
}
|
|
115
|
+
async function decodeProtobufBody(buf) {
|
|
116
|
+
const Type = loadProtobufDecoder();
|
|
117
|
+
const decoded = Type.decode(buf).toJSON();
|
|
118
|
+
const { reshapeGrpcRequest: reshapeGrpcRequest2 } = await import("./otel-grpc-B4XBSI4W.js");
|
|
119
|
+
return reshapeGrpcRequest2(decoded);
|
|
120
|
+
}
|
|
121
|
+
async function buildOtelReceiver(opts) {
|
|
122
|
+
const app = Fastify({
|
|
123
|
+
logger: false,
|
|
124
|
+
bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024
|
|
125
|
+
});
|
|
126
|
+
const queue = [];
|
|
127
|
+
let draining = false;
|
|
128
|
+
let drainPromise = Promise.resolve();
|
|
129
|
+
const drain = async () => {
|
|
130
|
+
if (draining) return;
|
|
131
|
+
draining = true;
|
|
132
|
+
try {
|
|
133
|
+
while (queue.length > 0) {
|
|
134
|
+
const span = queue.shift();
|
|
135
|
+
try {
|
|
136
|
+
await opts.onSpan(span);
|
|
137
|
+
} catch (err) {
|
|
138
|
+
console.warn(`[neat] otel handler error: ${err.message}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} finally {
|
|
142
|
+
draining = false;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const enqueue = (spans) => {
|
|
146
|
+
if (spans.length === 0) return;
|
|
147
|
+
for (const s of spans) queue.push(s);
|
|
148
|
+
drainPromise = drainPromise.then(() => drain());
|
|
149
|
+
};
|
|
150
|
+
app.addContentTypeParser(
|
|
151
|
+
"application/x-protobuf",
|
|
152
|
+
{ parseAs: "buffer", bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024 },
|
|
153
|
+
(_req, body, done) => {
|
|
154
|
+
done(null, body);
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
app.get("/health", async () => ({ ok: true }));
|
|
158
|
+
app.post("/v1/traces", async (req, reply) => {
|
|
159
|
+
const ct = (req.headers["content-type"] ?? "").toString().split(";")[0].trim().toLowerCase();
|
|
160
|
+
let body;
|
|
161
|
+
if (ct === "application/x-protobuf") {
|
|
162
|
+
try {
|
|
163
|
+
body = await decodeProtobufBody(req.body);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
return reply.code(400).send({
|
|
166
|
+
error: `protobuf decode failed: ${err.message}`
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
} else if (!ct || ct === "application/json") {
|
|
170
|
+
body = req.body ?? {};
|
|
171
|
+
} else {
|
|
172
|
+
return reply.code(415).send({ error: `unsupported content-type: ${ct}` });
|
|
173
|
+
}
|
|
174
|
+
const spans = parseOtlpRequest(body);
|
|
175
|
+
if (opts.onErrorSpanSync) {
|
|
176
|
+
try {
|
|
177
|
+
for (const span of spans) {
|
|
178
|
+
if (span.statusCode === 2) await opts.onErrorSpanSync(span);
|
|
179
|
+
}
|
|
180
|
+
} catch (err) {
|
|
181
|
+
return reply.code(500).send({
|
|
182
|
+
error: `error-event write failed: ${err.message}`
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
enqueue(spans);
|
|
187
|
+
return reply.code(200).send({ partialSuccess: {} });
|
|
188
|
+
});
|
|
189
|
+
const decorated = app;
|
|
190
|
+
decorated.flushPending = async () => {
|
|
191
|
+
while (queue.length > 0 || draining) {
|
|
192
|
+
await drainPromise;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
return decorated;
|
|
196
|
+
}
|
|
197
|
+
function logSpanHandler(span) {
|
|
198
|
+
const parent = span.parentSpanId ? span.parentSpanId.slice(0, 8) : "<root>";
|
|
199
|
+
const status2 = span.statusCode === 2 ? "ERROR" : "OK";
|
|
200
|
+
const db = span.dbSystem ? ` db=${span.dbSystem}/${span.dbName ?? "?"}` : "";
|
|
201
|
+
console.log(
|
|
202
|
+
`otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/otel-grpc.ts
|
|
207
|
+
function bytesToHex(buf) {
|
|
208
|
+
if (!buf) return "";
|
|
209
|
+
return Buffer.isBuffer(buf) ? buf.toString("hex") : "";
|
|
210
|
+
}
|
|
211
|
+
function nanosToString(n) {
|
|
212
|
+
if (n === void 0 || n === null) return "0";
|
|
213
|
+
return typeof n === "string" ? n : String(n);
|
|
214
|
+
}
|
|
215
|
+
function reshapeAttributes(attrs) {
|
|
216
|
+
const out = (attrs ?? []).map((kv) => ({
|
|
217
|
+
key: kv.key ?? "",
|
|
218
|
+
value: kv.value ? {
|
|
219
|
+
stringValue: kv.value.string_value,
|
|
220
|
+
boolValue: kv.value.bool_value,
|
|
221
|
+
intValue: kv.value.int_value,
|
|
222
|
+
doubleValue: kv.value.double_value,
|
|
223
|
+
arrayValue: kv.value.array_value ? {
|
|
224
|
+
values: (kv.value.array_value.values ?? []).map((v) => ({
|
|
225
|
+
stringValue: v.string_value,
|
|
226
|
+
boolValue: v.bool_value,
|
|
227
|
+
intValue: v.int_value,
|
|
228
|
+
doubleValue: v.double_value
|
|
229
|
+
}))
|
|
230
|
+
} : void 0
|
|
231
|
+
} : void 0
|
|
232
|
+
}));
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
function reshapeGrpcRequest(req) {
|
|
236
|
+
return {
|
|
237
|
+
resourceSpans: (req.resource_spans ?? []).map((rs) => ({
|
|
238
|
+
resource: rs.resource ? { attributes: reshapeAttributes(rs.resource.attributes) } : void 0,
|
|
239
|
+
scopeSpans: (rs.scope_spans ?? []).map((ss) => ({
|
|
240
|
+
spans: (ss.spans ?? []).map((s) => ({
|
|
241
|
+
traceId: bytesToHex(s.trace_id),
|
|
242
|
+
spanId: bytesToHex(s.span_id),
|
|
243
|
+
parentSpanId: s.parent_span_id ? bytesToHex(s.parent_span_id) : void 0,
|
|
244
|
+
name: s.name,
|
|
245
|
+
kind: s.kind,
|
|
246
|
+
startTimeUnixNano: nanosToString(s.start_time_unix_nano),
|
|
247
|
+
endTimeUnixNano: nanosToString(s.end_time_unix_nano),
|
|
248
|
+
attributes: reshapeAttributes(s.attributes),
|
|
249
|
+
events: (s.events ?? []).map((e) => ({
|
|
250
|
+
name: e.name,
|
|
251
|
+
timeUnixNano: nanosToString(e.time_unix_nano),
|
|
252
|
+
attributes: reshapeAttributes(e.attributes)
|
|
253
|
+
})),
|
|
254
|
+
status: s.status ? { code: s.status.code, message: s.status.message } : void 0
|
|
255
|
+
}))
|
|
256
|
+
}))
|
|
257
|
+
}))
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function resolveProtoRoot() {
|
|
261
|
+
const here = path2.dirname(fileURLToPath2(import.meta.url));
|
|
262
|
+
return path2.resolve(here, "..", "proto");
|
|
263
|
+
}
|
|
264
|
+
function loadTraceService() {
|
|
265
|
+
const protoRoot = resolveProtoRoot();
|
|
266
|
+
const def = protoLoader.loadSync(
|
|
267
|
+
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
268
|
+
{
|
|
269
|
+
keepCase: true,
|
|
270
|
+
longs: String,
|
|
271
|
+
enums: Number,
|
|
272
|
+
defaults: true,
|
|
273
|
+
oneofs: true,
|
|
274
|
+
includeDirs: [protoRoot]
|
|
275
|
+
}
|
|
276
|
+
);
|
|
277
|
+
const pkg = grpc.loadPackageDefinition(def);
|
|
278
|
+
return pkg.opentelemetry.proto.collector.trace.v1.TraceService.service;
|
|
279
|
+
}
|
|
280
|
+
async function startOtelGrpcReceiver(opts) {
|
|
281
|
+
const server = new grpc.Server();
|
|
282
|
+
const service = loadTraceService();
|
|
283
|
+
server.addService(service, {
|
|
284
|
+
Export: (call, callback) => {
|
|
285
|
+
void (async () => {
|
|
286
|
+
try {
|
|
287
|
+
const reshaped = reshapeGrpcRequest(call.request ?? {});
|
|
288
|
+
const spans = parseOtlpRequest(reshaped);
|
|
289
|
+
for (const span of spans) {
|
|
290
|
+
await opts.onSpan(span);
|
|
291
|
+
}
|
|
292
|
+
callback(null, { partial_success: {} });
|
|
293
|
+
} catch (err) {
|
|
294
|
+
callback({
|
|
295
|
+
code: grpc.status.INTERNAL,
|
|
296
|
+
message: err instanceof Error ? err.message : String(err)
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
})();
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
const host = opts.host ?? "0.0.0.0";
|
|
303
|
+
const port = opts.port ?? 4317;
|
|
304
|
+
const boundPort = await new Promise((resolve, reject) => {
|
|
305
|
+
server.bindAsync(`${host}:${port}`, grpc.ServerCredentials.createInsecure(), (err, p) => {
|
|
306
|
+
if (err) return reject(err);
|
|
307
|
+
resolve(p);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
return {
|
|
311
|
+
address: `${host}:${boundPort}`,
|
|
312
|
+
stop: () => new Promise((resolve) => {
|
|
313
|
+
server.tryShutdown(() => resolve());
|
|
314
|
+
})
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export {
|
|
319
|
+
reshapeGrpcRequest,
|
|
320
|
+
startOtelGrpcReceiver,
|
|
321
|
+
parseOtlpRequest,
|
|
322
|
+
buildOtelReceiver,
|
|
323
|
+
logSpanHandler
|
|
324
|
+
};
|
|
325
|
+
//# sourceMappingURL=chunk-I5IMCXRO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/otel-grpc.ts","../src/otel.ts"],"sourcesContent":["import { fileURLToPath } from 'node:url'\nimport path from 'node:path'\nimport * as grpc from '@grpc/grpc-js'\nimport * as protoLoader from '@grpc/proto-loader'\nimport {\n parseOtlpRequest,\n type OtlpTracesRequest,\n type ParsedSpan,\n type SpanHandler,\n} from './otel.js'\n\n// OTLP/gRPC receiver. Sits next to buildOtelReceiver (HTTP/JSON) in otel.ts;\n// shares the same parseOtlpRequest decoder so a span looks identical to the\n// downstream onSpan handler whether it came in over JSON or protobuf.\n//\n// Default OFF — opts.enabled (typically NEAT_OTLP_GRPC=true) decides whether\n// server.ts wires this up. We keep gRPC behind a flag so existing HTTP-only\n// deployments don't get a surprise port binding on upgrade.\n\nexport interface BuildOtelGrpcReceiverOptions {\n onSpan: SpanHandler\n}\n\n// proto-loader output for the trace service has fields like resource_spans,\n// scope_spans, span_id, etc. (snake_case keys, since we leave keepCase: true\n// when loading). The HTTP path uses camelCase JSON, so we shape-shift the\n// gRPC payload onto the HTTP shape and let parseOtlpRequest do the rest.\n//\n// All `bytes` fields arrive as Buffers; the HTTP wire format encodes them as\n// hex strings, so we hex-encode for consistency.\n\ninterface GrpcAnyValue {\n string_value?: string\n bool_value?: boolean\n int_value?: string | number\n double_value?: number\n array_value?: { values?: GrpcAnyValue[] }\n // bytes/kvlist fields exist in the proto but the demo doesn't use them.\n}\n\ninterface GrpcKeyValue {\n key?: string\n value?: GrpcAnyValue\n}\n\ninterface GrpcStatus {\n code?: number\n message?: string\n}\n\ninterface GrpcEvent {\n name?: string\n time_unix_nano?: string | number\n attributes?: GrpcKeyValue[]\n}\n\ninterface GrpcSpan {\n trace_id?: Buffer\n span_id?: Buffer\n parent_span_id?: Buffer\n name?: string\n kind?: number\n start_time_unix_nano?: string | number\n end_time_unix_nano?: string | number\n attributes?: GrpcKeyValue[]\n events?: GrpcEvent[]\n status?: GrpcStatus\n}\n\ninterface GrpcScopeSpans {\n spans?: GrpcSpan[]\n}\n\ninterface GrpcResourceSpans {\n resource?: { attributes?: GrpcKeyValue[] }\n scope_spans?: GrpcScopeSpans[]\n}\n\ninterface GrpcExportRequest {\n resource_spans?: GrpcResourceSpans[]\n}\n\nfunction bytesToHex(buf: Buffer | undefined): string {\n if (!buf) return ''\n return Buffer.isBuffer(buf) ? buf.toString('hex') : ''\n}\n\nfunction nanosToString(n: string | number | undefined): string {\n if (n === undefined || n === null) return '0'\n return typeof n === 'string' ? n : String(n)\n}\n\nfunction reshapeAttributes(\n attrs: GrpcKeyValue[] | undefined,\n): OtlpTracesRequest['resourceSpans'] extends Array<infer R>\n ? R extends { resource?: { attributes?: infer A } }\n ? A\n : never\n : never {\n // Map snake_case oneof fields to the camelCase the JSON path expects.\n const out = (attrs ?? []).map((kv) => ({\n key: kv.key ?? '',\n value: kv.value\n ? {\n stringValue: kv.value.string_value,\n boolValue: kv.value.bool_value,\n intValue: kv.value.int_value,\n doubleValue: kv.value.double_value,\n arrayValue: kv.value.array_value\n ? {\n values: (kv.value.array_value.values ?? []).map((v) => ({\n stringValue: v.string_value,\n boolValue: v.bool_value,\n intValue: v.int_value,\n doubleValue: v.double_value,\n })),\n }\n : undefined,\n }\n : undefined,\n }))\n return out as never\n}\n\nexport function reshapeGrpcRequest(req: GrpcExportRequest): OtlpTracesRequest {\n return {\n resourceSpans: (req.resource_spans ?? []).map((rs) => ({\n resource: rs.resource ? { attributes: reshapeAttributes(rs.resource.attributes) } : undefined,\n scopeSpans: (rs.scope_spans ?? []).map((ss) => ({\n spans: (ss.spans ?? []).map((s) => ({\n traceId: bytesToHex(s.trace_id),\n spanId: bytesToHex(s.span_id),\n parentSpanId: s.parent_span_id ? bytesToHex(s.parent_span_id) : undefined,\n name: s.name,\n kind: s.kind,\n startTimeUnixNano: nanosToString(s.start_time_unix_nano),\n endTimeUnixNano: nanosToString(s.end_time_unix_nano),\n attributes: reshapeAttributes(s.attributes),\n events: (s.events ?? []).map((e) => ({\n name: e.name,\n timeUnixNano: nanosToString(e.time_unix_nano),\n attributes: reshapeAttributes(e.attributes),\n })),\n status: s.status ? { code: s.status.code, message: s.status.message } : undefined,\n })),\n })),\n })),\n }\n}\n\n// Find the bundled .proto tree at packages/core/proto/. The dev server runs\n// from the source tree (tsx); the built bundles run from dist/. tsup keeps\n// source layout, so __dirname-relative resolution works for both — we look two\n// levels up from this file.\nfunction resolveProtoRoot(): string {\n // Built output (CJS) sets __dirname natively; ESM build is bundled by tsup\n // and keeps a dirname injection. import.meta.url is the safe bet.\n const here = path.dirname(fileURLToPath(import.meta.url))\n // src/ → packages/core/proto/, dist/ → packages/core/proto/.\n return path.resolve(here, '..', 'proto')\n}\n\nfunction loadTraceService(): grpc.ServiceDefinition {\n const protoRoot = resolveProtoRoot()\n const def = protoLoader.loadSync(\n 'opentelemetry/proto/collector/trace/v1/trace_service.proto',\n {\n keepCase: true,\n longs: String,\n enums: Number,\n defaults: true,\n oneofs: true,\n includeDirs: [protoRoot],\n },\n )\n const pkg = grpc.loadPackageDefinition(def) as unknown as {\n opentelemetry: {\n proto: {\n collector: {\n trace: {\n v1: {\n TraceService: { service: grpc.ServiceDefinition }\n }\n }\n }\n }\n }\n }\n return pkg.opentelemetry.proto.collector.trace.v1.TraceService.service\n}\n\nexport interface OtelGrpcReceiver {\n // Bound address (host:port) once .start() has resolved. Useful for tests.\n address: string\n // Stop accepting new requests, shut down the server.\n stop: () => Promise<void>\n}\n\nexport async function startOtelGrpcReceiver(\n opts: BuildOtelGrpcReceiverOptions & { host?: string; port?: number },\n): Promise<OtelGrpcReceiver> {\n const server = new grpc.Server()\n const service = loadTraceService()\n\n server.addService(service, {\n Export: (\n call: grpc.ServerUnaryCall<GrpcExportRequest, unknown>,\n callback: grpc.sendUnaryData<{ partial_success: object }>,\n ) => {\n void (async () => {\n try {\n const reshaped = reshapeGrpcRequest(call.request ?? {})\n const spans: ParsedSpan[] = parseOtlpRequest(reshaped)\n for (const span of spans) {\n await opts.onSpan(span)\n }\n callback(null, { partial_success: {} })\n } catch (err) {\n callback({\n code: grpc.status.INTERNAL,\n message: err instanceof Error ? err.message : String(err),\n })\n }\n })()\n },\n })\n\n const host = opts.host ?? '0.0.0.0'\n const port = opts.port ?? 4317\n\n const boundPort = await new Promise<number>((resolve, reject) => {\n server.bindAsync(`${host}:${port}`, grpc.ServerCredentials.createInsecure(), (err, p) => {\n if (err) return reject(err)\n resolve(p)\n })\n })\n\n return {\n address: `${host}:${boundPort}`,\n stop: () =>\n new Promise<void>((resolve) => {\n server.tryShutdown(() => resolve())\n }),\n }\n}\n","import path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport Fastify, { type FastifyInstance } from 'fastify'\nimport protobuf from 'protobufjs'\n\n// OTLP/HTTP receiver. Listens on /v1/traces and decodes the JSON wire format\n// (collector's `otlphttp` exporter with `encoding: json`). Each span is\n// flattened into a ParsedSpan and handed to the configured handler. The\n// handler is the seam #8 wires its edge mapper into; #7 itself stays decoupled\n// from graph mutation.\n\nexport interface ParsedSpan {\n service: string\n traceId: string\n spanId: string\n parentSpanId?: string\n name: string\n kind?: number\n startTimeUnixNano: string\n endTimeUnixNano: string\n // ISO8601 derived from startTimeUnixNano. Production paths (lastObserved on\n // OBSERVED edges) read this so the recorded time reflects when the span fired,\n // not when the receiver received it. Undefined only when startTimeUnixNano is\n // missing or unparseable — handler falls back to wall-clock in that case.\n // See docs/contracts/otel-ingest.md §lastObserved-from-span-time.\n startTimeIso?: string\n // bigint so the 9-digit-nanos arithmetic doesn't lose precision on long traces.\n durationNanos: bigint\n attributes: Record<string, AttributeValue>\n // Convenience accessors for the attributes #8 cares about.\n dbSystem?: string\n dbName?: string\n // 0 = UNSET, 1 = OK, 2 = ERROR per OTLP. We only care that 2 means error.\n statusCode?: number\n errorMessage?: string\n // Pre-extracted from a span event with name=\"exception\". OTLP SDKs record\n // exceptions this way (richer than status.message). handleSpan reads these\n // first, falling back to status.message and span.name. See\n // docs/contracts/otel-ingest.md §exception-data-from-span-events.\n exception?: {\n type?: string\n message?: string\n stacktrace?: string\n }\n}\n\nexport type AttributeValue =\n | string\n | number\n | boolean\n | bigint\n | string[]\n | number[]\n | boolean[]\n | null\n\nexport type SpanHandler = (span: ParsedSpan) => void | Promise<void>\n\nexport interface BuildOtelReceiverOptions {\n onSpan: SpanHandler\n // Synchronous handler for spans with statusCode === 2. The receiver awaits\n // it before replying, so a write failure can return 500 → OTel SDK retries.\n // Optional — wiring is expected to plumb appendErrorEvent here when error\n // durability matters; ad-hoc receivers leave it undefined.\n // See docs/contracts/otel-ingest.md §Error events.\n onErrorSpanSync?: (span: ParsedSpan) => Promise<void>\n // Fastify body limit. OTLP batches can be large; default is 16 MB.\n bodyLimit?: number\n}\n\ninterface OtlpKeyValue {\n key: string\n value?: OtlpAnyValue\n}\n\ninterface OtlpAnyValue {\n stringValue?: string\n intValue?: string | number\n doubleValue?: number\n boolValue?: boolean\n arrayValue?: { values?: OtlpAnyValue[] }\n // kvlistValue / bytesValue are skipped — neither is on the demo path.\n}\n\ninterface OtlpStatus {\n code?: number\n message?: string\n}\n\ninterface OtlpEvent {\n name?: string\n timeUnixNano?: string\n attributes?: OtlpKeyValue[]\n}\n\ninterface OtlpSpan {\n traceId?: string\n spanId?: string\n parentSpanId?: string\n name?: string\n kind?: number\n startTimeUnixNano?: string\n endTimeUnixNano?: string\n attributes?: OtlpKeyValue[]\n events?: OtlpEvent[]\n status?: OtlpStatus\n}\n\nfunction extractExceptionFromEvents(events: OtlpEvent[] | undefined): ParsedSpan['exception'] {\n if (!events) return undefined\n for (const ev of events) {\n if (ev.name !== 'exception') continue\n const attrs = attrsToRecord(ev.attributes)\n const out: ParsedSpan['exception'] = {}\n const t = attrs['exception.type']\n const m = attrs['exception.message']\n const s = attrs['exception.stacktrace']\n if (typeof t === 'string') out.type = t\n if (typeof m === 'string') out.message = m\n if (typeof s === 'string') out.stacktrace = s\n if (out.type || out.message || out.stacktrace) return out\n }\n return undefined\n}\n\ninterface OtlpScopeSpans {\n spans?: OtlpSpan[]\n}\n\ninterface OtlpResourceSpans {\n resource?: { attributes?: OtlpKeyValue[] }\n scopeSpans?: OtlpScopeSpans[]\n}\n\nexport interface OtlpTracesRequest {\n resourceSpans?: OtlpResourceSpans[]\n}\n\nfunction flattenAttribute(v: OtlpAnyValue | undefined): AttributeValue {\n if (!v) return null\n if (v.stringValue !== undefined) return v.stringValue\n if (v.boolValue !== undefined) return v.boolValue\n if (v.intValue !== undefined) {\n return typeof v.intValue === 'string' ? Number(v.intValue) : v.intValue\n }\n if (v.doubleValue !== undefined) return v.doubleValue\n if (v.arrayValue?.values) {\n return v.arrayValue.values.map((x) => flattenAttribute(x)) as AttributeValue\n }\n return null\n}\n\nfunction attrsToRecord(attrs: OtlpKeyValue[] | undefined): Record<string, AttributeValue> {\n const out: Record<string, AttributeValue> = {}\n if (!attrs) return out\n for (const kv of attrs) {\n if (kv.key) out[kv.key] = flattenAttribute(kv.value)\n }\n return out\n}\n\nfunction durationNanos(start?: string, end?: string): bigint {\n if (!start || !end) return 0n\n try {\n return BigInt(end) - BigInt(start)\n } catch {\n return 0n\n }\n}\n\n// Convert OTLP's startTimeUnixNano (a base-10 string of nanoseconds since the\n// Unix epoch) to ISO8601. Returns undefined when the input is missing, zero,\n// or unparseable, so the caller can fall back to wall-clock without surfacing\n// a fake timestamp on the edge.\nexport function isoFromUnixNano(nanos: string | undefined): string | undefined {\n if (!nanos || nanos === '0') return undefined\n try {\n const ms = Number(BigInt(nanos) / 1_000_000n)\n if (!Number.isFinite(ms)) return undefined\n return new Date(ms).toISOString()\n } catch {\n return undefined\n }\n}\n\nexport function parseOtlpRequest(body: OtlpTracesRequest): ParsedSpan[] {\n const out: ParsedSpan[] = []\n for (const rs of body.resourceSpans ?? []) {\n const resourceAttrs = attrsToRecord(rs.resource?.attributes)\n const service = typeof resourceAttrs['service.name'] === 'string'\n ? (resourceAttrs['service.name'] as string)\n : 'unknown'\n\n for (const ss of rs.scopeSpans ?? []) {\n for (const span of ss.spans ?? []) {\n const attrs = attrsToRecord(span.attributes)\n const parsed: ParsedSpan = {\n service,\n traceId: span.traceId ?? '',\n spanId: span.spanId ?? '',\n parentSpanId: span.parentSpanId || undefined,\n name: span.name ?? '',\n kind: span.kind,\n startTimeUnixNano: span.startTimeUnixNano ?? '0',\n endTimeUnixNano: span.endTimeUnixNano ?? '0',\n startTimeIso: isoFromUnixNano(span.startTimeUnixNano),\n durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),\n attributes: attrs,\n dbSystem: typeof attrs['db.system'] === 'string' ? (attrs['db.system'] as string) : undefined,\n dbName: typeof attrs['db.name'] === 'string' ? (attrs['db.name'] as string) : undefined,\n statusCode: span.status?.code,\n errorMessage: span.status?.message,\n exception: extractExceptionFromEvents(span.events),\n }\n out.push(parsed)\n }\n }\n }\n return out\n}\n\nexport interface OtelReceiver {\n app: FastifyInstance\n // Resolves once every span enqueued so far has been handed to opts.onSpan.\n // Test seam — production code never awaits this.\n flushPending: () => Promise<void>\n}\n\n// Lazy-loaded protobuf decoder for ExportTraceServiceRequest. The bundled\n// .proto tree at packages/core/proto/ is shared with the gRPC receiver\n// (ADR-020). Cached after first load so successive receiver builds reuse it.\nlet exportTraceServiceRequestType: protobuf.Type | null = null\n\nfunction loadProtobufDecoder(): protobuf.Type {\n if (exportTraceServiceRequestType) return exportTraceServiceRequestType\n const here = path.dirname(fileURLToPath(import.meta.url))\n const protoRoot = path.resolve(here, '..', 'proto')\n const root = new protobuf.Root()\n root.resolvePath = (_origin, target) => path.resolve(protoRoot, target)\n root.loadSync(\n 'opentelemetry/proto/collector/trace/v1/trace_service.proto',\n { keepCase: true },\n )\n exportTraceServiceRequestType = root.lookupType(\n 'opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest',\n )\n return exportTraceServiceRequestType\n}\n\nasync function decodeProtobufBody(buf: Buffer): Promise<OtlpTracesRequest> {\n const Type = loadProtobufDecoder()\n // Decode keeps the proto field names verbatim (keepCase: true), matching the\n // GrpcExportRequest shape that reshapeGrpcRequest already understands.\n // Dynamic import sidesteps the circular module dep with otel-grpc.ts.\n const decoded = Type.decode(buf).toJSON() as Record<string, unknown>\n const { reshapeGrpcRequest } = await import('./otel-grpc.js')\n return reshapeGrpcRequest(decoded as never)\n}\n\nexport async function buildOtelReceiver(\n opts: BuildOtelReceiverOptions,\n): Promise<FastifyInstance & { flushPending: () => Promise<void> }> {\n const app = Fastify({\n logger: false,\n bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024,\n })\n\n // Non-blocking ingest (ADR-033). The receiver replies 200 OK as soon as the\n // body is parsed; mutation runs through this queue, drained on the next tick.\n // OTel SDK exporters retry on timeout, so blocking ingest produces observable\n // backpressure on the system being observed — ambient observation requires no\n // observable effect.\n const queue: ParsedSpan[] = []\n let draining = false\n let drainPromise: Promise<void> = Promise.resolve()\n\n const drain = async (): Promise<void> => {\n if (draining) return\n draining = true\n try {\n while (queue.length > 0) {\n const span = queue.shift()!\n try {\n await opts.onSpan(span)\n } catch (err) {\n console.warn(`[neat] otel handler error: ${(err as Error).message}`)\n }\n }\n } finally {\n draining = false\n }\n }\n\n const enqueue = (spans: ParsedSpan[]): void => {\n if (spans.length === 0) return\n for (const s of spans) queue.push(s)\n // Schedule on the next tick so the 200 response is on the wire before any\n // mutation runs. Each call gets its own promise so flushPending() can wait\n // on the latest drain cycle.\n drainPromise = drainPromise.then(() => drain())\n }\n\n // Buffer application/x-protobuf bodies as raw bytes; the route handler\n // decodes them via the bundled .proto tree (ADR-020).\n app.addContentTypeParser(\n 'application/x-protobuf',\n { parseAs: 'buffer', bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024 },\n (_req, body, done) => {\n done(null, body)\n },\n )\n\n app.get('/health', async () => ({ ok: true }))\n\n app.post('/v1/traces', async (req, reply) => {\n // Content-Type dispatch (ADR-033). Both JSON and protobuf decode to the\n // same OtlpTracesRequest shape, then feed parseOtlpRequest unchanged.\n const ct = (req.headers['content-type'] ?? '').toString().split(';')[0]!.trim().toLowerCase()\n let body: OtlpTracesRequest\n if (ct === 'application/x-protobuf') {\n try {\n body = await decodeProtobufBody(req.body as Buffer)\n } catch (err) {\n return reply.code(400).send({\n error: `protobuf decode failed: ${(err as Error).message}`,\n })\n }\n } else if (!ct || ct === 'application/json') {\n body = (req.body ?? {}) as OtlpTracesRequest\n } else {\n return reply.code(415).send({ error: `unsupported content-type: ${ct}` })\n }\n const spans = parseOtlpRequest(body)\n // Synchronous error-event write before reply (ADR-033 §Error events).\n // Graph mutation stays on the async queue, but the receiver awaits the\n // file write so a write failure surfaces as 500 → OTel SDK retries.\n if (opts.onErrorSpanSync) {\n try {\n for (const span of spans) {\n if (span.statusCode === 2) await opts.onErrorSpanSync(span)\n }\n } catch (err) {\n return reply.code(500).send({\n error: `error-event write failed: ${(err as Error).message}`,\n })\n }\n }\n enqueue(spans)\n // OTLP success response is `{ partialSuccess: {} }` for \"all accepted\".\n return reply.code(200).send({ partialSuccess: {} })\n })\n\n // Attach flushPending so tests can wait for the queue without exporting a\n // separate handle. The cast goes through `unknown` because Fastify's typing\n // is parameterised over the raw server type and the simple intersection\n // confuses TS's structural narrowing.\n const decorated = app as unknown as FastifyInstance & { flushPending: () => Promise<void> }\n decorated.flushPending = async () => {\n // Settle the current drain chain, then loop until the queue is fully empty\n // (a span enqueued mid-flush would otherwise be missed).\n while (queue.length > 0 || draining) {\n await drainPromise\n }\n }\n return decorated\n}\n\nexport function logSpanHandler(span: ParsedSpan): void {\n const parent = span.parentSpanId ? span.parentSpanId.slice(0, 8) : '<root>'\n const status = span.statusCode === 2 ? 'ERROR' : 'OK'\n const db = span.dbSystem ? ` db=${span.dbSystem}/${span.dbName ?? '?'}` : ''\n console.log(\n `otel: ${span.service} ${span.name} parent=${parent} status=${status}${db}`,\n )\n}\n"],"mappings":"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","names":["fileURLToPath","path","reshapeGrpcRequest","status","path","fileURLToPath"]}
|