@astrasyncai/verification-gateway 4.0.0 → 4.1.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 +106 -29
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +398 -15
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +398 -15
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/http-pdlss.d.mts +3 -3
- package/dist/adapters/http-pdlss.d.ts +3 -3
- package/dist/adapters/http-pdlss.js.map +1 -1
- package/dist/adapters/http-pdlss.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +56 -36
- package/dist/adapters/mcp.d.ts +56 -36
- package/dist/adapters/mcp.js +220 -3
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +220 -3
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +433 -18
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +433 -18
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +2 -2
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +2 -2
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +13 -13
- package/dist/bin/astrasync-codex-hook.js +13 -13
- package/dist/bin/astrasync-guard.js +13 -13
- package/dist/bin/astrasync.js +80 -26
- package/dist/browser/background.js +13 -13
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +13 -13
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +2 -2
- package/dist/browser/browser-adapter.d.ts +2 -2
- package/dist/claude-code/claude-code-adapter.d.mts +2 -2
- package/dist/claude-code/claude-code-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/codex/index.d.mts +3 -3
- package/dist/codex/index.d.ts +3 -3
- package/dist/codex/index.js +13 -13
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +13 -13
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/cursor-adapter.d.mts +2 -2
- package/dist/cursor/cursor-adapter.d.ts +2 -2
- package/dist/cursor/extension.d.mts +2 -2
- package/dist/cursor/extension.d.ts +2 -2
- package/dist/cursor/extension.js +13 -13
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +13 -13
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +22 -7
- package/dist/edge-config.d.ts +22 -7
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +425 -0
- package/dist/edge-core/index.d.ts +425 -0
- package/dist/edge-core/index.js +1482 -0
- package/dist/edge-core/index.js.map +1 -0
- package/dist/edge-core/index.mjs +1437 -0
- package/dist/edge-core/index.mjs.map +1 -0
- package/dist/{express-BZajRs4i.d.mts → express-BVd1_3FE.d.ts} +9 -7
- package/dist/{express-CjCUB1k7.d.ts → express-D_4hTn5Z.d.mts} +9 -7
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +13 -13
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +13 -13
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +2 -2
- package/dist/git-trigger/git-hooks.d.ts +2 -2
- package/dist/{index-adgKhujR.d.ts → index-B0YHu_SP.d.ts} +30 -27
- package/dist/{index-B0cyMZDL.d.mts → index-BPEBlOsE.d.mts} +30 -27
- package/dist/{index-BRYteOqO.d.mts → index-DQb5-_1X.d.mts} +1 -1
- package/dist/{index-BZQdVqNw.d.ts → index-T1aBoUcc.d.ts} +1 -1
- package/dist/index.d.mts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.js +477 -265
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +474 -265
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/metadata-capture.d.mts +63 -4
- package/dist/metadata-capture.d.ts +63 -4
- package/dist/metadata-capture.js +67 -0
- package/dist/metadata-capture.js.map +1 -1
- package/dist/metadata-capture.mjs +64 -0
- package/dist/metadata-capture.mjs.map +1 -1
- package/dist/{nextjs-DeUTnOBd.d.mts → nextjs-WyeVr2Kp.d.mts} +3 -3
- package/dist/{nextjs-D_iFf5k-.d.ts → nextjs-w7RTbP1P.d.ts} +3 -3
- package/dist/platform-signatures.d.mts +5 -6
- package/dist/platform-signatures.d.ts +5 -6
- package/dist/platform-signatures.js.map +1 -1
- package/dist/platform-signatures.mjs.map +1 -1
- package/dist/registration/index.d.mts +10 -11
- package/dist/registration/index.d.ts +10 -11
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/{sdk-BM3mwEAq.d.ts → sdk-CbTNIkAa.d.mts} +4 -4
- package/dist/{sdk-_il1Q41f.d.mts → sdk-QeX0Z8Ho.d.ts} +4 -4
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-CHKCgDFC.d.ts → types-BLUx92FJ.d.ts} +1 -1
- package/dist/{types-DfnP7JiM.d.mts → types-DqfPU5Bl.d.mts} +1 -1
- package/dist/{types-BcDf9Kk0.d.mts → types-r850cOt0.d.mts} +106 -88
- package/dist/{types-fTQD448H.d.ts → types-sMxBT-nM.d.ts} +106 -88
- package/dist/ui/index.d.mts +11 -7
- package/dist/ui/index.d.ts +11 -7
- package/dist/ui/index.js +13 -9
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/index.mjs +10 -8
- package/dist/ui/index.mjs.map +1 -1
- package/dist/verify.d.mts +8 -7
- package/dist/verify.d.ts +8 -7
- package/dist/verify.js +1 -1
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +1 -1
- package/dist/verify.mjs.map +1 -1
- package/package.json +8 -2
package/dist/index.mjs
CHANGED
|
@@ -126,7 +126,7 @@ function getCapabilities(accessLevel) {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// src/version.ts
|
|
129
|
-
var SDK_VERSION = "4.
|
|
129
|
+
var SDK_VERSION = "4.1.0";
|
|
130
130
|
|
|
131
131
|
// src/well-known.ts
|
|
132
132
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -1124,6 +1124,7 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
|
|
|
1124
1124
|
}
|
|
1125
1125
|
|
|
1126
1126
|
// src/metadata-capture.ts
|
|
1127
|
+
var CAPTURE_SCHEMA_VERSION = 1;
|
|
1127
1128
|
var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
1128
1129
|
"cookie",
|
|
1129
1130
|
"set-cookie",
|
|
@@ -1268,6 +1269,373 @@ function extractPlatformHeaders(sanitized) {
|
|
|
1268
1269
|
}
|
|
1269
1270
|
return out;
|
|
1270
1271
|
}
|
|
1272
|
+
var CONNECTION_HEADER_SOURCES = [
|
|
1273
|
+
["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
|
|
1274
|
+
[
|
|
1275
|
+
"country",
|
|
1276
|
+
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
1277
|
+
],
|
|
1278
|
+
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
1279
|
+
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
1280
|
+
["asn", ["cloudfront-viewer-asn"]],
|
|
1281
|
+
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
1282
|
+
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
1283
|
+
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
1284
|
+
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
1285
|
+
// connection-layer truth — normalising them here is the permanent design.
|
|
1286
|
+
["tlsFingerprint", ["cf-ja3-hash"]],
|
|
1287
|
+
["ja4", ["cf-ja4"]]
|
|
1288
|
+
];
|
|
1289
|
+
function deriveConnectionFromHeaders(headers) {
|
|
1290
|
+
if (!headers) return void 0;
|
|
1291
|
+
const lower = {};
|
|
1292
|
+
for (const name of Object.keys(headers)) {
|
|
1293
|
+
const value = headers[name];
|
|
1294
|
+
if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
|
|
1295
|
+
}
|
|
1296
|
+
const connection = {};
|
|
1297
|
+
for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
|
|
1298
|
+
for (const source of sources) {
|
|
1299
|
+
const value = lower[source]?.trim();
|
|
1300
|
+
if (value) {
|
|
1301
|
+
connection[key] = value;
|
|
1302
|
+
break;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
if (!connection.ip) {
|
|
1307
|
+
const xff = lower["x-forwarded-for"];
|
|
1308
|
+
const client = xff?.split(",")[0]?.trim();
|
|
1309
|
+
if (client) connection.ip = client;
|
|
1310
|
+
}
|
|
1311
|
+
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
1312
|
+
}
|
|
1313
|
+
function buildSdkObservedMetadata(rawHeaders) {
|
|
1314
|
+
const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
1315
|
+
const flat = {};
|
|
1316
|
+
if (rawHeaders) {
|
|
1317
|
+
for (const name of Object.keys(rawHeaders)) {
|
|
1318
|
+
const value = rawHeaders[name];
|
|
1319
|
+
if (value === void 0) continue;
|
|
1320
|
+
flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
const connection = deriveConnectionFromHeaders(flat);
|
|
1324
|
+
return {
|
|
1325
|
+
headers,
|
|
1326
|
+
...apiKeyFormat && { apiKeyFormat },
|
|
1327
|
+
...platformHeaders && { platformHeaders },
|
|
1328
|
+
...connection && { connection },
|
|
1329
|
+
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// src/edge-config.ts
|
|
1334
|
+
var DEFAULT_EDGE_CONFIG = Object.freeze({
|
|
1335
|
+
version: 1,
|
|
1336
|
+
mode: "observe",
|
|
1337
|
+
depth: "classify",
|
|
1338
|
+
pathRules: [],
|
|
1339
|
+
sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
|
|
1340
|
+
failurePosture: "open"
|
|
1341
|
+
});
|
|
1342
|
+
var EDGE_MODES = ["observe", "enforce"];
|
|
1343
|
+
var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
|
|
1344
|
+
function isEdgeConfig(value) {
|
|
1345
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1346
|
+
const v = value;
|
|
1347
|
+
if (v.version !== 1) return false;
|
|
1348
|
+
if (!EDGE_MODES.includes(v.mode)) return false;
|
|
1349
|
+
if (!EDGE_DEPTHS.includes(v.depth)) return false;
|
|
1350
|
+
if (!Array.isArray(v.pathRules)) return false;
|
|
1351
|
+
for (const rule of v.pathRules) {
|
|
1352
|
+
if (typeof rule !== "object" || rule === null) return false;
|
|
1353
|
+
const r = rule;
|
|
1354
|
+
if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
|
|
1355
|
+
if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
|
|
1356
|
+
if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
|
|
1357
|
+
}
|
|
1358
|
+
const sampling = v.sampling;
|
|
1359
|
+
if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
|
|
1360
|
+
return false;
|
|
1361
|
+
}
|
|
1362
|
+
return v.failurePosture === "open";
|
|
1363
|
+
}
|
|
1364
|
+
async function fetchEdgeConfig(config, counterpartyId, opts) {
|
|
1365
|
+
if (!counterpartyId) return null;
|
|
1366
|
+
const headers = { Accept: "application/json" };
|
|
1367
|
+
if (config.apiKey) {
|
|
1368
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
1369
|
+
headers["X-API-Key"] = config.apiKey;
|
|
1370
|
+
}
|
|
1371
|
+
if (opts?.etag) headers["If-None-Match"] = opts.etag;
|
|
1372
|
+
try {
|
|
1373
|
+
const response = await fetch(
|
|
1374
|
+
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
|
|
1375
|
+
{ method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
|
|
1376
|
+
);
|
|
1377
|
+
if (response.status === 304) return { notModified: true };
|
|
1378
|
+
if (!response.ok) return null;
|
|
1379
|
+
const body = await response.json();
|
|
1380
|
+
const edgeConfig = body.data?.edgeConfig;
|
|
1381
|
+
if (!isEdgeConfig(edgeConfig)) return null;
|
|
1382
|
+
return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
|
|
1383
|
+
} catch {
|
|
1384
|
+
return null;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
var DEFAULT_TTL_MS = 60 * 1e3;
|
|
1388
|
+
var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
|
|
1389
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
1390
|
+
var inflight2 = /* @__PURE__ */ new Map();
|
|
1391
|
+
function cacheKey(apiBaseUrl, counterpartyId) {
|
|
1392
|
+
return `${apiBaseUrl}|${counterpartyId}`;
|
|
1393
|
+
}
|
|
1394
|
+
function degradeToObserve(config) {
|
|
1395
|
+
if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
|
|
1396
|
+
return config;
|
|
1397
|
+
}
|
|
1398
|
+
return {
|
|
1399
|
+
...config,
|
|
1400
|
+
mode: "observe",
|
|
1401
|
+
pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
async function revalidate(config, counterpartyId) {
|
|
1405
|
+
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
1406
|
+
const existing = inflight2.get(key);
|
|
1407
|
+
if (existing) return existing;
|
|
1408
|
+
const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
|
|
1409
|
+
if (result === null) return;
|
|
1410
|
+
const now = Date.now();
|
|
1411
|
+
if ("notModified" in result) {
|
|
1412
|
+
const entry = cache2.get(key);
|
|
1413
|
+
if (entry) entry.lastSuccessAt = now;
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
|
|
1417
|
+
}).finally(() => {
|
|
1418
|
+
inflight2.delete(key);
|
|
1419
|
+
});
|
|
1420
|
+
inflight2.set(key, promise);
|
|
1421
|
+
return promise;
|
|
1422
|
+
}
|
|
1423
|
+
async function getEdgeConfig(config, counterpartyId, opts) {
|
|
1424
|
+
const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
|
|
1425
|
+
const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
|
|
1426
|
+
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
1427
|
+
const entry = cache2.get(key);
|
|
1428
|
+
if (entry) {
|
|
1429
|
+
const age = Date.now() - entry.lastSuccessAt;
|
|
1430
|
+
if (age > ttlMs) {
|
|
1431
|
+
revalidate(config, counterpartyId).catch(() => {
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
|
|
1435
|
+
}
|
|
1436
|
+
await revalidate(config, counterpartyId).catch(() => {
|
|
1437
|
+
});
|
|
1438
|
+
return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
|
|
1439
|
+
}
|
|
1440
|
+
function matchEdgePathRule(rules, path) {
|
|
1441
|
+
for (const rule of rules) {
|
|
1442
|
+
if (globToRegExp(rule.pattern).test(path)) return rule;
|
|
1443
|
+
}
|
|
1444
|
+
return void 0;
|
|
1445
|
+
}
|
|
1446
|
+
function globToRegExp(pattern) {
|
|
1447
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
1448
|
+
return new RegExp(`^${escaped}$`, "i");
|
|
1449
|
+
}
|
|
1450
|
+
function _resetEdgeConfigCache() {
|
|
1451
|
+
cache2.clear();
|
|
1452
|
+
inflight2.clear();
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// src/platform-signatures.ts
|
|
1456
|
+
var PLATFORM_AGENT_SIGNATURES = [
|
|
1457
|
+
{
|
|
1458
|
+
vendor: "claude",
|
|
1459
|
+
displayName: "Anthropic Claude",
|
|
1460
|
+
uaPatterns: [/claude/i, /anthropic/i],
|
|
1461
|
+
agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
|
|
1462
|
+
apiKeyFormatPatterns: [/^sk-ant/i],
|
|
1463
|
+
headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
vendor: "chatgpt",
|
|
1467
|
+
displayName: "OpenAI ChatGPT",
|
|
1468
|
+
uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
|
|
1469
|
+
agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
|
|
1470
|
+
apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
|
|
1471
|
+
headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
|
|
1472
|
+
},
|
|
1473
|
+
{
|
|
1474
|
+
vendor: "gemini",
|
|
1475
|
+
displayName: "Google Gemini",
|
|
1476
|
+
uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
|
|
1477
|
+
agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
|
|
1478
|
+
apiKeyFormatPatterns: [/^aiza/i],
|
|
1479
|
+
headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
|
|
1480
|
+
},
|
|
1481
|
+
{
|
|
1482
|
+
vendor: "cursor",
|
|
1483
|
+
displayName: "Cursor",
|
|
1484
|
+
uaPatterns: [/cursor/i],
|
|
1485
|
+
agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
vendor: "goose",
|
|
1489
|
+
displayName: "Block Goose",
|
|
1490
|
+
uaPatterns: [/goose/i, /block-goose/i],
|
|
1491
|
+
agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
vendor: "perplexity",
|
|
1495
|
+
displayName: "Perplexity",
|
|
1496
|
+
uaPatterns: [/perplexity/i],
|
|
1497
|
+
agentCardPatterns: [/perplexity\.ai/i],
|
|
1498
|
+
apiKeyFormatPatterns: [/^pplx-/i]
|
|
1499
|
+
}
|
|
1500
|
+
];
|
|
1501
|
+
function matchPlatformSignature(signatures, input) {
|
|
1502
|
+
const ua = input.userAgent ?? "";
|
|
1503
|
+
const cardUrl = input.agentCardUrl ?? "";
|
|
1504
|
+
const apiKeyFormat = input.apiKeyFormat ?? "";
|
|
1505
|
+
const headerLines = [];
|
|
1506
|
+
if (input.platformHeaders) {
|
|
1507
|
+
for (const [name, value] of Object.entries(input.platformHeaders)) {
|
|
1508
|
+
headerLines.push(name, `${name}: ${value}`);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
for (const sig of signatures) {
|
|
1512
|
+
const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
|
|
1513
|
+
const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
|
|
1514
|
+
const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
|
|
1515
|
+
const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
|
|
1516
|
+
if (uaMatch || cardMatch || keyMatch || headerMatch) {
|
|
1517
|
+
const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
|
|
1518
|
+
const cardHost = (() => {
|
|
1519
|
+
try {
|
|
1520
|
+
return cardUrl ? new URL(cardUrl).host : "";
|
|
1521
|
+
} catch {
|
|
1522
|
+
return "";
|
|
1523
|
+
}
|
|
1524
|
+
})();
|
|
1525
|
+
const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
|
|
1526
|
+
return {
|
|
1527
|
+
vendor: sig.vendor,
|
|
1528
|
+
fingerprintKey: `${sig.vendor}:${keyBasis}`,
|
|
1529
|
+
displayName: sig.displayName
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
return void 0;
|
|
1534
|
+
}
|
|
1535
|
+
function detectPlatformFingerprint(input) {
|
|
1536
|
+
return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
// src/edge-core/classify.ts
|
|
1540
|
+
var STATIC_EXTENSIONS = /\.(css|js|mjs|map|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm|pdf|txt|xml)$/i;
|
|
1541
|
+
var BOT_UA_PATTERN = /curl|wget|python-requests|python-urllib|node-fetch|axios|got|okhttp|go-http-client|libwww|httpie|java\/|ruby|php|scrapy|headless|phantomjs|selenium|playwright|puppeteer|bot|crawler|spider|slurp/i;
|
|
1542
|
+
var BROWSER_UA_PATTERN = /mozilla\/\d/i;
|
|
1543
|
+
var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN };
|
|
1544
|
+
|
|
1545
|
+
// src/edge-core/events.ts
|
|
1546
|
+
function sampled(rate, random = Math.random) {
|
|
1547
|
+
if (rate <= 0) return false;
|
|
1548
|
+
if (rate >= 1) return true;
|
|
1549
|
+
return random() < rate;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
// src/adapters/anonymous-beacon.ts
|
|
1553
|
+
function readHeader(raw, name) {
|
|
1554
|
+
const value = raw[name];
|
|
1555
|
+
if (typeof value === "string") return value;
|
|
1556
|
+
if (Array.isArray(value)) return value[0];
|
|
1557
|
+
return void 0;
|
|
1558
|
+
}
|
|
1559
|
+
function classifyPassThroughTraffic(path, rawHeaders) {
|
|
1560
|
+
if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: "never" };
|
|
1561
|
+
const credentials = extractCredentials(rawHeaders, {});
|
|
1562
|
+
if (credentials.astraId || credentials.apiKey || credentials.jwt) {
|
|
1563
|
+
return { kind: "never" };
|
|
1564
|
+
}
|
|
1565
|
+
const userAgent = readHeader(rawHeaders, "user-agent") ?? "";
|
|
1566
|
+
const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
1567
|
+
const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });
|
|
1568
|
+
if (fingerprint) {
|
|
1569
|
+
return {
|
|
1570
|
+
kind: "platform",
|
|
1571
|
+
protocol: "platform-ua",
|
|
1572
|
+
evidence: { vendor: fingerprint.vendor, userAgent: userAgent || "(none)" }
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
if (!userAgent || _patterns.BOT_UA_PATTERN.test(userAgent) || !_patterns.BROWSER_UA_PATTERN.test(userAgent)) {
|
|
1576
|
+
return {
|
|
1577
|
+
kind: "anonymous-bot",
|
|
1578
|
+
protocol: "ua-heuristic",
|
|
1579
|
+
evidence: { userAgent: userAgent || "(none)" }
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
if (!readHeader(rawHeaders, "sec-fetch-mode") && !readHeader(rawHeaders, "accept-language")) {
|
|
1583
|
+
return {
|
|
1584
|
+
kind: "anonymous-bot",
|
|
1585
|
+
protocol: "ua-heuristic",
|
|
1586
|
+
evidence: { userAgent, spoofedBrowser: true }
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
return { kind: "never" };
|
|
1590
|
+
}
|
|
1591
|
+
function createAnonymousBeacon(config, options) {
|
|
1592
|
+
const counterpartyId = config.counterpartyId;
|
|
1593
|
+
if (!counterpartyId) return () => {
|
|
1594
|
+
};
|
|
1595
|
+
const random = options?.random ?? Math.random;
|
|
1596
|
+
let edgeConfig;
|
|
1597
|
+
let refreshing = false;
|
|
1598
|
+
const refreshConfig = () => {
|
|
1599
|
+
if (refreshing) return;
|
|
1600
|
+
refreshing = true;
|
|
1601
|
+
getEdgeConfig(config, counterpartyId).then((cfg) => {
|
|
1602
|
+
edgeConfig = cfg;
|
|
1603
|
+
}).catch(() => {
|
|
1604
|
+
}).finally(() => {
|
|
1605
|
+
refreshing = false;
|
|
1606
|
+
});
|
|
1607
|
+
};
|
|
1608
|
+
refreshConfig();
|
|
1609
|
+
return (input) => {
|
|
1610
|
+
try {
|
|
1611
|
+
refreshConfig();
|
|
1612
|
+
const cfg = edgeConfig;
|
|
1613
|
+
if (!cfg) return;
|
|
1614
|
+
const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);
|
|
1615
|
+
if (traffic.kind === "never") return;
|
|
1616
|
+
if (traffic.kind === "anonymous-bot" && !sampled(cfg.sampling.anonymousBeaconRate, random)) {
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
const userAgent = readHeader(input.rawHeaders, "user-agent");
|
|
1620
|
+
const xff = input.rawHeaders["x-forwarded-for"];
|
|
1621
|
+
const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
|
|
1622
|
+
const sourceIp = input.sourceIp ?? xffStr?.split(",")[0]?.trim();
|
|
1623
|
+
reportUnregisteredAttempt(config, {
|
|
1624
|
+
...input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl },
|
|
1625
|
+
counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? "api",
|
|
1626
|
+
...sourceIp && { sourceIp },
|
|
1627
|
+
...userAgent && { userAgent },
|
|
1628
|
+
requestPath: input.requestPath,
|
|
1629
|
+
requestMethod: input.requestMethod,
|
|
1630
|
+
...traffic.protocol && { protocol: traffic.protocol },
|
|
1631
|
+
...traffic.evidence && { evidence: traffic.evidence },
|
|
1632
|
+
observedMetadata: buildSdkObservedMetadata(input.rawHeaders)
|
|
1633
|
+
}).catch(() => {
|
|
1634
|
+
});
|
|
1635
|
+
} catch {
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1271
1639
|
|
|
1272
1640
|
// src/adapters/express.ts
|
|
1273
1641
|
function defaultExtractCredentials(req) {
|
|
@@ -1279,7 +1647,7 @@ function defaultExtractCredentials(req) {
|
|
|
1279
1647
|
function extractAstraSyncCredentials(req) {
|
|
1280
1648
|
return extractHttpCredentials(req.headers);
|
|
1281
1649
|
}
|
|
1282
|
-
function
|
|
1650
|
+
function headerValue2(value) {
|
|
1283
1651
|
if (typeof value === "string") return value;
|
|
1284
1652
|
if (Array.isArray(value)) return value[0];
|
|
1285
1653
|
return void 0;
|
|
@@ -1287,9 +1655,9 @@ function headerValue(value) {
|
|
|
1287
1655
|
function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtractAction) {
|
|
1288
1656
|
return resolveHttpPdlss({
|
|
1289
1657
|
method: req.method,
|
|
1290
|
-
astraPurpose:
|
|
1291
|
-
astraAction:
|
|
1292
|
-
legacyPurpose:
|
|
1658
|
+
astraPurpose: headerValue2(req.headers["x-astra-purpose"]),
|
|
1659
|
+
astraAction: headerValue2(req.headers["x-astra-action"]),
|
|
1660
|
+
legacyPurpose: headerValue2(req.headers["x-purpose"] ?? req.headers["X-Purpose"]),
|
|
1293
1661
|
queryPurpose: typeof req.query.purpose === "string" ? req.query.purpose : void 0,
|
|
1294
1662
|
routePurpose: routeConfig?.purpose,
|
|
1295
1663
|
routeAction: routeConfig?.action,
|
|
@@ -1372,6 +1740,11 @@ function defaultOnDenied(result, _req, res) {
|
|
|
1372
1740
|
}
|
|
1373
1741
|
var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
|
|
1374
1742
|
function createMiddleware(options) {
|
|
1743
|
+
if ("routes" in options) {
|
|
1744
|
+
console.warn(
|
|
1745
|
+
"[VerificationGateway] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
|
|
1746
|
+
);
|
|
1747
|
+
}
|
|
1375
1748
|
const {
|
|
1376
1749
|
extractCredentials: customExtractCredentials,
|
|
1377
1750
|
extractPurpose: customExtractPurpose,
|
|
@@ -1383,12 +1756,25 @@ function createMiddleware(options) {
|
|
|
1383
1756
|
routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
|
|
1384
1757
|
failOnError = "open",
|
|
1385
1758
|
caseInsensitiveRouteMatch = false,
|
|
1759
|
+
anonymousBeacon = true,
|
|
1386
1760
|
...config
|
|
1387
1761
|
} = options;
|
|
1388
1762
|
if (config.apiBaseUrl) {
|
|
1389
1763
|
prefetchWellKnown(config.apiBaseUrl).catch(() => {
|
|
1390
1764
|
});
|
|
1391
1765
|
}
|
|
1766
|
+
const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "api" }) : void 0;
|
|
1767
|
+
const beaconPassThrough = emitAnonymousBeacon ? (req) => {
|
|
1768
|
+
const xff = req.headers["x-forwarded-for"];
|
|
1769
|
+
const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
|
|
1770
|
+
emitAnonymousBeacon({
|
|
1771
|
+
requestPath: req.path,
|
|
1772
|
+
requestMethod: req.method,
|
|
1773
|
+
counterpartyUrl: config.counterpartyUrl || `${req.protocol}://${req.get("host")}`,
|
|
1774
|
+
sourceIp: req.ip ?? (xffStr ? xffStr.split(",")[0].trim() : void 0),
|
|
1775
|
+
rawHeaders: req.headers
|
|
1776
|
+
});
|
|
1777
|
+
} : void 0;
|
|
1392
1778
|
let cachedRoutes = [];
|
|
1393
1779
|
let lastFetchAt = 0;
|
|
1394
1780
|
let refreshing = null;
|
|
@@ -1449,6 +1835,7 @@ function createMiddleware(options) {
|
|
|
1449
1835
|
cachedRoutes.length === 0 ? "no-policy" : "no-match"
|
|
1450
1836
|
);
|
|
1451
1837
|
}
|
|
1838
|
+
beaconPassThrough?.(req);
|
|
1452
1839
|
return next();
|
|
1453
1840
|
}
|
|
1454
1841
|
const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
|
|
@@ -1459,6 +1846,7 @@ function createMiddleware(options) {
|
|
|
1459
1846
|
res.setHeader("X-Astra-Gateway-Mode", "unenforced");
|
|
1460
1847
|
res.setHeader("X-Astra-Gateway-Reason", "route-none");
|
|
1461
1848
|
}
|
|
1849
|
+
beaconPassThrough?.(req);
|
|
1462
1850
|
return next();
|
|
1463
1851
|
}
|
|
1464
1852
|
const pdlssPair = resolveRequestPdlss(
|
|
@@ -1551,16 +1939,10 @@ function createMiddleware(options) {
|
|
|
1551
1939
|
forwardedFor: forwardedForStr,
|
|
1552
1940
|
agentCardUrl,
|
|
1553
1941
|
// Workstream D — capture EVERY inbound header (SDK-only merchants
|
|
1554
|
-
// have no edge to do it upstream)
|
|
1555
|
-
// stripped; out of the verify
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
return {
|
|
1559
|
-
headers,
|
|
1560
|
-
...apiKeyFormat && { apiKeyFormat },
|
|
1561
|
-
...platformHeaders && { platformHeaders }
|
|
1562
|
-
};
|
|
1563
|
-
})()
|
|
1942
|
+
// have no edge to do it upstream) plus the CDN-derived connection
|
|
1943
|
+
// block. Local string work, secrets stripped; out of the verify
|
|
1944
|
+
// cache key so it doesn't defeat caching.
|
|
1945
|
+
observedMetadata: buildSdkObservedMetadata(req.headers)
|
|
1564
1946
|
}
|
|
1565
1947
|
};
|
|
1566
1948
|
let result = await verify(config, verificationRequest);
|
|
@@ -1754,7 +2136,7 @@ function resolveNextPdlss(request, routeConfig) {
|
|
|
1754
2136
|
routeAction: routeConfig?.action
|
|
1755
2137
|
});
|
|
1756
2138
|
}
|
|
1757
|
-
function
|
|
2139
|
+
function generateInterstitialHtml(result, options) {
|
|
1758
2140
|
const title = escapeHtml(options.commerceShield?.title || "AstraSync Agent Verification");
|
|
1759
2141
|
const message = escapeHtml(
|
|
1760
2142
|
options.commerceShield?.message || result.guidance?.message || "This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials."
|
|
@@ -1910,13 +2292,31 @@ function generateCommerceShieldHtml(result, options) {
|
|
|
1910
2292
|
}
|
|
1911
2293
|
var DEFAULT_ROUTES_REFRESH_MS2 = 5 * 60 * 1e3;
|
|
1912
2294
|
function createMiddleware2(options) {
|
|
2295
|
+
if ("routes" in options) {
|
|
2296
|
+
console.warn(
|
|
2297
|
+
"[VerificationGateway/Next.js] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
|
|
2298
|
+
);
|
|
2299
|
+
}
|
|
1913
2300
|
const {
|
|
1914
2301
|
skipPaths = [],
|
|
1915
|
-
|
|
2302
|
+
showInterstitial,
|
|
2303
|
+
showCommerceShield,
|
|
1916
2304
|
enableRuntimeChallenge = true,
|
|
1917
2305
|
routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS2,
|
|
2306
|
+
anonymousBeacon = true,
|
|
1918
2307
|
...config
|
|
1919
2308
|
} = options;
|
|
2309
|
+
const interstitialEnabled = showInterstitial ?? showCommerceShield ?? true;
|
|
2310
|
+
const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "website" }) : void 0;
|
|
2311
|
+
const beaconPassThrough = emitAnonymousBeacon ? (request, pathname) => {
|
|
2312
|
+
emitAnonymousBeacon({
|
|
2313
|
+
requestPath: pathname,
|
|
2314
|
+
requestMethod: request.method,
|
|
2315
|
+
counterpartyUrl: config.counterpartyUrl || request.nextUrl.origin,
|
|
2316
|
+
sourceIp: request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || void 0,
|
|
2317
|
+
rawHeaders: Object.fromEntries(request.headers.entries())
|
|
2318
|
+
});
|
|
2319
|
+
} : void 0;
|
|
1920
2320
|
let cachedRoutes = [];
|
|
1921
2321
|
let lastFetchAt = 0;
|
|
1922
2322
|
let refreshing = null;
|
|
@@ -1958,9 +2358,11 @@ function createMiddleware2(options) {
|
|
|
1958
2358
|
}
|
|
1959
2359
|
const routeConfig = findRouteConfig2(cachedRoutes, pathname, request.method);
|
|
1960
2360
|
if (!routeConfig) {
|
|
2361
|
+
beaconPassThrough?.(request, pathname);
|
|
1961
2362
|
return NextResponse.next();
|
|
1962
2363
|
}
|
|
1963
2364
|
if (routeConfig.minAccessLevel === "none") {
|
|
2365
|
+
beaconPassThrough?.(request, pathname);
|
|
1964
2366
|
return NextResponse.next();
|
|
1965
2367
|
}
|
|
1966
2368
|
const credentials = extractCredentialsFromNextRequest(request);
|
|
@@ -2012,8 +2414,8 @@ function createMiddleware2(options) {
|
|
|
2012
2414
|
{ status: 403 }
|
|
2013
2415
|
);
|
|
2014
2416
|
}
|
|
2015
|
-
if (
|
|
2016
|
-
return new NextResponse(
|
|
2417
|
+
if (interstitialEnabled) {
|
|
2418
|
+
return new NextResponse(generateInterstitialHtml(preCheckResult, options), {
|
|
2017
2419
|
status: 200,
|
|
2018
2420
|
headers: {
|
|
2019
2421
|
"Content-Type": "text/html",
|
|
@@ -2041,17 +2443,9 @@ function createMiddleware2(options) {
|
|
|
2041
2443
|
host: request.headers.get("host") || void 0,
|
|
2042
2444
|
forwardedFor,
|
|
2043
2445
|
agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0,
|
|
2044
|
-
// Workstream D — full sanitised header capture
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
Object.fromEntries(request.headers.entries())
|
|
2048
|
-
);
|
|
2049
|
-
return {
|
|
2050
|
-
headers,
|
|
2051
|
-
...apiKeyFormat && { apiKeyFormat },
|
|
2052
|
-
...platformHeaders && { platformHeaders }
|
|
2053
|
-
};
|
|
2054
|
-
})()
|
|
2446
|
+
// Workstream D — full sanitised header capture + CDN-derived
|
|
2447
|
+
// connection block (Web Headers → plain map).
|
|
2448
|
+
observedMetadata: buildSdkObservedMetadata(Object.fromEntries(request.headers.entries()))
|
|
2055
2449
|
}
|
|
2056
2450
|
};
|
|
2057
2451
|
let result = await verify(config, verificationRequest);
|
|
@@ -2106,8 +2500,8 @@ function createMiddleware2(options) {
|
|
|
2106
2500
|
}
|
|
2107
2501
|
);
|
|
2108
2502
|
}
|
|
2109
|
-
if (
|
|
2110
|
-
return new NextResponse(
|
|
2503
|
+
if (interstitialEnabled) {
|
|
2504
|
+
return new NextResponse(generateInterstitialHtml(result, options), {
|
|
2111
2505
|
status: 200,
|
|
2112
2506
|
headers: {
|
|
2113
2507
|
"Content-Type": "text/html",
|
|
@@ -2195,7 +2589,7 @@ var VerificationGatewayClient = class {
|
|
|
2195
2589
|
/**
|
|
2196
2590
|
* Quick verification — checks credentials and policy in one call.
|
|
2197
2591
|
*
|
|
2198
|
-
*
|
|
2592
|
+
* The return shape mirrors `VerificationResult`'s identity/policy
|
|
2199
2593
|
* split. Map to HTTP status the same way: `!identityVerified` → 401,
|
|
2200
2594
|
* `identityVerified && !policyAllowed` → 403.
|
|
2201
2595
|
*/
|
|
@@ -2625,8 +3019,8 @@ function extractX402TransactionValue(req) {
|
|
|
2625
3019
|
// src/transport/rfc9421.ts
|
|
2626
3020
|
import { parseDictionary } from "structured-headers";
|
|
2627
3021
|
function parseRFC9421(headers) {
|
|
2628
|
-
const sigInput =
|
|
2629
|
-
const sig =
|
|
3022
|
+
const sigInput = readHeader2(headers, "signature-input");
|
|
3023
|
+
const sig = readHeader2(headers, "signature");
|
|
2630
3024
|
if (!sigInput || !sig) return null;
|
|
2631
3025
|
let inputDict;
|
|
2632
3026
|
let sigDict;
|
|
@@ -2670,7 +3064,7 @@ function parseRFC9421(headers) {
|
|
|
2670
3064
|
if (signatures.length === 0) return null;
|
|
2671
3065
|
return { signatures };
|
|
2672
3066
|
}
|
|
2673
|
-
function
|
|
3067
|
+
function readHeader2(headers, name) {
|
|
2674
3068
|
for (const key of Object.keys(headers)) {
|
|
2675
3069
|
if (key.toLowerCase() === name) {
|
|
2676
3070
|
const raw = headers[key];
|
|
@@ -2988,11 +3382,11 @@ function extractACPContext(request) {
|
|
|
2988
3382
|
const purpose = mapACPRequestToPurpose(method, path);
|
|
2989
3383
|
const sessionId = extractSessionId2(path);
|
|
2990
3384
|
const headers = request.headers ?? {};
|
|
2991
|
-
const signatureHeader =
|
|
2992
|
-
const timestampHeader =
|
|
2993
|
-
const idempotencyKey =
|
|
2994
|
-
const apiVersion =
|
|
2995
|
-
const bearer = extractBearer(
|
|
3385
|
+
const signatureHeader = readHeader3(headers, "signature");
|
|
3386
|
+
const timestampHeader = readHeader3(headers, "timestamp");
|
|
3387
|
+
const idempotencyKey = readHeader3(headers, "idempotency-key");
|
|
3388
|
+
const apiVersion = readHeader3(headers, "api-version");
|
|
3389
|
+
const bearer = extractBearer(readHeader3(headers, "authorization"));
|
|
2996
3390
|
const body = request.body ?? {};
|
|
2997
3391
|
const merchantId = coerceString3(body.merchant_id ?? body.merchantId);
|
|
2998
3392
|
const totals = Array.isArray(body.totals) ? body.totals : void 0;
|
|
@@ -3060,7 +3454,7 @@ function extractFulfillmentOption(body) {
|
|
|
3060
3454
|
}
|
|
3061
3455
|
return void 0;
|
|
3062
3456
|
}
|
|
3063
|
-
function
|
|
3457
|
+
function readHeader3(headers, name) {
|
|
3064
3458
|
for (const key of Object.keys(headers)) {
|
|
3065
3459
|
if (key.toLowerCase() === name) {
|
|
3066
3460
|
const raw = headers[key];
|
|
@@ -3854,9 +4248,9 @@ function toBuf(bytes) {
|
|
|
3854
4248
|
new Uint8Array(out).set(bytes);
|
|
3855
4249
|
return out;
|
|
3856
4250
|
}
|
|
3857
|
-
function checkTimestamp(
|
|
3858
|
-
if (!
|
|
3859
|
-
const ts = parseTimestamp(
|
|
4251
|
+
function checkTimestamp(headerValue3, toleranceSec, nowFn) {
|
|
4252
|
+
if (!headerValue3) return { ok: false, error: "missing Timestamp header" };
|
|
4253
|
+
const ts = parseTimestamp(headerValue3);
|
|
3860
4254
|
if (ts === null) return { ok: false, error: "unparseable Timestamp header" };
|
|
3861
4255
|
const now = nowFn ? nowFn() : Math.floor(Date.now() / 1e3);
|
|
3862
4256
|
if (Math.abs(now - ts) > toleranceSec) {
|
|
@@ -3900,7 +4294,7 @@ async function getSubtle() {
|
|
|
3900
4294
|
// src/transport/mpp.ts
|
|
3901
4295
|
import { Challenge, Credential, Receipt } from "mppx";
|
|
3902
4296
|
function extractMPPFromRequest(request) {
|
|
3903
|
-
const auth =
|
|
4297
|
+
const auth = readHeader4(request.headers, "authorization");
|
|
3904
4298
|
if (!auth || !/^\s*Payment\s+/i.test(auth)) return null;
|
|
3905
4299
|
try {
|
|
3906
4300
|
const credential = Credential.deserialize(auth);
|
|
@@ -3928,7 +4322,7 @@ function extractMPPFromResponse(response) {
|
|
|
3928
4322
|
offeredMethods: methods
|
|
3929
4323
|
};
|
|
3930
4324
|
}
|
|
3931
|
-
const receiptHeader =
|
|
4325
|
+
const receiptHeader = readHeader4(response.headers, "payment-receipt");
|
|
3932
4326
|
if (receiptHeader) {
|
|
3933
4327
|
try {
|
|
3934
4328
|
const parsed = Receipt.deserialize(receiptHeader);
|
|
@@ -3948,7 +4342,7 @@ function extractMPPFromResponse(response) {
|
|
|
3948
4342
|
return { kind: "error", error: { type: "invalid-receipt-encoding" } };
|
|
3949
4343
|
}
|
|
3950
4344
|
}
|
|
3951
|
-
const contentType =
|
|
4345
|
+
const contentType = readHeader4(response.headers, "content-type");
|
|
3952
4346
|
if (contentType && /application\/problem\+json/i.test(contentType)) {
|
|
3953
4347
|
const body = typeof response.body === "object" && response.body !== null ? response.body : {};
|
|
3954
4348
|
return {
|
|
@@ -3971,7 +4365,7 @@ function extractMPPContext(message) {
|
|
|
3971
4365
|
return extractMPPFromRequest(message);
|
|
3972
4366
|
}
|
|
3973
4367
|
function collectChallenges(response) {
|
|
3974
|
-
const wwwAuth =
|
|
4368
|
+
const wwwAuth = readHeader4(response.headers, "www-authenticate");
|
|
3975
4369
|
if (!wwwAuth) return [];
|
|
3976
4370
|
const headers = new Headers();
|
|
3977
4371
|
headers.set("www-authenticate", wwwAuth);
|
|
@@ -3999,7 +4393,7 @@ function summarizeChallenge(ch) {
|
|
|
3999
4393
|
opaque: raw.opaque
|
|
4000
4394
|
};
|
|
4001
4395
|
}
|
|
4002
|
-
function
|
|
4396
|
+
function readHeader4(headers, name) {
|
|
4003
4397
|
for (const key of Object.keys(headers)) {
|
|
4004
4398
|
if (key.toLowerCase() === name) {
|
|
4005
4399
|
const raw = headers[key];
|
|
@@ -4091,14 +4485,14 @@ import {
|
|
|
4091
4485
|
} from "@x402/core/schemas";
|
|
4092
4486
|
import { safeBase64Decode } from "@x402/core/utils";
|
|
4093
4487
|
function extractX402FromRequest(request) {
|
|
4094
|
-
const
|
|
4488
|
+
const headerValue3 = readHeader5(request.headers, "x-payment");
|
|
4095
4489
|
if (request.body && typeof request.body === "object") {
|
|
4096
4490
|
const parsed = tryParsePayload(request.body);
|
|
4097
4491
|
if (parsed) return buildPayloadContext(parsed, "body");
|
|
4098
4492
|
}
|
|
4099
|
-
if (
|
|
4493
|
+
if (headerValue3) {
|
|
4100
4494
|
try {
|
|
4101
|
-
const decoded = safeBase64Decode(
|
|
4495
|
+
const decoded = safeBase64Decode(headerValue3);
|
|
4102
4496
|
if (decoded) {
|
|
4103
4497
|
const json = JSON.parse(decoded);
|
|
4104
4498
|
const parsed = tryParsePayload(json);
|
|
@@ -4121,10 +4515,10 @@ function extractX402FromResponse(response) {
|
|
|
4121
4515
|
const parsed = tryParseRequired(response.body);
|
|
4122
4516
|
if (parsed) return buildRequiredContext(parsed, "body");
|
|
4123
4517
|
}
|
|
4124
|
-
const
|
|
4125
|
-
if (
|
|
4518
|
+
const headerValue3 = readHeader5(response.headers, "x-payment-required");
|
|
4519
|
+
if (headerValue3) {
|
|
4126
4520
|
try {
|
|
4127
|
-
const decoded = safeBase64Decode(
|
|
4521
|
+
const decoded = safeBase64Decode(headerValue3);
|
|
4128
4522
|
if (decoded) {
|
|
4129
4523
|
const json = JSON.parse(decoded);
|
|
4130
4524
|
const parsed = tryParseRequired(json);
|
|
@@ -4221,7 +4615,7 @@ function coerceVersion(v) {
|
|
|
4221
4615
|
if (v === 1 || v === 2) return v;
|
|
4222
4616
|
return null;
|
|
4223
4617
|
}
|
|
4224
|
-
function
|
|
4618
|
+
function readHeader5(headers, name) {
|
|
4225
4619
|
if (!headers) return void 0;
|
|
4226
4620
|
for (const key of Object.keys(headers)) {
|
|
4227
4621
|
if (key.toLowerCase() === name) {
|
|
@@ -4969,8 +5363,11 @@ function mcpToPdlss(parsed, requestPath, headerPurpose, headerAction, toolGate)
|
|
|
4969
5363
|
} else if (parsed.actionFromBody && parsed.actionSourceFromBody) {
|
|
4970
5364
|
action = parsed.actionFromBody;
|
|
4971
5365
|
actionSource = parsed.actionSourceFromBody;
|
|
5366
|
+
} else if (parsed.method === "tools/call") {
|
|
5367
|
+
action = void 0;
|
|
5368
|
+
actionSource = void 0;
|
|
4972
5369
|
} else {
|
|
4973
|
-
action = parsed.toolName ?
|
|
5370
|
+
action = parsed.toolName ? `${parsed.method}:${parsed.toolName}` : parsed.method;
|
|
4974
5371
|
actionSource = "transport_layer";
|
|
4975
5372
|
}
|
|
4976
5373
|
return { purpose, action, resource, purposeSource, actionSource };
|
|
@@ -5085,6 +5482,15 @@ function createMcpMiddleware(options) {
|
|
|
5085
5482
|
prefetchWellKnown(config.apiBaseUrl).catch(() => {
|
|
5086
5483
|
});
|
|
5087
5484
|
}
|
|
5485
|
+
if (toolGates) {
|
|
5486
|
+
for (const [toolName, gate] of Object.entries(toolGates)) {
|
|
5487
|
+
if (typeof gate === "string") {
|
|
5488
|
+
console.warn(
|
|
5489
|
+
`[VerificationGateway/MCP] toolGates['${toolName}'] uses the bare-string shorthand ('${gate}'). Gated tools need a PDLSS purpose (else PDLSS_PURPOSE_REQUIRED 400) and evaluate purpose-only without a declared action. Use the object form instead: { minAccessLevel: '${gate}', purpose: '...', action: '...' }.`
|
|
5490
|
+
);
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5088
5494
|
return async (req, res, next) => {
|
|
5089
5495
|
try {
|
|
5090
5496
|
if (skip) return next();
|
|
@@ -5204,7 +5610,13 @@ function createMcpMiddleware(options) {
|
|
|
5204
5610
|
callerMetadata: {
|
|
5205
5611
|
sourceIp: req.ip,
|
|
5206
5612
|
userAgent: req.headers["user-agent"],
|
|
5207
|
-
host: req.headers.host
|
|
5613
|
+
host: req.headers.host,
|
|
5614
|
+
// Capture EVERY inbound header (parity with the express adapter —
|
|
5615
|
+
// MCP-only merchants have no edge to do it upstream) plus the
|
|
5616
|
+
// CDN-derived connection block. Local string work, secrets
|
|
5617
|
+
// stripped; out of the verify cache key so it doesn't defeat
|
|
5618
|
+
// caching.
|
|
5619
|
+
observedMetadata: buildSdkObservedMetadata(req.headers)
|
|
5208
5620
|
}
|
|
5209
5621
|
};
|
|
5210
5622
|
let result = await verify(config, verificationRequest);
|
|
@@ -5989,212 +6401,6 @@ async function recordDecision2(config, params) {
|
|
|
5989
6401
|
blockchainTxHash: result.blockchainTxHash
|
|
5990
6402
|
};
|
|
5991
6403
|
}
|
|
5992
|
-
|
|
5993
|
-
// src/edge-config.ts
|
|
5994
|
-
var DEFAULT_EDGE_CONFIG = Object.freeze({
|
|
5995
|
-
version: 1,
|
|
5996
|
-
mode: "observe",
|
|
5997
|
-
depth: "classify",
|
|
5998
|
-
pathRules: [],
|
|
5999
|
-
sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
|
|
6000
|
-
failurePosture: "open"
|
|
6001
|
-
});
|
|
6002
|
-
var EDGE_MODES = ["observe", "enforce"];
|
|
6003
|
-
var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
|
|
6004
|
-
function isEdgeConfig(value) {
|
|
6005
|
-
if (typeof value !== "object" || value === null) return false;
|
|
6006
|
-
const v = value;
|
|
6007
|
-
if (v.version !== 1) return false;
|
|
6008
|
-
if (!EDGE_MODES.includes(v.mode)) return false;
|
|
6009
|
-
if (!EDGE_DEPTHS.includes(v.depth)) return false;
|
|
6010
|
-
if (!Array.isArray(v.pathRules)) return false;
|
|
6011
|
-
for (const rule of v.pathRules) {
|
|
6012
|
-
if (typeof rule !== "object" || rule === null) return false;
|
|
6013
|
-
const r = rule;
|
|
6014
|
-
if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
|
|
6015
|
-
if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
|
|
6016
|
-
if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
|
|
6017
|
-
}
|
|
6018
|
-
const sampling = v.sampling;
|
|
6019
|
-
if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
|
|
6020
|
-
return false;
|
|
6021
|
-
}
|
|
6022
|
-
return v.failurePosture === "open";
|
|
6023
|
-
}
|
|
6024
|
-
async function fetchEdgeConfig(config, counterpartyId, opts) {
|
|
6025
|
-
if (!counterpartyId) return null;
|
|
6026
|
-
const headers = { Accept: "application/json" };
|
|
6027
|
-
if (config.apiKey) {
|
|
6028
|
-
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
6029
|
-
headers["X-API-Key"] = config.apiKey;
|
|
6030
|
-
}
|
|
6031
|
-
if (opts?.etag) headers["If-None-Match"] = opts.etag;
|
|
6032
|
-
try {
|
|
6033
|
-
const response = await fetch(
|
|
6034
|
-
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
|
|
6035
|
-
{ method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
|
|
6036
|
-
);
|
|
6037
|
-
if (response.status === 304) return { notModified: true };
|
|
6038
|
-
if (!response.ok) return null;
|
|
6039
|
-
const body = await response.json();
|
|
6040
|
-
const edgeConfig = body.data?.edgeConfig;
|
|
6041
|
-
if (!isEdgeConfig(edgeConfig)) return null;
|
|
6042
|
-
return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
|
|
6043
|
-
} catch {
|
|
6044
|
-
return null;
|
|
6045
|
-
}
|
|
6046
|
-
}
|
|
6047
|
-
var DEFAULT_TTL_MS = 60 * 1e3;
|
|
6048
|
-
var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
|
|
6049
|
-
var cache2 = /* @__PURE__ */ new Map();
|
|
6050
|
-
var inflight2 = /* @__PURE__ */ new Map();
|
|
6051
|
-
function cacheKey(apiBaseUrl, counterpartyId) {
|
|
6052
|
-
return `${apiBaseUrl}|${counterpartyId}`;
|
|
6053
|
-
}
|
|
6054
|
-
function degradeToObserve(config) {
|
|
6055
|
-
if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
|
|
6056
|
-
return config;
|
|
6057
|
-
}
|
|
6058
|
-
return {
|
|
6059
|
-
...config,
|
|
6060
|
-
mode: "observe",
|
|
6061
|
-
pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
|
|
6062
|
-
};
|
|
6063
|
-
}
|
|
6064
|
-
async function revalidate(config, counterpartyId) {
|
|
6065
|
-
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
6066
|
-
const existing = inflight2.get(key);
|
|
6067
|
-
if (existing) return existing;
|
|
6068
|
-
const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
|
|
6069
|
-
if (result === null) return;
|
|
6070
|
-
const now = Date.now();
|
|
6071
|
-
if ("notModified" in result) {
|
|
6072
|
-
const entry = cache2.get(key);
|
|
6073
|
-
if (entry) entry.lastSuccessAt = now;
|
|
6074
|
-
return;
|
|
6075
|
-
}
|
|
6076
|
-
cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
|
|
6077
|
-
}).finally(() => {
|
|
6078
|
-
inflight2.delete(key);
|
|
6079
|
-
});
|
|
6080
|
-
inflight2.set(key, promise);
|
|
6081
|
-
return promise;
|
|
6082
|
-
}
|
|
6083
|
-
async function getEdgeConfig(config, counterpartyId, opts) {
|
|
6084
|
-
const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
|
|
6085
|
-
const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
|
|
6086
|
-
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
6087
|
-
const entry = cache2.get(key);
|
|
6088
|
-
if (entry) {
|
|
6089
|
-
const age = Date.now() - entry.lastSuccessAt;
|
|
6090
|
-
if (age > ttlMs) {
|
|
6091
|
-
revalidate(config, counterpartyId).catch(() => {
|
|
6092
|
-
});
|
|
6093
|
-
}
|
|
6094
|
-
return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
|
|
6095
|
-
}
|
|
6096
|
-
await revalidate(config, counterpartyId).catch(() => {
|
|
6097
|
-
});
|
|
6098
|
-
return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
|
|
6099
|
-
}
|
|
6100
|
-
function matchEdgePathRule(rules, path) {
|
|
6101
|
-
for (const rule of rules) {
|
|
6102
|
-
if (globToRegExp(rule.pattern).test(path)) return rule;
|
|
6103
|
-
}
|
|
6104
|
-
return void 0;
|
|
6105
|
-
}
|
|
6106
|
-
function globToRegExp(pattern) {
|
|
6107
|
-
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
6108
|
-
return new RegExp(`^${escaped}$`, "i");
|
|
6109
|
-
}
|
|
6110
|
-
function _resetEdgeConfigCache() {
|
|
6111
|
-
cache2.clear();
|
|
6112
|
-
inflight2.clear();
|
|
6113
|
-
}
|
|
6114
|
-
|
|
6115
|
-
// src/platform-signatures.ts
|
|
6116
|
-
var PLATFORM_AGENT_SIGNATURES = [
|
|
6117
|
-
{
|
|
6118
|
-
vendor: "claude",
|
|
6119
|
-
displayName: "Anthropic Claude",
|
|
6120
|
-
uaPatterns: [/claude/i, /anthropic/i],
|
|
6121
|
-
agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
|
|
6122
|
-
apiKeyFormatPatterns: [/^sk-ant/i],
|
|
6123
|
-
headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
|
|
6124
|
-
},
|
|
6125
|
-
{
|
|
6126
|
-
vendor: "chatgpt",
|
|
6127
|
-
displayName: "OpenAI ChatGPT",
|
|
6128
|
-
uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
|
|
6129
|
-
agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
|
|
6130
|
-
apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
|
|
6131
|
-
headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
|
|
6132
|
-
},
|
|
6133
|
-
{
|
|
6134
|
-
vendor: "gemini",
|
|
6135
|
-
displayName: "Google Gemini",
|
|
6136
|
-
uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
|
|
6137
|
-
agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
|
|
6138
|
-
apiKeyFormatPatterns: [/^aiza/i],
|
|
6139
|
-
headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
|
|
6140
|
-
},
|
|
6141
|
-
{
|
|
6142
|
-
vendor: "cursor",
|
|
6143
|
-
displayName: "Cursor",
|
|
6144
|
-
uaPatterns: [/cursor/i],
|
|
6145
|
-
agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
|
|
6146
|
-
},
|
|
6147
|
-
{
|
|
6148
|
-
vendor: "goose",
|
|
6149
|
-
displayName: "Block Goose",
|
|
6150
|
-
uaPatterns: [/goose/i, /block-goose/i],
|
|
6151
|
-
agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
|
|
6152
|
-
},
|
|
6153
|
-
{
|
|
6154
|
-
vendor: "perplexity",
|
|
6155
|
-
displayName: "Perplexity",
|
|
6156
|
-
uaPatterns: [/perplexity/i],
|
|
6157
|
-
agentCardPatterns: [/perplexity\.ai/i],
|
|
6158
|
-
apiKeyFormatPatterns: [/^pplx-/i]
|
|
6159
|
-
}
|
|
6160
|
-
];
|
|
6161
|
-
function matchPlatformSignature(signatures, input) {
|
|
6162
|
-
const ua = input.userAgent ?? "";
|
|
6163
|
-
const cardUrl = input.agentCardUrl ?? "";
|
|
6164
|
-
const apiKeyFormat = input.apiKeyFormat ?? "";
|
|
6165
|
-
const headerLines = [];
|
|
6166
|
-
if (input.platformHeaders) {
|
|
6167
|
-
for (const [name, value] of Object.entries(input.platformHeaders)) {
|
|
6168
|
-
headerLines.push(name, `${name}: ${value}`);
|
|
6169
|
-
}
|
|
6170
|
-
}
|
|
6171
|
-
for (const sig of signatures) {
|
|
6172
|
-
const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
|
|
6173
|
-
const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
|
|
6174
|
-
const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
|
|
6175
|
-
const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
|
|
6176
|
-
if (uaMatch || cardMatch || keyMatch || headerMatch) {
|
|
6177
|
-
const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
|
|
6178
|
-
const cardHost = (() => {
|
|
6179
|
-
try {
|
|
6180
|
-
return cardUrl ? new URL(cardUrl).host : "";
|
|
6181
|
-
} catch {
|
|
6182
|
-
return "";
|
|
6183
|
-
}
|
|
6184
|
-
})();
|
|
6185
|
-
const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
|
|
6186
|
-
return {
|
|
6187
|
-
vendor: sig.vendor,
|
|
6188
|
-
fingerprintKey: `${sig.vendor}:${keyBasis}`,
|
|
6189
|
-
displayName: sig.displayName
|
|
6190
|
-
};
|
|
6191
|
-
}
|
|
6192
|
-
}
|
|
6193
|
-
return void 0;
|
|
6194
|
-
}
|
|
6195
|
-
function detectPlatformFingerprint(input) {
|
|
6196
|
-
return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
|
|
6197
|
-
}
|
|
6198
6404
|
export {
|
|
6199
6405
|
ACCESS_LEVEL_DESCRIPTIONS,
|
|
6200
6406
|
ACCESS_LEVEL_HIERARCHY,
|
|
@@ -6202,6 +6408,7 @@ export {
|
|
|
6202
6408
|
AstraSync,
|
|
6203
6409
|
AstraSyncError,
|
|
6204
6410
|
AuthenticationError,
|
|
6411
|
+
CAPTURE_SCHEMA_VERSION,
|
|
6205
6412
|
ChallengeHandler,
|
|
6206
6413
|
DEFAULT_EDGE_CONFIG,
|
|
6207
6414
|
DEFAULT_TRUST_THRESHOLDS,
|
|
@@ -6220,9 +6427,11 @@ export {
|
|
|
6220
6427
|
authorizeSettlement,
|
|
6221
6428
|
awaitStepUpApproval,
|
|
6222
6429
|
buildGuidance,
|
|
6430
|
+
buildSdkObservedMetadata,
|
|
6223
6431
|
clearCache,
|
|
6224
6432
|
createMcpMiddleware,
|
|
6225
6433
|
degradeToObserve,
|
|
6434
|
+
deriveConnectionFromHeaders,
|
|
6226
6435
|
detectPlatformFingerprint,
|
|
6227
6436
|
determineAccessLevel,
|
|
6228
6437
|
express_exports as express,
|