@astrasyncai/verification-gateway 4.3.0 → 4.4.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 (83) hide show
  1. package/dist/adapters/express.js +91 -19
  2. package/dist/adapters/express.js.map +1 -1
  3. package/dist/adapters/express.mjs +91 -19
  4. package/dist/adapters/express.mjs.map +1 -1
  5. package/dist/adapters/mcp.js +52 -13
  6. package/dist/adapters/mcp.js.map +1 -1
  7. package/dist/adapters/mcp.mjs +52 -13
  8. package/dist/adapters/mcp.mjs.map +1 -1
  9. package/dist/adapters/nextjs.js +89 -17
  10. package/dist/adapters/nextjs.js.map +1 -1
  11. package/dist/adapters/nextjs.mjs +89 -17
  12. package/dist/adapters/nextjs.mjs.map +1 -1
  13. package/dist/adapters/sdk.js +24 -6
  14. package/dist/adapters/sdk.js.map +1 -1
  15. package/dist/adapters/sdk.mjs +24 -6
  16. package/dist/adapters/sdk.mjs.map +1 -1
  17. package/dist/agent/index.js +24 -3
  18. package/dist/agent/index.js.map +1 -1
  19. package/dist/agent/index.mjs +24 -3
  20. package/dist/agent/index.mjs.map +1 -1
  21. package/dist/bin/astrasync-claude-hook.js +22 -4
  22. package/dist/bin/astrasync-codex-hook.js +22 -4
  23. package/dist/bin/astrasync-guard.js +26 -8
  24. package/dist/bin/astrasync.js +66 -23
  25. package/dist/browser/background.js +22 -4
  26. package/dist/browser/background.js.map +1 -1
  27. package/dist/browser/background.mjs +22 -4
  28. package/dist/browser/background.mjs.map +1 -1
  29. package/dist/cli/index.js +23 -2
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/cli/index.mjs +23 -2
  32. package/dist/cli/index.mjs.map +1 -1
  33. package/dist/codex/index.js +22 -4
  34. package/dist/codex/index.js.map +1 -1
  35. package/dist/codex/index.mjs +22 -4
  36. package/dist/codex/index.mjs.map +1 -1
  37. package/dist/cursor/extension.js +22 -4
  38. package/dist/cursor/extension.js.map +1 -1
  39. package/dist/cursor/extension.mjs +22 -4
  40. package/dist/cursor/extension.mjs.map +1 -1
  41. package/dist/edge-config.js +24 -1
  42. package/dist/edge-config.js.map +1 -1
  43. package/dist/edge-config.mjs +22 -1
  44. package/dist/edge-config.mjs.map +1 -1
  45. package/dist/edge-core/index.js +96 -11
  46. package/dist/edge-core/index.js.map +1 -1
  47. package/dist/edge-core/index.mjs +96 -11
  48. package/dist/edge-core/index.mjs.map +1 -1
  49. package/dist/gateway/gateway.js +22 -4
  50. package/dist/gateway/gateway.js.map +1 -1
  51. package/dist/gateway/gateway.mjs +22 -4
  52. package/dist/gateway/gateway.mjs.map +1 -1
  53. package/dist/index.d.mts +51 -2
  54. package/dist/index.d.ts +51 -2
  55. package/dist/index.js +151 -26
  56. package/dist/index.js.map +1 -1
  57. package/dist/index.mjs +147 -26
  58. package/dist/index.mjs.map +1 -1
  59. package/dist/metadata-capture.d.mts +17 -0
  60. package/dist/metadata-capture.d.ts +17 -0
  61. package/dist/metadata-capture.js +25 -4
  62. package/dist/metadata-capture.js.map +1 -1
  63. package/dist/metadata-capture.mjs +25 -4
  64. package/dist/metadata-capture.mjs.map +1 -1
  65. package/dist/platform-signatures.d.mts +18 -1
  66. package/dist/platform-signatures.d.ts +18 -1
  67. package/dist/platform-signatures.js +35 -2
  68. package/dist/platform-signatures.js.map +1 -1
  69. package/dist/platform-signatures.mjs +35 -2
  70. package/dist/platform-signatures.mjs.map +1 -1
  71. package/dist/registration/index.js +25 -4
  72. package/dist/registration/index.js.map +1 -1
  73. package/dist/registration/index.mjs +25 -4
  74. package/dist/registration/index.mjs.map +1 -1
  75. package/dist/transport/index.js +22 -1
  76. package/dist/transport/index.js.map +1 -1
  77. package/dist/transport/index.mjs +22 -1
  78. package/dist/transport/index.mjs.map +1 -1
  79. package/dist/verify.js +29 -11
  80. package/dist/verify.js.map +1 -1
  81. package/dist/verify.mjs +29 -11
  82. package/dist/verify.mjs.map +1 -1
  83. package/package.json +1 -1
@@ -1,3 +1,24 @@
1
+ // src/version.ts
2
+ var SDK_VERSION = "4.4.0";
3
+
4
+ // src/http.ts
5
+ var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
6
+ function withUserAgent(initHeaders) {
7
+ if (!initHeaders) return { "user-agent": SDK_USER_AGENT };
8
+ if (initHeaders instanceof Headers) {
9
+ const copy = new Headers(initHeaders);
10
+ if (!copy.has("user-agent")) copy.set("user-agent", SDK_USER_AGENT);
11
+ return copy;
12
+ }
13
+ if (Array.isArray(initHeaders)) {
14
+ const has2 = initHeaders.some(([name]) => name.toLowerCase() === "user-agent");
15
+ return has2 ? initHeaders : [...initHeaders, ["user-agent", SDK_USER_AGENT]];
16
+ }
17
+ const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === "user-agent");
18
+ return has ? initHeaders : { "user-agent": SDK_USER_AGENT, ...initHeaders };
19
+ }
20
+ var sdkFetch = (input, init) => fetch(input, { ...init, headers: withUserAgent(init?.headers) });
21
+
1
22
  // src/adapters/stepup-poll.ts
2
23
  var DEFAULT_POLL_INTERVAL_MS = 3e3;
3
24
  var MIN_POLL_INTERVAL_MS = 250;
@@ -12,7 +33,7 @@ function resolvePollUrl(config, pollUrl) {
12
33
  async function pollStepUpStatus(config, approval) {
13
34
  if (!approval.pollUrl) return null;
14
35
  try {
15
- const res = await fetch(resolvePollUrl(config, approval.pollUrl), {
36
+ const res = await sdkFetch(resolvePollUrl(config, approval.pollUrl), {
16
37
  method: "GET",
17
38
  signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS)
18
39
  });
@@ -64,9 +85,6 @@ function getTrustLevel(score) {
64
85
  return "BRONZE";
65
86
  }
66
87
 
67
- // src/version.ts
68
- var SDK_VERSION = "4.1.0";
69
-
70
88
  // src/well-known.ts
71
89
  var CACHE_TTL_MS = 60 * 60 * 1e3;
72
90
  var cache = /* @__PURE__ */ new Map();
@@ -95,7 +113,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
95
113
  initCheckPerformed = true;
96
114
  try {
97
115
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
98
- const response = await fetch(probeUrl, { method: "HEAD" });
116
+ const response = await sdkFetch(probeUrl, { method: "HEAD" });
99
117
  const contentType = response.headers.get("content-type") ?? "";
100
118
  if (contentType.startsWith("text/html")) {
101
119
  const message = `[VerificationGateway] apiBaseUrl '${apiBaseUrl}' returned HTML (content-type: ${contentType}). This usually means apiBaseUrl is pointing at a marketing site instead of the API. Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging).`;
@@ -109,7 +127,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
109
127
  );
110
128
  }
111
129
  if (apiKey) {
112
- const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
130
+ const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
113
131
  headers: { Authorization: `Bearer ${apiKey}` }
114
132
  });
115
133
  if (selfCheck.status === 401) {
@@ -356,7 +374,7 @@ async function callVerifyAccessAPI(config, request) {
356
374
  headers["X-API-Key"] = config.apiKey;
357
375
  }
358
376
  try {
359
- const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
377
+ const response = await sdkFetch(`${config.apiBaseUrl}/agents/verify-access`, {
360
378
  method: "POST",
361
379
  headers,
362
380
  body: JSON.stringify(body),
@@ -601,7 +619,7 @@ async function fetchRoutes(config, counterpartyId) {
601
619
  headers["X-API-Key"] = config.apiKey;
602
620
  }
603
621
  try {
604
- const response = await fetch(
622
+ const response = await sdkFetch(
605
623
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
606
624
  { method: "GET", headers }
607
625
  );
@@ -620,7 +638,7 @@ async function reportUnregisteredAttempt(config, data) {
620
638
  ...counterpartyUrl && { counterpartyUrl },
621
639
  ...config.counterpartyId && { counterpartyId: config.counterpartyId }
622
640
  };
623
- await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
641
+ await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
624
642
  method: "POST",
625
643
  headers: { "Content-Type": "application/json" },
626
644
  body: JSON.stringify(body)
@@ -629,7 +647,7 @@ async function reportUnregisteredAttempt(config, data) {
629
647
  }
630
648
  async function reportCounterpartyPreCheckFailure(config, data) {
631
649
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
632
- await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
650
+ await sdkFetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
633
651
  method: "POST",
634
652
  headers: { "Content-Type": "application/json" },
635
653
  body: JSON.stringify(data)
@@ -768,7 +786,13 @@ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
768
786
  "x-agent-card-url",
769
787
  "x-agent-provider"
770
788
  ]);
771
- var PLATFORM_HEADER_PREFIXES = ["x-goog-", "x-stainless-", "x-anthropic-", "x-openai-"];
789
+ var PLATFORM_HEADER_PREFIXES = [
790
+ "x-goog-",
791
+ "x-stainless-",
792
+ "x-anthropic-",
793
+ "x-openai-",
794
+ "sec-ch-"
795
+ ];
772
796
  var KEY_FORMAT_PREFIXES = [
773
797
  "sk-ant-api03",
774
798
  "sk-ant-api",
@@ -840,6 +864,7 @@ function sanitizeHeaders(raw) {
840
864
  const headers = {};
841
865
  const platformHeaders = {};
842
866
  let apiKeyFormat;
867
+ let cookieCount;
843
868
  let totalBytes = 0;
844
869
  let count = 0;
845
870
  if (!raw) return { headers };
@@ -854,6 +879,9 @@ function sanitizeHeaders(raw) {
854
879
  if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
855
880
  continue;
856
881
  }
882
+ if (name === "cookie") {
883
+ cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
884
+ }
857
885
  if (isSecretHeader(name)) continue;
858
886
  let value = joined;
859
887
  if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
@@ -869,6 +897,7 @@ function sanitizeHeaders(raw) {
869
897
  const result = { headers };
870
898
  if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
871
899
  if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
900
+ if (cookieCount !== void 0) result.cookieCount = cookieCount;
872
901
  return result;
873
902
  }
874
903
  var CONNECTION_HEADER_SOURCES = [
@@ -880,6 +909,9 @@ var CONNECTION_HEADER_SOURCES = [
880
909
  ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
881
910
  ["countryRegionName", ["cloudfront-viewer-country-region-name"]],
882
911
  ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
912
+ ["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
913
+ ["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
914
+ ["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
883
915
  ["asn", ["cloudfront-viewer-asn"]],
884
916
  ["tlsVersion", ["cloudfront-viewer-tls"]],
885
917
  ["httpVersion", ["cloudfront-viewer-http-version"]],
@@ -914,19 +946,25 @@ function deriveConnectionFromHeaders(headers) {
914
946
  }
915
947
  }
916
948
  }
917
- if (!connection.ip) {
949
+ {
918
950
  const addr = lower["cloudfront-viewer-address"]?.trim();
919
- if (addr) connection.ip = addr.replace(/:\d+$/, "");
951
+ const portMatch = addr?.match(/:(\d+)$/);
952
+ if (portMatch) connection.sourcePort = portMatch[1];
953
+ if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
920
954
  }
921
955
  if (!connection.ip) {
922
956
  const xff = lower["x-forwarded-for"];
923
957
  const client = xff?.split(",")[0]?.trim();
924
958
  if (client) connection.ip = client;
925
959
  }
960
+ if (!connection.tlsCipher) {
961
+ const cipher = connection.tlsVersion?.split(":")[1];
962
+ if (cipher) connection.tlsCipher = cipher;
963
+ }
926
964
  return Object.keys(connection).length > 0 ? connection : void 0;
927
965
  }
928
966
  function buildSdkObservedMetadata(rawHeaders) {
929
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
967
+ const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
930
968
  const flat = {};
931
969
  if (rawHeaders) {
932
970
  for (const name of Object.keys(rawHeaders)) {
@@ -941,6 +979,7 @@ function buildSdkObservedMetadata(rawHeaders) {
941
979
  ...apiKeyFormat && { apiKeyFormat },
942
980
  ...platformHeaders && { platformHeaders },
943
981
  ...connection && { connection },
982
+ ...cookieCount !== void 0 && { cookieCount },
944
983
  schemaVersion: CAPTURE_SCHEMA_VERSION
945
984
  };
946
985
  }
@@ -985,7 +1024,7 @@ async function fetchEdgeConfig(config, counterpartyId, opts) {
985
1024
  }
986
1025
  if (opts?.etag) headers["If-None-Match"] = opts.etag;
987
1026
  try {
988
- const response = await fetch(
1027
+ const response = await sdkFetch(
989
1028
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
990
1029
  { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
991
1030
  );
@@ -1097,12 +1136,43 @@ var PLATFORM_AGENT_SIGNATURES = [
1097
1136
  uaPatterns: [/perplexity/i],
1098
1137
  agentCardPatterns: [/perplexity\.ai/i],
1099
1138
  apiKeyFormatPatterns: [/^pplx-/i]
1139
+ },
1140
+ // Agentic browsers — versioned-token patterns ONLY (a stock Chrome UA must
1141
+ // never match). Distinct vendor keys (not 'chatgpt'/'perplexity'): the
1142
+ // browser product is a different surface than the assistant service, and
1143
+ // the DB registry mirrors one row per vendor. These sit after the primary
1144
+ // vendor entries so a UA carrying an explicit vendor token keeps its
1145
+ // primary attribution; a browser-shaped UA with the agentic token is
1146
+ // caught here BEFORE classify's human tier, which is what makes these
1147
+ // visits observable at all. Token drift is real (some builds mimic Chrome
1148
+ // outright) — re-verify against captured events when a new browser ships,
1149
+ // and check `sec-ch-ua` platformHeaders for the real brand.
1150
+ {
1151
+ vendor: "chatgpt-atlas",
1152
+ displayName: "ChatGPT Atlas browser",
1153
+ uaPatterns: [/\batlas\/\d/i],
1154
+ headerPatterns: [/^sec-ch-ua: .*atlas/i]
1155
+ },
1156
+ {
1157
+ vendor: "perplexity-comet",
1158
+ displayName: "Perplexity Comet browser",
1159
+ uaPatterns: [/\bcomet\/\d/i],
1160
+ headerPatterns: [/^sec-ch-ua: .*comet/i]
1161
+ },
1162
+ // Our own SDK self-identifies (sdkFetch stamps this UA) — first-party
1163
+ // traffic must never pollute the unknown/anonymous pool it exists to audit.
1164
+ {
1165
+ vendor: "astrasync-sdk",
1166
+ displayName: "AstraSync SDK",
1167
+ uaPatterns: [/^astrasync-sdk\//i]
1100
1168
  }
1101
1169
  ];
1102
1170
  function matchPlatformSignature(signatures, input) {
1103
1171
  const ua = input.userAgent ?? "";
1104
1172
  const cardUrl = input.agentCardUrl ?? "";
1105
1173
  const apiKeyFormat = input.apiKeyFormat ?? "";
1174
+ const ja4 = input.ja4 ?? "";
1175
+ const asn = input.asn ?? "";
1106
1176
  const headerLines = [];
1107
1177
  if (input.platformHeaders) {
1108
1178
  for (const [name, value] of Object.entries(input.platformHeaders)) {
@@ -1114,7 +1184,9 @@ function matchPlatformSignature(signatures, input) {
1114
1184
  const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
1115
1185
  const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
1116
1186
  const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
1117
- if (uaMatch || cardMatch || keyMatch || headerMatch) {
1187
+ const ja4Match = ja4.length > 0 && sig.ja4Patterns?.some((p) => p.test(ja4));
1188
+ const asnMatch = asn.length > 0 && sig.asnList?.includes(asn);
1189
+ if (uaMatch || cardMatch || keyMatch || headerMatch || ja4Match || asnMatch) {
1118
1190
  const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
1119
1191
  const cardHost = (() => {
1120
1192
  try {
@@ -1123,7 +1195,7 @@ function matchPlatformSignature(signatures, input) {
1123
1195
  return "";
1124
1196
  }
1125
1197
  })();
1126
- const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
1198
+ const keyBasis = uaBase || cardHost || apiKeyFormat || ja4 || asn && `asn${asn}` || "unknown";
1127
1199
  return {
1128
1200
  vendor: sig.vendor,
1129
1201
  fingerprintKey: `${sig.vendor}:${keyBasis}`,