@neat.is/core 0.5.2 → 0.5.4-dev.20260721
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-I72HTUOG.js → chunk-4RU3AAOI.js} +2 -2
- package/dist/{chunk-CFDPIMRP.js → chunk-I4NZ7PSN.js} +3 -2
- package/dist/chunk-I4NZ7PSN.js.map +1 -0
- package/dist/{chunk-BI3XKGVG.js → chunk-PEFX3DBR.js} +473 -127
- package/dist/chunk-PEFX3DBR.js.map +1 -0
- package/dist/{chunk-DPEPI2N6.js → chunk-VR73QNJD.js} +293 -22
- package/dist/chunk-VR73QNJD.js.map +1 -0
- package/dist/cli.cjs +1371 -479
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +343 -75
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +879 -310
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +888 -319
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-IDMIH6ZY.js → otel-grpc-TEGOXE6T.js} +3 -3
- package/dist/server.cjs +553 -192
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-BI3XKGVG.js.map +0 -1
- package/dist/chunk-CFDPIMRP.js.map +0 -1
- package/dist/chunk-DPEPI2N6.js.map +0 -1
- /package/dist/{chunk-I72HTUOG.js.map → chunk-4RU3AAOI.js.map} +0 -0
- /package/dist/{otel-grpc-IDMIH6ZY.js.map → otel-grpc-TEGOXE6T.js.map} +0 -0
|
@@ -31,13 +31,13 @@ import {
|
|
|
31
31
|
touchLastSeen,
|
|
32
32
|
upsertObservedEdge,
|
|
33
33
|
writeAtomically
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-PEFX3DBR.js";
|
|
35
35
|
import {
|
|
36
36
|
assertBindAuthority,
|
|
37
37
|
buildOtelReceiver,
|
|
38
38
|
listenSteppingOtlp,
|
|
39
39
|
readAuthEnv
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-I4NZ7PSN.js";
|
|
41
41
|
|
|
42
42
|
// src/daemon.ts
|
|
43
43
|
import {
|
|
@@ -98,8 +98,8 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
98
98
|
line: callSite.line
|
|
99
99
|
} : void 0;
|
|
100
100
|
const calls = Math.trunc(signal.callCount);
|
|
101
|
-
if (calls < 1) continue;
|
|
102
|
-
const errors = Math.min(Math.max(Math.trunc(signal.errorCount), 0), calls);
|
|
101
|
+
if (!Number.isFinite(calls) || calls < 1) continue;
|
|
102
|
+
const errors = Number.isFinite(signal.errorCount) ? Math.min(Math.max(Math.trunc(signal.errorCount), 0), calls) : 0;
|
|
103
103
|
let created = false;
|
|
104
104
|
let ok = true;
|
|
105
105
|
for (let i = 0; i < calls; i++) {
|
|
@@ -240,7 +240,12 @@ var JUNCTION_DEFAULT_RATE_LIMITS = {
|
|
|
240
240
|
supabase: { capacity: 30, refillMs: 1e4 },
|
|
241
241
|
// Not a documented API limit at all — a self-imposed ceiling on the raw
|
|
242
242
|
// pg_stat_statements connection (see module header above).
|
|
243
|
-
"supabase-postgres": { capacity: 20, refillMs: 3e3 }
|
|
243
|
+
"supabase-postgres": { capacity: 20, refillMs: 3e3 },
|
|
244
|
+
// Push provider (ADR-146): the Drains REST API is touched only by `neat
|
|
245
|
+
// connector add/remove/test` (provision/deprovision/validate), never a poll
|
|
246
|
+
// loop, so this bucket is exercised a handful of times per command. Kept
|
|
247
|
+
// conservative pending a documented Drains-API rate limit.
|
|
248
|
+
vercel: { capacity: 20, refillMs: 5e3 }
|
|
244
249
|
};
|
|
245
250
|
var JUNCTION_GENERIC_RATE_LIMIT = { capacity: 20, refillMs: 5e3 };
|
|
246
251
|
function defaultRateLimitFor(provider) {
|
|
@@ -534,7 +539,10 @@ function targetFromRestPath(path3) {
|
|
|
534
539
|
var ERROR_STATUS_THRESHOLD = 500;
|
|
535
540
|
function mapEdgeLogRowsToSignals(rows) {
|
|
536
541
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
542
|
+
if (!Array.isArray(rows)) return [];
|
|
537
543
|
for (const row of rows) {
|
|
544
|
+
if (!row || typeof row !== "object") continue;
|
|
545
|
+
if (typeof row.path !== "string" || typeof row.timestamp !== "string") continue;
|
|
538
546
|
const target = targetFromRestPath(row.path);
|
|
539
547
|
if (!target) continue;
|
|
540
548
|
const key = `${target.targetKind}:${target.name}`;
|
|
@@ -575,9 +583,12 @@ function tableNameFromQueryText(query) {
|
|
|
575
583
|
function diffPgStatStatementsToSignals(rows, previous, nowIso) {
|
|
576
584
|
const signals = [];
|
|
577
585
|
const seen = /* @__PURE__ */ new Set();
|
|
586
|
+
if (!Array.isArray(rows)) return signals;
|
|
578
587
|
for (const row of rows) {
|
|
579
|
-
|
|
588
|
+
if (!row || typeof row !== "object" || typeof row.queryid !== "string") continue;
|
|
580
589
|
const calls = Number(row.calls);
|
|
590
|
+
if (!Number.isFinite(calls)) continue;
|
|
591
|
+
seen.add(row.queryid);
|
|
581
592
|
const prior = previous.get(row.queryid);
|
|
582
593
|
previous.set(row.queryid, { calls });
|
|
583
594
|
if (!prior || calls < prior.calls) continue;
|
|
@@ -897,7 +908,12 @@ function upsertBucket(buckets2, key, isError, timestamp, build) {
|
|
|
897
908
|
}
|
|
898
909
|
function mapRailwayHttpLogsToSignals(entries, routeIndex) {
|
|
899
910
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
911
|
+
if (!Array.isArray(entries)) return [];
|
|
900
912
|
for (const entry of entries) {
|
|
913
|
+
if (!entry || typeof entry !== "object") continue;
|
|
914
|
+
if (typeof entry.method !== "string" || typeof entry.path !== "string" || typeof entry.timestamp !== "string") {
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
901
917
|
const method = entry.method.toUpperCase();
|
|
902
918
|
const normalizedPath = normalizePathTemplate(entry.path);
|
|
903
919
|
const match = findRailwayRoute(routeIndex, method, normalizedPath);
|
|
@@ -936,8 +952,11 @@ function mapRailwayHttpLogsToSignals(entries, routeIndex) {
|
|
|
936
952
|
}
|
|
937
953
|
function mapRailwayNetworkFlowLogsToSignals(entries) {
|
|
938
954
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
955
|
+
if (!Array.isArray(entries)) return [];
|
|
939
956
|
for (const entry of entries) {
|
|
940
|
-
if (!entry
|
|
957
|
+
if (!entry || typeof entry !== "object") continue;
|
|
958
|
+
if (typeof entry.peerServiceId !== "string" || entry.peerServiceId.length === 0) continue;
|
|
959
|
+
if (typeof entry.timestamp !== "string") continue;
|
|
941
960
|
const isError = entry.dropCause !== null && entry.dropCause !== "";
|
|
942
961
|
upsertBucket(buckets2, entry.peerServiceId, isError, entry.timestamp, () => ({
|
|
943
962
|
targetKind: PEER_SERVICE_TARGET_KIND,
|
|
@@ -1061,7 +1080,7 @@ async function fetchHttpRequestLogEntries(creds, sinceIso) {
|
|
|
1061
1080
|
throw new Error(`Cloud Logging entries.list failed: ${res.status} ${res.statusText}`);
|
|
1062
1081
|
}
|
|
1063
1082
|
const json = await res.json();
|
|
1064
|
-
out.push(...json.entries
|
|
1083
|
+
if (Array.isArray(json.entries)) out.push(...json.entries);
|
|
1065
1084
|
if (!json.nextPageToken) break;
|
|
1066
1085
|
pageToken = json.nextPageToken;
|
|
1067
1086
|
}
|
|
@@ -1097,7 +1116,7 @@ function resourceNameFor(type, labels) {
|
|
|
1097
1116
|
}
|
|
1098
1117
|
}
|
|
1099
1118
|
function pathFromRequestUrl(requestUrl) {
|
|
1100
|
-
if (
|
|
1119
|
+
if (typeof requestUrl !== "string" || requestUrl.length === 0) return null;
|
|
1101
1120
|
if (requestUrl.startsWith("/")) {
|
|
1102
1121
|
const withoutQuery = requestUrl.split("?")[0];
|
|
1103
1122
|
return withoutQuery && withoutQuery.length > 0 ? withoutQuery : "/";
|
|
@@ -1112,18 +1131,19 @@ function pathFromRequestUrl(requestUrl) {
|
|
|
1112
1131
|
}
|
|
1113
1132
|
var ERROR_STATUS_THRESHOLD2 = 500;
|
|
1114
1133
|
function mapLogEntryToSignal(entry) {
|
|
1134
|
+
if (!entry || typeof entry !== "object") return null;
|
|
1115
1135
|
const resourceType = entry.resource?.type;
|
|
1116
1136
|
if (!resourceType || !isFirebaseResourceType(resourceType)) return null;
|
|
1117
1137
|
const resourceName = resourceNameFor(resourceType, entry.resource?.labels);
|
|
1118
1138
|
if (!resourceName) return null;
|
|
1119
1139
|
const req = entry.httpRequest;
|
|
1120
1140
|
if (!req) return null;
|
|
1121
|
-
if (
|
|
1141
|
+
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
1122
1142
|
const method = req.requestMethod.toUpperCase();
|
|
1123
1143
|
const path3 = pathFromRequestUrl(req.requestUrl);
|
|
1124
1144
|
if (path3 === null) return null;
|
|
1125
1145
|
const timestamp = entry.timestamp;
|
|
1126
|
-
if (
|
|
1146
|
+
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
1127
1147
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
1128
1148
|
return {
|
|
1129
1149
|
targetKind: resourceType,
|
|
@@ -1269,7 +1289,7 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
|
|
|
1269
1289
|
throw new Error(`cloudflare connector: telemetry query returned an error (${message})`);
|
|
1270
1290
|
}
|
|
1271
1291
|
const events = payload.result?.events?.events;
|
|
1272
|
-
if (events
|
|
1292
|
+
if (!Array.isArray(events)) {
|
|
1273
1293
|
console.warn(
|
|
1274
1294
|
"[neat connector] cloudflare: telemetry query returned success:true but no result.events.events array \u2014 the response shape may have changed; treating as zero events this tick"
|
|
1275
1295
|
);
|
|
@@ -1295,7 +1315,7 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
|
1295
1315
|
]);
|
|
1296
1316
|
var LEADING_TOKEN_RE = /^(\S+)\s+\S/;
|
|
1297
1317
|
function parseHttpMethodFromTrigger(trigger) {
|
|
1298
|
-
if (
|
|
1318
|
+
if (typeof trigger !== "string") return null;
|
|
1299
1319
|
const match = LEADING_TOKEN_RE.exec(trigger.trim());
|
|
1300
1320
|
const token = match?.[1];
|
|
1301
1321
|
if (!token) return null;
|
|
@@ -1311,14 +1331,17 @@ function parsePathFromTrigger(trigger) {
|
|
|
1311
1331
|
}
|
|
1312
1332
|
var ERROR_STATUS_THRESHOLD3 = 500;
|
|
1313
1333
|
function mapEventToSignal(event) {
|
|
1334
|
+
if (!event || typeof event !== "object") return null;
|
|
1314
1335
|
const metadata = event.$metadata;
|
|
1315
1336
|
const workers = event.$workers;
|
|
1316
1337
|
const method = parseHttpMethodFromTrigger(metadata?.trigger);
|
|
1317
1338
|
if (!method) return null;
|
|
1318
1339
|
const scriptName = workers?.scriptName ?? metadata?.service;
|
|
1319
|
-
if (
|
|
1340
|
+
if (typeof scriptName !== "string" || scriptName.length === 0) return null;
|
|
1320
1341
|
const timestampMs = event.timestamp ?? metadata?.startTime;
|
|
1321
1342
|
if (typeof timestampMs !== "number" || !Number.isFinite(timestampMs)) return null;
|
|
1343
|
+
const observedAt = new Date(timestampMs);
|
|
1344
|
+
if (Number.isNaN(observedAt.getTime())) return null;
|
|
1322
1345
|
const statusCode = metadata?.statusCode;
|
|
1323
1346
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
1324
1347
|
const path3 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
@@ -1327,7 +1350,7 @@ function mapEventToSignal(event) {
|
|
|
1327
1350
|
targetName: scriptName,
|
|
1328
1351
|
callCount: 1,
|
|
1329
1352
|
errorCount: isError ? 1 : 0,
|
|
1330
|
-
lastObservedIso:
|
|
1353
|
+
lastObservedIso: observedAt.toISOString(),
|
|
1331
1354
|
method,
|
|
1332
1355
|
...path3 ? { path: path3 } : {},
|
|
1333
1356
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
@@ -1425,6 +1448,108 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
1425
1448
|
};
|
|
1426
1449
|
}
|
|
1427
1450
|
|
|
1451
|
+
// src/connectors/vercel/client.ts
|
|
1452
|
+
var DEFAULT_API_BASE_URL = "https://api.vercel.com";
|
|
1453
|
+
var DEFAULT_DRAIN_NAME = "neat-otlp";
|
|
1454
|
+
var TRACE_SCHEMAS = { trace: { version: "v1" } };
|
|
1455
|
+
function apiBase(config) {
|
|
1456
|
+
return config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
|
|
1457
|
+
}
|
|
1458
|
+
function teamQuery(config) {
|
|
1459
|
+
return `?teamId=${encodeURIComponent(config.teamId)}`;
|
|
1460
|
+
}
|
|
1461
|
+
function drainDelivery(config, otelToken) {
|
|
1462
|
+
return {
|
|
1463
|
+
type: "http",
|
|
1464
|
+
endpoint: config.endpoint,
|
|
1465
|
+
encoding: "json",
|
|
1466
|
+
headers: bearerAuthHeader(otelToken),
|
|
1467
|
+
...config.secret ? { secret: config.secret } : {}
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
async function describeError(res) {
|
|
1471
|
+
try {
|
|
1472
|
+
const data = await res.json();
|
|
1473
|
+
const message = data?.error?.message;
|
|
1474
|
+
return typeof message === "string" && message.length > 0 ? ` \u2014 ${message}` : "";
|
|
1475
|
+
} catch {
|
|
1476
|
+
return "";
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
async function createVercelDrain(config, credentials, fetchImpl = fetch) {
|
|
1480
|
+
const projectIds = config.projectIds ?? [];
|
|
1481
|
+
const body = {
|
|
1482
|
+
name: config.drainName ?? DEFAULT_DRAIN_NAME,
|
|
1483
|
+
projects: projectIds.length > 0 ? "some" : "all",
|
|
1484
|
+
...projectIds.length > 0 ? { projectIds } : {},
|
|
1485
|
+
schemas: TRACE_SCHEMAS,
|
|
1486
|
+
delivery: drainDelivery(config, credentials.otelToken),
|
|
1487
|
+
source: { kind: "self-served" }
|
|
1488
|
+
};
|
|
1489
|
+
const res = await junctionFetch(
|
|
1490
|
+
`${apiBase(config)}/v1/drains${teamQuery(config)}`,
|
|
1491
|
+
{
|
|
1492
|
+
method: "POST",
|
|
1493
|
+
headers: { "Content-Type": "application/json", ...bearerAuthHeader(credentials.token) },
|
|
1494
|
+
body: JSON.stringify(body)
|
|
1495
|
+
},
|
|
1496
|
+
{ provider: "vercel", accountKey: config.teamId, fetchImpl }
|
|
1497
|
+
);
|
|
1498
|
+
if (!res.ok) {
|
|
1499
|
+
throw new Error(
|
|
1500
|
+
`vercel connector: create drain failed (${res.status} ${res.statusText}${await describeError(res)})`
|
|
1501
|
+
);
|
|
1502
|
+
}
|
|
1503
|
+
const payload = await res.json().catch(() => null);
|
|
1504
|
+
if (!payload || typeof payload.id !== "string" || payload.id.length === 0) {
|
|
1505
|
+
throw new Error(
|
|
1506
|
+
"vercel connector: create drain returned no drain id \u2014 the Drains API response shape may have changed"
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
1509
|
+
return {
|
|
1510
|
+
id: payload.id,
|
|
1511
|
+
...payload.status ? { status: payload.status } : {},
|
|
1512
|
+
...payload.disabledReason ? { disabledReason: payload.disabledReason } : {}
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
async function deleteVercelDrain(config, drainId, credentials, fetchImpl = fetch) {
|
|
1516
|
+
const res = await junctionFetch(
|
|
1517
|
+
`${apiBase(config)}/v1/drains/${encodeURIComponent(drainId)}${teamQuery(config)}`,
|
|
1518
|
+
{ method: "DELETE", headers: { ...bearerAuthHeader(credentials.token) } },
|
|
1519
|
+
{ provider: "vercel", accountKey: config.teamId, fetchImpl }
|
|
1520
|
+
);
|
|
1521
|
+
if (res.ok || res.status === 404) return;
|
|
1522
|
+
throw new Error(
|
|
1523
|
+
`vercel connector: delete drain failed (${res.status} ${res.statusText}${await describeError(res)})`
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
async function testVercelDrainDelivery(config, credentials, fetchImpl = fetch) {
|
|
1527
|
+
const res = await junctionFetch(
|
|
1528
|
+
`${apiBase(config)}/v1/drains/test${teamQuery(config)}`,
|
|
1529
|
+
{
|
|
1530
|
+
method: "POST",
|
|
1531
|
+
headers: { "Content-Type": "application/json", ...bearerAuthHeader(credentials.token) },
|
|
1532
|
+
body: JSON.stringify({ schemas: TRACE_SCHEMAS, delivery: drainDelivery(config, credentials.otelToken) })
|
|
1533
|
+
},
|
|
1534
|
+
{ provider: "vercel", accountKey: config.teamId, fetchImpl }
|
|
1535
|
+
);
|
|
1536
|
+
if (res.status === 401 || res.status === 403) {
|
|
1537
|
+
return { status: "failure", error: `vercel rejected the API token (HTTP ${res.status})` };
|
|
1538
|
+
}
|
|
1539
|
+
if (!res.ok) {
|
|
1540
|
+
return {
|
|
1541
|
+
status: "failure",
|
|
1542
|
+
error: `vercel drain validation failed (${res.status} ${res.statusText}${await describeError(res)})`
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
const payload = await res.json().catch(() => null);
|
|
1546
|
+
return {
|
|
1547
|
+
...payload?.status ? { status: payload.status } : {},
|
|
1548
|
+
...payload?.error ? { error: payload.error } : {},
|
|
1549
|
+
...payload?.endpoint ? { endpoint: payload.endpoint } : {}
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1428
1553
|
// src/connectors/registry.ts
|
|
1429
1554
|
var CLOUDFLARE_API_BASE_URL = "https://api.cloudflare.com/client/v4";
|
|
1430
1555
|
async function authProbe(input) {
|
|
@@ -1576,8 +1701,96 @@ var PROVIDER_DISPATCH = {
|
|
|
1576
1701
|
}
|
|
1577
1702
|
}
|
|
1578
1703
|
};
|
|
1579
|
-
function
|
|
1580
|
-
return
|
|
1704
|
+
function vercelCredsFrom(credentials) {
|
|
1705
|
+
return { token: String(credentials.token ?? ""), otelToken: String(credentials.otelToken ?? "") };
|
|
1706
|
+
}
|
|
1707
|
+
function vercelConfigFromOptions(options) {
|
|
1708
|
+
const raw = options.projectIds;
|
|
1709
|
+
let projectIds;
|
|
1710
|
+
if (Array.isArray(raw)) projectIds = raw.filter((p) => typeof p === "string");
|
|
1711
|
+
else if (typeof raw === "string" && raw.trim().length > 0) {
|
|
1712
|
+
projectIds = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
1713
|
+
}
|
|
1714
|
+
return {
|
|
1715
|
+
teamId: String(options.teamId ?? ""),
|
|
1716
|
+
endpoint: String(options.endpoint ?? ""),
|
|
1717
|
+
...projectIds && projectIds.length > 0 ? { projectIds } : {},
|
|
1718
|
+
...typeof options.drainId === "string" ? { drainId: options.drainId } : {},
|
|
1719
|
+
...typeof options.drainName === "string" ? { drainName: options.drainName } : {},
|
|
1720
|
+
...typeof options.apiBaseUrl === "string" ? { apiBaseUrl: options.apiBaseUrl } : {},
|
|
1721
|
+
...typeof options.secret === "string" ? { secret: options.secret } : {}
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
var PUSH_PROVIDER_DISPATCH = {
|
|
1725
|
+
vercel: {
|
|
1726
|
+
provider: "vercel",
|
|
1727
|
+
// The Vercel access token is the "primary" secret a single `--token`
|
|
1728
|
+
// populates; `otelToken` (the daemon's OTLP bearer) is the second field.
|
|
1729
|
+
primaryCredentialKey: "token",
|
|
1730
|
+
requiredCredentialFields: ["token", "otelToken"],
|
|
1731
|
+
// teamId scopes every Drains call; endpoint is where the drain delivers.
|
|
1732
|
+
// projectIds is optional (absent → the drain covers the whole team).
|
|
1733
|
+
requiredOptionFields: ["teamId", "endpoint"],
|
|
1734
|
+
// POST /v1/drains/test — authenticates the token and pings the endpoint
|
|
1735
|
+
// with a sample event, so `success` means the credential is live *and* the
|
|
1736
|
+
// daemon's OTLP endpoint is reachable and accepted the drain's bearer.
|
|
1737
|
+
async validate({ credentials, options, fetchImpl }) {
|
|
1738
|
+
const result = await testVercelDrainDelivery(
|
|
1739
|
+
vercelConfigFromOptions(options),
|
|
1740
|
+
vercelCredsFrom(credentials),
|
|
1741
|
+
fetchImpl
|
|
1742
|
+
);
|
|
1743
|
+
if (result.status === "success") return { ok: true };
|
|
1744
|
+
return {
|
|
1745
|
+
ok: false,
|
|
1746
|
+
reason: result.error ?? `vercel drain delivery test returned "${result.status ?? "no status"}"`
|
|
1747
|
+
};
|
|
1748
|
+
},
|
|
1749
|
+
// POST /v1/drains — creates the trace drain, returns its id to store in
|
|
1750
|
+
// `options.drainId`. A created-but-not-enabled drain is surfaced as a note,
|
|
1751
|
+
// not a failure (the entry still points at a real drain).
|
|
1752
|
+
async provision({ credentials, options, fetchImpl }) {
|
|
1753
|
+
try {
|
|
1754
|
+
const created = await createVercelDrain(
|
|
1755
|
+
vercelConfigFromOptions(options),
|
|
1756
|
+
vercelCredsFrom(credentials),
|
|
1757
|
+
fetchImpl
|
|
1758
|
+
);
|
|
1759
|
+
const note = created.status && created.status !== "enabled" ? `the drain was created but its status is "${created.status}"${created.disabledReason ? ` (${created.disabledReason})` : ""} \u2014 check the Vercel dashboard` : void 0;
|
|
1760
|
+
return { ok: true, options: { drainId: created.id }, ...note ? { note } : {} };
|
|
1761
|
+
} catch (err) {
|
|
1762
|
+
return { ok: false, reason: err.message };
|
|
1763
|
+
}
|
|
1764
|
+
},
|
|
1765
|
+
// DELETE /v1/drains/{id} — idempotent (deleteVercelDrain treats 404 as
|
|
1766
|
+
// success). No recorded drainId → nothing to delete, still a success.
|
|
1767
|
+
async deprovision({ credentials, options, fetchImpl }) {
|
|
1768
|
+
const drainId = typeof options.drainId === "string" ? options.drainId : "";
|
|
1769
|
+
if (!drainId) {
|
|
1770
|
+
return { ok: true, note: "no drain id was recorded \u2014 nothing to delete on the Vercel side" };
|
|
1771
|
+
}
|
|
1772
|
+
try {
|
|
1773
|
+
await deleteVercelDrain(
|
|
1774
|
+
vercelConfigFromOptions(options),
|
|
1775
|
+
drainId,
|
|
1776
|
+
vercelCredsFrom(credentials),
|
|
1777
|
+
fetchImpl
|
|
1778
|
+
);
|
|
1779
|
+
return { ok: true };
|
|
1780
|
+
} catch (err) {
|
|
1781
|
+
return { ok: false, reason: err.message };
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
};
|
|
1786
|
+
function isPushProvider(provider) {
|
|
1787
|
+
return provider in PUSH_PROVIDER_DISPATCH;
|
|
1788
|
+
}
|
|
1789
|
+
function getProviderFieldSchema(provider) {
|
|
1790
|
+
return PROVIDER_DISPATCH[provider] ?? PUSH_PROVIDER_DISPATCH[provider];
|
|
1791
|
+
}
|
|
1792
|
+
function knownProviderNames() {
|
|
1793
|
+
return [...Object.keys(PROVIDER_DISPATCH), ...Object.keys(PUSH_PROVIDER_DISPATCH)].sort();
|
|
1581
1794
|
}
|
|
1582
1795
|
function resolveEntryCredentials(dispatch, entry, env) {
|
|
1583
1796
|
let credentials;
|
|
@@ -1601,6 +1814,13 @@ function resolveEntryCredentials(dispatch, entry, env) {
|
|
|
1601
1814
|
function buildRegistration(entry, graph, env = process.env) {
|
|
1602
1815
|
const dispatch = PROVIDER_DISPATCH[entry.provider];
|
|
1603
1816
|
if (!dispatch) {
|
|
1817
|
+
if (isPushProvider(entry.provider)) {
|
|
1818
|
+
return {
|
|
1819
|
+
ok: false,
|
|
1820
|
+
push: true,
|
|
1821
|
+
reason: `push provider "${entry.provider}" ingests via the OTLP receiver \u2014 nothing to poll`
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1604
1824
|
return { ok: false, reason: `unknown provider "${entry.provider}"` };
|
|
1605
1825
|
}
|
|
1606
1826
|
const creds = resolveEntryCredentials(dispatch, entry, env);
|
|
@@ -1635,7 +1855,7 @@ function buildRegistration(entry, graph, env = process.env) {
|
|
|
1635
1855
|
};
|
|
1636
1856
|
}
|
|
1637
1857
|
async function validateConnectorEntry(entry, env = process.env, fetchImpl) {
|
|
1638
|
-
const dispatch = PROVIDER_DISPATCH[entry.provider];
|
|
1858
|
+
const dispatch = PROVIDER_DISPATCH[entry.provider] ?? PUSH_PROVIDER_DISPATCH[entry.provider];
|
|
1639
1859
|
if (!dispatch) {
|
|
1640
1860
|
return { status: "unknown-provider", reason: `unknown provider "${entry.provider}"` };
|
|
1641
1861
|
}
|
|
@@ -1676,10 +1896,58 @@ async function loadConnectorRegistrations(input) {
|
|
|
1676
1896
|
if (!connectorMatchesProject(entry, project)) continue;
|
|
1677
1897
|
const result = buildRegistration(entry, graph, env);
|
|
1678
1898
|
if (result.ok) registrations.push(result.registration);
|
|
1679
|
-
else onSkip?.(entry, result.reason);
|
|
1899
|
+
else if (!result.push) onSkip?.(entry, result.reason);
|
|
1680
1900
|
}
|
|
1681
1901
|
return registrations;
|
|
1682
1902
|
}
|
|
1903
|
+
function resolvePushEntry(entry, env) {
|
|
1904
|
+
const dispatch = PUSH_PROVIDER_DISPATCH[entry.provider];
|
|
1905
|
+
if (!dispatch) {
|
|
1906
|
+
return PROVIDER_DISPATCH[entry.provider] ? {
|
|
1907
|
+
ok: false,
|
|
1908
|
+
outcome: {
|
|
1909
|
+
status: "not-push",
|
|
1910
|
+
reason: `provider "${entry.provider}" is polled, not provisioned \u2014 there is no drain to manage`
|
|
1911
|
+
}
|
|
1912
|
+
} : { ok: false, outcome: { status: "unknown-provider", reason: `unknown provider "${entry.provider}"` } };
|
|
1913
|
+
}
|
|
1914
|
+
const creds = resolveEntryCredentials(dispatch, entry, env);
|
|
1915
|
+
if (!creds.ok) {
|
|
1916
|
+
const status = creds.kind === "unset-env" ? "unset-env" : creds.kind === "missing-field" ? "missing-field" : "failed";
|
|
1917
|
+
return { ok: false, outcome: { status, reason: creds.reason } };
|
|
1918
|
+
}
|
|
1919
|
+
const options = entry.options ?? {};
|
|
1920
|
+
const missingOpts = dispatch.requiredOptionFields.filter((k) => !(k in options));
|
|
1921
|
+
if (missingOpts.length > 0) {
|
|
1922
|
+
return {
|
|
1923
|
+
ok: false,
|
|
1924
|
+
outcome: { status: "missing-field", reason: `options missing required field(s): ${missingOpts.join(", ")}` }
|
|
1925
|
+
};
|
|
1926
|
+
}
|
|
1927
|
+
return { ok: true, dispatch, credentials: creds.credentials, options };
|
|
1928
|
+
}
|
|
1929
|
+
async function provisionConnector(entry, env = process.env, fetchImpl) {
|
|
1930
|
+
const resolved = resolvePushEntry(entry, env);
|
|
1931
|
+
if (!resolved.ok) return resolved.outcome;
|
|
1932
|
+
const result = await resolved.dispatch.provision({
|
|
1933
|
+
credentials: resolved.credentials,
|
|
1934
|
+
options: resolved.options,
|
|
1935
|
+
...fetchImpl ? { fetchImpl } : {}
|
|
1936
|
+
});
|
|
1937
|
+
if (!result.ok) return { status: "failed", reason: result.reason };
|
|
1938
|
+
return { status: "ok", ...result.options ? { options: result.options } : {}, ...result.note ? { note: result.note } : {} };
|
|
1939
|
+
}
|
|
1940
|
+
async function deprovisionConnector(entry, env = process.env, fetchImpl) {
|
|
1941
|
+
const resolved = resolvePushEntry(entry, env);
|
|
1942
|
+
if (!resolved.ok) return resolved.outcome;
|
|
1943
|
+
const result = await resolved.dispatch.deprovision({
|
|
1944
|
+
credentials: resolved.credentials,
|
|
1945
|
+
options: resolved.options,
|
|
1946
|
+
...fetchImpl ? { fetchImpl } : {}
|
|
1947
|
+
});
|
|
1948
|
+
if (!result.ok) return { status: "failed", reason: result.reason };
|
|
1949
|
+
return { status: "ok", ...result.note ? { note: result.note } : {} };
|
|
1950
|
+
}
|
|
1683
1951
|
|
|
1684
1952
|
// src/unrouted.ts
|
|
1685
1953
|
import { promises as fs } from "fs";
|
|
@@ -2475,9 +2743,12 @@ async function startDaemon(opts = {}) {
|
|
|
2475
2743
|
}
|
|
2476
2744
|
|
|
2477
2745
|
export {
|
|
2478
|
-
|
|
2479
|
-
|
|
2746
|
+
isPushProvider,
|
|
2747
|
+
getProviderFieldSchema,
|
|
2748
|
+
knownProviderNames,
|
|
2480
2749
|
validateConnectorEntry,
|
|
2750
|
+
provisionConnector,
|
|
2751
|
+
deprovisionConnector,
|
|
2481
2752
|
readDaemonRecord,
|
|
2482
2753
|
resolveNeatVersion,
|
|
2483
2754
|
writeDaemonRecord,
|
|
@@ -2488,4 +2759,4 @@ export {
|
|
|
2488
2759
|
resolveHost,
|
|
2489
2760
|
startDaemon
|
|
2490
2761
|
};
|
|
2491
|
-
//# sourceMappingURL=chunk-
|
|
2762
|
+
//# sourceMappingURL=chunk-VR73QNJD.js.map
|