@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
@@ -1,4 +1,4 @@
1
1
  import 'next/server';
2
- import '../types-BcDf9Kk0.mjs';
3
- export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-DeUTnOBd.mjs';
2
+ import '../types-r850cOt0.mjs';
3
+ export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-WyeVr2Kp.mjs';
4
4
  import '../metadata-capture.mjs';
@@ -1,4 +1,4 @@
1
1
  import 'next/server';
2
- import '../types-fTQD448H.js';
3
- export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-D_iFf5k-.js';
2
+ import '../types-sMxBT-nM.js';
3
+ export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-w7RTbP1P.js';
4
4
  import '../metadata-capture.js';
@@ -102,7 +102,7 @@ function getTrustLevel(score) {
102
102
  }
103
103
 
104
104
  // src/version.ts
105
- var SDK_VERSION = "4.0.0";
105
+ var SDK_VERSION = "4.1.0";
106
106
 
107
107
  // src/well-known.ts
108
108
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -241,6 +241,40 @@ function cacheResult(request, result, configuredTtl, counterpartyId) {
241
241
  expiresAt: Date.now() + ttlSeconds * 1e3
242
242
  });
243
243
  }
244
+ function extractCredentials(headers, query) {
245
+ const credentials = {};
246
+ const ASTRA_ID_PATTERN = /^ASTRAE?-[A-Za-z0-9_-]{1,64}$/;
247
+ const astraIdHeader = headers["x-astra-id"] || headers["X-Astra-Id"] || headers["X-ASTRA-ID"] || headers["x-astra-agentid"] || headers["X-Astra-AgentId"] || headers["x-astra-agent-id"] || headers["X-Astra-Agent-Id"] || headers["X-ASTRA-AGENT-ID"];
248
+ if (astraIdHeader) {
249
+ const raw = Array.isArray(astraIdHeader) ? astraIdHeader[0] : typeof astraIdHeader === "string" ? astraIdHeader : void 0;
250
+ if (typeof raw === "string" && ASTRA_ID_PATTERN.test(raw)) {
251
+ credentials.astraId = raw;
252
+ }
253
+ }
254
+ const apiKeyHeader = headers["x-api-key"] || headers["X-Api-Key"] || headers["X-API-KEY"];
255
+ if (apiKeyHeader) {
256
+ credentials.apiKey = Array.isArray(apiKeyHeader) ? apiKeyHeader[0] : apiKeyHeader;
257
+ }
258
+ const authHeader = headers["authorization"] || headers["Authorization"];
259
+ if (authHeader) {
260
+ const authValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;
261
+ if (typeof authValue === "string") {
262
+ credentials.authorizationHeader = authValue;
263
+ if (authValue.startsWith("Bearer ")) {
264
+ credentials.jwt = authValue.slice(7);
265
+ }
266
+ }
267
+ }
268
+ if (query) {
269
+ if (query.astraId && !credentials.astraId) {
270
+ credentials.astraId = query.astraId;
271
+ }
272
+ if (query.apiKey && !credentials.apiKey) {
273
+ credentials.apiKey = query.apiKey;
274
+ }
275
+ }
276
+ return credentials;
277
+ }
244
278
  function createGuidanceResponse(_config, reason, options = {}) {
245
279
  const source = options.source ?? "no_credentials";
246
280
  const isApiError = source === "api_error";
@@ -615,6 +649,21 @@ async function fetchRoutes(config, counterpartyId) {
615
649
  return null;
616
650
  }
617
651
  }
652
+ async function reportUnregisteredAttempt(config, data) {
653
+ const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
654
+ const { counterpartyUrl, ...rest } = data;
655
+ const body = {
656
+ ...rest,
657
+ ...counterpartyUrl && { counterpartyUrl },
658
+ ...config.counterpartyId && { counterpartyId: config.counterpartyId }
659
+ };
660
+ await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
661
+ method: "POST",
662
+ headers: { "Content-Type": "application/json" },
663
+ body: JSON.stringify(body)
664
+ }).catch(() => {
665
+ });
666
+ }
618
667
  async function reportCounterpartyPreCheckFailure(config, data) {
619
668
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
620
669
  await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
@@ -720,6 +769,7 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
720
769
  }
721
770
 
722
771
  // src/metadata-capture.ts
772
+ var CAPTURE_SCHEMA_VERSION = 1;
723
773
  var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
724
774
  "cookie",
725
775
  "set-cookie",
@@ -856,6 +906,359 @@ function sanitizeHeaders(raw) {
856
906
  if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
857
907
  return result;
858
908
  }
909
+ var CONNECTION_HEADER_SOURCES = [
910
+ ["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
911
+ [
912
+ "country",
913
+ ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
914
+ ],
915
+ ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
916
+ ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
917
+ ["asn", ["cloudfront-viewer-asn"]],
918
+ ["tlsVersion", ["cloudfront-viewer-tls"]],
919
+ ["httpVersion", ["cloudfront-viewer-http-version"]],
920
+ // TLS fingerprints can only be computed where TLS terminates. When a CDN
921
+ // terminates TLS in front of the merchant, its fingerprint headers ARE the
922
+ // connection-layer truth — normalising them here is the permanent design.
923
+ ["tlsFingerprint", ["cf-ja3-hash"]],
924
+ ["ja4", ["cf-ja4"]]
925
+ ];
926
+ function deriveConnectionFromHeaders(headers) {
927
+ if (!headers) return void 0;
928
+ const lower = {};
929
+ for (const name of Object.keys(headers)) {
930
+ const value = headers[name];
931
+ if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
932
+ }
933
+ const connection = {};
934
+ for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
935
+ for (const source of sources) {
936
+ const value = lower[source]?.trim();
937
+ if (value) {
938
+ connection[key] = value;
939
+ break;
940
+ }
941
+ }
942
+ }
943
+ if (!connection.ip) {
944
+ const xff = lower["x-forwarded-for"];
945
+ const client = xff?.split(",")[0]?.trim();
946
+ if (client) connection.ip = client;
947
+ }
948
+ return Object.keys(connection).length > 0 ? connection : void 0;
949
+ }
950
+ function buildSdkObservedMetadata(rawHeaders) {
951
+ const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
952
+ const flat = {};
953
+ if (rawHeaders) {
954
+ for (const name of Object.keys(rawHeaders)) {
955
+ const value = rawHeaders[name];
956
+ if (value === void 0) continue;
957
+ flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
958
+ }
959
+ }
960
+ const connection = deriveConnectionFromHeaders(flat);
961
+ return {
962
+ headers,
963
+ ...apiKeyFormat && { apiKeyFormat },
964
+ ...platformHeaders && { platformHeaders },
965
+ ...connection && { connection },
966
+ schemaVersion: CAPTURE_SCHEMA_VERSION
967
+ };
968
+ }
969
+
970
+ // src/edge-config.ts
971
+ var DEFAULT_EDGE_CONFIG = Object.freeze({
972
+ version: 1,
973
+ mode: "observe",
974
+ depth: "classify",
975
+ pathRules: [],
976
+ sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
977
+ failurePosture: "open"
978
+ });
979
+ var EDGE_MODES = ["observe", "enforce"];
980
+ var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
981
+ function isEdgeConfig(value) {
982
+ if (typeof value !== "object" || value === null) return false;
983
+ const v = value;
984
+ if (v.version !== 1) return false;
985
+ if (!EDGE_MODES.includes(v.mode)) return false;
986
+ if (!EDGE_DEPTHS.includes(v.depth)) return false;
987
+ if (!Array.isArray(v.pathRules)) return false;
988
+ for (const rule of v.pathRules) {
989
+ if (typeof rule !== "object" || rule === null) return false;
990
+ const r = rule;
991
+ if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
992
+ if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
993
+ if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
994
+ }
995
+ const sampling = v.sampling;
996
+ if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
997
+ return false;
998
+ }
999
+ return v.failurePosture === "open";
1000
+ }
1001
+ async function fetchEdgeConfig(config, counterpartyId, opts) {
1002
+ if (!counterpartyId) return null;
1003
+ const headers = { Accept: "application/json" };
1004
+ if (config.apiKey) {
1005
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
1006
+ headers["X-API-Key"] = config.apiKey;
1007
+ }
1008
+ if (opts?.etag) headers["If-None-Match"] = opts.etag;
1009
+ try {
1010
+ const response = await fetch(
1011
+ `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
1012
+ { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
1013
+ );
1014
+ if (response.status === 304) return { notModified: true };
1015
+ if (!response.ok) return null;
1016
+ const body = await response.json();
1017
+ const edgeConfig = body.data?.edgeConfig;
1018
+ if (!isEdgeConfig(edgeConfig)) return null;
1019
+ return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
1020
+ } catch {
1021
+ return null;
1022
+ }
1023
+ }
1024
+ var DEFAULT_TTL_MS = 60 * 1e3;
1025
+ var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
1026
+ var cache2 = /* @__PURE__ */ new Map();
1027
+ var inflight = /* @__PURE__ */ new Map();
1028
+ function cacheKey(apiBaseUrl, counterpartyId) {
1029
+ return `${apiBaseUrl}|${counterpartyId}`;
1030
+ }
1031
+ function degradeToObserve(config) {
1032
+ if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
1033
+ return config;
1034
+ }
1035
+ return {
1036
+ ...config,
1037
+ mode: "observe",
1038
+ pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
1039
+ };
1040
+ }
1041
+ async function revalidate(config, counterpartyId) {
1042
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
1043
+ const existing = inflight.get(key);
1044
+ if (existing) return existing;
1045
+ const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
1046
+ if (result === null) return;
1047
+ const now = Date.now();
1048
+ if ("notModified" in result) {
1049
+ const entry = cache2.get(key);
1050
+ if (entry) entry.lastSuccessAt = now;
1051
+ return;
1052
+ }
1053
+ cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
1054
+ }).finally(() => {
1055
+ inflight.delete(key);
1056
+ });
1057
+ inflight.set(key, promise);
1058
+ return promise;
1059
+ }
1060
+ async function getEdgeConfig(config, counterpartyId, opts) {
1061
+ const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
1062
+ const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
1063
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
1064
+ const entry = cache2.get(key);
1065
+ if (entry) {
1066
+ const age = Date.now() - entry.lastSuccessAt;
1067
+ if (age > ttlMs) {
1068
+ revalidate(config, counterpartyId).catch(() => {
1069
+ });
1070
+ }
1071
+ return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
1072
+ }
1073
+ await revalidate(config, counterpartyId).catch(() => {
1074
+ });
1075
+ return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
1076
+ }
1077
+
1078
+ // src/platform-signatures.ts
1079
+ var PLATFORM_AGENT_SIGNATURES = [
1080
+ {
1081
+ vendor: "claude",
1082
+ displayName: "Anthropic Claude",
1083
+ uaPatterns: [/claude/i, /anthropic/i],
1084
+ agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
1085
+ apiKeyFormatPatterns: [/^sk-ant/i],
1086
+ headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
1087
+ },
1088
+ {
1089
+ vendor: "chatgpt",
1090
+ displayName: "OpenAI ChatGPT",
1091
+ uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
1092
+ agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
1093
+ apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
1094
+ headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
1095
+ },
1096
+ {
1097
+ vendor: "gemini",
1098
+ displayName: "Google Gemini",
1099
+ uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
1100
+ agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
1101
+ apiKeyFormatPatterns: [/^aiza/i],
1102
+ headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
1103
+ },
1104
+ {
1105
+ vendor: "cursor",
1106
+ displayName: "Cursor",
1107
+ uaPatterns: [/cursor/i],
1108
+ agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
1109
+ },
1110
+ {
1111
+ vendor: "goose",
1112
+ displayName: "Block Goose",
1113
+ uaPatterns: [/goose/i, /block-goose/i],
1114
+ agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
1115
+ },
1116
+ {
1117
+ vendor: "perplexity",
1118
+ displayName: "Perplexity",
1119
+ uaPatterns: [/perplexity/i],
1120
+ agentCardPatterns: [/perplexity\.ai/i],
1121
+ apiKeyFormatPatterns: [/^pplx-/i]
1122
+ }
1123
+ ];
1124
+ function matchPlatformSignature(signatures, input) {
1125
+ const ua = input.userAgent ?? "";
1126
+ const cardUrl = input.agentCardUrl ?? "";
1127
+ const apiKeyFormat = input.apiKeyFormat ?? "";
1128
+ const headerLines = [];
1129
+ if (input.platformHeaders) {
1130
+ for (const [name, value] of Object.entries(input.platformHeaders)) {
1131
+ headerLines.push(name, `${name}: ${value}`);
1132
+ }
1133
+ }
1134
+ for (const sig of signatures) {
1135
+ const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
1136
+ const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
1137
+ const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
1138
+ const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
1139
+ if (uaMatch || cardMatch || keyMatch || headerMatch) {
1140
+ const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
1141
+ const cardHost = (() => {
1142
+ try {
1143
+ return cardUrl ? new URL(cardUrl).host : "";
1144
+ } catch {
1145
+ return "";
1146
+ }
1147
+ })();
1148
+ const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
1149
+ return {
1150
+ vendor: sig.vendor,
1151
+ fingerprintKey: `${sig.vendor}:${keyBasis}`,
1152
+ displayName: sig.displayName
1153
+ };
1154
+ }
1155
+ }
1156
+ return void 0;
1157
+ }
1158
+ function detectPlatformFingerprint(input) {
1159
+ return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
1160
+ }
1161
+
1162
+ // src/edge-core/classify.ts
1163
+ 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;
1164
+ 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;
1165
+ var BROWSER_UA_PATTERN = /mozilla\/\d/i;
1166
+ var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN };
1167
+
1168
+ // src/edge-core/events.ts
1169
+ function sampled(rate, random = Math.random) {
1170
+ if (rate <= 0) return false;
1171
+ if (rate >= 1) return true;
1172
+ return random() < rate;
1173
+ }
1174
+
1175
+ // src/adapters/anonymous-beacon.ts
1176
+ function readHeader(raw, name) {
1177
+ const value = raw[name];
1178
+ if (typeof value === "string") return value;
1179
+ if (Array.isArray(value)) return value[0];
1180
+ return void 0;
1181
+ }
1182
+ function classifyPassThroughTraffic(path, rawHeaders) {
1183
+ if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: "never" };
1184
+ const credentials = extractCredentials(rawHeaders, {});
1185
+ if (credentials.astraId || credentials.apiKey || credentials.jwt) {
1186
+ return { kind: "never" };
1187
+ }
1188
+ const userAgent = readHeader(rawHeaders, "user-agent") ?? "";
1189
+ const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
1190
+ const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });
1191
+ if (fingerprint) {
1192
+ return {
1193
+ kind: "platform",
1194
+ protocol: "platform-ua",
1195
+ evidence: { vendor: fingerprint.vendor, userAgent: userAgent || "(none)" }
1196
+ };
1197
+ }
1198
+ if (!userAgent || _patterns.BOT_UA_PATTERN.test(userAgent) || !_patterns.BROWSER_UA_PATTERN.test(userAgent)) {
1199
+ return {
1200
+ kind: "anonymous-bot",
1201
+ protocol: "ua-heuristic",
1202
+ evidence: { userAgent: userAgent || "(none)" }
1203
+ };
1204
+ }
1205
+ if (!readHeader(rawHeaders, "sec-fetch-mode") && !readHeader(rawHeaders, "accept-language")) {
1206
+ return {
1207
+ kind: "anonymous-bot",
1208
+ protocol: "ua-heuristic",
1209
+ evidence: { userAgent, spoofedBrowser: true }
1210
+ };
1211
+ }
1212
+ return { kind: "never" };
1213
+ }
1214
+ function createAnonymousBeacon(config, options) {
1215
+ const counterpartyId = config.counterpartyId;
1216
+ if (!counterpartyId) return () => {
1217
+ };
1218
+ const random = options?.random ?? Math.random;
1219
+ let edgeConfig;
1220
+ let refreshing = false;
1221
+ const refreshConfig = () => {
1222
+ if (refreshing) return;
1223
+ refreshing = true;
1224
+ getEdgeConfig(config, counterpartyId).then((cfg) => {
1225
+ edgeConfig = cfg;
1226
+ }).catch(() => {
1227
+ }).finally(() => {
1228
+ refreshing = false;
1229
+ });
1230
+ };
1231
+ refreshConfig();
1232
+ return (input) => {
1233
+ try {
1234
+ refreshConfig();
1235
+ const cfg = edgeConfig;
1236
+ if (!cfg) return;
1237
+ const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);
1238
+ if (traffic.kind === "never") return;
1239
+ if (traffic.kind === "anonymous-bot" && !sampled(cfg.sampling.anonymousBeaconRate, random)) {
1240
+ return;
1241
+ }
1242
+ const userAgent = readHeader(input.rawHeaders, "user-agent");
1243
+ const xff = input.rawHeaders["x-forwarded-for"];
1244
+ const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
1245
+ const sourceIp = input.sourceIp ?? xffStr?.split(",")[0]?.trim();
1246
+ reportUnregisteredAttempt(config, {
1247
+ ...input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl },
1248
+ counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? "api",
1249
+ ...sourceIp && { sourceIp },
1250
+ ...userAgent && { userAgent },
1251
+ requestPath: input.requestPath,
1252
+ requestMethod: input.requestMethod,
1253
+ ...traffic.protocol && { protocol: traffic.protocol },
1254
+ ...traffic.evidence && { evidence: traffic.evidence },
1255
+ observedMetadata: buildSdkObservedMetadata(input.rawHeaders)
1256
+ }).catch(() => {
1257
+ });
1258
+ } catch {
1259
+ }
1260
+ };
1261
+ }
859
1262
 
860
1263
  // src/adapters/http-pdlss.ts
861
1264
  var HTTP_METHOD_ACTION_TABLE = {
@@ -1019,7 +1422,7 @@ function resolveNextPdlss(request, routeConfig) {
1019
1422
  routeAction: routeConfig?.action
1020
1423
  });
1021
1424
  }
1022
- function generateCommerceShieldHtml(result, options) {
1425
+ function generateInterstitialHtml(result, options) {
1023
1426
  const title = escapeHtml(options.commerceShield?.title || "AstraSync Agent Verification");
1024
1427
  const message = escapeHtml(
1025
1428
  options.commerceShield?.message || result.guidance?.message || "This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials."
@@ -1175,13 +1578,31 @@ function generateCommerceShieldHtml(result, options) {
1175
1578
  }
1176
1579
  var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
1177
1580
  function createMiddleware(options) {
1581
+ if ("routes" in options) {
1582
+ console.warn(
1583
+ "[VerificationGateway/Next.js] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
1584
+ );
1585
+ }
1178
1586
  const {
1179
1587
  skipPaths = [],
1180
- showCommerceShield = true,
1588
+ showInterstitial,
1589
+ showCommerceShield,
1181
1590
  enableRuntimeChallenge = true,
1182
1591
  routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
1592
+ anonymousBeacon = true,
1183
1593
  ...config
1184
1594
  } = options;
1595
+ const interstitialEnabled = showInterstitial ?? showCommerceShield ?? true;
1596
+ const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "website" }) : void 0;
1597
+ const beaconPassThrough = emitAnonymousBeacon ? (request, pathname) => {
1598
+ emitAnonymousBeacon({
1599
+ requestPath: pathname,
1600
+ requestMethod: request.method,
1601
+ counterpartyUrl: config.counterpartyUrl || request.nextUrl.origin,
1602
+ sourceIp: request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || void 0,
1603
+ rawHeaders: Object.fromEntries(request.headers.entries())
1604
+ });
1605
+ } : void 0;
1185
1606
  let cachedRoutes = [];
1186
1607
  let lastFetchAt = 0;
1187
1608
  let refreshing = null;
@@ -1223,9 +1644,11 @@ function createMiddleware(options) {
1223
1644
  }
1224
1645
  const routeConfig = findRouteConfig(cachedRoutes, pathname, request.method);
1225
1646
  if (!routeConfig) {
1647
+ beaconPassThrough?.(request, pathname);
1226
1648
  return NextResponse.next();
1227
1649
  }
1228
1650
  if (routeConfig.minAccessLevel === "none") {
1651
+ beaconPassThrough?.(request, pathname);
1229
1652
  return NextResponse.next();
1230
1653
  }
1231
1654
  const credentials = extractCredentialsFromNextRequest(request);
@@ -1277,8 +1700,8 @@ function createMiddleware(options) {
1277
1700
  { status: 403 }
1278
1701
  );
1279
1702
  }
1280
- if (showCommerceShield) {
1281
- return new NextResponse(generateCommerceShieldHtml(preCheckResult, options), {
1703
+ if (interstitialEnabled) {
1704
+ return new NextResponse(generateInterstitialHtml(preCheckResult, options), {
1282
1705
  status: 200,
1283
1706
  headers: {
1284
1707
  "Content-Type": "text/html",
@@ -1306,17 +1729,9 @@ function createMiddleware(options) {
1306
1729
  host: request.headers.get("host") || void 0,
1307
1730
  forwardedFor,
1308
1731
  agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0,
1309
- // Workstream D — full sanitised header capture (Web Headers → plain map).
1310
- observedMetadata: (() => {
1311
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(
1312
- Object.fromEntries(request.headers.entries())
1313
- );
1314
- return {
1315
- headers,
1316
- ...apiKeyFormat && { apiKeyFormat },
1317
- ...platformHeaders && { platformHeaders }
1318
- };
1319
- })()
1732
+ // Workstream D — full sanitised header capture + CDN-derived
1733
+ // connection block (Web Headers → plain map).
1734
+ observedMetadata: buildSdkObservedMetadata(Object.fromEntries(request.headers.entries()))
1320
1735
  }
1321
1736
  };
1322
1737
  let result = await verify(config, verificationRequest);
@@ -1371,8 +1786,8 @@ function createMiddleware(options) {
1371
1786
  }
1372
1787
  );
1373
1788
  }
1374
- if (showCommerceShield) {
1375
- return new NextResponse(generateCommerceShieldHtml(result, options), {
1789
+ if (interstitialEnabled) {
1790
+ return new NextResponse(generateInterstitialHtml(result, options), {
1376
1791
  status: 200,
1377
1792
  headers: {
1378
1793
  "Content-Type": "text/html",