@neat.is/core 0.9.5-dev.20260824 → 0.9.5

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/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  routeSpanToProject,
3
3
  startDaemon
4
- } from "./chunk-TGCWMMF6.js";
4
+ } from "./chunk-4SLKQNG7.js";
5
5
  import {
6
6
  ProjectNameCollisionError,
7
7
  addProject,
@@ -37,7 +37,7 @@ import {
37
37
  thresholdForEdgeType,
38
38
  touchLastSeen,
39
39
  writeAtomically
40
- } from "./chunk-IVVF37OU.js";
40
+ } from "./chunk-DGAI4VOE.js";
41
41
  import {
42
42
  startOtelGrpcReceiver
43
43
  } from "./chunk-ERE47MCR.js";
package/dist/neatd.cjs CHANGED
@@ -16021,7 +16021,7 @@ var Projects = class {
16021
16021
  init_cjs_shims();
16022
16022
  var import_fastify2 = __toESM(require("fastify"), 1);
16023
16023
  var import_cors = __toESM(require("@fastify/cors"), 1);
16024
- var import_types93 = require("@neat.is/types");
16024
+ var import_types97 = require("@neat.is/types");
16025
16025
 
16026
16026
  // src/extend/index.ts
16027
16027
  init_cjs_shims();
@@ -20130,9 +20130,229 @@ function createCloudRunConnector(graph, config = {}) {
20130
20130
  };
20131
20131
  }
20132
20132
 
20133
+ // src/connectors/gcp-lb/index.ts
20134
+ init_cjs_shims();
20135
+
20136
+ // src/connectors/gcp-lb/client.ts
20137
+ init_cjs_shims();
20138
+ function gcpLbRequestLogName(projectId) {
20139
+ return `projects/${projectId}/logs/requests`;
20140
+ }
20141
+ function buildGcpLbEntriesFilter(projectId, sinceIso) {
20142
+ return [
20143
+ `logName = "${gcpLbRequestLogName(projectId)}"`,
20144
+ `resource.type = "${GCP_LB_RESOURCE_TYPE}"`,
20145
+ 'httpRequest.requestMethod != ""',
20146
+ `timestamp >= "${sinceIso}"`
20147
+ ].join(" AND ");
20148
+ }
20149
+ var GCP_LB_RESOURCE_TYPE = "http_load_balancer";
20150
+ var DEFAULT_LOOKBACK_MS3 = 24 * 60 * 60 * 1e3;
20151
+ var ENTRIES_LIST_URL3 = "https://logging.googleapis.com/v2/entries:list";
20152
+ var PAGE_SIZE3 = 1e3;
20153
+ var MAX_PAGES3 = 20;
20154
+ async function fetchGcpLbRequestLogEntries(creds, sinceIso, apiUrl = ENTRIES_LIST_URL3) {
20155
+ const filter = buildGcpLbEntriesFilter(creds.projectId, sinceIso);
20156
+ const out = [];
20157
+ let pageToken;
20158
+ for (let page = 0; page < MAX_PAGES3; page++) {
20159
+ const body = {
20160
+ resourceNames: [`projects/${creds.projectId}`],
20161
+ filter,
20162
+ orderBy: "timestamp asc",
20163
+ pageSize: PAGE_SIZE3,
20164
+ ...pageToken ? { pageToken } : {}
20165
+ };
20166
+ const res = await junctionFetch(
20167
+ apiUrl,
20168
+ {
20169
+ method: "POST",
20170
+ headers: {
20171
+ ...bearerAuthHeader(creds.accessToken),
20172
+ "Content-Type": "application/json"
20173
+ },
20174
+ body: JSON.stringify(body)
20175
+ },
20176
+ // accountKey: the GCP project id — one customer's Cloud Logging quota is
20177
+ // scoped per GCP project (ADR-131's per-(provider, accountKey) rate-limit
20178
+ // bucket), the same key Cloud Run's and Firebase's connectors use.
20179
+ { provider: "gcp-lb", accountKey: creds.projectId }
20180
+ );
20181
+ if (!res.ok) {
20182
+ throw new Error(`Cloud Logging entries.list failed: ${res.status} ${res.statusText}`);
20183
+ }
20184
+ const json = await res.json();
20185
+ if (Array.isArray(json.entries)) out.push(...json.entries);
20186
+ if (!json.nextPageToken) break;
20187
+ pageToken = json.nextPageToken;
20188
+ }
20189
+ return out;
20190
+ }
20191
+
20192
+ // src/connectors/gcp-lb/map.ts
20193
+ init_cjs_shims();
20194
+
20195
+ // src/connectors/gcp-lb/types.ts
20196
+ init_cjs_shims();
20197
+ function readGcpLbCredentials(raw) {
20198
+ const projectId = raw["projectId"];
20199
+ const accessToken = raw["accessToken"];
20200
+ if (typeof projectId !== "string" || projectId.length === 0) {
20201
+ throw new Error("gcp-lb connector: credentials.projectId must be a non-empty string");
20202
+ }
20203
+ if (typeof accessToken !== "string" || accessToken.length === 0) {
20204
+ throw new Error("gcp-lb connector: credentials.accessToken must be a non-empty string");
20205
+ }
20206
+ return { projectId, accessToken };
20207
+ }
20208
+ var GCP_LB_TARGET_KIND = "http_load_balancer";
20209
+ var FIELD_SEP3 = "\0";
20210
+ function packGcpLbTargetName(identity) {
20211
+ return [identity.backendServiceName, identity.method, identity.path].join(FIELD_SEP3);
20212
+ }
20213
+ function parseGcpLbTargetName(targetName) {
20214
+ const firstSep = targetName.indexOf(FIELD_SEP3);
20215
+ if (firstSep === -1) return null;
20216
+ const backendServiceName = targetName.slice(0, firstSep);
20217
+ const rest = targetName.slice(firstSep + 1);
20218
+ const secondSep = rest.indexOf(FIELD_SEP3);
20219
+ if (secondSep === -1) return null;
20220
+ const method = rest.slice(0, secondSep);
20221
+ const path78 = rest.slice(secondSep + 1);
20222
+ if (!backendServiceName || !method || !path78) return null;
20223
+ return { backendServiceName, method, path: path78 };
20224
+ }
20225
+
20226
+ // src/connectors/gcp-lb/map.ts
20227
+ var GCP_LB_RESOURCE_TYPE2 = "http_load_balancer";
20228
+ function pathFromRequestUrl3(requestUrl) {
20229
+ if (typeof requestUrl !== "string" || requestUrl.length === 0) return null;
20230
+ if (requestUrl.startsWith("/")) {
20231
+ const withoutQuery = requestUrl.split("?")[0];
20232
+ return withoutQuery && withoutQuery.length > 0 ? withoutQuery : "/";
20233
+ }
20234
+ try {
20235
+ const candidate = requestUrl.startsWith("//") ? `https:${requestUrl}` : requestUrl;
20236
+ const parsed = new URL(candidate);
20237
+ return parsed.pathname || "/";
20238
+ } catch {
20239
+ return null;
20240
+ }
20241
+ }
20242
+ var ERROR_STATUS_THRESHOLD5 = 500;
20243
+ function mapLogEntryToSignal3(entry2) {
20244
+ if (!entry2 || typeof entry2 !== "object") return null;
20245
+ if (entry2.resource?.type !== GCP_LB_RESOURCE_TYPE2) return null;
20246
+ const backendServiceName = entry2.resource?.labels?.["backend_service_name"];
20247
+ if (typeof backendServiceName !== "string" || backendServiceName.length === 0) return null;
20248
+ const req2 = entry2.httpRequest;
20249
+ if (!req2) return null;
20250
+ if (typeof req2.requestMethod !== "string" || req2.requestMethod.length === 0) return null;
20251
+ const method = req2.requestMethod.toUpperCase();
20252
+ const path78 = pathFromRequestUrl3(req2.requestUrl);
20253
+ if (path78 === null) return null;
20254
+ const timestamp = entry2.timestamp;
20255
+ if (typeof timestamp !== "string" || timestamp.length === 0) return null;
20256
+ const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD5;
20257
+ return {
20258
+ targetKind: GCP_LB_TARGET_KIND,
20259
+ targetName: packGcpLbTargetName({ backendServiceName, method, path: path78 }),
20260
+ callCount: 1,
20261
+ errorCount: isError ? 1 : 0,
20262
+ lastObservedIso: timestamp
20263
+ };
20264
+ }
20265
+ function mapLogEntriesToSignals3(entries) {
20266
+ const out = [];
20267
+ for (const entry2 of entries) {
20268
+ const signal = mapLogEntryToSignal3(entry2);
20269
+ if (signal) out.push(signal);
20270
+ }
20271
+ return out;
20272
+ }
20273
+
20274
+ // src/connectors/gcp-lb/resolve.ts
20275
+ init_cjs_shims();
20276
+ var import_types82 = require("@neat.is/types");
20277
+ var GCP_LB_BACKEND_INFRA_KIND = "gcp-lb-backend";
20278
+ function findMatchingRouteNode3(graph, serviceName, method, normalizedPath) {
20279
+ let found = null;
20280
+ graph.forEachNode((_id, attrs) => {
20281
+ if (found) return;
20282
+ const node = attrs;
20283
+ if (node.type !== import_types82.NodeType.RouteNode) return;
20284
+ const route = attrs;
20285
+ if (route.service !== serviceName || !route.pathTemplate) return;
20286
+ if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
20287
+ const routeMethod = route.method.toUpperCase();
20288
+ if (routeMethod !== "ALL" && routeMethod !== method) return;
20289
+ found = route.id;
20290
+ });
20291
+ return found;
20292
+ }
20293
+ function createGcpLbResolveTarget(graph, config) {
20294
+ return (signal) => {
20295
+ if (signal.targetKind !== GCP_LB_TARGET_KIND) return null;
20296
+ const identity = parseGcpLbTargetName(signal.targetName);
20297
+ if (!identity) return null;
20298
+ const { backendServiceName, method, path: path78 } = identity;
20299
+ const mappedService = config.backendServiceMap?.[backendServiceName];
20300
+ if (mappedService) {
20301
+ const routeNodeId = findMatchingRouteNode3(
20302
+ graph,
20303
+ mappedService,
20304
+ method,
20305
+ normalizePathTemplate(path78)
20306
+ );
20307
+ if (routeNodeId) {
20308
+ return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types82.EdgeType.CALLS };
20309
+ }
20310
+ }
20311
+ return {
20312
+ targetNodeId: (0, import_types82.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
20313
+ serviceName: mappedService ?? backendServiceName,
20314
+ edgeType: import_types82.EdgeType.CALLS,
20315
+ ensureInfraNode: {
20316
+ kind: GCP_LB_BACKEND_INFRA_KIND,
20317
+ name: backendServiceName,
20318
+ provider: "gcp-lb"
20319
+ }
20320
+ };
20321
+ };
20322
+ }
20323
+
20324
+ // src/connectors/gcp-lb/index.ts
20325
+ var GcpLbConnector = class {
20326
+ constructor(config = {}) {
20327
+ this.config = config;
20328
+ }
20329
+ config;
20330
+ provider = "gcp-lb";
20331
+ async poll(ctx) {
20332
+ const creds = readGcpLbCredentials(ctx.credentials);
20333
+ const maxLookbackMs = this.config.maxLookbackMs ?? DEFAULT_LOOKBACK_MS3;
20334
+ const sinceIso = boundedSinceIso2(ctx.since, /* @__PURE__ */ new Date(), maxLookbackMs);
20335
+ const entries = await fetchGcpLbRequestLogEntries(creds, sinceIso, this.config.apiUrl);
20336
+ return mapLogEntriesToSignals3(entries);
20337
+ }
20338
+ };
20339
+ function boundedSinceIso2(since, now, maxLookbackMs) {
20340
+ const floor = new Date(now.getTime() - maxLookbackMs);
20341
+ if (!since) return floor.toISOString();
20342
+ const sinceMs = new Date(since).getTime();
20343
+ if (Number.isNaN(sinceMs)) return floor.toISOString();
20344
+ return sinceMs < floor.getTime() ? floor.toISOString() : new Date(sinceMs).toISOString();
20345
+ }
20346
+ function createGcpLbConnector(graph, config = {}) {
20347
+ return {
20348
+ connector: new GcpLbConnector(config),
20349
+ resolveTarget: createGcpLbResolveTarget(graph, config)
20350
+ };
20351
+ }
20352
+
20133
20353
  // src/connectors/render/index.ts
20134
20354
  init_cjs_shims();
20135
- var import_types81 = require("@neat.is/types");
20355
+ var import_types85 = require("@neat.is/types");
20136
20356
 
20137
20357
  // src/connectors/render/types.ts
20138
20358
  init_cjs_shims();
@@ -20210,7 +20430,7 @@ function buildRenderRouteIndex(graph, serviceName) {
20210
20430
  const out = [];
20211
20431
  graph.forEachNode((_id, attrs) => {
20212
20432
  const node = attrs;
20213
- if (node.type !== import_types81.NodeType.RouteNode) return;
20433
+ if (node.type !== import_types85.NodeType.RouteNode) return;
20214
20434
  const route = attrs;
20215
20435
  if (route.service !== serviceName) return;
20216
20436
  out.push({
@@ -20295,7 +20515,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
20295
20515
  function createRenderResolveTarget(config) {
20296
20516
  return (signal) => {
20297
20517
  if (signal.targetKind === ROUTE_TARGET_KIND2) {
20298
- return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types81.EdgeType.CALLS };
20518
+ return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types85.EdgeType.CALLS };
20299
20519
  }
20300
20520
  return null;
20301
20521
  };
@@ -20433,21 +20653,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
20433
20653
 
20434
20654
  // src/connectors/planetscale/resolve.ts
20435
20655
  init_cjs_shims();
20436
- var import_types85 = require("@neat.is/types");
20656
+ var import_types89 = require("@neat.is/types");
20437
20657
  var PLANETSCALE_DATABASE_KIND = "planetscale-database";
20438
20658
  function createPlanetscaleResolveTarget(graph, config) {
20439
20659
  const databaseName = `${config.organization}/${config.database}`;
20440
20660
  return (signal, _ctx) => {
20441
20661
  if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
20442
- const tableId = (0, import_types85.infraId)("sql-table", signal.targetName);
20662
+ const tableId = (0, import_types89.infraId)("sql-table", signal.targetName);
20443
20663
  if (graph.hasNode(tableId)) {
20444
- return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types85.EdgeType.CALLS };
20664
+ return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types89.EdgeType.CALLS };
20445
20665
  }
20446
- const providerId = (0, import_types85.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
20666
+ const providerId = (0, import_types89.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
20447
20667
  return {
20448
20668
  targetNodeId: providerId,
20449
20669
  serviceName: config.serviceName,
20450
- edgeType: import_types85.EdgeType.CALLS,
20670
+ edgeType: import_types89.EdgeType.CALLS,
20451
20671
  ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
20452
20672
  };
20453
20673
  };
@@ -20513,13 +20733,13 @@ function isTransientFailure(err) {
20513
20733
  if (code && INTERNAL_ERROR_CODE.test(code)) return true;
20514
20734
  return false;
20515
20735
  }
20516
- var FIELD_SEP3 = "\0";
20736
+ var FIELD_SEP4 = "\0";
20517
20737
  var EAS_TARGET_KIND = "eas-build";
20518
20738
  function packEasTargetName(identity) {
20519
- return [identity.serviceName, identity.phase].join(FIELD_SEP3);
20739
+ return [identity.serviceName, identity.phase].join(FIELD_SEP4);
20520
20740
  }
20521
20741
  function parseEasTargetName(targetName) {
20522
- const sep = targetName.indexOf(FIELD_SEP3);
20742
+ const sep = targetName.indexOf(FIELD_SEP4);
20523
20743
  if (sep === -1) return null;
20524
20744
  const serviceName = targetName.slice(0, sep);
20525
20745
  const phase = targetName.slice(sep + 1);
@@ -20712,7 +20932,7 @@ function mapBuildsToSignals(builds, serviceName) {
20712
20932
 
20713
20933
  // src/connectors/eas/resolve.ts
20714
20934
  init_cjs_shims();
20715
- var import_types90 = require("@neat.is/types");
20935
+ var import_types94 = require("@neat.is/types");
20716
20936
  var NO_ENV2 = "unknown";
20717
20937
  var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
20718
20938
  var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
@@ -20728,8 +20948,8 @@ function configBasenamesForPhase(phase) {
20728
20948
  function configNodeService(graph, configNodeId) {
20729
20949
  for (const edgeId of graph.inboundEdges(configNodeId)) {
20730
20950
  const edge = graph.getEdgeAttributes(edgeId);
20731
- if (edge.type !== import_types90.EdgeType.CONFIGURED_BY) continue;
20732
- const parsed = (0, import_types90.parseFileId)(edge.source);
20951
+ if (edge.type !== import_types94.EdgeType.CONFIGURED_BY) continue;
20952
+ const parsed = (0, import_types94.parseFileId)(edge.source);
20733
20953
  if (parsed) return parsed.service;
20734
20954
  }
20735
20955
  return null;
@@ -20740,7 +20960,7 @@ function findConfigNode(graph, basenames, serviceName) {
20740
20960
  graph.forEachNode((id, attrs) => {
20741
20961
  if (scoped) return;
20742
20962
  const node = attrs;
20743
- if (node.type !== import_types90.NodeType.ConfigNode) return;
20963
+ if (node.type !== import_types94.NodeType.ConfigNode) return;
20744
20964
  if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
20745
20965
  if (anyMatch === null) anyMatch = id;
20746
20966
  if (configNodeService(graph, id) === serviceName) scoped = id;
@@ -20757,13 +20977,13 @@ function createEasResolveTarget(graph) {
20757
20977
  if (basenames.length > 0) {
20758
20978
  const configNodeId = findConfigNode(graph, basenames, serviceName);
20759
20979
  if (configNodeId) {
20760
- return { targetNodeId: configNodeId, serviceName, edgeType: import_types90.EdgeType.CALLS };
20980
+ return { targetNodeId: configNodeId, serviceName, edgeType: import_types94.EdgeType.CALLS };
20761
20981
  }
20762
20982
  }
20763
20983
  return {
20764
20984
  targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
20765
20985
  serviceName,
20766
- edgeType: import_types90.EdgeType.CALLS
20986
+ edgeType: import_types94.EdgeType.CALLS
20767
20987
  };
20768
20988
  };
20769
20989
  }
@@ -20775,7 +20995,7 @@ function isBuildSince(build, sinceIso) {
20775
20995
  if (Number.isNaN(t) || Number.isNaN(s)) return true;
20776
20996
  return t > s;
20777
20997
  }
20778
- function boundedSinceIso2(since, now, maxLookbackMs) {
20998
+ function boundedSinceIso3(since, now, maxLookbackMs) {
20779
20999
  const floor = new Date(now.getTime() - maxLookbackMs);
20780
21000
  if (!since) return floor.toISOString();
20781
21001
  const sinceMs = new Date(since).getTime();
@@ -20794,7 +21014,7 @@ var EasConnector = class {
20794
21014
  const creds = readEasCredentials(ctx.credentials);
20795
21015
  const serviceName = this.config.serviceName ?? this.config.appId;
20796
21016
  const maxLookbackMs = this.config.maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS6;
20797
- const sinceIso = boundedSinceIso2(ctx.since, /* @__PURE__ */ new Date(), maxLookbackMs);
21017
+ const sinceIso = boundedSinceIso3(ctx.since, /* @__PURE__ */ new Date(), maxLookbackMs);
20798
21018
  const builds = await fetchErroredBuilds(creds.token, this.config, this.fetchImpl);
20799
21019
  const fresh = builds.filter((b) => isBuildSince(b, sinceIso));
20800
21020
  const maxLogBytes = this.config.maxLogBytes ?? DEFAULT_MAX_LOG_BYTES;
@@ -21025,6 +21245,40 @@ var PROVIDER_DISPATCH = {
21025
21245
  });
21026
21246
  }
21027
21247
  },
21248
+ "gcp-lb": {
21249
+ provider: "gcp-lb",
21250
+ // Like cloud-run, gcp-lb reads both projectId and accessToken from the
21251
+ // credential; the single-string form maps to the secret (the token), and the
21252
+ // required-fields check below catches a projectId that was never supplied.
21253
+ primaryCredentialKey: "accessToken",
21254
+ requiredCredentialFields: ["projectId", "accessToken"],
21255
+ requiredOptionFields: [],
21256
+ build(graph, options) {
21257
+ return createGcpLbConnector(graph, options);
21258
+ },
21259
+ // POST entries:list with pageSize 1 — the exact surface poll() reads, so the
21260
+ // probe checks the actual `logging.logEntries.list` permission the connector
21261
+ // needs. This is the same Cloud Logging read-verdict cloud-run's validate
21262
+ // uses (a lighter GET on logs.list would instead check `logging.logs.list`,
21263
+ // falsely rejecting a correctly-scoped custom role carrying only
21264
+ // `logging.logEntries.list`). A 2xx means the token can list log entries;
21265
+ // 401/403 means the provider rejected it.
21266
+ validate({ credentials, fetchImpl }) {
21267
+ const projectId = String(credentials.projectId ?? "");
21268
+ return authProbe({
21269
+ provider: "gcp-lb",
21270
+ accountKey: projectId || "validate",
21271
+ url: "https://logging.googleapis.com/v2/entries:list",
21272
+ token: String(credentials.accessToken ?? ""),
21273
+ init: {
21274
+ method: "POST",
21275
+ headers: { "Content-Type": "application/json" },
21276
+ body: JSON.stringify({ resourceNames: [`projects/${projectId}`], pageSize: 1 })
21277
+ },
21278
+ ...fetchImpl ? { fetchImpl } : {}
21279
+ });
21280
+ }
21281
+ },
21028
21282
  render: {
21029
21283
  provider: "render",
21030
21284
  primaryCredentialKey: "token",
@@ -21490,11 +21744,11 @@ function registerRoutes(scope, ctx) {
21490
21744
  const candidates = req2.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
21491
21745
  const parsed = [];
21492
21746
  for (const c of candidates) {
21493
- const r = import_types93.DivergenceTypeSchema.safeParse(c);
21747
+ const r = import_types97.DivergenceTypeSchema.safeParse(c);
21494
21748
  if (!r.success) {
21495
21749
  return reply.code(400).send({
21496
21750
  error: `unknown divergence type "${c}"`,
21497
- allowed: import_types93.DivergenceTypeSchema.options
21751
+ allowed: import_types97.DivergenceTypeSchema.options
21498
21752
  });
21499
21753
  }
21500
21754
  parsed.push(r.data);
@@ -21856,7 +22110,7 @@ function registerRoutes(scope, ctx) {
21856
22110
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
21857
22111
  let violations = await log.readAll();
21858
22112
  if (req2.query.severity) {
21859
- const sev = import_types93.PolicySeveritySchema.safeParse(req2.query.severity);
22113
+ const sev = import_types97.PolicySeveritySchema.safeParse(req2.query.severity);
21860
22114
  if (!sev.success) {
21861
22115
  return reply.code(400).send({
21862
22116
  error: "invalid severity",
@@ -21895,7 +22149,7 @@ function registerRoutes(scope, ctx) {
21895
22149
  scope.post("/policies/check", async (req2, reply) => {
21896
22150
  const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
21897
22151
  if (!proj) return;
21898
- const parsed = import_types93.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
22152
+ const parsed = import_types97.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
21899
22153
  if (!parsed.success) {
21900
22154
  return reply.code(400).send({
21901
22155
  error: "invalid /policies/check body",
@@ -22236,7 +22490,7 @@ function unroutedErrorsPath(neatHome4) {
22236
22490
  }
22237
22491
 
22238
22492
  // src/daemon.ts
22239
- var import_types94 = require("@neat.is/types");
22493
+ var import_types98 = require("@neat.is/types");
22240
22494
  function daemonJsonPath(scanPath) {
22241
22495
  return import_node_path75.default.join(scanPath, "neat-out", "daemon.json");
22242
22496
  }
@@ -22375,7 +22629,7 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
22375
22629
  if (!serviceName) return true;
22376
22630
  if (serviceNameMatchesProject(serviceName, project)) return true;
22377
22631
  return graph.someNode(
22378
- (_id, attrs) => attrs.type === import_types94.NodeType.ServiceNode && attrs.name === serviceName
22632
+ (_id, attrs) => attrs.type === import_types98.NodeType.ServiceNode && attrs.name === serviceName
22379
22633
  );
22380
22634
  }
22381
22635
  async function bootstrapProject(entry2, connectors = [], neatHome4) {