@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/edge-config.ts
2
23
  var DEFAULT_EDGE_CONFIG = Object.freeze({
3
24
  version: 1,
@@ -57,7 +78,13 @@ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
57
78
  "x-agent-card-url",
58
79
  "x-agent-provider"
59
80
  ]);
60
- var PLATFORM_HEADER_PREFIXES = ["x-goog-", "x-stainless-", "x-anthropic-", "x-openai-"];
81
+ var PLATFORM_HEADER_PREFIXES = [
82
+ "x-goog-",
83
+ "x-stainless-",
84
+ "x-anthropic-",
85
+ "x-openai-",
86
+ "sec-ch-"
87
+ ];
61
88
  var KEY_FORMAT_PREFIXES = [
62
89
  "sk-ant-api03",
63
90
  "sk-ant-api",
@@ -129,6 +156,7 @@ function sanitizeHeaders(raw) {
129
156
  const headers = {};
130
157
  const platformHeaders = {};
131
158
  let apiKeyFormat;
159
+ let cookieCount;
132
160
  let totalBytes = 0;
133
161
  let count = 0;
134
162
  if (!raw) return { headers };
@@ -143,6 +171,9 @@ function sanitizeHeaders(raw) {
143
171
  if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
144
172
  continue;
145
173
  }
174
+ if (name === "cookie") {
175
+ cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
176
+ }
146
177
  if (isSecretHeader(name)) continue;
147
178
  let value = joined;
148
179
  if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
@@ -158,6 +189,7 @@ function sanitizeHeaders(raw) {
158
189
  const result = { headers };
159
190
  if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
160
191
  if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
192
+ if (cookieCount !== void 0) result.cookieCount = cookieCount;
161
193
  return result;
162
194
  }
163
195
 
@@ -205,12 +237,43 @@ var PLATFORM_AGENT_SIGNATURES = [
205
237
  uaPatterns: [/perplexity/i],
206
238
  agentCardPatterns: [/perplexity\.ai/i],
207
239
  apiKeyFormatPatterns: [/^pplx-/i]
240
+ },
241
+ // Agentic browsers — versioned-token patterns ONLY (a stock Chrome UA must
242
+ // never match). Distinct vendor keys (not 'chatgpt'/'perplexity'): the
243
+ // browser product is a different surface than the assistant service, and
244
+ // the DB registry mirrors one row per vendor. These sit after the primary
245
+ // vendor entries so a UA carrying an explicit vendor token keeps its
246
+ // primary attribution; a browser-shaped UA with the agentic token is
247
+ // caught here BEFORE classify's human tier, which is what makes these
248
+ // visits observable at all. Token drift is real (some builds mimic Chrome
249
+ // outright) — re-verify against captured events when a new browser ships,
250
+ // and check `sec-ch-ua` platformHeaders for the real brand.
251
+ {
252
+ vendor: "chatgpt-atlas",
253
+ displayName: "ChatGPT Atlas browser",
254
+ uaPatterns: [/\batlas\/\d/i],
255
+ headerPatterns: [/^sec-ch-ua: .*atlas/i]
256
+ },
257
+ {
258
+ vendor: "perplexity-comet",
259
+ displayName: "Perplexity Comet browser",
260
+ uaPatterns: [/\bcomet\/\d/i],
261
+ headerPatterns: [/^sec-ch-ua: .*comet/i]
262
+ },
263
+ // Our own SDK self-identifies (sdkFetch stamps this UA) — first-party
264
+ // traffic must never pollute the unknown/anonymous pool it exists to audit.
265
+ {
266
+ vendor: "astrasync-sdk",
267
+ displayName: "AstraSync SDK",
268
+ uaPatterns: [/^astrasync-sdk\//i]
208
269
  }
209
270
  ];
210
271
  function matchPlatformSignature(signatures, input) {
211
272
  const ua = input.userAgent ?? "";
212
273
  const cardUrl = input.agentCardUrl ?? "";
213
274
  const apiKeyFormat = input.apiKeyFormat ?? "";
275
+ const ja4 = input.ja4 ?? "";
276
+ const asn = input.asn ?? "";
214
277
  const headerLines = [];
215
278
  if (input.platformHeaders) {
216
279
  for (const [name, value] of Object.entries(input.platformHeaders)) {
@@ -222,7 +285,9 @@ function matchPlatformSignature(signatures, input) {
222
285
  const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
223
286
  const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
224
287
  const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
225
- if (uaMatch || cardMatch || keyMatch || headerMatch) {
288
+ const ja4Match = ja4.length > 0 && sig.ja4Patterns?.some((p) => p.test(ja4));
289
+ const asnMatch = asn.length > 0 && sig.asnList?.includes(asn);
290
+ if (uaMatch || cardMatch || keyMatch || headerMatch || ja4Match || asnMatch) {
226
291
  const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
227
292
  const cardHost = (() => {
228
293
  try {
@@ -231,7 +296,7 @@ function matchPlatformSignature(signatures, input) {
231
296
  return "";
232
297
  }
233
298
  })();
234
- const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
299
+ const keyBasis = uaBase || cardHost || apiKeyFormat || ja4 || asn && `asn${asn}` || "unknown";
235
300
  return {
236
301
  vendor: sig.vendor,
237
302
  fingerprintKey: `${sig.vendor}:${keyBasis}`,
@@ -253,9 +318,6 @@ function getTrustLevel(score) {
253
318
  return "BRONZE";
254
319
  }
255
320
 
256
- // src/version.ts
257
- var SDK_VERSION = "4.1.0";
258
-
259
321
  // src/well-known.ts
260
322
  var CACHE_TTL_MS = 60 * 60 * 1e3;
261
323
  var cache = /* @__PURE__ */ new Map();
@@ -284,7 +346,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
284
346
  initCheckPerformed = true;
285
347
  try {
286
348
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
287
- const response = await fetch(probeUrl, { method: "HEAD" });
349
+ const response = await sdkFetch(probeUrl, { method: "HEAD" });
288
350
  const contentType = response.headers.get("content-type") ?? "";
289
351
  if (contentType.startsWith("text/html")) {
290
352
  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).`;
@@ -298,7 +360,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
298
360
  );
299
361
  }
300
362
  if (apiKey) {
301
- const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
363
+ const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
302
364
  headers: { Authorization: `Bearer ${apiKey}` }
303
365
  });
304
366
  if (selfCheck.status === 401) {
@@ -545,7 +607,7 @@ async function callVerifyAccessAPI(config, request) {
545
607
  headers["X-API-Key"] = config.apiKey;
546
608
  }
547
609
  try {
548
- const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
610
+ const response = await sdkFetch(`${config.apiBaseUrl}/agents/verify-access`, {
549
611
  method: "POST",
550
612
  headers,
551
613
  body: JSON.stringify(body),
@@ -790,7 +852,7 @@ async function reportUnregisteredAttempt(config, data) {
790
852
  ...counterpartyUrl && { counterpartyUrl },
791
853
  ...config.counterpartyId && { counterpartyId: config.counterpartyId }
792
854
  };
793
- await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
855
+ await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
794
856
  method: "POST",
795
857
  headers: { "Content-Type": "application/json" },
796
858
  body: JSON.stringify(body)
@@ -807,16 +869,39 @@ function requestUrl(req, host) {
807
869
  return `https://${host}${req.uri}${qs}`;
808
870
  }
809
871
  function buildObservedMetadata(req) {
810
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(req.headers);
872
+ const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(req.headers);
811
873
  const connection = req.connection ?? {};
874
+ const queryKeys = extractQueryKeys(req.querystring);
812
875
  return {
813
876
  headers,
814
877
  ...apiKeyFormat && { apiKeyFormat },
815
878
  ...platformHeaders && { platformHeaders },
816
879
  ...Object.keys(connection).length > 0 && { connection },
880
+ ...cookieCount !== void 0 && { cookieCount },
881
+ ...queryKeys && { queryKeys },
817
882
  schemaVersion: CAPTURE_SCHEMA_VERSION
818
883
  };
819
884
  }
885
+ var MAX_QUERY_KEYS = 32;
886
+ var MAX_QUERY_KEY_CHARS = 64;
887
+ function extractQueryKeys(querystring) {
888
+ if (!querystring) return void 0;
889
+ let params;
890
+ try {
891
+ params = new URLSearchParams(querystring);
892
+ } catch {
893
+ return void 0;
894
+ }
895
+ const keys = [];
896
+ for (const key of params.keys()) {
897
+ const normalized = key.toLowerCase().slice(0, MAX_QUERY_KEY_CHARS);
898
+ if (normalized && !keys.includes(normalized)) {
899
+ keys.push(normalized);
900
+ if (keys.length >= MAX_QUERY_KEYS) break;
901
+ }
902
+ }
903
+ return keys.length > 0 ? keys : void 0;
904
+ }
820
905
 
821
906
  // src/edge-core/detect.ts
822
907
  var SD_JWT_PATTERN = /^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;