@astrasyncai/verification-gateway 4.0.0 → 4.1.0

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.
Files changed (134) hide show
  1. package/README.md +106 -29
  2. package/dist/adapter-interface/interface.d.mts +2 -2
  3. package/dist/adapter-interface/interface.d.ts +2 -2
  4. package/dist/adapters/express.d.mts +2 -2
  5. package/dist/adapters/express.d.ts +2 -2
  6. package/dist/adapters/express.js +398 -15
  7. package/dist/adapters/express.js.map +1 -1
  8. package/dist/adapters/express.mjs +398 -15
  9. package/dist/adapters/express.mjs.map +1 -1
  10. package/dist/adapters/http-pdlss.d.mts +3 -3
  11. package/dist/adapters/http-pdlss.d.ts +3 -3
  12. package/dist/adapters/http-pdlss.js.map +1 -1
  13. package/dist/adapters/http-pdlss.mjs.map +1 -1
  14. package/dist/adapters/mcp.d.mts +56 -36
  15. package/dist/adapters/mcp.d.ts +56 -36
  16. package/dist/adapters/mcp.js +220 -3
  17. package/dist/adapters/mcp.js.map +1 -1
  18. package/dist/adapters/mcp.mjs +220 -3
  19. package/dist/adapters/mcp.mjs.map +1 -1
  20. package/dist/adapters/nextjs.d.mts +2 -2
  21. package/dist/adapters/nextjs.d.ts +2 -2
  22. package/dist/adapters/nextjs.js +433 -18
  23. package/dist/adapters/nextjs.js.map +1 -1
  24. package/dist/adapters/nextjs.mjs +433 -18
  25. package/dist/adapters/nextjs.mjs.map +1 -1
  26. package/dist/adapters/sdk.d.mts +2 -2
  27. package/dist/adapters/sdk.d.ts +2 -2
  28. package/dist/adapters/sdk.js +2 -2
  29. package/dist/adapters/sdk.js.map +1 -1
  30. package/dist/adapters/sdk.mjs +2 -2
  31. package/dist/adapters/sdk.mjs.map +1 -1
  32. package/dist/agent/index.d.mts +2 -2
  33. package/dist/agent/index.d.ts +2 -2
  34. package/dist/agent/index.js.map +1 -1
  35. package/dist/agent/index.mjs.map +1 -1
  36. package/dist/bin/astrasync-claude-hook.js +13 -13
  37. package/dist/bin/astrasync-codex-hook.js +13 -13
  38. package/dist/bin/astrasync-guard.js +13 -13
  39. package/dist/bin/astrasync.js +80 -26
  40. package/dist/browser/background.js +13 -13
  41. package/dist/browser/background.js.map +1 -1
  42. package/dist/browser/background.mjs +13 -13
  43. package/dist/browser/background.mjs.map +1 -1
  44. package/dist/browser/browser-adapter.d.mts +2 -2
  45. package/dist/browser/browser-adapter.d.ts +2 -2
  46. package/dist/claude-code/claude-code-adapter.d.mts +2 -2
  47. package/dist/claude-code/claude-code-adapter.d.ts +2 -2
  48. package/dist/cli/index.d.mts +2 -2
  49. package/dist/cli/index.d.ts +2 -2
  50. package/dist/codex/index.d.mts +3 -3
  51. package/dist/codex/index.d.ts +3 -3
  52. package/dist/codex/index.js +13 -13
  53. package/dist/codex/index.js.map +1 -1
  54. package/dist/codex/index.mjs +13 -13
  55. package/dist/codex/index.mjs.map +1 -1
  56. package/dist/cursor/cursor-adapter.d.mts +2 -2
  57. package/dist/cursor/cursor-adapter.d.ts +2 -2
  58. package/dist/cursor/extension.d.mts +2 -2
  59. package/dist/cursor/extension.d.ts +2 -2
  60. package/dist/cursor/extension.js +13 -13
  61. package/dist/cursor/extension.js.map +1 -1
  62. package/dist/cursor/extension.mjs +13 -13
  63. package/dist/cursor/extension.mjs.map +1 -1
  64. package/dist/edge-config.d.mts +22 -7
  65. package/dist/edge-config.d.ts +22 -7
  66. package/dist/edge-config.js.map +1 -1
  67. package/dist/edge-config.mjs.map +1 -1
  68. package/dist/edge-core/index.d.mts +425 -0
  69. package/dist/edge-core/index.d.ts +425 -0
  70. package/dist/edge-core/index.js +1482 -0
  71. package/dist/edge-core/index.js.map +1 -0
  72. package/dist/edge-core/index.mjs +1437 -0
  73. package/dist/edge-core/index.mjs.map +1 -0
  74. package/dist/{express-BZajRs4i.d.mts → express-BVd1_3FE.d.ts} +9 -7
  75. package/dist/{express-CjCUB1k7.d.ts → express-D_4hTn5Z.d.mts} +9 -7
  76. package/dist/gateway/gateway.d.mts +2 -2
  77. package/dist/gateway/gateway.d.ts +2 -2
  78. package/dist/gateway/gateway.js +13 -13
  79. package/dist/gateway/gateway.js.map +1 -1
  80. package/dist/gateway/gateway.mjs +13 -13
  81. package/dist/gateway/gateway.mjs.map +1 -1
  82. package/dist/git-trigger/git-hooks.d.mts +2 -2
  83. package/dist/git-trigger/git-hooks.d.ts +2 -2
  84. package/dist/{index-adgKhujR.d.ts → index-B0YHu_SP.d.ts} +30 -27
  85. package/dist/{index-B0cyMZDL.d.mts → index-BPEBlOsE.d.mts} +30 -27
  86. package/dist/{index-BRYteOqO.d.mts → index-DQb5-_1X.d.mts} +1 -1
  87. package/dist/{index-BZQdVqNw.d.ts → index-T1aBoUcc.d.ts} +1 -1
  88. package/dist/index.d.mts +11 -11
  89. package/dist/index.d.ts +11 -11
  90. package/dist/index.js +477 -265
  91. package/dist/index.js.map +1 -1
  92. package/dist/index.mjs +474 -265
  93. package/dist/index.mjs.map +1 -1
  94. package/dist/local-evaluator/evaluator.d.mts +2 -2
  95. package/dist/local-evaluator/evaluator.d.ts +2 -2
  96. package/dist/metadata-capture.d.mts +63 -4
  97. package/dist/metadata-capture.d.ts +63 -4
  98. package/dist/metadata-capture.js +67 -0
  99. package/dist/metadata-capture.js.map +1 -1
  100. package/dist/metadata-capture.mjs +64 -0
  101. package/dist/metadata-capture.mjs.map +1 -1
  102. package/dist/{nextjs-DeUTnOBd.d.mts → nextjs-WyeVr2Kp.d.mts} +3 -3
  103. package/dist/{nextjs-D_iFf5k-.d.ts → nextjs-w7RTbP1P.d.ts} +3 -3
  104. package/dist/platform-signatures.d.mts +5 -6
  105. package/dist/platform-signatures.d.ts +5 -6
  106. package/dist/platform-signatures.js.map +1 -1
  107. package/dist/platform-signatures.mjs.map +1 -1
  108. package/dist/registration/index.d.mts +10 -11
  109. package/dist/registration/index.d.ts +10 -11
  110. package/dist/registration/index.js.map +1 -1
  111. package/dist/registration/index.mjs.map +1 -1
  112. package/dist/{sdk-BM3mwEAq.d.ts → sdk-CbTNIkAa.d.mts} +4 -4
  113. package/dist/{sdk-_il1Q41f.d.mts → sdk-QeX0Z8Ho.d.ts} +4 -4
  114. package/dist/transport/index.d.mts +2 -2
  115. package/dist/transport/index.d.ts +2 -2
  116. package/dist/transport/index.js.map +1 -1
  117. package/dist/transport/index.mjs.map +1 -1
  118. package/dist/{types-CHKCgDFC.d.ts → types-BLUx92FJ.d.ts} +1 -1
  119. package/dist/{types-DfnP7JiM.d.mts → types-DqfPU5Bl.d.mts} +1 -1
  120. package/dist/{types-BcDf9Kk0.d.mts → types-r850cOt0.d.mts} +106 -88
  121. package/dist/{types-fTQD448H.d.ts → types-sMxBT-nM.d.ts} +106 -88
  122. package/dist/ui/index.d.mts +11 -7
  123. package/dist/ui/index.d.ts +11 -7
  124. package/dist/ui/index.js +13 -9
  125. package/dist/ui/index.js.map +1 -1
  126. package/dist/ui/index.mjs +10 -8
  127. package/dist/ui/index.mjs.map +1 -1
  128. package/dist/verify.d.mts +8 -7
  129. package/dist/verify.d.ts +8 -7
  130. package/dist/verify.js +1 -1
  131. package/dist/verify.js.map +1 -1
  132. package/dist/verify.mjs +1 -1
  133. package/dist/verify.mjs.map +1 -1
  134. package/package.json +8 -2
@@ -65,7 +65,7 @@ function getTrustLevel(score) {
65
65
  }
66
66
 
67
67
  // src/version.ts
68
- var SDK_VERSION = "4.0.0";
68
+ var SDK_VERSION = "4.1.0";
69
69
 
70
70
  // src/well-known.ts
71
71
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -677,6 +677,21 @@ async function fetchRoutes(config, counterpartyId) {
677
677
  return null;
678
678
  }
679
679
  }
680
+ async function reportUnregisteredAttempt(config, data) {
681
+ const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
682
+ const { counterpartyUrl, ...rest } = data;
683
+ const body = {
684
+ ...rest,
685
+ ...counterpartyUrl && { counterpartyUrl },
686
+ ...config.counterpartyId && { counterpartyId: config.counterpartyId }
687
+ };
688
+ await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
689
+ method: "POST",
690
+ headers: { "Content-Type": "application/json" },
691
+ body: JSON.stringify(body)
692
+ }).catch(() => {
693
+ });
694
+ }
680
695
  async function reportCounterpartyPreCheckFailure(config, data) {
681
696
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
682
697
  await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
@@ -874,6 +889,7 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
874
889
  }
875
890
 
876
891
  // src/metadata-capture.ts
892
+ var CAPTURE_SCHEMA_VERSION = 1;
877
893
  var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
878
894
  "cookie",
879
895
  "set-cookie",
@@ -1010,6 +1026,359 @@ function sanitizeHeaders(raw) {
1010
1026
  if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
1011
1027
  return result;
1012
1028
  }
1029
+ var CONNECTION_HEADER_SOURCES = [
1030
+ ["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
1031
+ [
1032
+ "country",
1033
+ ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
1034
+ ],
1035
+ ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
1036
+ ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
1037
+ ["asn", ["cloudfront-viewer-asn"]],
1038
+ ["tlsVersion", ["cloudfront-viewer-tls"]],
1039
+ ["httpVersion", ["cloudfront-viewer-http-version"]],
1040
+ // TLS fingerprints can only be computed where TLS terminates. When a CDN
1041
+ // terminates TLS in front of the merchant, its fingerprint headers ARE the
1042
+ // connection-layer truth — normalising them here is the permanent design.
1043
+ ["tlsFingerprint", ["cf-ja3-hash"]],
1044
+ ["ja4", ["cf-ja4"]]
1045
+ ];
1046
+ function deriveConnectionFromHeaders(headers) {
1047
+ if (!headers) return void 0;
1048
+ const lower = {};
1049
+ for (const name of Object.keys(headers)) {
1050
+ const value = headers[name];
1051
+ if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
1052
+ }
1053
+ const connection = {};
1054
+ for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
1055
+ for (const source of sources) {
1056
+ const value = lower[source]?.trim();
1057
+ if (value) {
1058
+ connection[key] = value;
1059
+ break;
1060
+ }
1061
+ }
1062
+ }
1063
+ if (!connection.ip) {
1064
+ const xff = lower["x-forwarded-for"];
1065
+ const client = xff?.split(",")[0]?.trim();
1066
+ if (client) connection.ip = client;
1067
+ }
1068
+ return Object.keys(connection).length > 0 ? connection : void 0;
1069
+ }
1070
+ function buildSdkObservedMetadata(rawHeaders) {
1071
+ const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
1072
+ const flat = {};
1073
+ if (rawHeaders) {
1074
+ for (const name of Object.keys(rawHeaders)) {
1075
+ const value = rawHeaders[name];
1076
+ if (value === void 0) continue;
1077
+ flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
1078
+ }
1079
+ }
1080
+ const connection = deriveConnectionFromHeaders(flat);
1081
+ return {
1082
+ headers,
1083
+ ...apiKeyFormat && { apiKeyFormat },
1084
+ ...platformHeaders && { platformHeaders },
1085
+ ...connection && { connection },
1086
+ schemaVersion: CAPTURE_SCHEMA_VERSION
1087
+ };
1088
+ }
1089
+
1090
+ // src/edge-config.ts
1091
+ var DEFAULT_EDGE_CONFIG = Object.freeze({
1092
+ version: 1,
1093
+ mode: "observe",
1094
+ depth: "classify",
1095
+ pathRules: [],
1096
+ sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
1097
+ failurePosture: "open"
1098
+ });
1099
+ var EDGE_MODES = ["observe", "enforce"];
1100
+ var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
1101
+ function isEdgeConfig(value) {
1102
+ if (typeof value !== "object" || value === null) return false;
1103
+ const v = value;
1104
+ if (v.version !== 1) return false;
1105
+ if (!EDGE_MODES.includes(v.mode)) return false;
1106
+ if (!EDGE_DEPTHS.includes(v.depth)) return false;
1107
+ if (!Array.isArray(v.pathRules)) return false;
1108
+ for (const rule of v.pathRules) {
1109
+ if (typeof rule !== "object" || rule === null) return false;
1110
+ const r = rule;
1111
+ if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
1112
+ if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
1113
+ if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
1114
+ }
1115
+ const sampling = v.sampling;
1116
+ if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
1117
+ return false;
1118
+ }
1119
+ return v.failurePosture === "open";
1120
+ }
1121
+ async function fetchEdgeConfig(config, counterpartyId, opts) {
1122
+ if (!counterpartyId) return null;
1123
+ const headers = { Accept: "application/json" };
1124
+ if (config.apiKey) {
1125
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
1126
+ headers["X-API-Key"] = config.apiKey;
1127
+ }
1128
+ if (opts?.etag) headers["If-None-Match"] = opts.etag;
1129
+ try {
1130
+ const response = await fetch(
1131
+ `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
1132
+ { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
1133
+ );
1134
+ if (response.status === 304) return { notModified: true };
1135
+ if (!response.ok) return null;
1136
+ const body = await response.json();
1137
+ const edgeConfig = body.data?.edgeConfig;
1138
+ if (!isEdgeConfig(edgeConfig)) return null;
1139
+ return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
1140
+ } catch {
1141
+ return null;
1142
+ }
1143
+ }
1144
+ var DEFAULT_TTL_MS = 60 * 1e3;
1145
+ var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
1146
+ var cache2 = /* @__PURE__ */ new Map();
1147
+ var inflight2 = /* @__PURE__ */ new Map();
1148
+ function cacheKey(apiBaseUrl, counterpartyId) {
1149
+ return `${apiBaseUrl}|${counterpartyId}`;
1150
+ }
1151
+ function degradeToObserve(config) {
1152
+ if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
1153
+ return config;
1154
+ }
1155
+ return {
1156
+ ...config,
1157
+ mode: "observe",
1158
+ pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
1159
+ };
1160
+ }
1161
+ async function revalidate(config, counterpartyId) {
1162
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
1163
+ const existing = inflight2.get(key);
1164
+ if (existing) return existing;
1165
+ const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
1166
+ if (result === null) return;
1167
+ const now = Date.now();
1168
+ if ("notModified" in result) {
1169
+ const entry = cache2.get(key);
1170
+ if (entry) entry.lastSuccessAt = now;
1171
+ return;
1172
+ }
1173
+ cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
1174
+ }).finally(() => {
1175
+ inflight2.delete(key);
1176
+ });
1177
+ inflight2.set(key, promise);
1178
+ return promise;
1179
+ }
1180
+ async function getEdgeConfig(config, counterpartyId, opts) {
1181
+ const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
1182
+ const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
1183
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
1184
+ const entry = cache2.get(key);
1185
+ if (entry) {
1186
+ const age = Date.now() - entry.lastSuccessAt;
1187
+ if (age > ttlMs) {
1188
+ revalidate(config, counterpartyId).catch(() => {
1189
+ });
1190
+ }
1191
+ return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
1192
+ }
1193
+ await revalidate(config, counterpartyId).catch(() => {
1194
+ });
1195
+ return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
1196
+ }
1197
+
1198
+ // src/platform-signatures.ts
1199
+ var PLATFORM_AGENT_SIGNATURES = [
1200
+ {
1201
+ vendor: "claude",
1202
+ displayName: "Anthropic Claude",
1203
+ uaPatterns: [/claude/i, /anthropic/i],
1204
+ agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
1205
+ apiKeyFormatPatterns: [/^sk-ant/i],
1206
+ headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
1207
+ },
1208
+ {
1209
+ vendor: "chatgpt",
1210
+ displayName: "OpenAI ChatGPT",
1211
+ uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
1212
+ agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
1213
+ apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
1214
+ headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
1215
+ },
1216
+ {
1217
+ vendor: "gemini",
1218
+ displayName: "Google Gemini",
1219
+ uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
1220
+ agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
1221
+ apiKeyFormatPatterns: [/^aiza/i],
1222
+ headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
1223
+ },
1224
+ {
1225
+ vendor: "cursor",
1226
+ displayName: "Cursor",
1227
+ uaPatterns: [/cursor/i],
1228
+ agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
1229
+ },
1230
+ {
1231
+ vendor: "goose",
1232
+ displayName: "Block Goose",
1233
+ uaPatterns: [/goose/i, /block-goose/i],
1234
+ agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
1235
+ },
1236
+ {
1237
+ vendor: "perplexity",
1238
+ displayName: "Perplexity",
1239
+ uaPatterns: [/perplexity/i],
1240
+ agentCardPatterns: [/perplexity\.ai/i],
1241
+ apiKeyFormatPatterns: [/^pplx-/i]
1242
+ }
1243
+ ];
1244
+ function matchPlatformSignature(signatures, input) {
1245
+ const ua = input.userAgent ?? "";
1246
+ const cardUrl = input.agentCardUrl ?? "";
1247
+ const apiKeyFormat = input.apiKeyFormat ?? "";
1248
+ const headerLines = [];
1249
+ if (input.platformHeaders) {
1250
+ for (const [name, value] of Object.entries(input.platformHeaders)) {
1251
+ headerLines.push(name, `${name}: ${value}`);
1252
+ }
1253
+ }
1254
+ for (const sig of signatures) {
1255
+ const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
1256
+ const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
1257
+ const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
1258
+ const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
1259
+ if (uaMatch || cardMatch || keyMatch || headerMatch) {
1260
+ const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
1261
+ const cardHost = (() => {
1262
+ try {
1263
+ return cardUrl ? new URL(cardUrl).host : "";
1264
+ } catch {
1265
+ return "";
1266
+ }
1267
+ })();
1268
+ const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
1269
+ return {
1270
+ vendor: sig.vendor,
1271
+ fingerprintKey: `${sig.vendor}:${keyBasis}`,
1272
+ displayName: sig.displayName
1273
+ };
1274
+ }
1275
+ }
1276
+ return void 0;
1277
+ }
1278
+ function detectPlatformFingerprint(input) {
1279
+ return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
1280
+ }
1281
+
1282
+ // src/edge-core/classify.ts
1283
+ var STATIC_EXTENSIONS = /\.(css|js|mjs|map|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm|pdf|txt|xml)$/i;
1284
+ var BOT_UA_PATTERN = /curl|wget|python-requests|python-urllib|node-fetch|axios|got|okhttp|go-http-client|libwww|httpie|java\/|ruby|php|scrapy|headless|phantomjs|selenium|playwright|puppeteer|bot|crawler|spider|slurp/i;
1285
+ var BROWSER_UA_PATTERN = /mozilla\/\d/i;
1286
+ var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN };
1287
+
1288
+ // src/edge-core/events.ts
1289
+ function sampled(rate, random = Math.random) {
1290
+ if (rate <= 0) return false;
1291
+ if (rate >= 1) return true;
1292
+ return random() < rate;
1293
+ }
1294
+
1295
+ // src/adapters/anonymous-beacon.ts
1296
+ function readHeader(raw, name) {
1297
+ const value = raw[name];
1298
+ if (typeof value === "string") return value;
1299
+ if (Array.isArray(value)) return value[0];
1300
+ return void 0;
1301
+ }
1302
+ function classifyPassThroughTraffic(path, rawHeaders) {
1303
+ if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: "never" };
1304
+ const credentials = extractCredentials(rawHeaders, {});
1305
+ if (credentials.astraId || credentials.apiKey || credentials.jwt) {
1306
+ return { kind: "never" };
1307
+ }
1308
+ const userAgent = readHeader(rawHeaders, "user-agent") ?? "";
1309
+ const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
1310
+ const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });
1311
+ if (fingerprint) {
1312
+ return {
1313
+ kind: "platform",
1314
+ protocol: "platform-ua",
1315
+ evidence: { vendor: fingerprint.vendor, userAgent: userAgent || "(none)" }
1316
+ };
1317
+ }
1318
+ if (!userAgent || _patterns.BOT_UA_PATTERN.test(userAgent) || !_patterns.BROWSER_UA_PATTERN.test(userAgent)) {
1319
+ return {
1320
+ kind: "anonymous-bot",
1321
+ protocol: "ua-heuristic",
1322
+ evidence: { userAgent: userAgent || "(none)" }
1323
+ };
1324
+ }
1325
+ if (!readHeader(rawHeaders, "sec-fetch-mode") && !readHeader(rawHeaders, "accept-language")) {
1326
+ return {
1327
+ kind: "anonymous-bot",
1328
+ protocol: "ua-heuristic",
1329
+ evidence: { userAgent, spoofedBrowser: true }
1330
+ };
1331
+ }
1332
+ return { kind: "never" };
1333
+ }
1334
+ function createAnonymousBeacon(config, options) {
1335
+ const counterpartyId = config.counterpartyId;
1336
+ if (!counterpartyId) return () => {
1337
+ };
1338
+ const random = options?.random ?? Math.random;
1339
+ let edgeConfig;
1340
+ let refreshing = false;
1341
+ const refreshConfig = () => {
1342
+ if (refreshing) return;
1343
+ refreshing = true;
1344
+ getEdgeConfig(config, counterpartyId).then((cfg) => {
1345
+ edgeConfig = cfg;
1346
+ }).catch(() => {
1347
+ }).finally(() => {
1348
+ refreshing = false;
1349
+ });
1350
+ };
1351
+ refreshConfig();
1352
+ return (input) => {
1353
+ try {
1354
+ refreshConfig();
1355
+ const cfg = edgeConfig;
1356
+ if (!cfg) return;
1357
+ const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);
1358
+ if (traffic.kind === "never") return;
1359
+ if (traffic.kind === "anonymous-bot" && !sampled(cfg.sampling.anonymousBeaconRate, random)) {
1360
+ return;
1361
+ }
1362
+ const userAgent = readHeader(input.rawHeaders, "user-agent");
1363
+ const xff = input.rawHeaders["x-forwarded-for"];
1364
+ const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
1365
+ const sourceIp = input.sourceIp ?? xffStr?.split(",")[0]?.trim();
1366
+ reportUnregisteredAttempt(config, {
1367
+ ...input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl },
1368
+ counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? "api",
1369
+ ...sourceIp && { sourceIp },
1370
+ ...userAgent && { userAgent },
1371
+ requestPath: input.requestPath,
1372
+ requestMethod: input.requestMethod,
1373
+ ...traffic.protocol && { protocol: traffic.protocol },
1374
+ ...traffic.evidence && { evidence: traffic.evidence },
1375
+ observedMetadata: buildSdkObservedMetadata(input.rawHeaders)
1376
+ }).catch(() => {
1377
+ });
1378
+ } catch {
1379
+ }
1380
+ };
1381
+ }
1013
1382
 
1014
1383
  // src/adapters/express.ts
1015
1384
  function defaultExtractCredentials(req) {
@@ -1021,7 +1390,7 @@ function defaultExtractCredentials(req) {
1021
1390
  function extractAstraSyncCredentials(req) {
1022
1391
  return extractHttpCredentials(req.headers);
1023
1392
  }
1024
- function headerValue(value) {
1393
+ function headerValue2(value) {
1025
1394
  if (typeof value === "string") return value;
1026
1395
  if (Array.isArray(value)) return value[0];
1027
1396
  return void 0;
@@ -1029,9 +1398,9 @@ function headerValue(value) {
1029
1398
  function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtractAction) {
1030
1399
  return resolveHttpPdlss({
1031
1400
  method: req.method,
1032
- astraPurpose: headerValue(req.headers["x-astra-purpose"]),
1033
- astraAction: headerValue(req.headers["x-astra-action"]),
1034
- legacyPurpose: headerValue(req.headers["x-purpose"] ?? req.headers["X-Purpose"]),
1401
+ astraPurpose: headerValue2(req.headers["x-astra-purpose"]),
1402
+ astraAction: headerValue2(req.headers["x-astra-action"]),
1403
+ legacyPurpose: headerValue2(req.headers["x-purpose"] ?? req.headers["X-Purpose"]),
1035
1404
  queryPurpose: typeof req.query.purpose === "string" ? req.query.purpose : void 0,
1036
1405
  routePurpose: routeConfig?.purpose,
1037
1406
  routeAction: routeConfig?.action,
@@ -1114,6 +1483,11 @@ function defaultOnDenied(result, _req, res) {
1114
1483
  }
1115
1484
  var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
1116
1485
  function createMiddleware(options) {
1486
+ if ("routes" in options) {
1487
+ console.warn(
1488
+ "[VerificationGateway] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
1489
+ );
1490
+ }
1117
1491
  const {
1118
1492
  extractCredentials: customExtractCredentials,
1119
1493
  extractPurpose: customExtractPurpose,
@@ -1125,12 +1499,25 @@ function createMiddleware(options) {
1125
1499
  routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
1126
1500
  failOnError = "open",
1127
1501
  caseInsensitiveRouteMatch = false,
1502
+ anonymousBeacon = true,
1128
1503
  ...config
1129
1504
  } = options;
1130
1505
  if (config.apiBaseUrl) {
1131
1506
  prefetchWellKnown(config.apiBaseUrl).catch(() => {
1132
1507
  });
1133
1508
  }
1509
+ const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "api" }) : void 0;
1510
+ const beaconPassThrough = emitAnonymousBeacon ? (req) => {
1511
+ const xff = req.headers["x-forwarded-for"];
1512
+ const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
1513
+ emitAnonymousBeacon({
1514
+ requestPath: req.path,
1515
+ requestMethod: req.method,
1516
+ counterpartyUrl: config.counterpartyUrl || `${req.protocol}://${req.get("host")}`,
1517
+ sourceIp: req.ip ?? (xffStr ? xffStr.split(",")[0].trim() : void 0),
1518
+ rawHeaders: req.headers
1519
+ });
1520
+ } : void 0;
1134
1521
  let cachedRoutes = [];
1135
1522
  let lastFetchAt = 0;
1136
1523
  let refreshing = null;
@@ -1191,6 +1578,7 @@ function createMiddleware(options) {
1191
1578
  cachedRoutes.length === 0 ? "no-policy" : "no-match"
1192
1579
  );
1193
1580
  }
1581
+ beaconPassThrough?.(req);
1194
1582
  return next();
1195
1583
  }
1196
1584
  const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
@@ -1201,6 +1589,7 @@ function createMiddleware(options) {
1201
1589
  res.setHeader("X-Astra-Gateway-Mode", "unenforced");
1202
1590
  res.setHeader("X-Astra-Gateway-Reason", "route-none");
1203
1591
  }
1592
+ beaconPassThrough?.(req);
1204
1593
  return next();
1205
1594
  }
1206
1595
  const pdlssPair = resolveRequestPdlss(
@@ -1293,16 +1682,10 @@ function createMiddleware(options) {
1293
1682
  forwardedFor: forwardedForStr,
1294
1683
  agentCardUrl,
1295
1684
  // Workstream D — capture EVERY inbound header (SDK-only merchants
1296
- // have no edge to do it upstream). Local string work, secrets
1297
- // stripped; out of the verify cache key so it doesn't defeat caching.
1298
- observedMetadata: (() => {
1299
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(req.headers);
1300
- return {
1301
- headers,
1302
- ...apiKeyFormat && { apiKeyFormat },
1303
- ...platformHeaders && { platformHeaders }
1304
- };
1305
- })()
1685
+ // have no edge to do it upstream) plus the CDN-derived connection
1686
+ // block. Local string work, secrets stripped; out of the verify
1687
+ // cache key so it doesn't defeat caching.
1688
+ observedMetadata: buildSdkObservedMetadata(req.headers)
1306
1689
  }
1307
1690
  };
1308
1691
  let result = await verify(config, verificationRequest);