@astrasyncai/verification-gateway 4.0.0 → 4.2.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 +100 -13
  39. package/dist/bin/astrasync.js +168 -27
  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 +24 -13
  53. package/dist/codex/index.js.map +1 -1
  54. package/dist/codex/index.mjs +24 -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
@@ -92,7 +92,7 @@ function getTrustLevel(score) {
92
92
  }
93
93
 
94
94
  // src/version.ts
95
- var SDK_VERSION = "4.0.0";
95
+ var SDK_VERSION = "4.1.0";
96
96
 
97
97
  // src/well-known.ts
98
98
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -704,6 +704,21 @@ async function fetchRoutes(config, counterpartyId) {
704
704
  return null;
705
705
  }
706
706
  }
707
+ async function reportUnregisteredAttempt(config, data) {
708
+ const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
709
+ const { counterpartyUrl, ...rest } = data;
710
+ const body = {
711
+ ...rest,
712
+ ...counterpartyUrl && { counterpartyUrl },
713
+ ...config.counterpartyId && { counterpartyId: config.counterpartyId }
714
+ };
715
+ await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
716
+ method: "POST",
717
+ headers: { "Content-Type": "application/json" },
718
+ body: JSON.stringify(body)
719
+ }).catch(() => {
720
+ });
721
+ }
707
722
  async function reportCounterpartyPreCheckFailure(config, data) {
708
723
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
709
724
  await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
@@ -901,6 +916,7 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
901
916
  }
902
917
 
903
918
  // src/metadata-capture.ts
919
+ var CAPTURE_SCHEMA_VERSION = 1;
904
920
  var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
905
921
  "cookie",
906
922
  "set-cookie",
@@ -1037,6 +1053,359 @@ function sanitizeHeaders(raw) {
1037
1053
  if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
1038
1054
  return result;
1039
1055
  }
1056
+ var CONNECTION_HEADER_SOURCES = [
1057
+ ["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
1058
+ [
1059
+ "country",
1060
+ ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
1061
+ ],
1062
+ ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
1063
+ ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
1064
+ ["asn", ["cloudfront-viewer-asn"]],
1065
+ ["tlsVersion", ["cloudfront-viewer-tls"]],
1066
+ ["httpVersion", ["cloudfront-viewer-http-version"]],
1067
+ // TLS fingerprints can only be computed where TLS terminates. When a CDN
1068
+ // terminates TLS in front of the merchant, its fingerprint headers ARE the
1069
+ // connection-layer truth — normalising them here is the permanent design.
1070
+ ["tlsFingerprint", ["cf-ja3-hash"]],
1071
+ ["ja4", ["cf-ja4"]]
1072
+ ];
1073
+ function deriveConnectionFromHeaders(headers) {
1074
+ if (!headers) return void 0;
1075
+ const lower = {};
1076
+ for (const name of Object.keys(headers)) {
1077
+ const value = headers[name];
1078
+ if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
1079
+ }
1080
+ const connection = {};
1081
+ for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
1082
+ for (const source of sources) {
1083
+ const value = lower[source]?.trim();
1084
+ if (value) {
1085
+ connection[key] = value;
1086
+ break;
1087
+ }
1088
+ }
1089
+ }
1090
+ if (!connection.ip) {
1091
+ const xff = lower["x-forwarded-for"];
1092
+ const client = xff?.split(",")[0]?.trim();
1093
+ if (client) connection.ip = client;
1094
+ }
1095
+ return Object.keys(connection).length > 0 ? connection : void 0;
1096
+ }
1097
+ function buildSdkObservedMetadata(rawHeaders) {
1098
+ const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
1099
+ const flat = {};
1100
+ if (rawHeaders) {
1101
+ for (const name of Object.keys(rawHeaders)) {
1102
+ const value = rawHeaders[name];
1103
+ if (value === void 0) continue;
1104
+ flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
1105
+ }
1106
+ }
1107
+ const connection = deriveConnectionFromHeaders(flat);
1108
+ return {
1109
+ headers,
1110
+ ...apiKeyFormat && { apiKeyFormat },
1111
+ ...platformHeaders && { platformHeaders },
1112
+ ...connection && { connection },
1113
+ schemaVersion: CAPTURE_SCHEMA_VERSION
1114
+ };
1115
+ }
1116
+
1117
+ // src/edge-config.ts
1118
+ var DEFAULT_EDGE_CONFIG = Object.freeze({
1119
+ version: 1,
1120
+ mode: "observe",
1121
+ depth: "classify",
1122
+ pathRules: [],
1123
+ sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
1124
+ failurePosture: "open"
1125
+ });
1126
+ var EDGE_MODES = ["observe", "enforce"];
1127
+ var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
1128
+ function isEdgeConfig(value) {
1129
+ if (typeof value !== "object" || value === null) return false;
1130
+ const v = value;
1131
+ if (v.version !== 1) return false;
1132
+ if (!EDGE_MODES.includes(v.mode)) return false;
1133
+ if (!EDGE_DEPTHS.includes(v.depth)) return false;
1134
+ if (!Array.isArray(v.pathRules)) return false;
1135
+ for (const rule of v.pathRules) {
1136
+ if (typeof rule !== "object" || rule === null) return false;
1137
+ const r = rule;
1138
+ if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
1139
+ if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
1140
+ if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
1141
+ }
1142
+ const sampling = v.sampling;
1143
+ if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
1144
+ return false;
1145
+ }
1146
+ return v.failurePosture === "open";
1147
+ }
1148
+ async function fetchEdgeConfig(config, counterpartyId, opts) {
1149
+ if (!counterpartyId) return null;
1150
+ const headers = { Accept: "application/json" };
1151
+ if (config.apiKey) {
1152
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
1153
+ headers["X-API-Key"] = config.apiKey;
1154
+ }
1155
+ if (opts?.etag) headers["If-None-Match"] = opts.etag;
1156
+ try {
1157
+ const response = await fetch(
1158
+ `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
1159
+ { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
1160
+ );
1161
+ if (response.status === 304) return { notModified: true };
1162
+ if (!response.ok) return null;
1163
+ const body = await response.json();
1164
+ const edgeConfig = body.data?.edgeConfig;
1165
+ if (!isEdgeConfig(edgeConfig)) return null;
1166
+ return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
1167
+ } catch {
1168
+ return null;
1169
+ }
1170
+ }
1171
+ var DEFAULT_TTL_MS = 60 * 1e3;
1172
+ var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
1173
+ var cache2 = /* @__PURE__ */ new Map();
1174
+ var inflight2 = /* @__PURE__ */ new Map();
1175
+ function cacheKey(apiBaseUrl, counterpartyId) {
1176
+ return `${apiBaseUrl}|${counterpartyId}`;
1177
+ }
1178
+ function degradeToObserve(config) {
1179
+ if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
1180
+ return config;
1181
+ }
1182
+ return {
1183
+ ...config,
1184
+ mode: "observe",
1185
+ pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
1186
+ };
1187
+ }
1188
+ async function revalidate(config, counterpartyId) {
1189
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
1190
+ const existing = inflight2.get(key);
1191
+ if (existing) return existing;
1192
+ const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
1193
+ if (result === null) return;
1194
+ const now = Date.now();
1195
+ if ("notModified" in result) {
1196
+ const entry = cache2.get(key);
1197
+ if (entry) entry.lastSuccessAt = now;
1198
+ return;
1199
+ }
1200
+ cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
1201
+ }).finally(() => {
1202
+ inflight2.delete(key);
1203
+ });
1204
+ inflight2.set(key, promise);
1205
+ return promise;
1206
+ }
1207
+ async function getEdgeConfig(config, counterpartyId, opts) {
1208
+ const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
1209
+ const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
1210
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
1211
+ const entry = cache2.get(key);
1212
+ if (entry) {
1213
+ const age = Date.now() - entry.lastSuccessAt;
1214
+ if (age > ttlMs) {
1215
+ revalidate(config, counterpartyId).catch(() => {
1216
+ });
1217
+ }
1218
+ return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
1219
+ }
1220
+ await revalidate(config, counterpartyId).catch(() => {
1221
+ });
1222
+ return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
1223
+ }
1224
+
1225
+ // src/platform-signatures.ts
1226
+ var PLATFORM_AGENT_SIGNATURES = [
1227
+ {
1228
+ vendor: "claude",
1229
+ displayName: "Anthropic Claude",
1230
+ uaPatterns: [/claude/i, /anthropic/i],
1231
+ agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
1232
+ apiKeyFormatPatterns: [/^sk-ant/i],
1233
+ headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
1234
+ },
1235
+ {
1236
+ vendor: "chatgpt",
1237
+ displayName: "OpenAI ChatGPT",
1238
+ uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
1239
+ agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
1240
+ apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
1241
+ headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
1242
+ },
1243
+ {
1244
+ vendor: "gemini",
1245
+ displayName: "Google Gemini",
1246
+ uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
1247
+ agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
1248
+ apiKeyFormatPatterns: [/^aiza/i],
1249
+ headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
1250
+ },
1251
+ {
1252
+ vendor: "cursor",
1253
+ displayName: "Cursor",
1254
+ uaPatterns: [/cursor/i],
1255
+ agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
1256
+ },
1257
+ {
1258
+ vendor: "goose",
1259
+ displayName: "Block Goose",
1260
+ uaPatterns: [/goose/i, /block-goose/i],
1261
+ agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
1262
+ },
1263
+ {
1264
+ vendor: "perplexity",
1265
+ displayName: "Perplexity",
1266
+ uaPatterns: [/perplexity/i],
1267
+ agentCardPatterns: [/perplexity\.ai/i],
1268
+ apiKeyFormatPatterns: [/^pplx-/i]
1269
+ }
1270
+ ];
1271
+ function matchPlatformSignature(signatures, input) {
1272
+ const ua = input.userAgent ?? "";
1273
+ const cardUrl = input.agentCardUrl ?? "";
1274
+ const apiKeyFormat = input.apiKeyFormat ?? "";
1275
+ const headerLines = [];
1276
+ if (input.platformHeaders) {
1277
+ for (const [name, value] of Object.entries(input.platformHeaders)) {
1278
+ headerLines.push(name, `${name}: ${value}`);
1279
+ }
1280
+ }
1281
+ for (const sig of signatures) {
1282
+ const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
1283
+ const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
1284
+ const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
1285
+ const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
1286
+ if (uaMatch || cardMatch || keyMatch || headerMatch) {
1287
+ const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
1288
+ const cardHost = (() => {
1289
+ try {
1290
+ return cardUrl ? new URL(cardUrl).host : "";
1291
+ } catch {
1292
+ return "";
1293
+ }
1294
+ })();
1295
+ const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
1296
+ return {
1297
+ vendor: sig.vendor,
1298
+ fingerprintKey: `${sig.vendor}:${keyBasis}`,
1299
+ displayName: sig.displayName
1300
+ };
1301
+ }
1302
+ }
1303
+ return void 0;
1304
+ }
1305
+ function detectPlatformFingerprint(input) {
1306
+ return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
1307
+ }
1308
+
1309
+ // src/edge-core/classify.ts
1310
+ 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;
1311
+ 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;
1312
+ var BROWSER_UA_PATTERN = /mozilla\/\d/i;
1313
+ var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN };
1314
+
1315
+ // src/edge-core/events.ts
1316
+ function sampled(rate, random = Math.random) {
1317
+ if (rate <= 0) return false;
1318
+ if (rate >= 1) return true;
1319
+ return random() < rate;
1320
+ }
1321
+
1322
+ // src/adapters/anonymous-beacon.ts
1323
+ function readHeader(raw, name) {
1324
+ const value = raw[name];
1325
+ if (typeof value === "string") return value;
1326
+ if (Array.isArray(value)) return value[0];
1327
+ return void 0;
1328
+ }
1329
+ function classifyPassThroughTraffic(path, rawHeaders) {
1330
+ if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: "never" };
1331
+ const credentials = extractCredentials(rawHeaders, {});
1332
+ if (credentials.astraId || credentials.apiKey || credentials.jwt) {
1333
+ return { kind: "never" };
1334
+ }
1335
+ const userAgent = readHeader(rawHeaders, "user-agent") ?? "";
1336
+ const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
1337
+ const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });
1338
+ if (fingerprint) {
1339
+ return {
1340
+ kind: "platform",
1341
+ protocol: "platform-ua",
1342
+ evidence: { vendor: fingerprint.vendor, userAgent: userAgent || "(none)" }
1343
+ };
1344
+ }
1345
+ if (!userAgent || _patterns.BOT_UA_PATTERN.test(userAgent) || !_patterns.BROWSER_UA_PATTERN.test(userAgent)) {
1346
+ return {
1347
+ kind: "anonymous-bot",
1348
+ protocol: "ua-heuristic",
1349
+ evidence: { userAgent: userAgent || "(none)" }
1350
+ };
1351
+ }
1352
+ if (!readHeader(rawHeaders, "sec-fetch-mode") && !readHeader(rawHeaders, "accept-language")) {
1353
+ return {
1354
+ kind: "anonymous-bot",
1355
+ protocol: "ua-heuristic",
1356
+ evidence: { userAgent, spoofedBrowser: true }
1357
+ };
1358
+ }
1359
+ return { kind: "never" };
1360
+ }
1361
+ function createAnonymousBeacon(config, options) {
1362
+ const counterpartyId = config.counterpartyId;
1363
+ if (!counterpartyId) return () => {
1364
+ };
1365
+ const random = options?.random ?? Math.random;
1366
+ let edgeConfig;
1367
+ let refreshing = false;
1368
+ const refreshConfig = () => {
1369
+ if (refreshing) return;
1370
+ refreshing = true;
1371
+ getEdgeConfig(config, counterpartyId).then((cfg) => {
1372
+ edgeConfig = cfg;
1373
+ }).catch(() => {
1374
+ }).finally(() => {
1375
+ refreshing = false;
1376
+ });
1377
+ };
1378
+ refreshConfig();
1379
+ return (input) => {
1380
+ try {
1381
+ refreshConfig();
1382
+ const cfg = edgeConfig;
1383
+ if (!cfg) return;
1384
+ const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);
1385
+ if (traffic.kind === "never") return;
1386
+ if (traffic.kind === "anonymous-bot" && !sampled(cfg.sampling.anonymousBeaconRate, random)) {
1387
+ return;
1388
+ }
1389
+ const userAgent = readHeader(input.rawHeaders, "user-agent");
1390
+ const xff = input.rawHeaders["x-forwarded-for"];
1391
+ const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
1392
+ const sourceIp = input.sourceIp ?? xffStr?.split(",")[0]?.trim();
1393
+ reportUnregisteredAttempt(config, {
1394
+ ...input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl },
1395
+ counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? "api",
1396
+ ...sourceIp && { sourceIp },
1397
+ ...userAgent && { userAgent },
1398
+ requestPath: input.requestPath,
1399
+ requestMethod: input.requestMethod,
1400
+ ...traffic.protocol && { protocol: traffic.protocol },
1401
+ ...traffic.evidence && { evidence: traffic.evidence },
1402
+ observedMetadata: buildSdkObservedMetadata(input.rawHeaders)
1403
+ }).catch(() => {
1404
+ });
1405
+ } catch {
1406
+ }
1407
+ };
1408
+ }
1040
1409
 
1041
1410
  // src/adapters/express.ts
1042
1411
  function defaultExtractCredentials(req) {
@@ -1048,7 +1417,7 @@ function defaultExtractCredentials(req) {
1048
1417
  function extractAstraSyncCredentials(req) {
1049
1418
  return extractHttpCredentials(req.headers);
1050
1419
  }
1051
- function headerValue(value) {
1420
+ function headerValue2(value) {
1052
1421
  if (typeof value === "string") return value;
1053
1422
  if (Array.isArray(value)) return value[0];
1054
1423
  return void 0;
@@ -1056,9 +1425,9 @@ function headerValue(value) {
1056
1425
  function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtractAction) {
1057
1426
  return resolveHttpPdlss({
1058
1427
  method: req.method,
1059
- astraPurpose: headerValue(req.headers["x-astra-purpose"]),
1060
- astraAction: headerValue(req.headers["x-astra-action"]),
1061
- legacyPurpose: headerValue(req.headers["x-purpose"] ?? req.headers["X-Purpose"]),
1428
+ astraPurpose: headerValue2(req.headers["x-astra-purpose"]),
1429
+ astraAction: headerValue2(req.headers["x-astra-action"]),
1430
+ legacyPurpose: headerValue2(req.headers["x-purpose"] ?? req.headers["X-Purpose"]),
1062
1431
  queryPurpose: typeof req.query.purpose === "string" ? req.query.purpose : void 0,
1063
1432
  routePurpose: routeConfig?.purpose,
1064
1433
  routeAction: routeConfig?.action,
@@ -1141,6 +1510,11 @@ function defaultOnDenied(result, _req, res) {
1141
1510
  }
1142
1511
  var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
1143
1512
  function createMiddleware(options) {
1513
+ if ("routes" in options) {
1514
+ console.warn(
1515
+ "[VerificationGateway] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
1516
+ );
1517
+ }
1144
1518
  const {
1145
1519
  extractCredentials: customExtractCredentials,
1146
1520
  extractPurpose: customExtractPurpose,
@@ -1152,12 +1526,25 @@ function createMiddleware(options) {
1152
1526
  routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
1153
1527
  failOnError = "open",
1154
1528
  caseInsensitiveRouteMatch = false,
1529
+ anonymousBeacon = true,
1155
1530
  ...config
1156
1531
  } = options;
1157
1532
  if (config.apiBaseUrl) {
1158
1533
  prefetchWellKnown(config.apiBaseUrl).catch(() => {
1159
1534
  });
1160
1535
  }
1536
+ const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "api" }) : void 0;
1537
+ const beaconPassThrough = emitAnonymousBeacon ? (req) => {
1538
+ const xff = req.headers["x-forwarded-for"];
1539
+ const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
1540
+ emitAnonymousBeacon({
1541
+ requestPath: req.path,
1542
+ requestMethod: req.method,
1543
+ counterpartyUrl: config.counterpartyUrl || `${req.protocol}://${req.get("host")}`,
1544
+ sourceIp: req.ip ?? (xffStr ? xffStr.split(",")[0].trim() : void 0),
1545
+ rawHeaders: req.headers
1546
+ });
1547
+ } : void 0;
1161
1548
  let cachedRoutes = [];
1162
1549
  let lastFetchAt = 0;
1163
1550
  let refreshing = null;
@@ -1218,6 +1605,7 @@ function createMiddleware(options) {
1218
1605
  cachedRoutes.length === 0 ? "no-policy" : "no-match"
1219
1606
  );
1220
1607
  }
1608
+ beaconPassThrough?.(req);
1221
1609
  return next();
1222
1610
  }
1223
1611
  const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
@@ -1228,6 +1616,7 @@ function createMiddleware(options) {
1228
1616
  res.setHeader("X-Astra-Gateway-Mode", "unenforced");
1229
1617
  res.setHeader("X-Astra-Gateway-Reason", "route-none");
1230
1618
  }
1619
+ beaconPassThrough?.(req);
1231
1620
  return next();
1232
1621
  }
1233
1622
  const pdlssPair = resolveRequestPdlss(
@@ -1320,16 +1709,10 @@ function createMiddleware(options) {
1320
1709
  forwardedFor: forwardedForStr,
1321
1710
  agentCardUrl,
1322
1711
  // Workstream D — capture EVERY inbound header (SDK-only merchants
1323
- // have no edge to do it upstream). Local string work, secrets
1324
- // stripped; out of the verify cache key so it doesn't defeat caching.
1325
- observedMetadata: (() => {
1326
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(req.headers);
1327
- return {
1328
- headers,
1329
- ...apiKeyFormat && { apiKeyFormat },
1330
- ...platformHeaders && { platformHeaders }
1331
- };
1332
- })()
1712
+ // have no edge to do it upstream) plus the CDN-derived connection
1713
+ // block. Local string work, secrets stripped; out of the verify
1714
+ // cache key so it doesn't defeat caching.
1715
+ observedMetadata: buildSdkObservedMetadata(req.headers)
1333
1716
  }
1334
1717
  };
1335
1718
  let result = await verify(config, verificationRequest);