@neat.is/core 0.4.29 → 0.4.30-dev.20260717

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/cli.cjs CHANGED
@@ -1571,7 +1571,7 @@ function getTransitiveDependencies(graph, nodeId, depth = TRANSITIVE_DEPENDENCIE
1571
1571
  const enqueued = /* @__PURE__ */ new Set([nodeId]);
1572
1572
  while (queue.length > 0) {
1573
1573
  const frame = queue.shift();
1574
- if (frame.distance > 0 && frame.edge) {
1574
+ if (frame.distance > 0 && frame.edge && frame.edge.type !== import_types.EdgeType.CONTAINS) {
1575
1575
  seen.set(frame.nodeId, {
1576
1576
  nodeId: frame.nodeId,
1577
1577
  distance: frame.distance,
@@ -10551,25 +10551,21 @@ function readRailwayToken(credentials) {
10551
10551
  }
10552
10552
  return token;
10553
10553
  }
10554
- async function railwayGraphQL(apiUrl, token, query, variables, accountKey) {
10554
+ function projectAccessTokenHeader(token) {
10555
+ return { "Project-Access-Token": token };
10556
+ }
10557
+ async function railwayGraphQL(apiUrl, token, query, variables, accountKey, fetchImpl) {
10555
10558
  const res = await junctionFetch(
10556
10559
  apiUrl,
10557
10560
  {
10558
10561
  method: "POST",
10559
10562
  headers: {
10560
10563
  "Content-Type": "application/json",
10561
- // docs.railway.com/integrations/api/graphql-overview confirms
10562
- // `Authorization: Bearer <token>` for an account/workspace token;
10563
- // Railway also documents a dedicated `Project-Access-Token: <token>`
10564
- // header for the project-scoped token ADR-127 targets specifically.
10565
- // This connector sends the Bearer form — needs-endpoint-testing
10566
- // whether a live Project-Access-Token requires the dedicated header
10567
- // instead once this poller runs against a real project.
10568
- ...bearerAuthHeader(token)
10564
+ ...projectAccessTokenHeader(token)
10569
10565
  },
10570
10566
  body: JSON.stringify({ query, variables })
10571
10567
  },
10572
- { provider: "railway", accountKey }
10568
+ { provider: "railway", accountKey, ...fetchImpl ? { fetchImpl } : {} }
10573
10569
  );
10574
10570
  if (!res.ok) {
10575
10571
  throw new Error(`Railway GraphQL request failed: ${res.status} ${res.statusText}`);
@@ -10582,20 +10578,8 @@ async function railwayGraphQL(apiUrl, token, query, variables, accountKey) {
10582
10578
  return body.data;
10583
10579
  }
10584
10580
  var HTTP_LOGS_QUERY = `
10585
- query HttpLogs(
10586
- $environmentId: String!
10587
- $serviceId: String!
10588
- $startDate: String!
10589
- $endDate: String!
10590
- $limit: Int
10591
- ) {
10592
- httpLogs(
10593
- environmentId: $environmentId
10594
- serviceId: $serviceId
10595
- startDate: $startDate
10596
- endDate: $endDate
10597
- limit: $limit
10598
- ) {
10581
+ query HttpLogs($deploymentId: String!, $startDate: String, $endDate: String, $limit: Int) {
10582
+ httpLogs(deploymentId: $deploymentId, startDate: $startDate, endDate: $endDate, limit: $limit) {
10599
10583
  timestamp
10600
10584
  method
10601
10585
  path
@@ -10608,21 +10592,9 @@ var HTTP_LOGS_QUERY = `
10608
10592
  }
10609
10593
  `;
10610
10594
  var NETWORK_FLOW_LOGS_QUERY = `
10611
- query NetworkFlowLogs(
10612
- $environmentId: String!
10613
- $serviceId: String!
10614
- $startDate: String!
10615
- $endDate: String!
10616
- $limit: Int
10617
- ) {
10618
- networkFlowLogs(
10619
- environmentId: $environmentId
10620
- serviceId: $serviceId
10621
- startDate: $startDate
10622
- endDate: $endDate
10623
- limit: $limit
10624
- ) {
10625
- timestamp
10595
+ query NetworkFlowLogs($environmentId: String!, $serviceId: String) {
10596
+ networkFlowLogs(environmentId: $environmentId, serviceId: $serviceId) {
10597
+ timestamp: captureStart
10626
10598
  peerServiceId
10627
10599
  peerKind
10628
10600
  direction
@@ -10632,34 +10604,43 @@ var NETWORK_FLOW_LOGS_QUERY = `
10632
10604
  }
10633
10605
  }
10634
10606
  `;
10635
- async function fetchRailwayHttpLogs(config, token, startDate, endDate) {
10607
+ var DEPLOYMENTS_QUERY = `
10608
+ query LatestDeployment($environmentId: String!, $serviceId: String!) {
10609
+ deployments(input: { environmentId: $environmentId, serviceId: $serviceId }, first: 5) {
10610
+ edges { node { id status createdAt } }
10611
+ }
10612
+ }
10613
+ `;
10614
+ async function resolveLatestRailwayDeploymentId(config, token, fetchImpl) {
10615
+ const data = await railwayGraphQL(
10616
+ config.apiUrl ?? DEFAULT_RAILWAY_API_URL,
10617
+ token,
10618
+ DEPLOYMENTS_QUERY,
10619
+ { environmentId: config.environmentId, serviceId: config.serviceId },
10620
+ config.environmentId,
10621
+ fetchImpl
10622
+ );
10623
+ const nodes = data.deployments.edges.map((e) => e.node);
10624
+ const newestFirst = [...nodes].sort((a, b) => b.createdAt.localeCompare(a.createdAt));
10625
+ const success = newestFirst.find((n) => n.status === "SUCCESS");
10626
+ return (success ?? newestFirst[0])?.id ?? null;
10627
+ }
10628
+ async function fetchRailwayHttpLogs(config, token, deploymentId, startDate, endDate) {
10636
10629
  const data = await railwayGraphQL(
10637
10630
  config.apiUrl ?? DEFAULT_RAILWAY_API_URL,
10638
10631
  token,
10639
10632
  HTTP_LOGS_QUERY,
10640
- {
10641
- environmentId: config.environmentId,
10642
- serviceId: config.serviceId,
10643
- startDate,
10644
- endDate,
10645
- limit: config.limit ?? DEFAULT_LOG_LIMIT2
10646
- },
10633
+ { deploymentId, startDate, endDate, limit: config.limit ?? DEFAULT_LOG_LIMIT2 },
10647
10634
  config.environmentId
10648
10635
  );
10649
10636
  return data.httpLogs;
10650
10637
  }
10651
- async function fetchRailwayNetworkFlowLogs(config, token, startDate, endDate) {
10638
+ async function fetchRailwayNetworkFlowLogs(config, token) {
10652
10639
  const data = await railwayGraphQL(
10653
10640
  config.apiUrl ?? DEFAULT_RAILWAY_API_URL,
10654
10641
  token,
10655
10642
  NETWORK_FLOW_LOGS_QUERY,
10656
- {
10657
- environmentId: config.environmentId,
10658
- serviceId: config.serviceId,
10659
- startDate,
10660
- endDate,
10661
- limit: config.limit ?? DEFAULT_LOG_LIMIT2
10662
- },
10643
+ { environmentId: config.environmentId, serviceId: config.serviceId },
10663
10644
  config.environmentId
10664
10645
  );
10665
10646
  return data.networkFlowLogs;
@@ -10795,10 +10776,19 @@ function createRailwayConnector(graph, config) {
10795
10776
  const maxLookbackMs = config.maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS2;
10796
10777
  const startDate = boundedRailwayStartDate(ctx.since, now, maxLookbackMs);
10797
10778
  const endDate = now.toISOString();
10798
- const [httpLogs, flowLogs] = await Promise.all([
10799
- fetchRailwayHttpLogs(config, token, startDate, endDate),
10800
- fetchRailwayNetworkFlowLogs(config, token, startDate, endDate)
10779
+ const deploymentId = await resolveLatestRailwayDeploymentId(config, token);
10780
+ const [httpLogsResult, flowLogsResult] = await Promise.allSettled([
10781
+ deploymentId ? fetchRailwayHttpLogs(config, token, deploymentId, startDate, endDate) : Promise.resolve([]),
10782
+ fetchRailwayNetworkFlowLogs(config, token)
10801
10783
  ]);
10784
+ if (httpLogsResult.status === "rejected") {
10785
+ console.error("[neat connector] railway httpLogs poll failed", httpLogsResult.reason);
10786
+ }
10787
+ if (flowLogsResult.status === "rejected") {
10788
+ console.error("[neat connector] railway networkFlowLogs poll failed", flowLogsResult.reason);
10789
+ }
10790
+ const httpLogs = httpLogsResult.status === "fulfilled" ? httpLogsResult.value : [];
10791
+ const flowLogs = flowLogsResult.status === "fulfilled" ? flowLogsResult.value : [];
10802
10792
  const serviceName = config.serviceNameById[config.serviceId];
10803
10793
  const routeIndex = serviceName ? buildRailwayRouteIndex(graph, serviceName) : [];
10804
10794
  return [
@@ -11054,6 +11044,12 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
11054
11044
  timeframe: { from: window.fromMs, to: window.toMs },
11055
11045
  view: "events",
11056
11046
  limit: config.eventLimit ?? DEFAULT_EVENT_LIMIT,
11047
+ // The inline query definition. WITHOUT `parameters`, the API treats
11048
+ // `queryId` as a reference to a previously *saved* query and answers 400
11049
+ // "Query not found" (confirmed against the live endpoint) — omitting it was
11050
+ // the reason the connector never worked against real Cloudflare. Naming the
11051
+ // `cloudflare-workers` dataset runs the invocation-telemetry query ad-hoc.
11052
+ parameters: { datasets: ["cloudflare-workers"] },
11057
11053
  // Execute without persisting — this is a read, not a saved query
11058
11054
  // (connectors.md §2's "never writes on the read path" applies to
11059
11055
  // Cloudflare's own query-history state too).
@@ -11308,24 +11304,35 @@ var PROVIDER_DISPATCH = {
11308
11304
  resolveTarget: createRailwayResolveTarget(config)
11309
11305
  };
11310
11306
  },
11311
- // A minimal GraphQL POST Railway's gateway 401s an unauthenticated call
11312
- // at the HTTP layer, so a 2xx confirms the token was accepted regardless of
11313
- // the query's own shape (the connector's real queries are still
11314
- // needs-endpoint-testing per railway/types.ts auth is what we check).
11315
- validate({ credentials, options, fetchImpl }) {
11307
+ // Runs the same `deployments` lookup the poller itself needs
11308
+ // (railway/client.ts's resolveLatestRailwayDeploymentId) rather than a
11309
+ // trivial `{ __typename }` probe. That trivial form is a false positive
11310
+ // for this provider: `Authorization: Bearer <token>` authenticates at
11311
+ // Railway's HTTP gateway (any well-formed token gets a 2xx on a query
11312
+ // that touches no real data) but is not authorized for the connector's
11313
+ // actual queries, which come back as an HTTP-200 response carrying a
11314
+ // GraphQL-level "Not Authorized" error — invisible to authProbe's
11315
+ // status-code-only check. Probing with the real lookup, through the same
11316
+ // Project-Access-Token header client.ts sends, catches both failure
11317
+ // modes: an HTTP-level rejection (thrown as a fetch/status error) and a
11318
+ // GraphQL-level one (thrown by railwayGraphQL's own body.errors check).
11319
+ async validate({ credentials, options, fetchImpl }) {
11316
11320
  const cfg = options;
11317
- return authProbe({
11318
- provider: "railway",
11319
- accountKey: cfg.environmentId ?? "validate",
11320
- url: cfg.apiUrl ?? DEFAULT_RAILWAY_API_URL,
11321
- token: String(credentials.token ?? ""),
11322
- init: {
11323
- method: "POST",
11324
- headers: { "Content-Type": "application/json" },
11325
- body: JSON.stringify({ query: "{ __typename }" })
11326
- },
11327
- ...fetchImpl ? { fetchImpl } : {}
11328
- });
11321
+ if (!cfg.environmentId || !cfg.serviceId) {
11322
+ return { ok: false, reason: "railway: environmentId and serviceId are required to validate" };
11323
+ }
11324
+ const config = {
11325
+ environmentId: cfg.environmentId,
11326
+ serviceId: cfg.serviceId,
11327
+ serviceNameById: cfg.serviceNameById ?? {},
11328
+ ...cfg.apiUrl ? { apiUrl: cfg.apiUrl } : {}
11329
+ };
11330
+ try {
11331
+ await resolveLatestRailwayDeploymentId(config, String(credentials.token ?? ""), fetchImpl);
11332
+ return { ok: true };
11333
+ } catch (err) {
11334
+ return { ok: false, reason: `railway auth check failed: ${err.message}` };
11335
+ }
11329
11336
  }
11330
11337
  },
11331
11338
  firebase: {