@neat.is/core 0.4.30-dev.20260716 → 0.4.30
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-AOLXZWRU.js → chunk-2AJHEZIB.js} +84 -77
- package/dist/chunk-2AJHEZIB.js.map +1 -0
- package/dist/{chunk-6HPRD53A.js → chunk-4M2YMGUM.js} +2 -2
- package/dist/chunk-4M2YMGUM.js.map +1 -0
- package/dist/cli.cjs +83 -76
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +83 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +83 -76
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +1 -1
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-6HPRD53A.js.map +0 -1
- package/dist/chunk-AOLXZWRU.js.map +0 -1
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
touchLastSeen,
|
|
32
32
|
upsertObservedEdge,
|
|
33
33
|
writeAtomically
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-4M2YMGUM.js";
|
|
35
35
|
import {
|
|
36
36
|
assertBindAuthority,
|
|
37
37
|
buildOtelReceiver,
|
|
@@ -724,25 +724,21 @@ function readRailwayToken(credentials) {
|
|
|
724
724
|
}
|
|
725
725
|
return token;
|
|
726
726
|
}
|
|
727
|
-
|
|
727
|
+
function projectAccessTokenHeader(token) {
|
|
728
|
+
return { "Project-Access-Token": token };
|
|
729
|
+
}
|
|
730
|
+
async function railwayGraphQL(apiUrl, token, query, variables, accountKey, fetchImpl) {
|
|
728
731
|
const res = await junctionFetch(
|
|
729
732
|
apiUrl,
|
|
730
733
|
{
|
|
731
734
|
method: "POST",
|
|
732
735
|
headers: {
|
|
733
736
|
"Content-Type": "application/json",
|
|
734
|
-
|
|
735
|
-
// `Authorization: Bearer <token>` for an account/workspace token;
|
|
736
|
-
// Railway also documents a dedicated `Project-Access-Token: <token>`
|
|
737
|
-
// header for the project-scoped token ADR-127 targets specifically.
|
|
738
|
-
// This connector sends the Bearer form — needs-endpoint-testing
|
|
739
|
-
// whether a live Project-Access-Token requires the dedicated header
|
|
740
|
-
// instead once this poller runs against a real project.
|
|
741
|
-
...bearerAuthHeader(token)
|
|
737
|
+
...projectAccessTokenHeader(token)
|
|
742
738
|
},
|
|
743
739
|
body: JSON.stringify({ query, variables })
|
|
744
740
|
},
|
|
745
|
-
{ provider: "railway", accountKey }
|
|
741
|
+
{ provider: "railway", accountKey, ...fetchImpl ? { fetchImpl } : {} }
|
|
746
742
|
);
|
|
747
743
|
if (!res.ok) {
|
|
748
744
|
throw new Error(`Railway GraphQL request failed: ${res.status} ${res.statusText}`);
|
|
@@ -755,20 +751,8 @@ async function railwayGraphQL(apiUrl, token, query, variables, accountKey) {
|
|
|
755
751
|
return body.data;
|
|
756
752
|
}
|
|
757
753
|
var HTTP_LOGS_QUERY = `
|
|
758
|
-
query HttpLogs(
|
|
759
|
-
$
|
|
760
|
-
$serviceId: String!
|
|
761
|
-
$startDate: String!
|
|
762
|
-
$endDate: String!
|
|
763
|
-
$limit: Int
|
|
764
|
-
) {
|
|
765
|
-
httpLogs(
|
|
766
|
-
environmentId: $environmentId
|
|
767
|
-
serviceId: $serviceId
|
|
768
|
-
startDate: $startDate
|
|
769
|
-
endDate: $endDate
|
|
770
|
-
limit: $limit
|
|
771
|
-
) {
|
|
754
|
+
query HttpLogs($deploymentId: String!, $startDate: String, $endDate: String, $limit: Int) {
|
|
755
|
+
httpLogs(deploymentId: $deploymentId, startDate: $startDate, endDate: $endDate, limit: $limit) {
|
|
772
756
|
timestamp
|
|
773
757
|
method
|
|
774
758
|
path
|
|
@@ -781,21 +765,9 @@ var HTTP_LOGS_QUERY = `
|
|
|
781
765
|
}
|
|
782
766
|
`;
|
|
783
767
|
var NETWORK_FLOW_LOGS_QUERY = `
|
|
784
|
-
query NetworkFlowLogs(
|
|
785
|
-
$environmentId:
|
|
786
|
-
|
|
787
|
-
$startDate: String!
|
|
788
|
-
$endDate: String!
|
|
789
|
-
$limit: Int
|
|
790
|
-
) {
|
|
791
|
-
networkFlowLogs(
|
|
792
|
-
environmentId: $environmentId
|
|
793
|
-
serviceId: $serviceId
|
|
794
|
-
startDate: $startDate
|
|
795
|
-
endDate: $endDate
|
|
796
|
-
limit: $limit
|
|
797
|
-
) {
|
|
798
|
-
timestamp
|
|
768
|
+
query NetworkFlowLogs($environmentId: String!, $serviceId: String) {
|
|
769
|
+
networkFlowLogs(environmentId: $environmentId, serviceId: $serviceId) {
|
|
770
|
+
timestamp: captureStart
|
|
799
771
|
peerServiceId
|
|
800
772
|
peerKind
|
|
801
773
|
direction
|
|
@@ -805,34 +777,43 @@ var NETWORK_FLOW_LOGS_QUERY = `
|
|
|
805
777
|
}
|
|
806
778
|
}
|
|
807
779
|
`;
|
|
808
|
-
|
|
780
|
+
var DEPLOYMENTS_QUERY = `
|
|
781
|
+
query LatestDeployment($environmentId: String!, $serviceId: String!) {
|
|
782
|
+
deployments(input: { environmentId: $environmentId, serviceId: $serviceId }, first: 5) {
|
|
783
|
+
edges { node { id status createdAt } }
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
`;
|
|
787
|
+
async function resolveLatestRailwayDeploymentId(config, token, fetchImpl) {
|
|
788
|
+
const data = await railwayGraphQL(
|
|
789
|
+
config.apiUrl ?? DEFAULT_RAILWAY_API_URL,
|
|
790
|
+
token,
|
|
791
|
+
DEPLOYMENTS_QUERY,
|
|
792
|
+
{ environmentId: config.environmentId, serviceId: config.serviceId },
|
|
793
|
+
config.environmentId,
|
|
794
|
+
fetchImpl
|
|
795
|
+
);
|
|
796
|
+
const nodes = data.deployments.edges.map((e) => e.node);
|
|
797
|
+
const newestFirst = [...nodes].sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
798
|
+
const success = newestFirst.find((n) => n.status === "SUCCESS");
|
|
799
|
+
return (success ?? newestFirst[0])?.id ?? null;
|
|
800
|
+
}
|
|
801
|
+
async function fetchRailwayHttpLogs(config, token, deploymentId, startDate, endDate) {
|
|
809
802
|
const data = await railwayGraphQL(
|
|
810
803
|
config.apiUrl ?? DEFAULT_RAILWAY_API_URL,
|
|
811
804
|
token,
|
|
812
805
|
HTTP_LOGS_QUERY,
|
|
813
|
-
{
|
|
814
|
-
environmentId: config.environmentId,
|
|
815
|
-
serviceId: config.serviceId,
|
|
816
|
-
startDate,
|
|
817
|
-
endDate,
|
|
818
|
-
limit: config.limit ?? DEFAULT_LOG_LIMIT2
|
|
819
|
-
},
|
|
806
|
+
{ deploymentId, startDate, endDate, limit: config.limit ?? DEFAULT_LOG_LIMIT2 },
|
|
820
807
|
config.environmentId
|
|
821
808
|
);
|
|
822
809
|
return data.httpLogs;
|
|
823
810
|
}
|
|
824
|
-
async function fetchRailwayNetworkFlowLogs(config, token
|
|
811
|
+
async function fetchRailwayNetworkFlowLogs(config, token) {
|
|
825
812
|
const data = await railwayGraphQL(
|
|
826
813
|
config.apiUrl ?? DEFAULT_RAILWAY_API_URL,
|
|
827
814
|
token,
|
|
828
815
|
NETWORK_FLOW_LOGS_QUERY,
|
|
829
|
-
{
|
|
830
|
-
environmentId: config.environmentId,
|
|
831
|
-
serviceId: config.serviceId,
|
|
832
|
-
startDate,
|
|
833
|
-
endDate,
|
|
834
|
-
limit: config.limit ?? DEFAULT_LOG_LIMIT2
|
|
835
|
-
},
|
|
816
|
+
{ environmentId: config.environmentId, serviceId: config.serviceId },
|
|
836
817
|
config.environmentId
|
|
837
818
|
);
|
|
838
819
|
return data.networkFlowLogs;
|
|
@@ -968,10 +949,19 @@ function createRailwayConnector(graph, config) {
|
|
|
968
949
|
const maxLookbackMs = config.maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS2;
|
|
969
950
|
const startDate = boundedRailwayStartDate(ctx.since, now, maxLookbackMs);
|
|
970
951
|
const endDate = now.toISOString();
|
|
971
|
-
const
|
|
972
|
-
|
|
973
|
-
|
|
952
|
+
const deploymentId = await resolveLatestRailwayDeploymentId(config, token);
|
|
953
|
+
const [httpLogsResult, flowLogsResult] = await Promise.allSettled([
|
|
954
|
+
deploymentId ? fetchRailwayHttpLogs(config, token, deploymentId, startDate, endDate) : Promise.resolve([]),
|
|
955
|
+
fetchRailwayNetworkFlowLogs(config, token)
|
|
974
956
|
]);
|
|
957
|
+
if (httpLogsResult.status === "rejected") {
|
|
958
|
+
console.error("[neat connector] railway httpLogs poll failed", httpLogsResult.reason);
|
|
959
|
+
}
|
|
960
|
+
if (flowLogsResult.status === "rejected") {
|
|
961
|
+
console.error("[neat connector] railway networkFlowLogs poll failed", flowLogsResult.reason);
|
|
962
|
+
}
|
|
963
|
+
const httpLogs = httpLogsResult.status === "fulfilled" ? httpLogsResult.value : [];
|
|
964
|
+
const flowLogs = flowLogsResult.status === "fulfilled" ? flowLogsResult.value : [];
|
|
975
965
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
976
966
|
const routeIndex = serviceName ? buildRailwayRouteIndex(graph, serviceName) : [];
|
|
977
967
|
return [
|
|
@@ -1216,6 +1206,12 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
|
|
|
1216
1206
|
timeframe: { from: window.fromMs, to: window.toMs },
|
|
1217
1207
|
view: "events",
|
|
1218
1208
|
limit: config.eventLimit ?? DEFAULT_EVENT_LIMIT,
|
|
1209
|
+
// The inline query definition. WITHOUT `parameters`, the API treats
|
|
1210
|
+
// `queryId` as a reference to a previously *saved* query and answers 400
|
|
1211
|
+
// "Query not found" (confirmed against the live endpoint) — omitting it was
|
|
1212
|
+
// the reason the connector never worked against real Cloudflare. Naming the
|
|
1213
|
+
// `cloudflare-workers` dataset runs the invocation-telemetry query ad-hoc.
|
|
1214
|
+
parameters: { datasets: ["cloudflare-workers"] },
|
|
1219
1215
|
// Execute without persisting — this is a read, not a saved query
|
|
1220
1216
|
// (connectors.md §2's "never writes on the read path" applies to
|
|
1221
1217
|
// Cloudflare's own query-history state too).
|
|
@@ -1466,24 +1462,35 @@ var PROVIDER_DISPATCH = {
|
|
|
1466
1462
|
resolveTarget: createRailwayResolveTarget(config)
|
|
1467
1463
|
};
|
|
1468
1464
|
},
|
|
1469
|
-
//
|
|
1470
|
-
//
|
|
1471
|
-
//
|
|
1472
|
-
//
|
|
1473
|
-
|
|
1465
|
+
// Runs the same `deployments` lookup the poller itself needs
|
|
1466
|
+
// (railway/client.ts's resolveLatestRailwayDeploymentId) rather than a
|
|
1467
|
+
// trivial `{ __typename }` probe. That trivial form is a false positive
|
|
1468
|
+
// for this provider: `Authorization: Bearer <token>` authenticates at
|
|
1469
|
+
// Railway's HTTP gateway (any well-formed token gets a 2xx on a query
|
|
1470
|
+
// that touches no real data) but is not authorized for the connector's
|
|
1471
|
+
// actual queries, which come back as an HTTP-200 response carrying a
|
|
1472
|
+
// GraphQL-level "Not Authorized" error — invisible to authProbe's
|
|
1473
|
+
// status-code-only check. Probing with the real lookup, through the same
|
|
1474
|
+
// Project-Access-Token header client.ts sends, catches both failure
|
|
1475
|
+
// modes: an HTTP-level rejection (thrown as a fetch/status error) and a
|
|
1476
|
+
// GraphQL-level one (thrown by railwayGraphQL's own body.errors check).
|
|
1477
|
+
async validate({ credentials, options, fetchImpl }) {
|
|
1474
1478
|
const cfg = options;
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1479
|
+
if (!cfg.environmentId || !cfg.serviceId) {
|
|
1480
|
+
return { ok: false, reason: "railway: environmentId and serviceId are required to validate" };
|
|
1481
|
+
}
|
|
1482
|
+
const config = {
|
|
1483
|
+
environmentId: cfg.environmentId,
|
|
1484
|
+
serviceId: cfg.serviceId,
|
|
1485
|
+
serviceNameById: cfg.serviceNameById ?? {},
|
|
1486
|
+
...cfg.apiUrl ? { apiUrl: cfg.apiUrl } : {}
|
|
1487
|
+
};
|
|
1488
|
+
try {
|
|
1489
|
+
await resolveLatestRailwayDeploymentId(config, String(credentials.token ?? ""), fetchImpl);
|
|
1490
|
+
return { ok: true };
|
|
1491
|
+
} catch (err) {
|
|
1492
|
+
return { ok: false, reason: `railway auth check failed: ${err.message}` };
|
|
1493
|
+
}
|
|
1487
1494
|
}
|
|
1488
1495
|
},
|
|
1489
1496
|
firebase: {
|
|
@@ -2454,4 +2461,4 @@ export {
|
|
|
2454
2461
|
resolveHost,
|
|
2455
2462
|
startDaemon
|
|
2456
2463
|
};
|
|
2457
|
-
//# sourceMappingURL=chunk-
|
|
2464
|
+
//# sourceMappingURL=chunk-2AJHEZIB.js.map
|