@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
@@ -25,6 +25,27 @@ __export(express_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(express_exports);
27
27
 
28
+ // src/version.ts
29
+ var SDK_VERSION = "4.4.0";
30
+
31
+ // src/http.ts
32
+ var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
33
+ function withUserAgent(initHeaders) {
34
+ if (!initHeaders) return { "user-agent": SDK_USER_AGENT };
35
+ if (initHeaders instanceof Headers) {
36
+ const copy = new Headers(initHeaders);
37
+ if (!copy.has("user-agent")) copy.set("user-agent", SDK_USER_AGENT);
38
+ return copy;
39
+ }
40
+ if (Array.isArray(initHeaders)) {
41
+ const has2 = initHeaders.some(([name]) => name.toLowerCase() === "user-agent");
42
+ return has2 ? initHeaders : [...initHeaders, ["user-agent", SDK_USER_AGENT]];
43
+ }
44
+ const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === "user-agent");
45
+ return has ? initHeaders : { "user-agent": SDK_USER_AGENT, ...initHeaders };
46
+ }
47
+ var sdkFetch = (input, init) => fetch(input, { ...init, headers: withUserAgent(init?.headers) });
48
+
28
49
  // src/adapters/stepup-poll.ts
29
50
  var DEFAULT_POLL_INTERVAL_MS = 3e3;
30
51
  var MIN_POLL_INTERVAL_MS = 250;
@@ -39,7 +60,7 @@ function resolvePollUrl(config, pollUrl) {
39
60
  async function pollStepUpStatus(config, approval) {
40
61
  if (!approval.pollUrl) return null;
41
62
  try {
42
- const res = await fetch(resolvePollUrl(config, approval.pollUrl), {
63
+ const res = await sdkFetch(resolvePollUrl(config, approval.pollUrl), {
43
64
  method: "GET",
44
65
  signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS)
45
66
  });
@@ -91,9 +112,6 @@ function getTrustLevel(score) {
91
112
  return "BRONZE";
92
113
  }
93
114
 
94
- // src/version.ts
95
- var SDK_VERSION = "4.1.0";
96
-
97
115
  // src/well-known.ts
98
116
  var CACHE_TTL_MS = 60 * 60 * 1e3;
99
117
  var cache = /* @__PURE__ */ new Map();
@@ -104,7 +122,7 @@ function wellKnownUrl(apiBaseUrl) {
104
122
  }
105
123
  async function fetchWellKnown(apiBaseUrl) {
106
124
  const url = wellKnownUrl(apiBaseUrl);
107
- const response = await fetch(url, {
125
+ const response = await sdkFetch(url, {
108
126
  method: "GET",
109
127
  headers: { Accept: "application/json" },
110
128
  signal: AbortSignal.timeout(5e3)
@@ -174,7 +192,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
174
192
  initCheckPerformed = true;
175
193
  try {
176
194
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
177
- const response = await fetch(probeUrl, { method: "HEAD" });
195
+ const response = await sdkFetch(probeUrl, { method: "HEAD" });
178
196
  const contentType = response.headers.get("content-type") ?? "";
179
197
  if (contentType.startsWith("text/html")) {
180
198
  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).`;
@@ -188,7 +206,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
188
206
  );
189
207
  }
190
208
  if (apiKey) {
191
- const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
209
+ const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
192
210
  headers: { Authorization: `Bearer ${apiKey}` }
193
211
  });
194
212
  if (selfCheck.status === 401) {
@@ -435,7 +453,7 @@ async function callVerifyAccessAPI(config, request) {
435
453
  headers["X-API-Key"] = config.apiKey;
436
454
  }
437
455
  try {
438
- const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
456
+ const response = await sdkFetch(`${config.apiBaseUrl}/agents/verify-access`, {
439
457
  method: "POST",
440
458
  headers,
441
459
  body: JSON.stringify(body),
@@ -678,7 +696,7 @@ async function recordDecision(config, sessionId, decision, reason) {
678
696
  headers["Authorization"] = `Bearer ${config.apiKey}`;
679
697
  headers["X-API-Key"] = config.apiKey;
680
698
  }
681
- await fetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
699
+ await sdkFetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
682
700
  method: "POST",
683
701
  headers,
684
702
  body: JSON.stringify({ decision, reason })
@@ -693,7 +711,7 @@ async function fetchRoutes(config, counterpartyId) {
693
711
  headers["X-API-Key"] = config.apiKey;
694
712
  }
695
713
  try {
696
- const response = await fetch(
714
+ const response = await sdkFetch(
697
715
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
698
716
  { method: "GET", headers }
699
717
  );
@@ -712,7 +730,7 @@ async function reportUnregisteredAttempt(config, data) {
712
730
  ...counterpartyUrl && { counterpartyUrl },
713
731
  ...config.counterpartyId && { counterpartyId: config.counterpartyId }
714
732
  };
715
- await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
733
+ await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
716
734
  method: "POST",
717
735
  headers: { "Content-Type": "application/json" },
718
736
  body: JSON.stringify(body)
@@ -721,7 +739,7 @@ async function reportUnregisteredAttempt(config, data) {
721
739
  }
722
740
  async function reportCounterpartyPreCheckFailure(config, data) {
723
741
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
724
- await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
742
+ await sdkFetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
725
743
  method: "POST",
726
744
  headers: { "Content-Type": "application/json" },
727
745
  body: JSON.stringify(data)
@@ -977,7 +995,13 @@ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
977
995
  "x-agent-card-url",
978
996
  "x-agent-provider"
979
997
  ]);
980
- var PLATFORM_HEADER_PREFIXES = ["x-goog-", "x-stainless-", "x-anthropic-", "x-openai-"];
998
+ var PLATFORM_HEADER_PREFIXES = [
999
+ "x-goog-",
1000
+ "x-stainless-",
1001
+ "x-anthropic-",
1002
+ "x-openai-",
1003
+ "sec-ch-"
1004
+ ];
981
1005
  var KEY_FORMAT_PREFIXES = [
982
1006
  "sk-ant-api03",
983
1007
  "sk-ant-api",
@@ -1049,6 +1073,7 @@ function sanitizeHeaders(raw) {
1049
1073
  const headers = {};
1050
1074
  const platformHeaders = {};
1051
1075
  let apiKeyFormat;
1076
+ let cookieCount;
1052
1077
  let totalBytes = 0;
1053
1078
  let count = 0;
1054
1079
  if (!raw) return { headers };
@@ -1063,6 +1088,9 @@ function sanitizeHeaders(raw) {
1063
1088
  if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
1064
1089
  continue;
1065
1090
  }
1091
+ if (name === "cookie") {
1092
+ cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
1093
+ }
1066
1094
  if (isSecretHeader(name)) continue;
1067
1095
  let value = joined;
1068
1096
  if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
@@ -1078,6 +1106,7 @@ function sanitizeHeaders(raw) {
1078
1106
  const result = { headers };
1079
1107
  if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
1080
1108
  if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
1109
+ if (cookieCount !== void 0) result.cookieCount = cookieCount;
1081
1110
  return result;
1082
1111
  }
1083
1112
  var CONNECTION_HEADER_SOURCES = [
@@ -1089,6 +1118,9 @@ var CONNECTION_HEADER_SOURCES = [
1089
1118
  ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
1090
1119
  ["countryRegionName", ["cloudfront-viewer-country-region-name"]],
1091
1120
  ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
1121
+ ["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
1122
+ ["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
1123
+ ["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
1092
1124
  ["asn", ["cloudfront-viewer-asn"]],
1093
1125
  ["tlsVersion", ["cloudfront-viewer-tls"]],
1094
1126
  ["httpVersion", ["cloudfront-viewer-http-version"]],
@@ -1123,19 +1155,25 @@ function deriveConnectionFromHeaders(headers) {
1123
1155
  }
1124
1156
  }
1125
1157
  }
1126
- if (!connection.ip) {
1158
+ {
1127
1159
  const addr = lower["cloudfront-viewer-address"]?.trim();
1128
- if (addr) connection.ip = addr.replace(/:\d+$/, "");
1160
+ const portMatch = addr?.match(/:(\d+)$/);
1161
+ if (portMatch) connection.sourcePort = portMatch[1];
1162
+ if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
1129
1163
  }
1130
1164
  if (!connection.ip) {
1131
1165
  const xff = lower["x-forwarded-for"];
1132
1166
  const client = xff?.split(",")[0]?.trim();
1133
1167
  if (client) connection.ip = client;
1134
1168
  }
1169
+ if (!connection.tlsCipher) {
1170
+ const cipher = connection.tlsVersion?.split(":")[1];
1171
+ if (cipher) connection.tlsCipher = cipher;
1172
+ }
1135
1173
  return Object.keys(connection).length > 0 ? connection : void 0;
1136
1174
  }
1137
1175
  function buildSdkObservedMetadata(rawHeaders) {
1138
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
1176
+ const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
1139
1177
  const flat = {};
1140
1178
  if (rawHeaders) {
1141
1179
  for (const name of Object.keys(rawHeaders)) {
@@ -1150,6 +1188,7 @@ function buildSdkObservedMetadata(rawHeaders) {
1150
1188
  ...apiKeyFormat && { apiKeyFormat },
1151
1189
  ...platformHeaders && { platformHeaders },
1152
1190
  ...connection && { connection },
1191
+ ...cookieCount !== void 0 && { cookieCount },
1153
1192
  schemaVersion: CAPTURE_SCHEMA_VERSION
1154
1193
  };
1155
1194
  }
@@ -1194,7 +1233,7 @@ async function fetchEdgeConfig(config, counterpartyId, opts) {
1194
1233
  }
1195
1234
  if (opts?.etag) headers["If-None-Match"] = opts.etag;
1196
1235
  try {
1197
- const response = await fetch(
1236
+ const response = await sdkFetch(
1198
1237
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
1199
1238
  { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
1200
1239
  );
@@ -1306,12 +1345,43 @@ var PLATFORM_AGENT_SIGNATURES = [
1306
1345
  uaPatterns: [/perplexity/i],
1307
1346
  agentCardPatterns: [/perplexity\.ai/i],
1308
1347
  apiKeyFormatPatterns: [/^pplx-/i]
1348
+ },
1349
+ // Agentic browsers — versioned-token patterns ONLY (a stock Chrome UA must
1350
+ // never match). Distinct vendor keys (not 'chatgpt'/'perplexity'): the
1351
+ // browser product is a different surface than the assistant service, and
1352
+ // the DB registry mirrors one row per vendor. These sit after the primary
1353
+ // vendor entries so a UA carrying an explicit vendor token keeps its
1354
+ // primary attribution; a browser-shaped UA with the agentic token is
1355
+ // caught here BEFORE classify's human tier, which is what makes these
1356
+ // visits observable at all. Token drift is real (some builds mimic Chrome
1357
+ // outright) — re-verify against captured events when a new browser ships,
1358
+ // and check `sec-ch-ua` platformHeaders for the real brand.
1359
+ {
1360
+ vendor: "chatgpt-atlas",
1361
+ displayName: "ChatGPT Atlas browser",
1362
+ uaPatterns: [/\batlas\/\d/i],
1363
+ headerPatterns: [/^sec-ch-ua: .*atlas/i]
1364
+ },
1365
+ {
1366
+ vendor: "perplexity-comet",
1367
+ displayName: "Perplexity Comet browser",
1368
+ uaPatterns: [/\bcomet\/\d/i],
1369
+ headerPatterns: [/^sec-ch-ua: .*comet/i]
1370
+ },
1371
+ // Our own SDK self-identifies (sdkFetch stamps this UA) — first-party
1372
+ // traffic must never pollute the unknown/anonymous pool it exists to audit.
1373
+ {
1374
+ vendor: "astrasync-sdk",
1375
+ displayName: "AstraSync SDK",
1376
+ uaPatterns: [/^astrasync-sdk\//i]
1309
1377
  }
1310
1378
  ];
1311
1379
  function matchPlatformSignature(signatures, input) {
1312
1380
  const ua = input.userAgent ?? "";
1313
1381
  const cardUrl = input.agentCardUrl ?? "";
1314
1382
  const apiKeyFormat = input.apiKeyFormat ?? "";
1383
+ const ja4 = input.ja4 ?? "";
1384
+ const asn = input.asn ?? "";
1315
1385
  const headerLines = [];
1316
1386
  if (input.platformHeaders) {
1317
1387
  for (const [name, value] of Object.entries(input.platformHeaders)) {
@@ -1323,7 +1393,9 @@ function matchPlatformSignature(signatures, input) {
1323
1393
  const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
1324
1394
  const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
1325
1395
  const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
1326
- if (uaMatch || cardMatch || keyMatch || headerMatch) {
1396
+ const ja4Match = ja4.length > 0 && sig.ja4Patterns?.some((p) => p.test(ja4));
1397
+ const asnMatch = asn.length > 0 && sig.asnList?.includes(asn);
1398
+ if (uaMatch || cardMatch || keyMatch || headerMatch || ja4Match || asnMatch) {
1327
1399
  const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
1328
1400
  const cardHost = (() => {
1329
1401
  try {
@@ -1332,7 +1404,7 @@ function matchPlatformSignature(signatures, input) {
1332
1404
  return "";
1333
1405
  }
1334
1406
  })();
1335
- const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
1407
+ const keyBasis = uaBase || cardHost || apiKeyFormat || ja4 || asn && `asn${asn}` || "unknown";
1336
1408
  return {
1337
1409
  vendor: sig.vendor,
1338
1410
  fingerprintKey: `${sig.vendor}:${keyBasis}`,