@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/cli.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  resolveNeatVersion,
10
10
  validateConnectorEntry,
11
11
  writeDaemonRecord
12
- } from "./chunk-AOLXZWRU.js";
12
+ } from "./chunk-2AJHEZIB.js";
13
13
  import {
14
14
  buildSearchIndex
15
15
  } from "./chunk-BIY46Q6U.js";
@@ -68,7 +68,7 @@ import {
68
68
  startPersistLoop,
69
69
  startStalenessLoop,
70
70
  upsertConnectorEntry
71
- } from "./chunk-6HPRD53A.js";
71
+ } from "./chunk-4M2YMGUM.js";
72
72
  import {
73
73
  startOtelGrpcReceiver
74
74
  } from "./chunk-I72HTUOG.js";
package/dist/index.cjs CHANGED
@@ -1565,7 +1565,7 @@ function getTransitiveDependencies(graph, nodeId, depth = TRANSITIVE_DEPENDENCIE
1565
1565
  const enqueued = /* @__PURE__ */ new Set([nodeId]);
1566
1566
  while (queue.length > 0) {
1567
1567
  const frame = queue.shift();
1568
- if (frame.distance > 0 && frame.edge) {
1568
+ if (frame.distance > 0 && frame.edge && frame.edge.type !== import_types.EdgeType.CONTAINS) {
1569
1569
  seen.set(frame.nodeId, {
1570
1570
  nodeId: frame.nodeId,
1571
1571
  distance: frame.distance,
@@ -10287,25 +10287,21 @@ function readRailwayToken(credentials) {
10287
10287
  }
10288
10288
  return token;
10289
10289
  }
10290
- async function railwayGraphQL(apiUrl, token, query, variables, accountKey) {
10290
+ function projectAccessTokenHeader(token) {
10291
+ return { "Project-Access-Token": token };
10292
+ }
10293
+ async function railwayGraphQL(apiUrl, token, query, variables, accountKey, fetchImpl) {
10291
10294
  const res = await junctionFetch(
10292
10295
  apiUrl,
10293
10296
  {
10294
10297
  method: "POST",
10295
10298
  headers: {
10296
10299
  "Content-Type": "application/json",
10297
- // docs.railway.com/integrations/api/graphql-overview confirms
10298
- // `Authorization: Bearer <token>` for an account/workspace token;
10299
- // Railway also documents a dedicated `Project-Access-Token: <token>`
10300
- // header for the project-scoped token ADR-127 targets specifically.
10301
- // This connector sends the Bearer form — needs-endpoint-testing
10302
- // whether a live Project-Access-Token requires the dedicated header
10303
- // instead once this poller runs against a real project.
10304
- ...bearerAuthHeader(token)
10300
+ ...projectAccessTokenHeader(token)
10305
10301
  },
10306
10302
  body: JSON.stringify({ query, variables })
10307
10303
  },
10308
- { provider: "railway", accountKey }
10304
+ { provider: "railway", accountKey, ...fetchImpl ? { fetchImpl } : {} }
10309
10305
  );
10310
10306
  if (!res.ok) {
10311
10307
  throw new Error(`Railway GraphQL request failed: ${res.status} ${res.statusText}`);
@@ -10318,20 +10314,8 @@ async function railwayGraphQL(apiUrl, token, query, variables, accountKey) {
10318
10314
  return body.data;
10319
10315
  }
10320
10316
  var HTTP_LOGS_QUERY = `
10321
- query HttpLogs(
10322
- $environmentId: String!
10323
- $serviceId: String!
10324
- $startDate: String!
10325
- $endDate: String!
10326
- $limit: Int
10327
- ) {
10328
- httpLogs(
10329
- environmentId: $environmentId
10330
- serviceId: $serviceId
10331
- startDate: $startDate
10332
- endDate: $endDate
10333
- limit: $limit
10334
- ) {
10317
+ query HttpLogs($deploymentId: String!, $startDate: String, $endDate: String, $limit: Int) {
10318
+ httpLogs(deploymentId: $deploymentId, startDate: $startDate, endDate: $endDate, limit: $limit) {
10335
10319
  timestamp
10336
10320
  method
10337
10321
  path
@@ -10344,21 +10328,9 @@ var HTTP_LOGS_QUERY = `
10344
10328
  }
10345
10329
  `;
10346
10330
  var NETWORK_FLOW_LOGS_QUERY = `
10347
- query NetworkFlowLogs(
10348
- $environmentId: String!
10349
- $serviceId: String!
10350
- $startDate: String!
10351
- $endDate: String!
10352
- $limit: Int
10353
- ) {
10354
- networkFlowLogs(
10355
- environmentId: $environmentId
10356
- serviceId: $serviceId
10357
- startDate: $startDate
10358
- endDate: $endDate
10359
- limit: $limit
10360
- ) {
10361
- timestamp
10331
+ query NetworkFlowLogs($environmentId: String!, $serviceId: String) {
10332
+ networkFlowLogs(environmentId: $environmentId, serviceId: $serviceId) {
10333
+ timestamp: captureStart
10362
10334
  peerServiceId
10363
10335
  peerKind
10364
10336
  direction
@@ -10368,34 +10340,43 @@ var NETWORK_FLOW_LOGS_QUERY = `
10368
10340
  }
10369
10341
  }
10370
10342
  `;
10371
- async function fetchRailwayHttpLogs(config, token, startDate, endDate) {
10343
+ var DEPLOYMENTS_QUERY = `
10344
+ query LatestDeployment($environmentId: String!, $serviceId: String!) {
10345
+ deployments(input: { environmentId: $environmentId, serviceId: $serviceId }, first: 5) {
10346
+ edges { node { id status createdAt } }
10347
+ }
10348
+ }
10349
+ `;
10350
+ async function resolveLatestRailwayDeploymentId(config, token, fetchImpl) {
10351
+ const data = await railwayGraphQL(
10352
+ config.apiUrl ?? DEFAULT_RAILWAY_API_URL,
10353
+ token,
10354
+ DEPLOYMENTS_QUERY,
10355
+ { environmentId: config.environmentId, serviceId: config.serviceId },
10356
+ config.environmentId,
10357
+ fetchImpl
10358
+ );
10359
+ const nodes = data.deployments.edges.map((e) => e.node);
10360
+ const newestFirst = [...nodes].sort((a, b) => b.createdAt.localeCompare(a.createdAt));
10361
+ const success = newestFirst.find((n) => n.status === "SUCCESS");
10362
+ return (success ?? newestFirst[0])?.id ?? null;
10363
+ }
10364
+ async function fetchRailwayHttpLogs(config, token, deploymentId, startDate, endDate) {
10372
10365
  const data = await railwayGraphQL(
10373
10366
  config.apiUrl ?? DEFAULT_RAILWAY_API_URL,
10374
10367
  token,
10375
10368
  HTTP_LOGS_QUERY,
10376
- {
10377
- environmentId: config.environmentId,
10378
- serviceId: config.serviceId,
10379
- startDate,
10380
- endDate,
10381
- limit: config.limit ?? DEFAULT_LOG_LIMIT2
10382
- },
10369
+ { deploymentId, startDate, endDate, limit: config.limit ?? DEFAULT_LOG_LIMIT2 },
10383
10370
  config.environmentId
10384
10371
  );
10385
10372
  return data.httpLogs;
10386
10373
  }
10387
- async function fetchRailwayNetworkFlowLogs(config, token, startDate, endDate) {
10374
+ async function fetchRailwayNetworkFlowLogs(config, token) {
10388
10375
  const data = await railwayGraphQL(
10389
10376
  config.apiUrl ?? DEFAULT_RAILWAY_API_URL,
10390
10377
  token,
10391
10378
  NETWORK_FLOW_LOGS_QUERY,
10392
- {
10393
- environmentId: config.environmentId,
10394
- serviceId: config.serviceId,
10395
- startDate,
10396
- endDate,
10397
- limit: config.limit ?? DEFAULT_LOG_LIMIT2
10398
- },
10379
+ { environmentId: config.environmentId, serviceId: config.serviceId },
10399
10380
  config.environmentId
10400
10381
  );
10401
10382
  return data.networkFlowLogs;
@@ -10531,10 +10512,19 @@ function createRailwayConnector(graph, config) {
10531
10512
  const maxLookbackMs = config.maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS2;
10532
10513
  const startDate = boundedRailwayStartDate(ctx.since, now, maxLookbackMs);
10533
10514
  const endDate = now.toISOString();
10534
- const [httpLogs, flowLogs] = await Promise.all([
10535
- fetchRailwayHttpLogs(config, token, startDate, endDate),
10536
- fetchRailwayNetworkFlowLogs(config, token, startDate, endDate)
10515
+ const deploymentId = await resolveLatestRailwayDeploymentId(config, token);
10516
+ const [httpLogsResult, flowLogsResult] = await Promise.allSettled([
10517
+ deploymentId ? fetchRailwayHttpLogs(config, token, deploymentId, startDate, endDate) : Promise.resolve([]),
10518
+ fetchRailwayNetworkFlowLogs(config, token)
10537
10519
  ]);
10520
+ if (httpLogsResult.status === "rejected") {
10521
+ console.error("[neat connector] railway httpLogs poll failed", httpLogsResult.reason);
10522
+ }
10523
+ if (flowLogsResult.status === "rejected") {
10524
+ console.error("[neat connector] railway networkFlowLogs poll failed", flowLogsResult.reason);
10525
+ }
10526
+ const httpLogs = httpLogsResult.status === "fulfilled" ? httpLogsResult.value : [];
10527
+ const flowLogs = flowLogsResult.status === "fulfilled" ? flowLogsResult.value : [];
10538
10528
  const serviceName = config.serviceNameById[config.serviceId];
10539
10529
  const routeIndex = serviceName ? buildRailwayRouteIndex(graph, serviceName) : [];
10540
10530
  return [
@@ -10790,6 +10780,12 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
10790
10780
  timeframe: { from: window.fromMs, to: window.toMs },
10791
10781
  view: "events",
10792
10782
  limit: config.eventLimit ?? DEFAULT_EVENT_LIMIT,
10783
+ // The inline query definition. WITHOUT `parameters`, the API treats
10784
+ // `queryId` as a reference to a previously *saved* query and answers 400
10785
+ // "Query not found" (confirmed against the live endpoint) — omitting it was
10786
+ // the reason the connector never worked against real Cloudflare. Naming the
10787
+ // `cloudflare-workers` dataset runs the invocation-telemetry query ad-hoc.
10788
+ parameters: { datasets: ["cloudflare-workers"] },
10793
10789
  // Execute without persisting — this is a read, not a saved query
10794
10790
  // (connectors.md §2's "never writes on the read path" applies to
10795
10791
  // Cloudflare's own query-history state too).
@@ -11044,24 +11040,35 @@ var PROVIDER_DISPATCH = {
11044
11040
  resolveTarget: createRailwayResolveTarget(config)
11045
11041
  };
11046
11042
  },
11047
- // A minimal GraphQL POST Railway's gateway 401s an unauthenticated call
11048
- // at the HTTP layer, so a 2xx confirms the token was accepted regardless of
11049
- // the query's own shape (the connector's real queries are still
11050
- // needs-endpoint-testing per railway/types.ts auth is what we check).
11051
- validate({ credentials, options, fetchImpl }) {
11043
+ // Runs the same `deployments` lookup the poller itself needs
11044
+ // (railway/client.ts's resolveLatestRailwayDeploymentId) rather than a
11045
+ // trivial `{ __typename }` probe. That trivial form is a false positive
11046
+ // for this provider: `Authorization: Bearer <token>` authenticates at
11047
+ // Railway's HTTP gateway (any well-formed token gets a 2xx on a query
11048
+ // that touches no real data) but is not authorized for the connector's
11049
+ // actual queries, which come back as an HTTP-200 response carrying a
11050
+ // GraphQL-level "Not Authorized" error — invisible to authProbe's
11051
+ // status-code-only check. Probing with the real lookup, through the same
11052
+ // Project-Access-Token header client.ts sends, catches both failure
11053
+ // modes: an HTTP-level rejection (thrown as a fetch/status error) and a
11054
+ // GraphQL-level one (thrown by railwayGraphQL's own body.errors check).
11055
+ async validate({ credentials, options, fetchImpl }) {
11052
11056
  const cfg = options;
11053
- return authProbe({
11054
- provider: "railway",
11055
- accountKey: cfg.environmentId ?? "validate",
11056
- url: cfg.apiUrl ?? DEFAULT_RAILWAY_API_URL,
11057
- token: String(credentials.token ?? ""),
11058
- init: {
11059
- method: "POST",
11060
- headers: { "Content-Type": "application/json" },
11061
- body: JSON.stringify({ query: "{ __typename }" })
11062
- },
11063
- ...fetchImpl ? { fetchImpl } : {}
11064
- });
11057
+ if (!cfg.environmentId || !cfg.serviceId) {
11058
+ return { ok: false, reason: "railway: environmentId and serviceId are required to validate" };
11059
+ }
11060
+ const config = {
11061
+ environmentId: cfg.environmentId,
11062
+ serviceId: cfg.serviceId,
11063
+ serviceNameById: cfg.serviceNameById ?? {},
11064
+ ...cfg.apiUrl ? { apiUrl: cfg.apiUrl } : {}
11065
+ };
11066
+ try {
11067
+ await resolveLatestRailwayDeploymentId(config, String(credentials.token ?? ""), fetchImpl);
11068
+ return { ok: true };
11069
+ } catch (err) {
11070
+ return { ok: false, reason: `railway auth check failed: ${err.message}` };
11071
+ }
11065
11072
  }
11066
11073
  },
11067
11074
  firebase: {