@neat.is/core 0.4.28-dev.20260708 → 0.4.28-dev.20260710

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.
@@ -3,6 +3,7 @@ import {
3
3
  Projects,
4
4
  attachGraphToEventBus,
5
5
  buildApi,
6
+ ensureInfraNode,
6
7
  ensureObservedFileNode,
7
8
  ensureServiceNode,
8
9
  extractFromDirectory,
@@ -24,7 +25,7 @@ import {
24
25
  touchLastSeen,
25
26
  upsertObservedEdge,
26
27
  writeAtomically
27
- } from "./chunk-O4MRDWD7.js";
28
+ } from "./chunk-5T6J3WKC.js";
28
29
  import {
29
30
  assertBindAuthority,
30
31
  buildOtelReceiver,
@@ -56,6 +57,10 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
56
57
  unresolved++;
57
58
  continue;
58
59
  }
60
+ if (resolved.ensureInfraNode) {
61
+ const { kind, name, provider } = resolved.ensureInfraNode;
62
+ ensureInfraNode(graph, kind, name, provider);
63
+ }
59
64
  const serviceNodeId = ensureServiceNode(graph, resolved.serviceName, NO_ENV);
60
65
  const callSite = signal.callSite ? { relPath: signal.callSite.file, line: signal.callSite.line } : void 0;
61
66
  const sourceId = callSite ? ensureObservedFileNode(graph, resolved.serviceName, serviceNodeId, callSite) : serviceNodeId;
@@ -1105,7 +1110,7 @@ function createFirebaseConnector(graph, serviceMap) {
1105
1110
  }
1106
1111
 
1107
1112
  // src/connectors/cloudflare/connector.ts
1108
- import { EdgeType as EdgeType4, fileId } from "@neat.is/types";
1113
+ import { EdgeType as EdgeType4, NodeType as NodeType3, fileId, infraId as infraId2 } from "@neat.is/types";
1109
1114
 
1110
1115
  // src/connectors/cloudflare/client.ts
1111
1116
  import { randomUUID } from "crypto";
@@ -1154,7 +1159,14 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
1154
1159
  const message = payload.errors?.map((e) => e.message).join("; ") || "unknown error";
1155
1160
  throw new Error(`cloudflare connector: telemetry query returned an error (${message})`);
1156
1161
  }
1157
- return payload.result?.events?.events ?? [];
1162
+ const events = payload.result?.events?.events;
1163
+ if (events === void 0) {
1164
+ console.warn(
1165
+ "[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"
1166
+ );
1167
+ return [];
1168
+ }
1169
+ return events;
1158
1170
  }
1159
1171
 
1160
1172
  // src/connectors/cloudflare/types.ts
@@ -1181,6 +1193,13 @@ function parseHttpMethodFromTrigger(trigger) {
1181
1193
  const method = token.toUpperCase();
1182
1194
  return HTTP_METHODS.has(method) ? method : null;
1183
1195
  }
1196
+ function parsePathFromTrigger(trigger) {
1197
+ const trimmed = trigger.trim();
1198
+ const spaceIdx = trimmed.indexOf(" ");
1199
+ if (spaceIdx === -1) return void 0;
1200
+ const rest = trimmed.slice(spaceIdx + 1).trim();
1201
+ return rest.length > 0 ? rest : void 0;
1202
+ }
1184
1203
  var ERROR_STATUS_THRESHOLD3 = 500;
1185
1204
  function mapEventToSignal(event) {
1186
1205
  const metadata = event.$metadata;
@@ -1193,6 +1212,7 @@ function mapEventToSignal(event) {
1193
1212
  if (typeof timestampMs !== "number" || !Number.isFinite(timestampMs)) return null;
1194
1213
  const statusCode = metadata?.statusCode;
1195
1214
  const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
1215
+ const path4 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
1196
1216
  return {
1197
1217
  targetKind: CLOUDFLARE_TARGET_KIND,
1198
1218
  targetName: scriptName,
@@ -1200,6 +1220,7 @@ function mapEventToSignal(event) {
1200
1220
  errorCount: isError ? 1 : 0,
1201
1221
  lastObservedIso: new Date(timestampMs).toISOString(),
1202
1222
  method,
1223
+ ...path4 ? { path: path4 } : {},
1203
1224
  ...typeof statusCode === "number" ? { statusCode } : {},
1204
1225
  ...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
1205
1226
  };
@@ -1234,15 +1255,63 @@ var CloudflareConnector = class {
1234
1255
  return signals;
1235
1256
  }
1236
1257
  };
1237
- function createCloudflareResolveTarget(config) {
1258
+ function findTaggedWorkerFileNode(graph, workerName) {
1259
+ let found = null;
1260
+ graph.forEachNode((id, attrs) => {
1261
+ if (found) return;
1262
+ const a = attrs;
1263
+ if (a.type === NodeType3.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
1264
+ found = id;
1265
+ }
1266
+ });
1267
+ return found;
1268
+ }
1269
+ function findMatchingRouteNode(graph, serviceName, method, path4) {
1270
+ const normalizedPath = normalizePathTemplate(path4);
1271
+ let found = null;
1272
+ graph.forEachNode((id, attrs) => {
1273
+ if (found) return;
1274
+ const a = attrs;
1275
+ if (a.type !== NodeType3.RouteNode || a.service !== serviceName) return;
1276
+ if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
1277
+ const routeMethod = (a.method ?? "").toUpperCase();
1278
+ if (routeMethod !== "ALL" && routeMethod !== method) return;
1279
+ found = id;
1280
+ });
1281
+ return found;
1282
+ }
1283
+ function createCloudflareResolveTarget(config, graph) {
1238
1284
  return (signal) => {
1239
1285
  if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
1240
- const mapping = config.workers[signal.targetName];
1241
- if (!mapping) return null;
1286
+ const scriptName = signal.targetName;
1287
+ const { method, path: path4 } = signal;
1288
+ const resolveRouteGrain = (serviceName, wholeFileId) => {
1289
+ if (!method || !path4) return wholeFileId;
1290
+ return findMatchingRouteNode(graph, serviceName, method, path4) ?? wholeFileId;
1291
+ };
1292
+ const mapping = config.workers?.[scriptName];
1293
+ if (mapping) {
1294
+ const wholeFileId = fileId(mapping.service, mapping.entryFile);
1295
+ return {
1296
+ targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
1297
+ serviceName: mapping.service,
1298
+ edgeType: EdgeType4.CALLS
1299
+ };
1300
+ }
1301
+ const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
1302
+ if (taggedFileId) {
1303
+ const fileNode = graph.getNodeAttributes(taggedFileId);
1304
+ return {
1305
+ targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
1306
+ serviceName: fileNode.service,
1307
+ edgeType: EdgeType4.CALLS
1308
+ };
1309
+ }
1242
1310
  return {
1243
- targetNodeId: fileId(mapping.service, mapping.entryFile),
1244
- serviceName: mapping.service,
1245
- edgeType: EdgeType4.CALLS
1311
+ targetNodeId: infraId2("cloudflare-worker", scriptName),
1312
+ serviceName: scriptName,
1313
+ edgeType: EdgeType4.CALLS,
1314
+ ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
1246
1315
  };
1247
1316
  };
1248
1317
  }
@@ -1634,12 +1703,16 @@ var PROVIDER_DISPATCH = {
1634
1703
  provider: "cloudflare",
1635
1704
  primaryCredentialKey: "apiToken",
1636
1705
  requiredCredentialFields: ["apiToken"],
1637
- requiredOptionFields: ["accountId", "workers"],
1638
- build(_graph, options) {
1706
+ // `workers` dropped as a required field (ADR-133) — the mapping is now
1707
+ // derived from the extracted graph's platform tag; an `options.workers`
1708
+ // entry still works as an explicit override
1709
+ // (CloudflareConnectorConfig.workers).
1710
+ requiredOptionFields: ["accountId"],
1711
+ build(graph, options) {
1639
1712
  const config = options;
1640
1713
  return {
1641
1714
  connector: new CloudflareConnector(config),
1642
- resolveTarget: createCloudflareResolveTarget(config)
1715
+ resolveTarget: createCloudflareResolveTarget(config, graph)
1643
1716
  };
1644
1717
  },
1645
1718
  // GET /user/tokens/verify — Cloudflare's own purpose-built "is this API
@@ -1780,7 +1853,7 @@ function unroutedErrorsPath(neatHome2) {
1780
1853
  }
1781
1854
 
1782
1855
  // src/daemon.ts
1783
- import { NodeType as NodeType3 } from "@neat.is/types";
1856
+ import { NodeType as NodeType4 } from "@neat.is/types";
1784
1857
  function daemonJsonPath(scanPath) {
1785
1858
  return path3.join(scanPath, "neat-out", "daemon.json");
1786
1859
  }
@@ -1927,7 +2000,7 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
1927
2000
  if (!serviceName) return true;
1928
2001
  if (serviceNameMatchesProject(serviceName, project)) return true;
1929
2002
  return graph.someNode(
1930
- (_id, attrs) => attrs.type === NodeType3.ServiceNode && attrs.name === serviceName
2003
+ (_id, attrs) => attrs.type === NodeType4.ServiceNode && attrs.name === serviceName
1931
2004
  );
1932
2005
  }
1933
2006
  async function bootstrapProject(entry, connectors = [], neatHome2) {
@@ -2563,4 +2636,4 @@ export {
2563
2636
  resolveHost,
2564
2637
  startDaemon
2565
2638
  };
2566
- //# sourceMappingURL=chunk-NY5Q6NE2.js.map
2639
+ //# sourceMappingURL=chunk-UJ6WBLIE.js.map