@astrasyncai/verification-gateway 4.2.1 → 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 (138) hide show
  1. package/README.md +45 -21
  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 +145 -21
  7. package/dist/adapters/express.js.map +1 -1
  8. package/dist/adapters/express.mjs +145 -21
  9. package/dist/adapters/express.mjs.map +1 -1
  10. package/dist/adapters/mcp.d.mts +38 -30
  11. package/dist/adapters/mcp.d.ts +38 -30
  12. package/dist/adapters/mcp.js +72 -16
  13. package/dist/adapters/mcp.js.map +1 -1
  14. package/dist/adapters/mcp.mjs +72 -16
  15. package/dist/adapters/mcp.mjs.map +1 -1
  16. package/dist/adapters/nextjs.d.mts +2 -2
  17. package/dist/adapters/nextjs.d.ts +2 -2
  18. package/dist/adapters/nextjs.js +141 -19
  19. package/dist/adapters/nextjs.js.map +1 -1
  20. package/dist/adapters/nextjs.mjs +141 -19
  21. package/dist/adapters/nextjs.mjs.map +1 -1
  22. package/dist/adapters/sdk.d.mts +2 -2
  23. package/dist/adapters/sdk.d.ts +2 -2
  24. package/dist/adapters/sdk.js +24 -6
  25. package/dist/adapters/sdk.js.map +1 -1
  26. package/dist/adapters/sdk.mjs +24 -6
  27. package/dist/adapters/sdk.mjs.map +1 -1
  28. package/dist/agent/index.d.mts +2 -2
  29. package/dist/agent/index.d.ts +2 -2
  30. package/dist/agent/index.js +24 -3
  31. package/dist/agent/index.js.map +1 -1
  32. package/dist/agent/index.mjs +24 -3
  33. package/dist/agent/index.mjs.map +1 -1
  34. package/dist/bin/astrasync-claude-hook.js +22 -4
  35. package/dist/bin/astrasync-codex-hook.js +22 -4
  36. package/dist/bin/astrasync-guard.js +26 -8
  37. package/dist/bin/astrasync.js +76 -23
  38. package/dist/browser/background.js +22 -4
  39. package/dist/browser/background.js.map +1 -1
  40. package/dist/browser/background.mjs +22 -4
  41. package/dist/browser/background.mjs.map +1 -1
  42. package/dist/browser/browser-adapter.d.mts +2 -2
  43. package/dist/browser/browser-adapter.d.ts +2 -2
  44. package/dist/claude-code/claude-code-adapter.d.mts +2 -2
  45. package/dist/claude-code/claude-code-adapter.d.ts +2 -2
  46. package/dist/cli/index.d.mts +2 -2
  47. package/dist/cli/index.d.ts +2 -2
  48. package/dist/cli/index.js +23 -2
  49. package/dist/cli/index.js.map +1 -1
  50. package/dist/cli/index.mjs +23 -2
  51. package/dist/cli/index.mjs.map +1 -1
  52. package/dist/codex/index.d.mts +2 -2
  53. package/dist/codex/index.d.ts +2 -2
  54. package/dist/codex/index.js +22 -4
  55. package/dist/codex/index.js.map +1 -1
  56. package/dist/codex/index.mjs +22 -4
  57. package/dist/codex/index.mjs.map +1 -1
  58. package/dist/cursor/cursor-adapter.d.mts +2 -2
  59. package/dist/cursor/cursor-adapter.d.ts +2 -2
  60. package/dist/cursor/extension.d.mts +2 -2
  61. package/dist/cursor/extension.d.ts +2 -2
  62. package/dist/cursor/extension.js +22 -4
  63. package/dist/cursor/extension.js.map +1 -1
  64. package/dist/cursor/extension.mjs +22 -4
  65. package/dist/cursor/extension.mjs.map +1 -1
  66. package/dist/edge-config.d.mts +1 -1
  67. package/dist/edge-config.d.ts +1 -1
  68. package/dist/edge-config.js +24 -1
  69. package/dist/edge-config.js.map +1 -1
  70. package/dist/edge-config.mjs +22 -1
  71. package/dist/edge-config.mjs.map +1 -1
  72. package/dist/edge-core/index.d.mts +1 -1
  73. package/dist/edge-core/index.d.ts +1 -1
  74. package/dist/edge-core/index.js +121 -16
  75. package/dist/edge-core/index.js.map +1 -1
  76. package/dist/edge-core/index.mjs +121 -16
  77. package/dist/edge-core/index.mjs.map +1 -1
  78. package/dist/{express-D_4hTn5Z.d.mts → express-CR6F3njD.d.mts} +1 -1
  79. package/dist/{express-BVd1_3FE.d.ts → express-DaqL11tx.d.ts} +1 -1
  80. package/dist/gateway/gateway.d.mts +2 -2
  81. package/dist/gateway/gateway.d.ts +2 -2
  82. package/dist/gateway/gateway.js +22 -4
  83. package/dist/gateway/gateway.js.map +1 -1
  84. package/dist/gateway/gateway.mjs +22 -4
  85. package/dist/gateway/gateway.mjs.map +1 -1
  86. package/dist/git-trigger/git-hooks.d.mts +2 -2
  87. package/dist/git-trigger/git-hooks.d.ts +2 -2
  88. package/dist/{index-BqHKlLOU.d.ts → index-B5Ts1WtM.d.ts} +1 -1
  89. package/dist/{index-T1aBoUcc.d.ts → index-BfIxCYIZ.d.ts} +1 -1
  90. package/dist/{index-BTeQ9fgV.d.mts → index-Cub7lK-T.d.mts} +1 -1
  91. package/dist/{index-DQb5-_1X.d.mts → index-CwAh7Tln.d.mts} +1 -1
  92. package/dist/index.d.mts +58 -9
  93. package/dist/index.d.ts +58 -9
  94. package/dist/index.js +218 -54
  95. package/dist/index.js.map +1 -1
  96. package/dist/index.mjs +214 -54
  97. package/dist/index.mjs.map +1 -1
  98. package/dist/local-evaluator/evaluator.d.mts +2 -2
  99. package/dist/local-evaluator/evaluator.d.ts +2 -2
  100. package/dist/metadata-capture.d.mts +35 -5
  101. package/dist/metadata-capture.d.ts +35 -5
  102. package/dist/metadata-capture.js +44 -6
  103. package/dist/metadata-capture.js.map +1 -1
  104. package/dist/metadata-capture.mjs +43 -6
  105. package/dist/metadata-capture.mjs.map +1 -1
  106. package/dist/{nextjs-w7RTbP1P.d.ts → nextjs-DL6uE1ye.d.ts} +1 -1
  107. package/dist/{nextjs-WyeVr2Kp.d.mts → nextjs-DlX6xwbU.d.mts} +1 -1
  108. package/dist/platform-signatures.d.mts +18 -1
  109. package/dist/platform-signatures.d.ts +18 -1
  110. package/dist/platform-signatures.js +35 -2
  111. package/dist/platform-signatures.js.map +1 -1
  112. package/dist/platform-signatures.mjs +35 -2
  113. package/dist/platform-signatures.mjs.map +1 -1
  114. package/dist/registration/index.js +25 -4
  115. package/dist/registration/index.js.map +1 -1
  116. package/dist/registration/index.mjs +25 -4
  117. package/dist/registration/index.mjs.map +1 -1
  118. package/dist/{sdk-CbTNIkAa.d.mts → sdk-Bbh9B_dw.d.mts} +1 -1
  119. package/dist/{sdk-QeX0Z8Ho.d.ts → sdk-C6SASmsh.d.ts} +1 -1
  120. package/dist/transport/index.d.mts +2 -2
  121. package/dist/transport/index.d.ts +2 -2
  122. package/dist/transport/index.js +22 -1
  123. package/dist/transport/index.js.map +1 -1
  124. package/dist/transport/index.mjs +22 -1
  125. package/dist/transport/index.mjs.map +1 -1
  126. package/dist/{types-r850cOt0.d.mts → types-C0zfSXMB.d.mts} +22 -0
  127. package/dist/{types-DqfPU5Bl.d.mts → types-C7Rb-w0d.d.mts} +1 -1
  128. package/dist/{types-sMxBT-nM.d.ts → types-DwSfO7Sb.d.ts} +22 -0
  129. package/dist/{types-BLUx92FJ.d.ts → types-nIh3HtuA.d.ts} +1 -1
  130. package/dist/ui/index.d.mts +1 -1
  131. package/dist/ui/index.d.ts +1 -1
  132. package/dist/verify.d.mts +1 -1
  133. package/dist/verify.d.ts +1 -1
  134. package/dist/verify.js +29 -11
  135. package/dist/verify.js.map +1 -1
  136. package/dist/verify.mjs +29 -11
  137. package/dist/verify.mjs.map +1 -1
  138. package/package.json +1 -1
@@ -1,7 +1,44 @@
1
1
  import { Request, Response, RequestHandler } from 'express';
2
- import { a as AccessLevel, G as GatewayConfig, x as VerificationResult } from '../types-r850cOt0.mjs';
2
+ import { a as AccessLevel, G as GatewayConfig, x as VerificationResult } from '../types-C0zfSXMB.mjs';
3
3
  import '../metadata-capture.mjs';
4
4
 
5
+ /**
6
+ * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.
7
+ *
8
+ * Header carrying upstream verify-access proof so an inner-hop endpoint can
9
+ * dedupe (skip verify-access when the same ASTRA-id was already verified a
10
+ * few ms earlier). Emitted by the MCP adapter toward tool fetches and by the
11
+ * edge gateway toward the origin at authenticate/authorize depth. Value
12
+ * format:
13
+ *
14
+ * {astraId};{sessionId};{checkedAt-ms}
15
+ *
16
+ * Receivers MUST validate that `checkedAt` is recent (≤ 60s window
17
+ * recommended) and that `astraId` matches the agent identity claimed on the
18
+ * inner hop. The header alone is NOT proof-of-identity — it's an UNSIGNED
19
+ * dedupe advisory: trust it (`trustVerifiedHop`) only where every network
20
+ * path to the inner hop crosses a stripping gateway or an equivalent trusted
21
+ * boundary, exactly like the unsigned X-AstraSync-* attestation headers.
22
+ * Pair with the existing X-Astra-Id auth.
23
+ */
24
+ declare const MCP_VERIFIED_HOP_HEADER = "X-Astra-Verified-Hop";
25
+ interface VerifiedHopMarker {
26
+ astraId: string;
27
+ sessionId?: string;
28
+ checkedAt: number;
29
+ }
30
+ declare function serializeVerifiedHop(marker: VerifiedHopMarker): string;
31
+ declare function parseVerifiedHop(value: string | undefined | null): VerifiedHopMarker | null;
32
+ /**
33
+ * Returns true when `marker.astraId` matches the inner-hop's claimed
34
+ * ASTRA-id AND the marker is recent enough. Inner-hop middleware uses this
35
+ * to skip a duplicate verify-access call.
36
+ */
37
+ declare function isVerifiedHopValidFor(marker: VerifiedHopMarker | null, expectedAstraId: string, opts?: {
38
+ maxAgeMs?: number;
39
+ now?: number;
40
+ }): boolean;
41
+
5
42
  /**
6
43
  * MCP server-side helpers — companion to `transport/mcp.ts` (which handles the
7
44
  * agent-side `_meta.astrasync` block).
@@ -31,35 +68,6 @@ import '../metadata-capture.mjs';
31
68
  * The Express MCP adapter is in `adapters/mcp.ts` and consumes these.
32
69
  */
33
70
 
34
- /**
35
- * Header carrying upstream verify-access proof so an inner-hop REST endpoint
36
- * can dedupe (skip verify-access when the same ASTRA-id was already verified
37
- * a few ms earlier). Value format:
38
- *
39
- * {astraId};{sessionId};{checkedAt-ms}
40
- *
41
- * Receivers MUST validate that `checkedAt` is recent (≤ 60s window
42
- * recommended) and that `astraId` matches the agent identity claimed on the
43
- * inner hop. The header alone is NOT proof-of-identity — it's a dedupe
44
- * advisory. Pair with the existing X-Astra-Id auth.
45
- */
46
- declare const MCP_VERIFIED_HOP_HEADER = "X-Astra-Verified-Hop";
47
- interface VerifiedHopMarker {
48
- astraId: string;
49
- sessionId?: string;
50
- checkedAt: number;
51
- }
52
- declare function serializeVerifiedHop(marker: VerifiedHopMarker): string;
53
- declare function parseVerifiedHop(value: string | undefined | null): VerifiedHopMarker | null;
54
- /**
55
- * Returns true when `marker.astraId` matches the inner-hop's claimed
56
- * ASTRA-id AND the marker is recent enough. Inner-hop middleware uses this
57
- * to skip a duplicate verify-access call.
58
- */
59
- declare function isVerifiedHopValidFor(marker: VerifiedHopMarker | null, expectedAstraId: string, opts?: {
60
- maxAgeMs?: number;
61
- now?: number;
62
- }): boolean;
63
71
  /**
64
72
  * Output of `parseMcpJsonRpc`. Self-describing so the middleware doesn't have
65
73
  * to re-introspect the body to figure out gating.
@@ -1,7 +1,44 @@
1
1
  import { Request, Response, RequestHandler } from 'express';
2
- import { a as AccessLevel, G as GatewayConfig, x as VerificationResult } from '../types-sMxBT-nM.js';
2
+ import { a as AccessLevel, G as GatewayConfig, x as VerificationResult } from '../types-DwSfO7Sb.js';
3
3
  import '../metadata-capture.js';
4
4
 
5
+ /**
6
+ * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.
7
+ *
8
+ * Header carrying upstream verify-access proof so an inner-hop endpoint can
9
+ * dedupe (skip verify-access when the same ASTRA-id was already verified a
10
+ * few ms earlier). Emitted by the MCP adapter toward tool fetches and by the
11
+ * edge gateway toward the origin at authenticate/authorize depth. Value
12
+ * format:
13
+ *
14
+ * {astraId};{sessionId};{checkedAt-ms}
15
+ *
16
+ * Receivers MUST validate that `checkedAt` is recent (≤ 60s window
17
+ * recommended) and that `astraId` matches the agent identity claimed on the
18
+ * inner hop. The header alone is NOT proof-of-identity — it's an UNSIGNED
19
+ * dedupe advisory: trust it (`trustVerifiedHop`) only where every network
20
+ * path to the inner hop crosses a stripping gateway or an equivalent trusted
21
+ * boundary, exactly like the unsigned X-AstraSync-* attestation headers.
22
+ * Pair with the existing X-Astra-Id auth.
23
+ */
24
+ declare const MCP_VERIFIED_HOP_HEADER = "X-Astra-Verified-Hop";
25
+ interface VerifiedHopMarker {
26
+ astraId: string;
27
+ sessionId?: string;
28
+ checkedAt: number;
29
+ }
30
+ declare function serializeVerifiedHop(marker: VerifiedHopMarker): string;
31
+ declare function parseVerifiedHop(value: string | undefined | null): VerifiedHopMarker | null;
32
+ /**
33
+ * Returns true when `marker.astraId` matches the inner-hop's claimed
34
+ * ASTRA-id AND the marker is recent enough. Inner-hop middleware uses this
35
+ * to skip a duplicate verify-access call.
36
+ */
37
+ declare function isVerifiedHopValidFor(marker: VerifiedHopMarker | null, expectedAstraId: string, opts?: {
38
+ maxAgeMs?: number;
39
+ now?: number;
40
+ }): boolean;
41
+
5
42
  /**
6
43
  * MCP server-side helpers — companion to `transport/mcp.ts` (which handles the
7
44
  * agent-side `_meta.astrasync` block).
@@ -31,35 +68,6 @@ import '../metadata-capture.js';
31
68
  * The Express MCP adapter is in `adapters/mcp.ts` and consumes these.
32
69
  */
33
70
 
34
- /**
35
- * Header carrying upstream verify-access proof so an inner-hop REST endpoint
36
- * can dedupe (skip verify-access when the same ASTRA-id was already verified
37
- * a few ms earlier). Value format:
38
- *
39
- * {astraId};{sessionId};{checkedAt-ms}
40
- *
41
- * Receivers MUST validate that `checkedAt` is recent (≤ 60s window
42
- * recommended) and that `astraId` matches the agent identity claimed on the
43
- * inner hop. The header alone is NOT proof-of-identity — it's a dedupe
44
- * advisory. Pair with the existing X-Astra-Id auth.
45
- */
46
- declare const MCP_VERIFIED_HOP_HEADER = "X-Astra-Verified-Hop";
47
- interface VerifiedHopMarker {
48
- astraId: string;
49
- sessionId?: string;
50
- checkedAt: number;
51
- }
52
- declare function serializeVerifiedHop(marker: VerifiedHopMarker): string;
53
- declare function parseVerifiedHop(value: string | undefined | null): VerifiedHopMarker | null;
54
- /**
55
- * Returns true when `marker.astraId` matches the inner-hop's claimed
56
- * ASTRA-id AND the marker is recent enough. Inner-hop middleware uses this
57
- * to skip a duplicate verify-access call.
58
- */
59
- declare function isVerifiedHopValidFor(marker: VerifiedHopMarker | null, expectedAstraId: string, opts?: {
60
- maxAgeMs?: number;
61
- now?: number;
62
- }): boolean;
63
71
  /**
64
72
  * Output of `parseMcpJsonRpc`. Self-describing so the middleware doesn't have
65
73
  * to re-introspect the body to figure out gating.
@@ -31,6 +31,27 @@ __export(mcp_exports, {
31
31
  });
32
32
  module.exports = __toCommonJS(mcp_exports);
33
33
 
34
+ // src/version.ts
35
+ var SDK_VERSION = "4.4.0";
36
+
37
+ // src/http.ts
38
+ var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
39
+ function withUserAgent(initHeaders) {
40
+ if (!initHeaders) return { "user-agent": SDK_USER_AGENT };
41
+ if (initHeaders instanceof Headers) {
42
+ const copy = new Headers(initHeaders);
43
+ if (!copy.has("user-agent")) copy.set("user-agent", SDK_USER_AGENT);
44
+ return copy;
45
+ }
46
+ if (Array.isArray(initHeaders)) {
47
+ const has2 = initHeaders.some(([name]) => name.toLowerCase() === "user-agent");
48
+ return has2 ? initHeaders : [...initHeaders, ["user-agent", SDK_USER_AGENT]];
49
+ }
50
+ const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === "user-agent");
51
+ return has ? initHeaders : { "user-agent": SDK_USER_AGENT, ...initHeaders };
52
+ }
53
+ var sdkFetch = (input, init) => fetch(input, { ...init, headers: withUserAgent(init?.headers) });
54
+
34
55
  // src/access-levels.ts
35
56
  function getTrustLevel(score) {
36
57
  if (score >= 80) return "PLATINUM";
@@ -39,9 +60,6 @@ function getTrustLevel(score) {
39
60
  return "BRONZE";
40
61
  }
41
62
 
42
- // src/version.ts
43
- var SDK_VERSION = "4.1.0";
44
-
45
63
  // src/well-known.ts
46
64
  var CACHE_TTL_MS = 60 * 60 * 1e3;
47
65
  var cache = /* @__PURE__ */ new Map();
@@ -52,7 +70,7 @@ function wellKnownUrl(apiBaseUrl) {
52
70
  }
53
71
  async function fetchWellKnown(apiBaseUrl) {
54
72
  const url = wellKnownUrl(apiBaseUrl);
55
- const response = await fetch(url, {
73
+ const response = await sdkFetch(url, {
56
74
  method: "GET",
57
75
  headers: { Accept: "application/json" },
58
76
  signal: AbortSignal.timeout(5e3)
@@ -122,7 +140,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
122
140
  initCheckPerformed = true;
123
141
  try {
124
142
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
125
- const response = await fetch(probeUrl, { method: "HEAD" });
143
+ const response = await sdkFetch(probeUrl, { method: "HEAD" });
126
144
  const contentType = response.headers.get("content-type") ?? "";
127
145
  if (contentType.startsWith("text/html")) {
128
146
  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).`;
@@ -136,7 +154,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
136
154
  );
137
155
  }
138
156
  if (apiKey) {
139
- const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
157
+ const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
140
158
  headers: { Authorization: `Bearer ${apiKey}` }
141
159
  });
142
160
  if (selfCheck.status === 401) {
@@ -383,7 +401,7 @@ async function callVerifyAccessAPI(config, request) {
383
401
  headers["X-API-Key"] = config.apiKey;
384
402
  }
385
403
  try {
386
- const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
404
+ const response = await sdkFetch(`${config.apiBaseUrl}/agents/verify-access`, {
387
405
  method: "POST",
388
406
  headers,
389
407
  body: JSON.stringify(body),
@@ -626,7 +644,7 @@ async function recordDecision(config, sessionId, decision, reason) {
626
644
  headers["Authorization"] = `Bearer ${config.apiKey}`;
627
645
  headers["X-API-Key"] = config.apiKey;
628
646
  }
629
- await fetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
647
+ await sdkFetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
630
648
  method: "POST",
631
649
  headers,
632
650
  body: JSON.stringify({ decision, reason })
@@ -644,7 +662,9 @@ var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
644
662
  "x-astrasync-signature",
645
663
  "x-astrasync-secret",
646
664
  "x-hub-signature",
647
- "x-hub-signature-256"
665
+ "x-hub-signature-256",
666
+ // Short-lived verify dedupe token — must never persist in stored metadata.
667
+ "x-astra-verified-hop"
648
668
  ]);
649
669
  var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
650
670
  var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
@@ -669,7 +689,13 @@ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
669
689
  "x-agent-card-url",
670
690
  "x-agent-provider"
671
691
  ]);
672
- var PLATFORM_HEADER_PREFIXES = ["x-goog-", "x-stainless-", "x-anthropic-", "x-openai-"];
692
+ var PLATFORM_HEADER_PREFIXES = [
693
+ "x-goog-",
694
+ "x-stainless-",
695
+ "x-anthropic-",
696
+ "x-openai-",
697
+ "sec-ch-"
698
+ ];
673
699
  var KEY_FORMAT_PREFIXES = [
674
700
  "sk-ant-api03",
675
701
  "sk-ant-api",
@@ -741,6 +767,7 @@ function sanitizeHeaders(raw) {
741
767
  const headers = {};
742
768
  const platformHeaders = {};
743
769
  let apiKeyFormat;
770
+ let cookieCount;
744
771
  let totalBytes = 0;
745
772
  let count = 0;
746
773
  if (!raw) return { headers };
@@ -755,6 +782,9 @@ function sanitizeHeaders(raw) {
755
782
  if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
756
783
  continue;
757
784
  }
785
+ if (name === "cookie") {
786
+ cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
787
+ }
758
788
  if (isSecretHeader(name)) continue;
759
789
  let value = joined;
760
790
  if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
@@ -770,6 +800,7 @@ function sanitizeHeaders(raw) {
770
800
  const result = { headers };
771
801
  if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
772
802
  if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
803
+ if (cookieCount !== void 0) result.cookieCount = cookieCount;
773
804
  return result;
774
805
  }
775
806
  var CONNECTION_HEADER_SOURCES = [
@@ -779,16 +810,28 @@ var CONNECTION_HEADER_SOURCES = [
779
810
  ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
780
811
  ],
781
812
  ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
813
+ ["countryRegionName", ["cloudfront-viewer-country-region-name"]],
782
814
  ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
815
+ ["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
816
+ ["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
817
+ ["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
783
818
  ["asn", ["cloudfront-viewer-asn"]],
784
819
  ["tlsVersion", ["cloudfront-viewer-tls"]],
785
820
  ["httpVersion", ["cloudfront-viewer-http-version"]],
821
+ ["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
822
+ ["metroCode", ["cloudfront-viewer-metro-code"]],
786
823
  // TLS fingerprints can only be computed where TLS terminates. When a CDN
787
824
  // terminates TLS in front of the merchant, its fingerprint headers ARE the
788
825
  // connection-layer truth — normalising them here is the permanent design.
789
- ["tlsFingerprint", ["cf-ja3-hash"]],
790
- ["ja4", ["cf-ja4"]]
826
+ // CloudFront delivers JA3/JA4 only via an origin request policy and only
827
+ // for HTTPS viewer connections.
828
+ ["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
829
+ ["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
830
+ // Header-structure fingerprint: browser/SDK-distinctive header ordering.
831
+ ["headerOrder", ["cloudfront-viewer-header-order"]],
832
+ ["headerCount", ["cloudfront-viewer-header-count"]]
791
833
  ];
834
+ var MAX_CONNECTION_VALUE_CHARS = 256;
792
835
  function deriveConnectionFromHeaders(headers) {
793
836
  if (!headers) return void 0;
794
837
  const lower = {};
@@ -801,20 +844,30 @@ function deriveConnectionFromHeaders(headers) {
801
844
  for (const source of sources) {
802
845
  const value = lower[source]?.trim();
803
846
  if (value) {
804
- connection[key] = value;
847
+ connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
805
848
  break;
806
849
  }
807
850
  }
808
851
  }
852
+ {
853
+ const addr = lower["cloudfront-viewer-address"]?.trim();
854
+ const portMatch = addr?.match(/:(\d+)$/);
855
+ if (portMatch) connection.sourcePort = portMatch[1];
856
+ if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
857
+ }
809
858
  if (!connection.ip) {
810
859
  const xff = lower["x-forwarded-for"];
811
860
  const client = xff?.split(",")[0]?.trim();
812
861
  if (client) connection.ip = client;
813
862
  }
863
+ if (!connection.tlsCipher) {
864
+ const cipher = connection.tlsVersion?.split(":")[1];
865
+ if (cipher) connection.tlsCipher = cipher;
866
+ }
814
867
  return Object.keys(connection).length > 0 ? connection : void 0;
815
868
  }
816
869
  function buildSdkObservedMetadata(rawHeaders) {
817
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
870
+ const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
818
871
  const flat = {};
819
872
  if (rawHeaders) {
820
873
  for (const name of Object.keys(rawHeaders)) {
@@ -829,6 +882,7 @@ function buildSdkObservedMetadata(rawHeaders) {
829
882
  ...apiKeyFormat && { apiKeyFormat },
830
883
  ...platformHeaders && { platformHeaders },
831
884
  ...connection && { connection },
885
+ ...cookieCount !== void 0 && { cookieCount },
832
886
  schemaVersion: CAPTURE_SCHEMA_VERSION
833
887
  };
834
888
  }
@@ -860,7 +914,7 @@ function resolvePollUrl(config, pollUrl) {
860
914
  async function pollStepUpStatus(config, approval) {
861
915
  if (!approval.pollUrl) return null;
862
916
  try {
863
- const res = await fetch(resolvePollUrl(config, approval.pollUrl), {
917
+ const res = await sdkFetch(resolvePollUrl(config, approval.pollUrl), {
864
918
  method: "GET",
865
919
  signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS)
866
920
  });
@@ -904,7 +958,7 @@ async function awaitStepUpApproval(config, approval) {
904
958
  return "timeout";
905
959
  }
906
960
 
907
- // src/transport/mcp-server.ts
961
+ // src/verified-hop.ts
908
962
  var MCP_VERIFIED_HOP_HEADER = "X-Astra-Verified-Hop";
909
963
  var MCP_VERIFIED_HOP_MAX_AGE_MS = 6e4;
910
964
  function serializeVerifiedHop(marker) {
@@ -931,6 +985,8 @@ function isVerifiedHopValidFor(marker, expectedAstraId, opts = {}) {
931
985
  const now = opts.now ?? Date.now();
932
986
  return now - marker.checkedAt <= maxAge && now >= marker.checkedAt;
933
987
  }
988
+
989
+ // src/transport/mcp-server.ts
934
990
  function parseMcpJsonRpc(body) {
935
991
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
936
992
  const obj = body;