@astrasyncai/verification-gateway 5.14.0 → 5.15.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.
- package/README.md +27 -17
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +477 -240
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +477 -240
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +20 -6
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +20 -6
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +1 -1
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +460 -239
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +460 -239
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +18 -10
- package/dist/adapters/sdk.d.ts +18 -10
- package/dist/adapters/sdk.js +80 -23
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +80 -23
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +55 -11
- package/dist/bin/astrasync-codex-hook.js +55 -11
- package/dist/bin/astrasync-guard.js +55 -11
- package/dist/bin/astrasync.js +288 -33
- package/dist/browser/background.js +50 -6
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +60 -6
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.js +55 -11
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +65 -11
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +55 -11
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +65 -11
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +31 -2
- package/dist/edge-config.d.ts +31 -2
- package/dist/edge-config.js +35 -5
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +32 -4
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +11 -2
- package/dist/edge-core/index.d.ts +11 -2
- package/dist/edge-core/index.js +93 -10
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +91 -10
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +50 -6
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +60 -6
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +1 -1
- package/dist/git-trigger/git-hooks.d.ts +1 -1
- package/dist/index.d.mts +1314 -34
- package/dist/index.d.ts +1314 -34
- package/dist/index.js +5116 -2612
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5063 -2614
- package/dist/index.mjs.map +1 -1
- package/dist/registration/index.d.mts +28 -2
- package/dist/registration/index.d.ts +28 -2
- package/dist/registration/index.js +18 -3
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +15 -2
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.d.mts +7 -5
- package/dist/transport/index.d.ts +7 -5
- package/dist/transport/index.js +61 -5
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +67 -11
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-C_b4QTyO.d.ts → types-DtJjlW4O.d.ts} +104 -10
- package/dist/{types-BCkwBA84.d.mts → types-Dxf9DBpr.d.mts} +106 -12
- package/dist/{types-BCkwBA84.d.ts → types-Dxf9DBpr.d.ts} +106 -12
- package/dist/{types-DlshIIR-.d.mts → types-Eg6VoBNH.d.mts} +104 -10
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +20 -6
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +20 -6
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/dist/adapters/nextjs.mjs
CHANGED
|
@@ -1,5 +1,419 @@
|
|
|
1
|
+
// src/metadata-capture.ts
|
|
2
|
+
var CAPTURE_SCHEMA_VERSION = 1;
|
|
3
|
+
var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
4
|
+
"cookie",
|
|
5
|
+
"set-cookie",
|
|
6
|
+
"x-csrf-token",
|
|
7
|
+
"proxy-authorization",
|
|
8
|
+
"x-astrasync-signature",
|
|
9
|
+
"x-astrasync-secret",
|
|
10
|
+
"x-hub-signature",
|
|
11
|
+
"x-hub-signature-256",
|
|
12
|
+
// Short-lived verify dedupe token — must never persist in stored metadata.
|
|
13
|
+
"x-astra-verified-hop"
|
|
14
|
+
]);
|
|
15
|
+
var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
|
|
16
|
+
var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
17
|
+
"authorization",
|
|
18
|
+
"x-api-key",
|
|
19
|
+
"x-goog-api-key",
|
|
20
|
+
"api-key"
|
|
21
|
+
]);
|
|
22
|
+
function isSignatureHeader(name) {
|
|
23
|
+
return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
|
|
24
|
+
}
|
|
25
|
+
var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
26
|
+
"openai-organization",
|
|
27
|
+
"openai-project",
|
|
28
|
+
"openai-version",
|
|
29
|
+
"openai-processing-ms",
|
|
30
|
+
"anthropic-version",
|
|
31
|
+
"anthropic-beta",
|
|
32
|
+
"x-goog-user-project",
|
|
33
|
+
"x-goog-api-client",
|
|
34
|
+
"user-agent",
|
|
35
|
+
"x-agent-card-url",
|
|
36
|
+
"x-agent-provider"
|
|
37
|
+
]);
|
|
38
|
+
var PLATFORM_HEADER_PREFIXES = [
|
|
39
|
+
"x-goog-",
|
|
40
|
+
"x-stainless-",
|
|
41
|
+
"x-anthropic-",
|
|
42
|
+
"x-openai-",
|
|
43
|
+
"sec-ch-"
|
|
44
|
+
];
|
|
45
|
+
var KEY_FORMAT_PREFIXES = [
|
|
46
|
+
"sk-ant-api03",
|
|
47
|
+
"sk-ant-api",
|
|
48
|
+
"sk-ant",
|
|
49
|
+
"sk-proj",
|
|
50
|
+
"sk-svcacct",
|
|
51
|
+
"sk-or-v1",
|
|
52
|
+
"sk-or",
|
|
53
|
+
"sk-lf",
|
|
54
|
+
"sk-",
|
|
55
|
+
"gsk_",
|
|
56
|
+
"aiza",
|
|
57
|
+
"ya29",
|
|
58
|
+
"ghp_",
|
|
59
|
+
"gho_",
|
|
60
|
+
"github_pat_",
|
|
61
|
+
"xai-",
|
|
62
|
+
"pplx-",
|
|
63
|
+
"r8_",
|
|
64
|
+
"hf_",
|
|
65
|
+
"astra-",
|
|
66
|
+
"astrae-"
|
|
67
|
+
];
|
|
68
|
+
var MAX_HEADERS = 64;
|
|
69
|
+
var MAX_HEADER_VALUE_BYTES = 1024;
|
|
70
|
+
var MAX_TOTAL_BYTES = 16 * 1024;
|
|
71
|
+
function byteLength(s) {
|
|
72
|
+
let bytes = 0;
|
|
73
|
+
for (let i = 0; i < s.length; i++) {
|
|
74
|
+
const code = s.charCodeAt(i);
|
|
75
|
+
if (code < 128) bytes += 1;
|
|
76
|
+
else if (code < 2048) bytes += 2;
|
|
77
|
+
else if (code >= 55296 && code <= 56319) {
|
|
78
|
+
bytes += 4;
|
|
79
|
+
i++;
|
|
80
|
+
} else bytes += 3;
|
|
81
|
+
}
|
|
82
|
+
return bytes;
|
|
83
|
+
}
|
|
84
|
+
function extractApiKeyFormat(rawValue) {
|
|
85
|
+
if (!rawValue) return void 0;
|
|
86
|
+
let value = rawValue.trim();
|
|
87
|
+
const spaceIdx = value.indexOf(" ");
|
|
88
|
+
if (spaceIdx > 0) {
|
|
89
|
+
const scheme = value.slice(0, spaceIdx).toLowerCase();
|
|
90
|
+
if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
|
|
91
|
+
value = value.slice(spaceIdx + 1).trim();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const lower = value.toLowerCase();
|
|
95
|
+
for (const prefix of KEY_FORMAT_PREFIXES) {
|
|
96
|
+
if (lower.startsWith(prefix)) {
|
|
97
|
+
return prefix;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return void 0;
|
|
101
|
+
}
|
|
102
|
+
function isSecretHeader(name) {
|
|
103
|
+
if (SECRET_HEADER_NAMES.has(name)) return true;
|
|
104
|
+
if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
|
|
105
|
+
if (isSignatureHeader(name)) return true;
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
function isPlatformHeader(name) {
|
|
109
|
+
if (PLATFORM_HEADER_NAMES.has(name)) return true;
|
|
110
|
+
return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
|
|
111
|
+
}
|
|
112
|
+
function sanitizeHeaders(raw) {
|
|
113
|
+
const headers = {};
|
|
114
|
+
const platformHeaders = {};
|
|
115
|
+
let apiKeyFormat;
|
|
116
|
+
let cookieCount;
|
|
117
|
+
let totalBytes = 0;
|
|
118
|
+
let count = 0;
|
|
119
|
+
if (!raw) return { headers };
|
|
120
|
+
for (const rawName of Object.keys(raw)) {
|
|
121
|
+
if (count >= MAX_HEADERS) break;
|
|
122
|
+
const name = rawName.toLowerCase();
|
|
123
|
+
const rawValue = raw[rawName];
|
|
124
|
+
if (rawValue === void 0) continue;
|
|
125
|
+
const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
|
|
126
|
+
if (CREDENTIAL_HEADER_NAMES.has(name)) {
|
|
127
|
+
const fmt = extractApiKeyFormat(joined);
|
|
128
|
+
if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (name === "cookie") {
|
|
132
|
+
cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
|
|
133
|
+
}
|
|
134
|
+
if (isSecretHeader(name)) continue;
|
|
135
|
+
let value = joined;
|
|
136
|
+
if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
|
|
137
|
+
value = value.slice(0, MAX_HEADER_VALUE_BYTES);
|
|
138
|
+
}
|
|
139
|
+
const entryBytes = byteLength(name) + byteLength(value);
|
|
140
|
+
if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
|
|
141
|
+
totalBytes += entryBytes;
|
|
142
|
+
count++;
|
|
143
|
+
headers[name] = value;
|
|
144
|
+
if (isPlatformHeader(name)) platformHeaders[name] = value;
|
|
145
|
+
}
|
|
146
|
+
const result = { headers };
|
|
147
|
+
if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
|
|
148
|
+
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
149
|
+
if (cookieCount !== void 0) result.cookieCount = cookieCount;
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
var CONNECTION_HEADER_SOURCES = [
|
|
153
|
+
["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
|
|
154
|
+
[
|
|
155
|
+
"country",
|
|
156
|
+
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
157
|
+
],
|
|
158
|
+
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
159
|
+
["countryRegionName", ["cloudfront-viewer-country-region-name"]],
|
|
160
|
+
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
161
|
+
["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
|
|
162
|
+
["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
|
|
163
|
+
["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
|
|
164
|
+
["asn", ["cloudfront-viewer-asn"]],
|
|
165
|
+
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
166
|
+
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
167
|
+
["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
|
|
168
|
+
["metroCode", ["cloudfront-viewer-metro-code"]],
|
|
169
|
+
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
170
|
+
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
171
|
+
// connection-layer truth — normalising them here is the permanent design.
|
|
172
|
+
// CloudFront delivers JA3/JA4 only via an origin request policy and only
|
|
173
|
+
// for HTTPS viewer connections.
|
|
174
|
+
["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
|
|
175
|
+
["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
|
|
176
|
+
// Header-structure fingerprint: browser/SDK-distinctive header ordering.
|
|
177
|
+
["headerOrder", ["cloudfront-viewer-header-order"]],
|
|
178
|
+
["headerCount", ["cloudfront-viewer-header-count"]]
|
|
179
|
+
];
|
|
180
|
+
var MAX_CONNECTION_VALUE_CHARS = 256;
|
|
181
|
+
function deriveConnectionFromHeaders(headers) {
|
|
182
|
+
if (!headers) return void 0;
|
|
183
|
+
const lower = {};
|
|
184
|
+
for (const name of Object.keys(headers)) {
|
|
185
|
+
const value = headers[name];
|
|
186
|
+
if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
|
|
187
|
+
}
|
|
188
|
+
const connection = {};
|
|
189
|
+
for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
|
|
190
|
+
for (const source of sources) {
|
|
191
|
+
const value = lower[source]?.trim();
|
|
192
|
+
if (value) {
|
|
193
|
+
connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
{
|
|
199
|
+
const addr = lower["cloudfront-viewer-address"]?.trim();
|
|
200
|
+
const portMatch = addr?.match(/:(\d+)$/);
|
|
201
|
+
if (portMatch) connection.sourcePort = portMatch[1];
|
|
202
|
+
if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
|
|
203
|
+
}
|
|
204
|
+
if (!connection.ip) {
|
|
205
|
+
const xff = lower["x-forwarded-for"];
|
|
206
|
+
const client = xff?.split(",")[0]?.trim();
|
|
207
|
+
if (client) connection.ip = client;
|
|
208
|
+
}
|
|
209
|
+
if (!connection.tlsCipher) {
|
|
210
|
+
const cipher = connection.tlsVersion?.split(":")[1];
|
|
211
|
+
if (cipher) connection.tlsCipher = cipher;
|
|
212
|
+
}
|
|
213
|
+
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
214
|
+
}
|
|
215
|
+
function buildSdkObservedMetadata(rawHeaders) {
|
|
216
|
+
const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
|
|
217
|
+
const flat = {};
|
|
218
|
+
if (rawHeaders) {
|
|
219
|
+
for (const name of Object.keys(rawHeaders)) {
|
|
220
|
+
const value = rawHeaders[name];
|
|
221
|
+
if (value === void 0) continue;
|
|
222
|
+
flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const connection = deriveConnectionFromHeaders(flat);
|
|
226
|
+
return {
|
|
227
|
+
headers,
|
|
228
|
+
...apiKeyFormat && { apiKeyFormat },
|
|
229
|
+
...platformHeaders && { platformHeaders },
|
|
230
|
+
...connection && { connection },
|
|
231
|
+
...cookieCount !== void 0 && { cookieCount },
|
|
232
|
+
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/edge-core/request.ts
|
|
237
|
+
function headerValue(req, name) {
|
|
238
|
+
return req.headers[name.toLowerCase()];
|
|
239
|
+
}
|
|
240
|
+
function requestUrl(req, host) {
|
|
241
|
+
const qs = req.querystring ? `?${req.querystring}` : "";
|
|
242
|
+
return `https://${host}${req.uri}${qs}`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/edge-core/detect.ts
|
|
246
|
+
var SD_JWT_PATTERN = /^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;
|
|
247
|
+
function decodeBase64Url(seg) {
|
|
248
|
+
const b64 = seg.replace(/-/g, "+").replace(/_/g, "/");
|
|
249
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
250
|
+
const binary = atob(padded);
|
|
251
|
+
const bytes = new Uint8Array(binary.length);
|
|
252
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
253
|
+
return new TextDecoder().decode(bytes);
|
|
254
|
+
}
|
|
255
|
+
function sniffJwtHeader(compact) {
|
|
256
|
+
try {
|
|
257
|
+
const seg = compact.split(".")[0];
|
|
258
|
+
return JSON.parse(decodeBase64Url(seg));
|
|
259
|
+
} catch {
|
|
260
|
+
return void 0;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function parseJsonBody(bodyText) {
|
|
264
|
+
if (!bodyText) return void 0;
|
|
265
|
+
try {
|
|
266
|
+
const parsed = JSON.parse(bodyText);
|
|
267
|
+
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
268
|
+
} catch {
|
|
269
|
+
return void 0;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function detectCommerce(req, host) {
|
|
273
|
+
const url = requestUrl(req, host);
|
|
274
|
+
const method = req.method;
|
|
275
|
+
const headers = req.headers;
|
|
276
|
+
const jsonBody = parseJsonBody(req.bodyText);
|
|
277
|
+
const truncated = req.bodyTruncated ? { bodyTruncated: true } : {};
|
|
278
|
+
const authHeader = headerValue(req, "authorization");
|
|
279
|
+
const bearer = authHeader?.replace(/^Bearer\s+/i, "");
|
|
280
|
+
const mandateHeader = headerValue(req, "x-payment-mandate") ?? headerValue(req, "payment-mandate");
|
|
281
|
+
const sdJwtCandidate = [mandateHeader, bearer].find((v) => v && SD_JWT_PATTERN.test(v));
|
|
282
|
+
if (sdJwtCandidate) {
|
|
283
|
+
const typ = sniffJwtHeader(sdJwtCandidate)?.typ;
|
|
284
|
+
return {
|
|
285
|
+
protocol: "vi-sd-jwt",
|
|
286
|
+
artifacts: { viSdJwt: sdJwtCandidate },
|
|
287
|
+
evidence: { typ, ...truncated }
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const signature = headerValue(req, "signature");
|
|
291
|
+
const signatureInput = headerValue(req, "signature-input");
|
|
292
|
+
if (signature && signatureInput) {
|
|
293
|
+
const signatureAgent = headerValue(req, "signature-agent");
|
|
294
|
+
const registryHint = headerValue(req, "x-agent-registry");
|
|
295
|
+
const lowerInput = signatureInput.toLowerCase();
|
|
296
|
+
const protocol = signatureAgent ? "rfc9421-web-bot-auth" : registryHint?.toLowerCase().includes("visa") || lowerInput.includes("visa") ? "rfc9421-tap" : registryHint?.toLowerCase().includes("mastercard") || lowerInput.includes("mastercard") ? "rfc9421-agent-pay" : "rfc9421";
|
|
297
|
+
return {
|
|
298
|
+
protocol,
|
|
299
|
+
artifacts: {
|
|
300
|
+
rfc9421: { headers, method, url, ...req.bodyText && { body: req.bodyText } }
|
|
301
|
+
},
|
|
302
|
+
evidence: {
|
|
303
|
+
...signatureAgent && { signatureAgent },
|
|
304
|
+
...registryHint && { registryHint },
|
|
305
|
+
keyid: signatureInput.match(/keyid="([^"]+)"/)?.[1],
|
|
306
|
+
...truncated
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
const acpTimestamp = headerValue(req, "timestamp");
|
|
311
|
+
if (signature && !signatureInput && (acpTimestamp || headerValue(req, "idempotency-key"))) {
|
|
312
|
+
return {
|
|
313
|
+
protocol: "acp",
|
|
314
|
+
artifacts: {
|
|
315
|
+
acpRequest: {
|
|
316
|
+
method,
|
|
317
|
+
url,
|
|
318
|
+
headers,
|
|
319
|
+
...req.bodyText && { rawBody: req.bodyText },
|
|
320
|
+
...jsonBody && { body: jsonBody }
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
evidence: { hasTimestamp: Boolean(acpTimestamp), ...truncated }
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
if (/\/checkout[-_]sessions(\/|$)/.test(req.uri)) {
|
|
327
|
+
return {
|
|
328
|
+
protocol: "ucp",
|
|
329
|
+
artifacts: { ucpRequest: { method, url, ...jsonBody && { body: jsonBody } } },
|
|
330
|
+
evidence: { path: req.uri, ...truncated }
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
if (jsonBody) {
|
|
334
|
+
const intent = jsonBody.intent_mandate ?? jsonBody.intentMandate;
|
|
335
|
+
const cart = jsonBody.cart_mandate ?? jsonBody.cartMandate;
|
|
336
|
+
const payment = jsonBody.payment_mandate ?? jsonBody.paymentMandate;
|
|
337
|
+
if (typeof intent === "string" || typeof cart === "string" || typeof payment === "string") {
|
|
338
|
+
return {
|
|
339
|
+
protocol: "ap2",
|
|
340
|
+
artifacts: {
|
|
341
|
+
ap2Mandates: {
|
|
342
|
+
...typeof intent === "string" && { intent },
|
|
343
|
+
...typeof cart === "string" && { cart },
|
|
344
|
+
...typeof payment === "string" && { payment }
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
evidence: {
|
|
348
|
+
mandatesPresent: [
|
|
349
|
+
typeof intent === "string" && "intent",
|
|
350
|
+
typeof cart === "string" && "cart",
|
|
351
|
+
typeof payment === "string" && "payment"
|
|
352
|
+
].filter(Boolean),
|
|
353
|
+
...truncated
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (authHeader && /^Payment\s+/i.test(authHeader) || headerValue(req, "payment-authorization")) {
|
|
359
|
+
return {
|
|
360
|
+
protocol: "mpp",
|
|
361
|
+
artifacts: {
|
|
362
|
+
mppRequest: {
|
|
363
|
+
method,
|
|
364
|
+
url,
|
|
365
|
+
headers,
|
|
366
|
+
...req.bodyText && { rawBody: req.bodyText },
|
|
367
|
+
...jsonBody && { body: jsonBody }
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
evidence: truncated
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
if (headerValue(req, "payment-signature") || headerValue(req, "x-payment")) {
|
|
374
|
+
return {
|
|
375
|
+
protocol: "x402",
|
|
376
|
+
artifacts: {
|
|
377
|
+
x402Request: { method, url, headers, ...jsonBody && { body: jsonBody } }
|
|
378
|
+
},
|
|
379
|
+
evidence: truncated
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
return void 0;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// src/adapters/commerce-detect.ts
|
|
386
|
+
var MAX_BODY_BYTES = 64 * 1024;
|
|
387
|
+
function detect(req, host) {
|
|
388
|
+
try {
|
|
389
|
+
return detectCommerce(req, host)?.artifacts;
|
|
390
|
+
} catch {
|
|
391
|
+
return void 0;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
async function detectFetchCommerce(request) {
|
|
395
|
+
const url = new URL(request.url);
|
|
396
|
+
const headers = {};
|
|
397
|
+
request.headers.forEach((v, k) => headers[k.toLowerCase()] = v);
|
|
398
|
+
let bodyText;
|
|
399
|
+
const length = Number(headers["content-length"] ?? 0);
|
|
400
|
+
if (request.method !== "GET" && request.method !== "HEAD" && length <= MAX_BODY_BYTES) {
|
|
401
|
+
bodyText = await request.clone().text().catch(() => void 0);
|
|
402
|
+
}
|
|
403
|
+
return detect(
|
|
404
|
+
{
|
|
405
|
+
method: request.method,
|
|
406
|
+
uri: url.pathname,
|
|
407
|
+
querystring: url.search.replace(/^\?/, ""),
|
|
408
|
+
headers,
|
|
409
|
+
...bodyText ? { bodyText } : {}
|
|
410
|
+
},
|
|
411
|
+
headers["x-forwarded-host"] ?? url.host
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
1
415
|
// src/version.ts
|
|
2
|
-
var SDK_VERSION = "5.
|
|
416
|
+
var SDK_VERSION = "5.15.0";
|
|
3
417
|
|
|
4
418
|
// src/http.ts
|
|
5
419
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -463,6 +877,7 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
463
877
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
464
878
|
if (requestData.commercePhase) body.commercePhase = requestData.commercePhase;
|
|
465
879
|
if (requestData.checkoutSessionId) body.checkoutSessionId = requestData.checkoutSessionId;
|
|
880
|
+
if (requestData.checkoutJwt) body.checkoutJwt = requestData.checkoutJwt;
|
|
466
881
|
if (requestData.checkoutItems) body.checkoutItems = requestData.checkoutItems;
|
|
467
882
|
if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
|
|
468
883
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
@@ -613,7 +1028,8 @@ async function verify(config, request, options) {
|
|
|
613
1028
|
"[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access decisions (verified ID + runtime challenge + PDLSS + trust score). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
|
|
614
1029
|
);
|
|
615
1030
|
}
|
|
616
|
-
|
|
1031
|
+
const uncacheable = Boolean(request.commerceArtifacts);
|
|
1032
|
+
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
617
1033
|
const cached = getCachedResult(request, mergedConfig.counterpartyId);
|
|
618
1034
|
if (cached) {
|
|
619
1035
|
if (mergedConfig.debug) {
|
|
@@ -694,7 +1110,10 @@ async function verify(config, request, options) {
|
|
|
694
1110
|
// MERCHANT caller only (bridge callers strip it before the agent plane).
|
|
695
1111
|
settlementToken: apiResponse.settlementToken,
|
|
696
1112
|
// 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
|
|
697
|
-
fulfilment: apiResponse.fulfilment
|
|
1113
|
+
fulfilment: apiResponse.fulfilment,
|
|
1114
|
+
mandates: apiResponse.mandates,
|
|
1115
|
+
kyaToken: apiResponse.kyaToken,
|
|
1116
|
+
aep: apiResponse.aep
|
|
698
1117
|
};
|
|
699
1118
|
return result2;
|
|
700
1119
|
}
|
|
@@ -704,7 +1123,10 @@ async function verify(config, request, options) {
|
|
|
704
1123
|
trustScore: apiResponse.agent.trustScore,
|
|
705
1124
|
trustLevel: getTrustLevel(apiResponse.agent.trustScore),
|
|
706
1125
|
blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
|
|
707
|
-
status: apiResponse.agent.agentStatus
|
|
1126
|
+
status: apiResponse.agent.agentStatus,
|
|
1127
|
+
...apiResponse.agent.protocolIdentities && {
|
|
1128
|
+
protocolIdentities: apiResponse.agent.protocolIdentities
|
|
1129
|
+
}
|
|
708
1130
|
} : void 0;
|
|
709
1131
|
const developer = apiResponse.developer ? {
|
|
710
1132
|
astradId: apiResponse.developer.kyaOwnerId,
|
|
@@ -755,7 +1177,11 @@ async function verify(config, request, options) {
|
|
|
755
1177
|
settlementOutcome: apiResponse.settlementOutcome,
|
|
756
1178
|
settlementToken: apiResponse.settlementToken,
|
|
757
1179
|
// 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
|
|
758
|
-
fulfilment: apiResponse.fulfilment
|
|
1180
|
+
fulfilment: apiResponse.fulfilment,
|
|
1181
|
+
// 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
|
|
1182
|
+
mandates: apiResponse.mandates,
|
|
1183
|
+
kyaToken: apiResponse.kyaToken,
|
|
1184
|
+
aep: apiResponse.aep
|
|
759
1185
|
};
|
|
760
1186
|
if (result.recommendation === "deny") {
|
|
761
1187
|
result.policyAllowed = false;
|
|
@@ -775,7 +1201,9 @@ async function verify(config, request, options) {
|
|
|
775
1201
|
}
|
|
776
1202
|
const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
|
|
777
1203
|
if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
|
|
778
|
-
|
|
1204
|
+
if (!uncacheable) {
|
|
1205
|
+
cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
|
|
1206
|
+
}
|
|
779
1207
|
}
|
|
780
1208
|
return result;
|
|
781
1209
|
}
|
|
@@ -929,239 +1357,30 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
|
|
|
929
1357
|
return failures;
|
|
930
1358
|
}
|
|
931
1359
|
|
|
932
|
-
// src/
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
]);
|
|
946
|
-
var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
|
|
947
|
-
var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
948
|
-
"authorization",
|
|
949
|
-
"x-api-key",
|
|
950
|
-
"x-goog-api-key",
|
|
951
|
-
"api-key"
|
|
952
|
-
]);
|
|
953
|
-
function isSignatureHeader(name) {
|
|
954
|
-
return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
|
|
955
|
-
}
|
|
956
|
-
var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
957
|
-
"openai-organization",
|
|
958
|
-
"openai-project",
|
|
959
|
-
"openai-version",
|
|
960
|
-
"openai-processing-ms",
|
|
961
|
-
"anthropic-version",
|
|
962
|
-
"anthropic-beta",
|
|
963
|
-
"x-goog-user-project",
|
|
964
|
-
"x-goog-api-client",
|
|
965
|
-
"user-agent",
|
|
966
|
-
"x-agent-card-url",
|
|
967
|
-
"x-agent-provider"
|
|
968
|
-
]);
|
|
969
|
-
var PLATFORM_HEADER_PREFIXES = [
|
|
970
|
-
"x-goog-",
|
|
971
|
-
"x-stainless-",
|
|
972
|
-
"x-anthropic-",
|
|
973
|
-
"x-openai-",
|
|
974
|
-
"sec-ch-"
|
|
975
|
-
];
|
|
976
|
-
var KEY_FORMAT_PREFIXES = [
|
|
977
|
-
"sk-ant-api03",
|
|
978
|
-
"sk-ant-api",
|
|
979
|
-
"sk-ant",
|
|
980
|
-
"sk-proj",
|
|
981
|
-
"sk-svcacct",
|
|
982
|
-
"sk-or-v1",
|
|
983
|
-
"sk-or",
|
|
984
|
-
"sk-lf",
|
|
985
|
-
"sk-",
|
|
986
|
-
"gsk_",
|
|
987
|
-
"aiza",
|
|
988
|
-
"ya29",
|
|
989
|
-
"ghp_",
|
|
990
|
-
"gho_",
|
|
991
|
-
"github_pat_",
|
|
992
|
-
"xai-",
|
|
993
|
-
"pplx-",
|
|
994
|
-
"r8_",
|
|
995
|
-
"hf_",
|
|
996
|
-
"astra-",
|
|
997
|
-
"astrae-"
|
|
998
|
-
];
|
|
999
|
-
var MAX_HEADERS = 64;
|
|
1000
|
-
var MAX_HEADER_VALUE_BYTES = 1024;
|
|
1001
|
-
var MAX_TOTAL_BYTES = 16 * 1024;
|
|
1002
|
-
function byteLength(s) {
|
|
1003
|
-
let bytes = 0;
|
|
1004
|
-
for (let i = 0; i < s.length; i++) {
|
|
1005
|
-
const code = s.charCodeAt(i);
|
|
1006
|
-
if (code < 128) bytes += 1;
|
|
1007
|
-
else if (code < 2048) bytes += 2;
|
|
1008
|
-
else if (code >= 55296 && code <= 56319) {
|
|
1009
|
-
bytes += 4;
|
|
1010
|
-
i++;
|
|
1011
|
-
} else bytes += 3;
|
|
1012
|
-
}
|
|
1013
|
-
return bytes;
|
|
1014
|
-
}
|
|
1015
|
-
function extractApiKeyFormat(rawValue) {
|
|
1016
|
-
if (!rawValue) return void 0;
|
|
1017
|
-
let value = rawValue.trim();
|
|
1018
|
-
const spaceIdx = value.indexOf(" ");
|
|
1019
|
-
if (spaceIdx > 0) {
|
|
1020
|
-
const scheme = value.slice(0, spaceIdx).toLowerCase();
|
|
1021
|
-
if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
|
|
1022
|
-
value = value.slice(spaceIdx + 1).trim();
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
const lower = value.toLowerCase();
|
|
1026
|
-
for (const prefix of KEY_FORMAT_PREFIXES) {
|
|
1027
|
-
if (lower.startsWith(prefix)) {
|
|
1028
|
-
return prefix;
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
return void 0;
|
|
1032
|
-
}
|
|
1033
|
-
function isSecretHeader(name) {
|
|
1034
|
-
if (SECRET_HEADER_NAMES.has(name)) return true;
|
|
1035
|
-
if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
|
|
1036
|
-
if (isSignatureHeader(name)) return true;
|
|
1037
|
-
return false;
|
|
1038
|
-
}
|
|
1039
|
-
function isPlatformHeader(name) {
|
|
1040
|
-
if (PLATFORM_HEADER_NAMES.has(name)) return true;
|
|
1041
|
-
return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
|
|
1042
|
-
}
|
|
1043
|
-
function sanitizeHeaders(raw) {
|
|
1044
|
-
const headers = {};
|
|
1045
|
-
const platformHeaders = {};
|
|
1046
|
-
let apiKeyFormat;
|
|
1047
|
-
let cookieCount;
|
|
1048
|
-
let totalBytes = 0;
|
|
1049
|
-
let count = 0;
|
|
1050
|
-
if (!raw) return { headers };
|
|
1051
|
-
for (const rawName of Object.keys(raw)) {
|
|
1052
|
-
if (count >= MAX_HEADERS) break;
|
|
1053
|
-
const name = rawName.toLowerCase();
|
|
1054
|
-
const rawValue = raw[rawName];
|
|
1055
|
-
if (rawValue === void 0) continue;
|
|
1056
|
-
const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
|
|
1057
|
-
if (CREDENTIAL_HEADER_NAMES.has(name)) {
|
|
1058
|
-
const fmt = extractApiKeyFormat(joined);
|
|
1059
|
-
if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
|
|
1060
|
-
continue;
|
|
1061
|
-
}
|
|
1062
|
-
if (name === "cookie") {
|
|
1063
|
-
cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
|
|
1064
|
-
}
|
|
1065
|
-
if (isSecretHeader(name)) continue;
|
|
1066
|
-
let value = joined;
|
|
1067
|
-
if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
|
|
1068
|
-
value = value.slice(0, MAX_HEADER_VALUE_BYTES);
|
|
1069
|
-
}
|
|
1070
|
-
const entryBytes = byteLength(name) + byteLength(value);
|
|
1071
|
-
if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
|
|
1072
|
-
totalBytes += entryBytes;
|
|
1073
|
-
count++;
|
|
1074
|
-
headers[name] = value;
|
|
1075
|
-
if (isPlatformHeader(name)) platformHeaders[name] = value;
|
|
1076
|
-
}
|
|
1077
|
-
const result = { headers };
|
|
1078
|
-
if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
|
|
1079
|
-
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
1080
|
-
if (cookieCount !== void 0) result.cookieCount = cookieCount;
|
|
1081
|
-
return result;
|
|
1082
|
-
}
|
|
1083
|
-
var CONNECTION_HEADER_SOURCES = [
|
|
1084
|
-
["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
|
|
1085
|
-
[
|
|
1086
|
-
"country",
|
|
1087
|
-
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
1088
|
-
],
|
|
1089
|
-
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
1090
|
-
["countryRegionName", ["cloudfront-viewer-country-region-name"]],
|
|
1091
|
-
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
1092
|
-
["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
|
|
1093
|
-
["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
|
|
1094
|
-
["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
|
|
1095
|
-
["asn", ["cloudfront-viewer-asn"]],
|
|
1096
|
-
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
1097
|
-
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
1098
|
-
["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
|
|
1099
|
-
["metroCode", ["cloudfront-viewer-metro-code"]],
|
|
1100
|
-
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
1101
|
-
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
1102
|
-
// connection-layer truth — normalising them here is the permanent design.
|
|
1103
|
-
// CloudFront delivers JA3/JA4 only via an origin request policy and only
|
|
1104
|
-
// for HTTPS viewer connections.
|
|
1105
|
-
["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
|
|
1106
|
-
["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
|
|
1107
|
-
// Header-structure fingerprint: browser/SDK-distinctive header ordering.
|
|
1108
|
-
["headerOrder", ["cloudfront-viewer-header-order"]],
|
|
1109
|
-
["headerCount", ["cloudfront-viewer-header-count"]]
|
|
1110
|
-
];
|
|
1111
|
-
var MAX_CONNECTION_VALUE_CHARS = 256;
|
|
1112
|
-
function deriveConnectionFromHeaders(headers) {
|
|
1113
|
-
if (!headers) return void 0;
|
|
1114
|
-
const lower = {};
|
|
1115
|
-
for (const name of Object.keys(headers)) {
|
|
1116
|
-
const value = headers[name];
|
|
1117
|
-
if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
|
|
1118
|
-
}
|
|
1119
|
-
const connection = {};
|
|
1120
|
-
for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
|
|
1121
|
-
for (const source of sources) {
|
|
1122
|
-
const value = lower[source]?.trim();
|
|
1123
|
-
if (value) {
|
|
1124
|
-
connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
|
|
1125
|
-
break;
|
|
1126
|
-
}
|
|
1360
|
+
// src/route-pattern.ts
|
|
1361
|
+
function routePatternToRegExp(pattern, opts = {}) {
|
|
1362
|
+
let source = "";
|
|
1363
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
1364
|
+
const ch = pattern[i];
|
|
1365
|
+
if (ch === "*") {
|
|
1366
|
+
source += ".*";
|
|
1367
|
+
} else if (ch === ":" && /[A-Za-z_]/.test(pattern[i + 1] ?? "") && (i === 0 || pattern[i - 1] === "/")) {
|
|
1368
|
+
let j = i + 1;
|
|
1369
|
+
while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) j++;
|
|
1370
|
+
source += "[^/]+";
|
|
1371
|
+
i = j - 1;
|
|
1372
|
+
} else {
|
|
1373
|
+
source += ch.replace(/[.+?^${}()|[\]\\/]/g, "\\$&");
|
|
1127
1374
|
}
|
|
1128
1375
|
}
|
|
1129
|
-
{
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
|
|
1134
|
-
}
|
|
1135
|
-
if (!connection.ip) {
|
|
1136
|
-
const xff = lower["x-forwarded-for"];
|
|
1137
|
-
const client = xff?.split(",")[0]?.trim();
|
|
1138
|
-
if (client) connection.ip = client;
|
|
1139
|
-
}
|
|
1140
|
-
if (!connection.tlsCipher) {
|
|
1141
|
-
const cipher = connection.tlsVersion?.split(":")[1];
|
|
1142
|
-
if (cipher) connection.tlsCipher = cipher;
|
|
1376
|
+
try {
|
|
1377
|
+
return new RegExp(`^${source}$`, opts.caseInsensitive ? "i" : "");
|
|
1378
|
+
} catch {
|
|
1379
|
+
return null;
|
|
1143
1380
|
}
|
|
1144
|
-
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
1145
1381
|
}
|
|
1146
|
-
function
|
|
1147
|
-
|
|
1148
|
-
const flat = {};
|
|
1149
|
-
if (rawHeaders) {
|
|
1150
|
-
for (const name of Object.keys(rawHeaders)) {
|
|
1151
|
-
const value = rawHeaders[name];
|
|
1152
|
-
if (value === void 0) continue;
|
|
1153
|
-
flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
const connection = deriveConnectionFromHeaders(flat);
|
|
1157
|
-
return {
|
|
1158
|
-
headers,
|
|
1159
|
-
...apiKeyFormat && { apiKeyFormat },
|
|
1160
|
-
...platformHeaders && { platformHeaders },
|
|
1161
|
-
...connection && { connection },
|
|
1162
|
-
...cookieCount !== void 0 && { cookieCount },
|
|
1163
|
-
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
1164
|
-
};
|
|
1382
|
+
function matchRoutePattern(pattern, path, opts = {}) {
|
|
1383
|
+
return routePatternToRegExp(pattern, opts)?.test(path) ?? false;
|
|
1165
1384
|
}
|
|
1166
1385
|
|
|
1167
1386
|
// src/edge-config.ts
|
|
@@ -1196,6 +1415,7 @@ function isEdgeConfig(value) {
|
|
|
1196
1415
|
if (r.sampling !== void 0 && !isSamplingShape(r.sampling)) return false;
|
|
1197
1416
|
}
|
|
1198
1417
|
if (!isSamplingShape(v.sampling)) return false;
|
|
1418
|
+
if (v.minTls !== void 0 && v.minTls !== "1.2" && v.minTls !== "1.3") return false;
|
|
1199
1419
|
if (v.queryValueAllowlist !== void 0) {
|
|
1200
1420
|
if (!Array.isArray(v.queryValueAllowlist) || v.queryValueAllowlist.length > 16 || !v.queryValueAllowlist.every((e) => typeof e === "string" && e.length > 0 && e.length <= 64)) {
|
|
1201
1421
|
return false;
|
|
@@ -1911,9 +2131,7 @@ function extractCredentialsFromNextRequest(request) {
|
|
|
1911
2131
|
return credentials;
|
|
1912
2132
|
}
|
|
1913
2133
|
function matchRoute(pattern, path) {
|
|
1914
|
-
|
|
1915
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
1916
|
-
return regex.test(path);
|
|
2134
|
+
return matchRoutePattern(pattern, path);
|
|
1917
2135
|
}
|
|
1918
2136
|
function findRouteConfig(routes, path, method) {
|
|
1919
2137
|
return routes.find((route) => {
|
|
@@ -2104,7 +2322,8 @@ function createMiddleware(options) {
|
|
|
2104
2322
|
skipPaths = [],
|
|
2105
2323
|
showInterstitial,
|
|
2106
2324
|
showCommerceShield,
|
|
2107
|
-
|
|
2325
|
+
// Round 27.8: opt-in only (the merchant turns it on); was default-on.
|
|
2326
|
+
enableRuntimeChallenge = false,
|
|
2108
2327
|
routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
|
|
2109
2328
|
anonymousBeacon = true,
|
|
2110
2329
|
trustVerifiedHop = false,
|
|
@@ -2241,8 +2460,10 @@ function createMiddleware(options) {
|
|
|
2241
2460
|
const originalClientIp = forwardedFor?.split(",")[0]?.trim();
|
|
2242
2461
|
const attemptHeader = request.headers.get("x-astra-attempt-id");
|
|
2243
2462
|
const inboundAttemptId = attemptHeader && /^att_[0-9a-f]{32}$/.test(attemptHeader) ? attemptHeader : void 0;
|
|
2463
|
+
const commerceArtifacts = await detectFetchCommerce(request);
|
|
2244
2464
|
const verificationRequest = {
|
|
2245
2465
|
credentials,
|
|
2466
|
+
...commerceArtifacts && { commerceArtifacts },
|
|
2246
2467
|
purpose,
|
|
2247
2468
|
action: pdlssPair.action,
|
|
2248
2469
|
resource: pathname,
|