@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
package/dist/index.mjs CHANGED
@@ -126,7 +126,25 @@ function getCapabilities(accessLevel) {
126
126
  }
127
127
 
128
128
  // src/version.ts
129
- var SDK_VERSION = "4.1.0";
129
+ var SDK_VERSION = "4.4.0";
130
+
131
+ // src/http.ts
132
+ var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
133
+ function withUserAgent(initHeaders) {
134
+ if (!initHeaders) return { "user-agent": SDK_USER_AGENT };
135
+ if (initHeaders instanceof Headers) {
136
+ const copy = new Headers(initHeaders);
137
+ if (!copy.has("user-agent")) copy.set("user-agent", SDK_USER_AGENT);
138
+ return copy;
139
+ }
140
+ if (Array.isArray(initHeaders)) {
141
+ const has2 = initHeaders.some(([name]) => name.toLowerCase() === "user-agent");
142
+ return has2 ? initHeaders : [...initHeaders, ["user-agent", SDK_USER_AGENT]];
143
+ }
144
+ const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === "user-agent");
145
+ return has ? initHeaders : { "user-agent": SDK_USER_AGENT, ...initHeaders };
146
+ }
147
+ var sdkFetch = (input, init) => fetch(input, { ...init, headers: withUserAgent(init?.headers) });
130
148
 
131
149
  // src/well-known.ts
132
150
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -138,7 +156,7 @@ function wellKnownUrl(apiBaseUrl) {
138
156
  }
139
157
  async function fetchWellKnown(apiBaseUrl) {
140
158
  const url = wellKnownUrl(apiBaseUrl);
141
- const response = await fetch(url, {
159
+ const response = await sdkFetch(url, {
142
160
  method: "GET",
143
161
  headers: { Accept: "application/json" },
144
162
  signal: AbortSignal.timeout(5e3)
@@ -208,7 +226,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
208
226
  initCheckPerformed = true;
209
227
  try {
210
228
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
211
- const response = await fetch(probeUrl, { method: "HEAD" });
229
+ const response = await sdkFetch(probeUrl, { method: "HEAD" });
212
230
  const contentType = response.headers.get("content-type") ?? "";
213
231
  if (contentType.startsWith("text/html")) {
214
232
  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).`;
@@ -222,7 +240,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
222
240
  );
223
241
  }
224
242
  if (apiKey) {
225
- const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
243
+ const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
226
244
  headers: { Authorization: `Bearer ${apiKey}` }
227
245
  });
228
246
  if (selfCheck.status === 401) {
@@ -475,7 +493,7 @@ async function callVerifyAccessAPI(config, request) {
475
493
  headers["X-API-Key"] = config.apiKey;
476
494
  }
477
495
  try {
478
- const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
496
+ const response = await sdkFetch(`${config.apiBaseUrl}/agents/verify-access`, {
479
497
  method: "POST",
480
498
  headers,
481
499
  body: JSON.stringify(body),
@@ -718,7 +736,7 @@ async function recordDecision(config, sessionId, decision, reason) {
718
736
  headers["Authorization"] = `Bearer ${config.apiKey}`;
719
737
  headers["X-API-Key"] = config.apiKey;
720
738
  }
721
- await fetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
739
+ await sdkFetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
722
740
  method: "POST",
723
741
  headers,
724
742
  body: JSON.stringify({ decision, reason })
@@ -736,7 +754,7 @@ async function reportAttempt(config, report) {
736
754
  ...report,
737
755
  ...!report.counterpartyId && config.counterpartyId && { counterpartyId: config.counterpartyId }
738
756
  };
739
- await fetch(`${apiBaseUrl}/agents/verify-access/attempt-report`, {
757
+ await sdkFetch(`${apiBaseUrl}/agents/verify-access/attempt-report`, {
740
758
  method: "POST",
741
759
  headers,
742
760
  body: JSON.stringify(body)
@@ -751,7 +769,7 @@ async function fetchRoutes(config, counterpartyId) {
751
769
  headers["X-API-Key"] = config.apiKey;
752
770
  }
753
771
  try {
754
- const response = await fetch(
772
+ const response = await sdkFetch(
755
773
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
756
774
  { method: "GET", headers }
757
775
  );
@@ -770,7 +788,7 @@ async function reportUnregisteredAttempt(config, data) {
770
788
  ...counterpartyUrl && { counterpartyUrl },
771
789
  ...config.counterpartyId && { counterpartyId: config.counterpartyId }
772
790
  };
773
- await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
791
+ await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
774
792
  method: "POST",
775
793
  headers: { "Content-Type": "application/json" },
776
794
  body: JSON.stringify(body)
@@ -779,7 +797,7 @@ async function reportUnregisteredAttempt(config, data) {
779
797
  }
780
798
  async function reportCounterpartyPreCheckFailure(config, data) {
781
799
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
782
- await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
800
+ await sdkFetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
783
801
  method: "POST",
784
802
  headers: { "Content-Type": "application/json" },
785
803
  body: JSON.stringify(data)
@@ -813,7 +831,7 @@ function resolvePollUrl(config, pollUrl) {
813
831
  async function pollStepUpStatus(config, approval) {
814
832
  if (!approval.pollUrl) return null;
815
833
  try {
816
- const res = await fetch(resolvePollUrl(config, approval.pollUrl), {
834
+ const res = await sdkFetch(resolvePollUrl(config, approval.pollUrl), {
817
835
  method: "GET",
818
836
  signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS)
819
837
  });
@@ -1188,7 +1206,13 @@ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
1188
1206
  "x-agent-card-url",
1189
1207
  "x-agent-provider"
1190
1208
  ]);
1191
- var PLATFORM_HEADER_PREFIXES = ["x-goog-", "x-stainless-", "x-anthropic-", "x-openai-"];
1209
+ var PLATFORM_HEADER_PREFIXES = [
1210
+ "x-goog-",
1211
+ "x-stainless-",
1212
+ "x-anthropic-",
1213
+ "x-openai-",
1214
+ "sec-ch-"
1215
+ ];
1192
1216
  var KEY_FORMAT_PREFIXES = [
1193
1217
  "sk-ant-api03",
1194
1218
  "sk-ant-api",
@@ -1260,6 +1284,7 @@ function sanitizeHeaders(raw) {
1260
1284
  const headers = {};
1261
1285
  const platformHeaders = {};
1262
1286
  let apiKeyFormat;
1287
+ let cookieCount;
1263
1288
  let totalBytes = 0;
1264
1289
  let count = 0;
1265
1290
  if (!raw) return { headers };
@@ -1274,6 +1299,9 @@ function sanitizeHeaders(raw) {
1274
1299
  if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
1275
1300
  continue;
1276
1301
  }
1302
+ if (name === "cookie") {
1303
+ cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
1304
+ }
1277
1305
  if (isSecretHeader(name)) continue;
1278
1306
  let value = joined;
1279
1307
  if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
@@ -1289,6 +1317,7 @@ function sanitizeHeaders(raw) {
1289
1317
  const result = { headers };
1290
1318
  if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
1291
1319
  if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
1320
+ if (cookieCount !== void 0) result.cookieCount = cookieCount;
1292
1321
  return result;
1293
1322
  }
1294
1323
  function extractPlatformHeaders(sanitized) {
@@ -1308,6 +1337,9 @@ var CONNECTION_HEADER_SOURCES = [
1308
1337
  ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
1309
1338
  ["countryRegionName", ["cloudfront-viewer-country-region-name"]],
1310
1339
  ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
1340
+ ["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
1341
+ ["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
1342
+ ["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
1311
1343
  ["asn", ["cloudfront-viewer-asn"]],
1312
1344
  ["tlsVersion", ["cloudfront-viewer-tls"]],
1313
1345
  ["httpVersion", ["cloudfront-viewer-http-version"]],
@@ -1342,19 +1374,25 @@ function deriveConnectionFromHeaders(headers) {
1342
1374
  }
1343
1375
  }
1344
1376
  }
1345
- if (!connection.ip) {
1377
+ {
1346
1378
  const addr = lower["cloudfront-viewer-address"]?.trim();
1347
- if (addr) connection.ip = addr.replace(/:\d+$/, "");
1379
+ const portMatch = addr?.match(/:(\d+)$/);
1380
+ if (portMatch) connection.sourcePort = portMatch[1];
1381
+ if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
1348
1382
  }
1349
1383
  if (!connection.ip) {
1350
1384
  const xff = lower["x-forwarded-for"];
1351
1385
  const client = xff?.split(",")[0]?.trim();
1352
1386
  if (client) connection.ip = client;
1353
1387
  }
1388
+ if (!connection.tlsCipher) {
1389
+ const cipher = connection.tlsVersion?.split(":")[1];
1390
+ if (cipher) connection.tlsCipher = cipher;
1391
+ }
1354
1392
  return Object.keys(connection).length > 0 ? connection : void 0;
1355
1393
  }
1356
1394
  function buildSdkObservedMetadata(rawHeaders) {
1357
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
1395
+ const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
1358
1396
  const flat = {};
1359
1397
  if (rawHeaders) {
1360
1398
  for (const name of Object.keys(rawHeaders)) {
@@ -1369,6 +1407,7 @@ function buildSdkObservedMetadata(rawHeaders) {
1369
1407
  ...apiKeyFormat && { apiKeyFormat },
1370
1408
  ...platformHeaders && { platformHeaders },
1371
1409
  ...connection && { connection },
1410
+ ...cookieCount !== void 0 && { cookieCount },
1372
1411
  schemaVersion: CAPTURE_SCHEMA_VERSION
1373
1412
  };
1374
1413
  }
@@ -1413,7 +1452,7 @@ async function fetchEdgeConfig(config, counterpartyId, opts) {
1413
1452
  }
1414
1453
  if (opts?.etag) headers["If-None-Match"] = opts.etag;
1415
1454
  try {
1416
- const response = await fetch(
1455
+ const response = await sdkFetch(
1417
1456
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
1418
1457
  { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
1419
1458
  );
@@ -1539,12 +1578,43 @@ var PLATFORM_AGENT_SIGNATURES = [
1539
1578
  uaPatterns: [/perplexity/i],
1540
1579
  agentCardPatterns: [/perplexity\.ai/i],
1541
1580
  apiKeyFormatPatterns: [/^pplx-/i]
1581
+ },
1582
+ // Agentic browsers — versioned-token patterns ONLY (a stock Chrome UA must
1583
+ // never match). Distinct vendor keys (not 'chatgpt'/'perplexity'): the
1584
+ // browser product is a different surface than the assistant service, and
1585
+ // the DB registry mirrors one row per vendor. These sit after the primary
1586
+ // vendor entries so a UA carrying an explicit vendor token keeps its
1587
+ // primary attribution; a browser-shaped UA with the agentic token is
1588
+ // caught here BEFORE classify's human tier, which is what makes these
1589
+ // visits observable at all. Token drift is real (some builds mimic Chrome
1590
+ // outright) — re-verify against captured events when a new browser ships,
1591
+ // and check `sec-ch-ua` platformHeaders for the real brand.
1592
+ {
1593
+ vendor: "chatgpt-atlas",
1594
+ displayName: "ChatGPT Atlas browser",
1595
+ uaPatterns: [/\batlas\/\d/i],
1596
+ headerPatterns: [/^sec-ch-ua: .*atlas/i]
1597
+ },
1598
+ {
1599
+ vendor: "perplexity-comet",
1600
+ displayName: "Perplexity Comet browser",
1601
+ uaPatterns: [/\bcomet\/\d/i],
1602
+ headerPatterns: [/^sec-ch-ua: .*comet/i]
1603
+ },
1604
+ // Our own SDK self-identifies (sdkFetch stamps this UA) — first-party
1605
+ // traffic must never pollute the unknown/anonymous pool it exists to audit.
1606
+ {
1607
+ vendor: "astrasync-sdk",
1608
+ displayName: "AstraSync SDK",
1609
+ uaPatterns: [/^astrasync-sdk\//i]
1542
1610
  }
1543
1611
  ];
1544
1612
  function matchPlatformSignature(signatures, input) {
1545
1613
  const ua = input.userAgent ?? "";
1546
1614
  const cardUrl = input.agentCardUrl ?? "";
1547
1615
  const apiKeyFormat = input.apiKeyFormat ?? "";
1616
+ const ja4 = input.ja4 ?? "";
1617
+ const asn = input.asn ?? "";
1548
1618
  const headerLines = [];
1549
1619
  if (input.platformHeaders) {
1550
1620
  for (const [name, value] of Object.entries(input.platformHeaders)) {
@@ -1556,7 +1626,9 @@ function matchPlatformSignature(signatures, input) {
1556
1626
  const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
1557
1627
  const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
1558
1628
  const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
1559
- if (uaMatch || cardMatch || keyMatch || headerMatch) {
1629
+ const ja4Match = ja4.length > 0 && sig.ja4Patterns?.some((p) => p.test(ja4));
1630
+ const asnMatch = asn.length > 0 && sig.asnList?.includes(asn);
1631
+ if (uaMatch || cardMatch || keyMatch || headerMatch || ja4Match || asnMatch) {
1560
1632
  const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
1561
1633
  const cardHost = (() => {
1562
1634
  try {
@@ -1565,7 +1637,7 @@ function matchPlatformSignature(signatures, input) {
1565
1637
  return "";
1566
1638
  }
1567
1639
  })();
1568
- const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
1640
+ const keyBasis = uaBase || cardHost || apiKeyFormat || ja4 || asn && `asn${asn}` || "unknown";
1569
1641
  return {
1570
1642
  vendor: sig.vendor,
1571
1643
  fingerprintKey: `${sig.vendor}:${keyBasis}`,
@@ -3396,7 +3468,7 @@ async function fetchUCPManifest(manifestUrl, options = {}) {
3396
3468
  const controller = new AbortController();
3397
3469
  const timer = setTimeout(() => controller.abort(), timeoutMs);
3398
3470
  try {
3399
- const res = await fetch(manifestUrl, { signal: controller.signal });
3471
+ const res = await sdkFetch(manifestUrl, { signal: controller.signal });
3400
3472
  if (!res.ok) return null;
3401
3473
  return await res.json();
3402
3474
  } catch {
@@ -5944,7 +6016,7 @@ var AstraSync = class {
5944
6016
  */
5945
6017
  async pollRegistration(requestId) {
5946
6018
  const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;
5947
- const res = await fetch(url, { headers: { Accept: "application/json" } });
6019
+ const res = await sdkFetch(url, { headers: { Accept: "application/json" } });
5948
6020
  if (!res.ok) {
5949
6021
  const errBody = await res.json().catch(() => ({}));
5950
6022
  throw new AstraSyncError(
@@ -6001,7 +6073,7 @@ var AstraSync = class {
6001
6073
  * Check API health.
6002
6074
  */
6003
6075
  async health() {
6004
- const res = await fetch(`${this.baseUrl}/api/health/`);
6076
+ const res = await sdkFetch(`${this.baseUrl}/api/health/`);
6005
6077
  if (!res.ok) {
6006
6078
  throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);
6007
6079
  }
@@ -6028,7 +6100,7 @@ var AstraSync = class {
6028
6100
  const signature = await this.signRequest(method, endpoint, body || {});
6029
6101
  headers["X-AstraSync-Signature"] = signature;
6030
6102
  }
6031
- const res = await fetch(url, {
6103
+ const res = await sdkFetch(url, {
6032
6104
  method,
6033
6105
  headers,
6034
6106
  ...body ? { body: JSON.stringify(body) } : {}
@@ -6053,7 +6125,7 @@ var AstraSync = class {
6053
6125
  if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {
6054
6126
  return this.cachedJwt;
6055
6127
  }
6056
- const res = await fetch(`${this.baseUrl}/api/auth/login`, {
6128
+ const res = await sdkFetch(`${this.baseUrl}/api/auth/login`, {
6057
6129
  method: "POST",
6058
6130
  headers: { "Content-Type": "application/json" },
6059
6131
  body: JSON.stringify({ email: this.email, password: this.password })
@@ -6196,7 +6268,7 @@ var AgentClient = class _AgentClient {
6196
6268
  const url = `${this.apiBaseUrl.replace(/\/+$/, "")}/api/agents/${encodeURIComponent(
6197
6269
  this.credentials.agentId
6198
6270
  )}/ownership`;
6199
- const resp = await fetch(url, {
6271
+ const resp = await sdkFetch(url, {
6200
6272
  method: "GET",
6201
6273
  headers: {
6202
6274
  Authorization: `Bearer ${this.apiKey}`,
@@ -6234,7 +6306,7 @@ var AgentClient = class _AgentClient {
6234
6306
  }
6235
6307
  }
6236
6308
  const enrichedHeaders = setHttpHeaders(existingHeaders, creds);
6237
- return fetch(url, {
6309
+ return sdkFetch(url, {
6238
6310
  ...fetchOptions,
6239
6311
  headers: enrichedHeaders
6240
6312
  });
@@ -6423,7 +6495,7 @@ async function recordDecision2(config, params) {
6423
6495
  if (config.customHeaders) {
6424
6496
  Object.assign(headers, config.customHeaders);
6425
6497
  }
6426
- const response = await fetch(url, {
6498
+ const response = await sdkFetch(url, {
6427
6499
  method: "POST",
6428
6500
  headers,
6429
6501
  body: JSON.stringify(body)
@@ -6440,6 +6512,51 @@ async function recordDecision2(config, params) {
6440
6512
  blockchainTxHash: result.blockchainTxHash
6441
6513
  };
6442
6514
  }
6515
+
6516
+ // src/runtime-signatures.ts
6517
+ var RUNTIME_SIGNATURES = [
6518
+ {
6519
+ runtime: "browser-automation",
6520
+ displayName: "Browser automation",
6521
+ uaPatterns: [/headless/i, /phantomjs/i, /selenium/i, /playwright/i, /puppeteer/i]
6522
+ },
6523
+ {
6524
+ runtime: "nodejs",
6525
+ displayName: "Node.js runtime",
6526
+ // `node` exactly is the global-fetch default UA; the token forms cover
6527
+ // the common Node HTTP libraries.
6528
+ uaPatterns: [/^node$/i, /^undici/i, /node-fetch/i, /^axios/i, /^got\b/i, /needle/i]
6529
+ },
6530
+ {
6531
+ runtime: "python",
6532
+ displayName: "Python runtime",
6533
+ uaPatterns: [/python-requests/i, /python-urllib/i, /^python\b/i, /httpx/i, /aiohttp/i]
6534
+ },
6535
+ { runtime: "go", displayName: "Go runtime", uaPatterns: [/go-http-client/i] },
6536
+ {
6537
+ runtime: "java",
6538
+ displayName: "Java runtime",
6539
+ uaPatterns: [/^java\//i, /okhttp/i, /apache-httpclient/i]
6540
+ },
6541
+ { runtime: "curl", displayName: "curl", uaPatterns: [/^curl\//i] },
6542
+ { runtime: "wget", displayName: "wget", uaPatterns: [/^wget\//i] },
6543
+ { runtime: "ruby", displayName: "Ruby runtime", uaPatterns: [/^ruby\b/i, /faraday/i] },
6544
+ {
6545
+ runtime: "php",
6546
+ displayName: "PHP runtime",
6547
+ uaPatterns: [/^php\b/i, /guzzlehttp/i, /^symfony/i]
6548
+ },
6549
+ { runtime: "dotnet", displayName: ".NET runtime", uaPatterns: [/^dotnet/i, /httpclient/i] },
6550
+ { runtime: "dart", displayName: "Dart runtime", uaPatterns: [/^dart/i] }
6551
+ ];
6552
+ function detectRuntime(userAgent) {
6553
+ if (!userAgent) return void 0;
6554
+ const ua = userAgent.trim();
6555
+ for (const sig of RUNTIME_SIGNATURES) {
6556
+ if (sig.uaPatterns.some((p) => p.test(ua))) return sig.displayName;
6557
+ }
6558
+ return void 0;
6559
+ }
6443
6560
  export {
6444
6561
  ACCESS_LEVEL_DESCRIPTIONS,
6445
6562
  ACCESS_LEVEL_HIERARCHY,
@@ -6456,9 +6573,11 @@ export {
6456
6573
  MAX_HEADER_VALUE_BYTES,
6457
6574
  MAX_TOTAL_BYTES,
6458
6575
  PLATFORM_AGENT_SIGNATURES,
6576
+ RUNTIME_SIGNATURES,
6459
6577
  RegistrationDeniedError,
6460
6578
  RegistrationExpiredError,
6461
6579
  RegistrationTimeoutError,
6580
+ SDK_USER_AGENT,
6462
6581
  TRUST_LEVEL_RANGES,
6463
6582
  SDK_VERSION as VERSION,
6464
6583
  _resetEdgeConfigCache,
@@ -6472,6 +6591,7 @@ export {
6472
6591
  degradeToObserve,
6473
6592
  deriveConnectionFromHeaders,
6474
6593
  detectPlatformFingerprint,
6594
+ detectRuntime,
6475
6595
  determineAccessLevel,
6476
6596
  express_exports as express,
6477
6597
  extractApiKeyFormat,
@@ -6500,6 +6620,7 @@ export {
6500
6620
  reportUnregisteredAttempt,
6501
6621
  sanitizeHeaders,
6502
6622
  sdk_exports as sdk,
6623
+ sdkFetch,
6503
6624
  setMcpMeta,
6504
6625
  transport_exports as transport,
6505
6626
  verify