@neat.is/core 0.10.3 → 0.10.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-DLQNMU3R.js → chunk-2OQVIBZZ.js} +59 -22
- package/dist/chunk-2OQVIBZZ.js.map +1 -0
- package/dist/{chunk-M7CGATVC.js → chunk-EFBWQIKG.js} +12 -2
- package/dist/chunk-EFBWQIKG.js.map +1 -0
- package/dist/{chunk-5SJHA5ZH.js → chunk-LXQCL4MP.js} +2 -2
- package/dist/{chunk-LNIVRE4L.js → chunk-TUGYIRUT.js} +51 -2
- package/dist/{chunk-LNIVRE4L.js.map → chunk-TUGYIRUT.js.map} +1 -1
- package/dist/cli.cjs +58 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +114 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +114 -20
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-CU73Y5WT.js → otel-grpc-B7ABHLV7.js} +3 -3
- package/dist/server.cjs +62 -2
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +7 -4
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-DLQNMU3R.js.map +0 -1
- package/dist/chunk-M7CGATVC.js.map +0 -1
- /package/dist/{chunk-5SJHA5ZH.js.map → chunk-LXQCL4MP.js.map} +0 -0
- /package/dist/{otel-grpc-CU73Y5WT.js.map → otel-grpc-B7ABHLV7.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -126,6 +126,29 @@ declare class Projects {
|
|
|
126
126
|
attachSearchIndex(name: string, index: SearchIndex | undefined): void;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
/** What one pass did: whether the bound-repo list was read, and how the repos it took on came out. */
|
|
130
|
+
interface RepoSyncPassCounts {
|
|
131
|
+
listed: boolean;
|
|
132
|
+
synced: number;
|
|
133
|
+
failed: number;
|
|
134
|
+
}
|
|
135
|
+
/** A finished pass, as the on-demand trigger reports it. */
|
|
136
|
+
interface RepoSyncPassSummary extends RepoSyncPassCounts {
|
|
137
|
+
startedAt: string;
|
|
138
|
+
finishedAt: string;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The answer to "sync now" (#1293). `started` — nothing was running, a pass has begun. `queued` — a pass was
|
|
142
|
+
* already running, and one more will follow it. Joining the running pass outright would be wrong: it read
|
|
143
|
+
* the bound-repo list before this request, so a repo bound since would be missed; the follow-up re-reads the
|
|
144
|
+
* list. Any number of requests during one pass coalesce into that single follow-up. `lastPass` is the most
|
|
145
|
+
* recent pass to finish, absent until one has.
|
|
146
|
+
*/
|
|
147
|
+
interface RepoSyncRequestResult {
|
|
148
|
+
status: 'started' | 'queued';
|
|
149
|
+
lastPass?: RepoSyncPassSummary;
|
|
150
|
+
}
|
|
151
|
+
|
|
129
152
|
/**
|
|
130
153
|
* A connector implements exactly one method. Everything downstream of
|
|
131
154
|
* `poll()` — resolving a static call site, minting the OBSERVED edge — is
|
|
@@ -293,6 +316,7 @@ interface BuildApiOptions {
|
|
|
293
316
|
authToken?: string;
|
|
294
317
|
trustProxy?: boolean;
|
|
295
318
|
publicRead?: boolean;
|
|
319
|
+
otlpReceiver?: () => FastifyInstance | undefined;
|
|
296
320
|
bootstrap?: {
|
|
297
321
|
status: (name: string) => 'bootstrapping' | 'active' | 'broken' | undefined;
|
|
298
322
|
list: () => Array<{
|
|
@@ -306,6 +330,7 @@ interface BuildApiOptions {
|
|
|
306
330
|
path: string;
|
|
307
331
|
};
|
|
308
332
|
connectorsHome?: string;
|
|
333
|
+
repoSync?: (project: string) => (() => RepoSyncRequestResult) | undefined;
|
|
309
334
|
runPoll?: typeof runConnectorPoll;
|
|
310
335
|
}
|
|
311
336
|
declare function buildApi(opts: BuildApiOptions): Promise<FastifyInstance>;
|
|
@@ -597,6 +622,7 @@ interface ProjectSlot {
|
|
|
597
622
|
stopHostedConnectors: () => void;
|
|
598
623
|
stopK8sSubstrate: () => void;
|
|
599
624
|
stopRepoSync: () => void;
|
|
625
|
+
syncRepos?: () => RepoSyncRequestResult;
|
|
600
626
|
detachEvents: () => void;
|
|
601
627
|
status: 'active' | 'broken';
|
|
602
628
|
errorReason?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -126,6 +126,29 @@ declare class Projects {
|
|
|
126
126
|
attachSearchIndex(name: string, index: SearchIndex | undefined): void;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
/** What one pass did: whether the bound-repo list was read, and how the repos it took on came out. */
|
|
130
|
+
interface RepoSyncPassCounts {
|
|
131
|
+
listed: boolean;
|
|
132
|
+
synced: number;
|
|
133
|
+
failed: number;
|
|
134
|
+
}
|
|
135
|
+
/** A finished pass, as the on-demand trigger reports it. */
|
|
136
|
+
interface RepoSyncPassSummary extends RepoSyncPassCounts {
|
|
137
|
+
startedAt: string;
|
|
138
|
+
finishedAt: string;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The answer to "sync now" (#1293). `started` — nothing was running, a pass has begun. `queued` — a pass was
|
|
142
|
+
* already running, and one more will follow it. Joining the running pass outright would be wrong: it read
|
|
143
|
+
* the bound-repo list before this request, so a repo bound since would be missed; the follow-up re-reads the
|
|
144
|
+
* list. Any number of requests during one pass coalesce into that single follow-up. `lastPass` is the most
|
|
145
|
+
* recent pass to finish, absent until one has.
|
|
146
|
+
*/
|
|
147
|
+
interface RepoSyncRequestResult {
|
|
148
|
+
status: 'started' | 'queued';
|
|
149
|
+
lastPass?: RepoSyncPassSummary;
|
|
150
|
+
}
|
|
151
|
+
|
|
129
152
|
/**
|
|
130
153
|
* A connector implements exactly one method. Everything downstream of
|
|
131
154
|
* `poll()` — resolving a static call site, minting the OBSERVED edge — is
|
|
@@ -293,6 +316,7 @@ interface BuildApiOptions {
|
|
|
293
316
|
authToken?: string;
|
|
294
317
|
trustProxy?: boolean;
|
|
295
318
|
publicRead?: boolean;
|
|
319
|
+
otlpReceiver?: () => FastifyInstance | undefined;
|
|
296
320
|
bootstrap?: {
|
|
297
321
|
status: (name: string) => 'bootstrapping' | 'active' | 'broken' | undefined;
|
|
298
322
|
list: () => Array<{
|
|
@@ -306,6 +330,7 @@ interface BuildApiOptions {
|
|
|
306
330
|
path: string;
|
|
307
331
|
};
|
|
308
332
|
connectorsHome?: string;
|
|
333
|
+
repoSync?: (project: string) => (() => RepoSyncRequestResult) | undefined;
|
|
309
334
|
runPoll?: typeof runConnectorPoll;
|
|
310
335
|
}
|
|
311
336
|
declare function buildApi(opts: BuildApiOptions): Promise<FastifyInstance>;
|
|
@@ -597,6 +622,7 @@ interface ProjectSlot {
|
|
|
597
622
|
stopHostedConnectors: () => void;
|
|
598
623
|
stopK8sSubstrate: () => void;
|
|
599
624
|
stopRepoSync: () => void;
|
|
625
|
+
syncRepos?: () => RepoSyncRequestResult;
|
|
600
626
|
detachEvents: () => void;
|
|
601
627
|
status: 'active' | 'broken';
|
|
602
628
|
errorReason?: string;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
routeSpanToProject,
|
|
3
3
|
startDaemon
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2OQVIBZZ.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-TUGYIRUT.js";
|
|
41
41
|
import {
|
|
42
42
|
startOtelGrpcReceiver
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-LXQCL4MP.js";
|
|
44
44
|
import {
|
|
45
45
|
buildOtelReceiver,
|
|
46
46
|
logSpanHandler,
|
|
47
47
|
parseOtlpRequest
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-EFBWQIKG.js";
|
|
49
49
|
export {
|
|
50
50
|
ProjectNameCollisionError,
|
|
51
51
|
addProject,
|
package/dist/neatd.cjs
CHANGED
|
@@ -51,6 +51,10 @@ function assertBindAuthority(host, token) {
|
|
|
51
51
|
if (isLoopbackHost2(host)) return;
|
|
52
52
|
throw new BindAuthorityError(host);
|
|
53
53
|
}
|
|
54
|
+
function isBearerDelegated(req2) {
|
|
55
|
+
const config = req2.routeOptions?.config;
|
|
56
|
+
return config?.bearerDelegated === true;
|
|
57
|
+
}
|
|
54
58
|
function mountBearerAuth(app, opts) {
|
|
55
59
|
if (!opts.token || opts.token.length === 0) return;
|
|
56
60
|
if (opts.trustProxy) return;
|
|
@@ -66,6 +70,10 @@ function mountBearerAuth(app, opts) {
|
|
|
66
70
|
done();
|
|
67
71
|
return;
|
|
68
72
|
}
|
|
73
|
+
if (isBearerDelegated(req2)) {
|
|
74
|
+
done();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
69
77
|
if (publicRead && PUBLIC_READ_METHODS.has(req2.method)) {
|
|
70
78
|
done();
|
|
71
79
|
return;
|
|
@@ -99,7 +107,7 @@ function readAuthEnv(env = process.env) {
|
|
|
99
107
|
publicRead: parseBoolEnv(env.NEAT_PUBLIC_READ)
|
|
100
108
|
};
|
|
101
109
|
}
|
|
102
|
-
var import_node_crypto, LOOPBACK_HOSTS, BindAuthorityError, PUBLIC_READ_METHODS, DEFAULT_UNAUTH_PATHS, PROJECT_SCOPED_UNAUTH_PATTERN;
|
|
110
|
+
var import_node_crypto, LOOPBACK_HOSTS, BindAuthorityError, PUBLIC_READ_METHODS, DEFAULT_UNAUTH_PATHS, PROJECT_SCOPED_UNAUTH_PATTERN, BEARER_DELEGATED;
|
|
103
111
|
var init_auth = __esm({
|
|
104
112
|
"src/auth.ts"() {
|
|
105
113
|
"use strict";
|
|
@@ -129,6 +137,7 @@ var init_auth = __esm({
|
|
|
129
137
|
PROJECT_SCOPED_UNAUTH_PATTERN = new RegExp(
|
|
130
138
|
`^/projects/[^/]+/(?:${DEFAULT_UNAUTH_PATHS.map((p) => p.slice(1)).join("|")})$`
|
|
131
139
|
);
|
|
140
|
+
BEARER_DELEGATED = { bearerDelegated: true };
|
|
132
141
|
}
|
|
133
142
|
});
|
|
134
143
|
|
|
@@ -23518,6 +23527,19 @@ function registerRoutes(scope, ctx) {
|
|
|
23518
23527
|
});
|
|
23519
23528
|
}
|
|
23520
23529
|
});
|
|
23530
|
+
scope.post("/repo-sync", async (req2, reply) => {
|
|
23531
|
+
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
23532
|
+
if (!proj) return;
|
|
23533
|
+
const syncNow = ctx.repoSync?.(proj.name);
|
|
23534
|
+
if (!syncNow) {
|
|
23535
|
+
return reply.code(404).send({
|
|
23536
|
+
error: "repo-sync is not running for this project",
|
|
23537
|
+
project: proj.name,
|
|
23538
|
+
hint: "Only a hosted daemon syncs bound repos. On a local daemon, POST /graph/scan re-extracts the project path."
|
|
23539
|
+
});
|
|
23540
|
+
}
|
|
23541
|
+
return reply.code(202).send({ project: proj.name, ...syncNow() });
|
|
23542
|
+
});
|
|
23521
23543
|
scope.post("/graph/scan", async (req2, reply) => {
|
|
23522
23544
|
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
23523
23545
|
if (!proj) return;
|
|
@@ -23765,6 +23787,39 @@ function registerRoutes(scope, ctx) {
|
|
|
23765
23787
|
}
|
|
23766
23788
|
});
|
|
23767
23789
|
}
|
|
23790
|
+
var OTLP_BODY_LIMIT = 16 * 1024 * 1024;
|
|
23791
|
+
function otlpOnRest(getReceiver) {
|
|
23792
|
+
return async function plugin(scope) {
|
|
23793
|
+
scope.removeAllContentTypeParsers();
|
|
23794
|
+
scope.addContentTypeParser(
|
|
23795
|
+
"*",
|
|
23796
|
+
{ parseAs: "buffer", bodyLimit: OTLP_BODY_LIMIT },
|
|
23797
|
+
(_req, body, done) => done(null, body)
|
|
23798
|
+
);
|
|
23799
|
+
const relay = async (req2, reply) => {
|
|
23800
|
+
const receiver = getReceiver();
|
|
23801
|
+
if (!receiver) {
|
|
23802
|
+
return reply.code(503).header("retry-after", "1").send({ error: "OTLP receiver is starting" });
|
|
23803
|
+
}
|
|
23804
|
+
const headers = { ...req2.headers };
|
|
23805
|
+
delete headers["content-length"];
|
|
23806
|
+
delete headers["transfer-encoding"];
|
|
23807
|
+
delete headers.connection;
|
|
23808
|
+
const res = await receiver.inject({
|
|
23809
|
+
method: "POST",
|
|
23810
|
+
url: req2.url,
|
|
23811
|
+
headers,
|
|
23812
|
+
payload: req2.body
|
|
23813
|
+
});
|
|
23814
|
+
const contentType = res.headers["content-type"];
|
|
23815
|
+
if (contentType !== void 0) void reply.header("content-type", contentType);
|
|
23816
|
+
return reply.code(res.statusCode).send(res.rawPayload);
|
|
23817
|
+
};
|
|
23818
|
+
const route = { config: BEARER_DELEGATED, bodyLimit: OTLP_BODY_LIMIT };
|
|
23819
|
+
scope.post("/v1/traces", route, relay);
|
|
23820
|
+
scope.post("/projects/:project/v1/traces", route, relay);
|
|
23821
|
+
};
|
|
23822
|
+
}
|
|
23768
23823
|
async function buildApi(opts) {
|
|
23769
23824
|
const app = (0, import_fastify2.default)({ logger: false, routerOptions: { maxParamLength: 1024 } });
|
|
23770
23825
|
await app.register(import_cors.default, { origin: true });
|
|
@@ -23783,6 +23838,7 @@ async function buildApi(opts) {
|
|
|
23783
23838
|
authProxy: trustProxy === true,
|
|
23784
23839
|
requiresAuth
|
|
23785
23840
|
}));
|
|
23841
|
+
if (opts.otlpReceiver) await app.register(otlpOnRest(opts.otlpReceiver));
|
|
23786
23842
|
const startedAt = opts.startedAt ?? Date.now();
|
|
23787
23843
|
const registry = buildLegacyRegistry(opts);
|
|
23788
23844
|
const legacyErrorsExplicit = !opts.projects && opts.errorsPath !== void 0;
|
|
@@ -23813,6 +23869,7 @@ async function buildApi(opts) {
|
|
|
23813
23869
|
bootstrap: opts.bootstrap,
|
|
23814
23870
|
singleProject: opts.singleProject?.name,
|
|
23815
23871
|
connectorsHome: opts.connectorsHome,
|
|
23872
|
+
repoSync: opts.repoSync,
|
|
23816
23873
|
runPoll: opts.runPoll ?? runConnectorPoll
|
|
23817
23874
|
};
|
|
23818
23875
|
app.get("/health", async () => {
|
|
@@ -24371,6 +24428,7 @@ async function syncOneRepo(r, input) {
|
|
|
24371
24428
|
detail: `extracted ${nodes} node${nodes === 1 ? "" : "s"}, ${edges} edge${edges === 1 ? "" : "s"}`,
|
|
24372
24429
|
lastSyncAt: new Date(input.now?.() ?? Date.now()).toISOString()
|
|
24373
24430
|
});
|
|
24431
|
+
return true;
|
|
24374
24432
|
} catch (err) {
|
|
24375
24433
|
input.onError?.(label, err);
|
|
24376
24434
|
await cpPostStatus(deps, r.owner, r.name, {
|
|
@@ -24378,50 +24436,76 @@ async function syncOneRepo(r, input) {
|
|
|
24378
24436
|
detail: scrubToken(err.message).slice(0, 300)
|
|
24379
24437
|
}).catch(() => {
|
|
24380
24438
|
});
|
|
24439
|
+
return false;
|
|
24381
24440
|
} finally {
|
|
24382
24441
|
if (dir) await (0, import_promises2.rm)(dir, { recursive: true, force: true }).catch(() => {
|
|
24383
24442
|
});
|
|
24384
24443
|
}
|
|
24385
24444
|
}
|
|
24386
|
-
async function
|
|
24445
|
+
async function runRepoSyncPassCounted(input) {
|
|
24446
|
+
const counts = { listed: false, synced: 0, failed: 0 };
|
|
24387
24447
|
let repos;
|
|
24388
24448
|
try {
|
|
24389
24449
|
repos = await cpGet2(`/internal/projects/${input.deps.projectId}/repos`, input.deps);
|
|
24390
24450
|
} catch (err) {
|
|
24391
24451
|
input.onSkip?.("(all)", `control plane repo list unreadable \u2014 ${err.message}`);
|
|
24392
|
-
return
|
|
24452
|
+
return counts;
|
|
24393
24453
|
}
|
|
24394
|
-
if (!Array.isArray(repos)) return
|
|
24454
|
+
if (!Array.isArray(repos)) return counts;
|
|
24455
|
+
counts.listed = true;
|
|
24395
24456
|
for (const r of repos) {
|
|
24396
24457
|
if (!input.forceResync && !needsSync(r)) continue;
|
|
24397
|
-
await syncOneRepo(r, input)
|
|
24458
|
+
if (await syncOneRepo(r, input)) counts.synced++;
|
|
24459
|
+
else counts.failed++;
|
|
24398
24460
|
}
|
|
24399
|
-
return
|
|
24461
|
+
return counts;
|
|
24400
24462
|
}
|
|
24401
24463
|
async function startRepoSync(input) {
|
|
24402
24464
|
const intervalMs = input.intervalMs ?? DEFAULT_SYNC_INTERVAL_MS;
|
|
24465
|
+
const now = () => input.now?.() ?? Date.now();
|
|
24403
24466
|
let stopped = false;
|
|
24404
|
-
let
|
|
24467
|
+
let inFlight = null;
|
|
24468
|
+
let again = false;
|
|
24469
|
+
let lastPass;
|
|
24405
24470
|
let bootResyncDone = false;
|
|
24406
|
-
const
|
|
24407
|
-
if (stopped || running) return;
|
|
24408
|
-
running = true;
|
|
24471
|
+
const run = async () => {
|
|
24409
24472
|
try {
|
|
24410
|
-
|
|
24411
|
-
|
|
24473
|
+
do {
|
|
24474
|
+
again = false;
|
|
24475
|
+
const startedAt = new Date(now()).toISOString();
|
|
24476
|
+
const counts = await runRepoSyncPassCounted({ ...input, forceResync: !bootResyncDone });
|
|
24477
|
+
if (counts.listed) bootResyncDone = true;
|
|
24478
|
+
lastPass = { ...counts, startedAt, finishedAt: new Date(now()).toISOString() };
|
|
24479
|
+
} while (again && !stopped);
|
|
24412
24480
|
} finally {
|
|
24413
|
-
|
|
24481
|
+
inFlight = null;
|
|
24414
24482
|
}
|
|
24415
24483
|
};
|
|
24416
|
-
|
|
24417
|
-
|
|
24418
|
-
|
|
24419
|
-
}
|
|
24484
|
+
const tick = () => {
|
|
24485
|
+
if (stopped || inFlight) return;
|
|
24486
|
+
inFlight = run();
|
|
24487
|
+
};
|
|
24488
|
+
tick();
|
|
24489
|
+
const timer = setInterval(tick, intervalMs);
|
|
24420
24490
|
if (typeof timer.unref === "function") timer.unref();
|
|
24421
|
-
|
|
24491
|
+
const stop = () => {
|
|
24422
24492
|
stopped = true;
|
|
24423
24493
|
clearInterval(timer);
|
|
24424
24494
|
};
|
|
24495
|
+
return Object.assign(stop, {
|
|
24496
|
+
syncNow: () => {
|
|
24497
|
+
const summary = lastPass ? { lastPass } : {};
|
|
24498
|
+
if (inFlight) {
|
|
24499
|
+
again = true;
|
|
24500
|
+
return { status: "queued", ...summary };
|
|
24501
|
+
}
|
|
24502
|
+
inFlight = run();
|
|
24503
|
+
return { status: "started", ...summary };
|
|
24504
|
+
},
|
|
24505
|
+
settled: async () => {
|
|
24506
|
+
while (inFlight) await inFlight;
|
|
24507
|
+
}
|
|
24508
|
+
});
|
|
24425
24509
|
}
|
|
24426
24510
|
async function maybeStartRepoSync(input) {
|
|
24427
24511
|
const env = input.env ?? process.env;
|
|
@@ -25191,6 +25275,7 @@ async function bootstrapProject(entry2, connectors = [], neatHome4) {
|
|
|
25191
25275
|
stopHostedConnectors,
|
|
25192
25276
|
stopK8sSubstrate,
|
|
25193
25277
|
stopRepoSync,
|
|
25278
|
+
...stopRepoSync.syncNow ? { syncRepos: stopRepoSync.syncNow } : {},
|
|
25194
25279
|
detachEvents,
|
|
25195
25280
|
status: "active"
|
|
25196
25281
|
};
|
|
@@ -25462,7 +25547,14 @@ async function startDaemon(opts = {}) {
|
|
|
25462
25547
|
// through the same resolved home the slot bootstrap read it from, so a
|
|
25463
25548
|
// daemon given an explicit NEAT_HOME serves status for the same file it
|
|
25464
25549
|
// polls.
|
|
25465
|
-
connectorsHome: home
|
|
25550
|
+
connectorsHome: home,
|
|
25551
|
+
// #1293 — "sync this project's repos now". Looked up per request: the
|
|
25552
|
+
// slot, and with it the trigger, appears once bootstrap has run.
|
|
25553
|
+
repoSync: (name) => slots.get(name)?.syncRepos,
|
|
25554
|
+
// OTLP answers on this listener too, so a host that routes a single
|
|
25555
|
+
// port still delivers a tenant app's spans. Bound late: the receiver
|
|
25556
|
+
// is built below, once the REST bind has succeeded.
|
|
25557
|
+
otlpReceiver: () => otlpApp ?? void 0
|
|
25466
25558
|
});
|
|
25467
25559
|
restAddress = await restApp.listen({ port: restPort, host });
|
|
25468
25560
|
console.log(
|
|
@@ -25643,7 +25735,9 @@ async function startDaemon(opts = {}) {
|
|
|
25643
25735
|
}
|
|
25644
25736
|
});
|
|
25645
25737
|
otlpAddress = await listenSteppingOtlp(otlpApp, otlpPort, host);
|
|
25646
|
-
console.log(
|
|
25738
|
+
console.log(
|
|
25739
|
+
`neatd: OTLP listening on http://${host}:${portFromListenAddress(otlpAddress, otlpPort)}/v1/traces (also at /v1/traces on the REST port)`
|
|
25740
|
+
);
|
|
25647
25741
|
} catch (err) {
|
|
25648
25742
|
for (const slot of slots.values()) {
|
|
25649
25743
|
teardownSlot(slot);
|