@astrasyncai/verification-gateway 3.12.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 +482 -22
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +482 -22
- 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 +309 -10
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +309 -10
- 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 +518 -25
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +518 -25
- 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 +72 -9
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +72 -9
- 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 +83 -20
- package/dist/bin/astrasync-codex-hook.js +83 -20
- package/dist/bin/astrasync-guard.js +83 -20
- package/dist/bin/astrasync.js +150 -33
- package/dist/browser/background.js +83 -20
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +83 -20
- 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 +83 -20
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +83 -20
- 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 +83 -20
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +83 -20
- 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-B39o89gf.d.mts → express-BVd1_3FE.d.ts} +9 -7
- package/dist/{express-BuxKNO_q.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 +83 -20
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +83 -20
- 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-CLHdqs2M.d.ts → index-B0YHu_SP.d.ts} +30 -27
- package/dist/{index-DME3w3lf.d.mts → index-BPEBlOsE.d.mts} +30 -27
- package/dist/{index-CqydB4ks.d.mts → index-DQb5-_1X.d.mts} +1 -1
- package/dist/{index-BG62SXso.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 +595 -272
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +592 -272
- 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-D74W7wt-.d.mts → nextjs-WyeVr2Kp.d.mts} +3 -3
- package/dist/{nextjs-Ddlw_J1J.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-CT7gdkfR.d.ts → sdk-CbTNIkAa.d.mts} +4 -4
- package/dist/{sdk-Bn6bj7kt.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-DHu7m9HI.d.ts → types-BLUx92FJ.d.ts} +1 -1
- package/dist/{types-Djw4GLtz.d.mts → types-DqfPU5Bl.d.mts} +1 -1
- package/dist/{types-BntuzEEn.d.mts → types-r850cOt0.d.mts} +121 -88
- package/dist/{types-SDu4Llbe.d.ts → types-sMxBT-nM.d.ts} +121 -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 +11 -8
- package/dist/verify.d.ts +11 -8
- package/dist/verify.js +76 -8
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +75 -8
- package/dist/verify.mjs.map +1 -1
- package/package.json +8 -2
|
@@ -65,7 +65,7 @@ function getTrustLevel(score) {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// src/version.ts
|
|
68
|
-
var SDK_VERSION = "
|
|
68
|
+
var SDK_VERSION = "4.1.0";
|
|
69
69
|
|
|
70
70
|
// src/well-known.ts
|
|
71
71
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -143,7 +143,7 @@ var DEFAULT_CONFIG = {
|
|
|
143
143
|
};
|
|
144
144
|
var initCheckPerformed = false;
|
|
145
145
|
var deprecationWarningShown = false;
|
|
146
|
-
async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
146
|
+
async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
147
147
|
initCheckPerformed = true;
|
|
148
148
|
try {
|
|
149
149
|
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
@@ -160,6 +160,28 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
|
160
160
|
`[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
|
|
161
161
|
);
|
|
162
162
|
}
|
|
163
|
+
if (apiKey) {
|
|
164
|
+
const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
|
|
165
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
166
|
+
});
|
|
167
|
+
if (selfCheck.status === 401) {
|
|
168
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
169
|
+
const message = `[VerificationGateway] the configured AstraSync API key was REJECTED at startup (${body.code ?? "api_key_invalid"}: ${body.message ?? "invalid key"}). Every inbound agent will be turned away until the key is rotated` + (body.remediation?.manageUrl ? ` at ${body.remediation.manageUrl}` : "") + `.`;
|
|
170
|
+
if (strictInit) {
|
|
171
|
+
throw new Error(`${message} (strictInit=true)`);
|
|
172
|
+
}
|
|
173
|
+
console.error(message);
|
|
174
|
+
} else if (selfCheck.ok) {
|
|
175
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
176
|
+
if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
|
|
177
|
+
console.warn(
|
|
178
|
+
`[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
|
|
179
|
+
);
|
|
180
|
+
} else if (debug) {
|
|
181
|
+
console.log("[VerificationGateway] API key self-check passed");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
163
185
|
} catch (err) {
|
|
164
186
|
if (strictInit) {
|
|
165
187
|
throw err;
|
|
@@ -271,8 +293,17 @@ function extractCredentials(headers, query) {
|
|
|
271
293
|
function createGuidanceResponse(_config, reason, options = {}) {
|
|
272
294
|
const source = options.source ?? "no_credentials";
|
|
273
295
|
const isApiError = source === "api_error";
|
|
296
|
+
const isMisconfig = source === "merchant_misconfig";
|
|
274
297
|
const urls = options.urls;
|
|
275
|
-
const guidance =
|
|
298
|
+
const guidance = isMisconfig ? {
|
|
299
|
+
message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, or rotated). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
|
|
300
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
301
|
+
documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
|
|
302
|
+
steps: [
|
|
303
|
+
"Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
|
|
304
|
+
"Do not retry: the failure is deterministic until the operator updates their key"
|
|
305
|
+
]
|
|
306
|
+
} : isApiError ? {
|
|
276
307
|
message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
|
|
277
308
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
278
309
|
documentationUrl: urls?.documentationUrl ?? "",
|
|
@@ -310,13 +341,22 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
310
341
|
// partners (and their custom onDenied handlers) can branch on
|
|
311
342
|
// dimension. Without this, the synthesised stub was indistinguishable
|
|
312
343
|
// from a real policy deny.
|
|
313
|
-
failures:
|
|
344
|
+
failures: isMisconfig ? [
|
|
345
|
+
{
|
|
346
|
+
dimension: "verify_access.merchant_misconfigured",
|
|
347
|
+
message: reason ?? "The integration API key was rejected by AstraSync",
|
|
348
|
+
guidance: guidance.message
|
|
349
|
+
}
|
|
350
|
+
] : isApiError ? [
|
|
314
351
|
{
|
|
315
352
|
dimension: "verify_access.api_error",
|
|
316
353
|
message: reason ?? "Verification temporarily unavailable",
|
|
317
354
|
guidance: guidance.message
|
|
318
355
|
}
|
|
319
356
|
] : void 0,
|
|
357
|
+
// 4.0.0: typed marker so adapters render the misconfig envelope (503 +
|
|
358
|
+
// MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
|
|
359
|
+
...isMisconfig && { misconfigured: true },
|
|
320
360
|
correlationId: options.correlationId,
|
|
321
361
|
attemptId: options.attemptId,
|
|
322
362
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
@@ -371,7 +411,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
371
411
|
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
372
412
|
method: "POST",
|
|
373
413
|
headers,
|
|
374
|
-
body: JSON.stringify(body)
|
|
414
|
+
body: JSON.stringify(body),
|
|
415
|
+
signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
|
|
375
416
|
});
|
|
376
417
|
const data = await response.json();
|
|
377
418
|
if (response.status === 410) {
|
|
@@ -395,6 +436,17 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
395
436
|
};
|
|
396
437
|
}
|
|
397
438
|
if (!response.ok) {
|
|
439
|
+
if (response.status === 401) {
|
|
440
|
+
return {
|
|
441
|
+
success: false,
|
|
442
|
+
error: data.message || data.error || "Integration API key rejected",
|
|
443
|
+
misconfig: true,
|
|
444
|
+
misconfigCode: typeof data?.code === "string" ? data.code : void 0,
|
|
445
|
+
remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
|
|
446
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
447
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
448
|
+
};
|
|
449
|
+
}
|
|
398
450
|
return {
|
|
399
451
|
success: false,
|
|
400
452
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
@@ -416,9 +468,19 @@ async function verify(config, request, options) {
|
|
|
416
468
|
const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
|
|
417
469
|
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
418
470
|
if (mergedConfig.strictInit) {
|
|
419
|
-
await performInitCheck(
|
|
471
|
+
await performInitCheck(
|
|
472
|
+
mergedConfig.apiBaseUrl,
|
|
473
|
+
mergedConfig.debug,
|
|
474
|
+
true,
|
|
475
|
+
mergedConfig.apiKey
|
|
476
|
+
);
|
|
420
477
|
} else {
|
|
421
|
-
void performInitCheck(
|
|
478
|
+
void performInitCheck(
|
|
479
|
+
mergedConfig.apiBaseUrl,
|
|
480
|
+
mergedConfig.debug,
|
|
481
|
+
false,
|
|
482
|
+
mergedConfig.apiKey
|
|
483
|
+
);
|
|
422
484
|
}
|
|
423
485
|
}
|
|
424
486
|
if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
|
|
@@ -457,9 +519,10 @@ async function verify(config, request, options) {
|
|
|
457
519
|
const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
|
|
458
520
|
if (!apiResponse.success) {
|
|
459
521
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
460
|
-
source: "api_error",
|
|
522
|
+
source: apiResponse.misconfig ? "merchant_misconfig" : "api_error",
|
|
461
523
|
correlationId: apiResponse.correlationId,
|
|
462
524
|
attemptId: apiResponse.attemptId,
|
|
525
|
+
remediation: apiResponse.remediation,
|
|
463
526
|
urls
|
|
464
527
|
});
|
|
465
528
|
}
|
|
@@ -614,6 +677,21 @@ async function fetchRoutes(config, counterpartyId) {
|
|
|
614
677
|
return null;
|
|
615
678
|
}
|
|
616
679
|
}
|
|
680
|
+
async function reportUnregisteredAttempt(config, data) {
|
|
681
|
+
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
682
|
+
const { counterpartyUrl, ...rest } = data;
|
|
683
|
+
const body = {
|
|
684
|
+
...rest,
|
|
685
|
+
...counterpartyUrl && { counterpartyUrl },
|
|
686
|
+
...config.counterpartyId && { counterpartyId: config.counterpartyId }
|
|
687
|
+
};
|
|
688
|
+
await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
|
|
689
|
+
method: "POST",
|
|
690
|
+
headers: { "Content-Type": "application/json" },
|
|
691
|
+
body: JSON.stringify(body)
|
|
692
|
+
}).catch(() => {
|
|
693
|
+
});
|
|
694
|
+
}
|
|
617
695
|
async function reportCounterpartyPreCheckFailure(config, data) {
|
|
618
696
|
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
619
697
|
await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
|
|
@@ -811,6 +889,7 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
|
|
|
811
889
|
}
|
|
812
890
|
|
|
813
891
|
// src/metadata-capture.ts
|
|
892
|
+
var CAPTURE_SCHEMA_VERSION = 1;
|
|
814
893
|
var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
815
894
|
"cookie",
|
|
816
895
|
"set-cookie",
|
|
@@ -947,6 +1026,359 @@ function sanitizeHeaders(raw) {
|
|
|
947
1026
|
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
948
1027
|
return result;
|
|
949
1028
|
}
|
|
1029
|
+
var CONNECTION_HEADER_SOURCES = [
|
|
1030
|
+
["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
|
|
1031
|
+
[
|
|
1032
|
+
"country",
|
|
1033
|
+
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
1034
|
+
],
|
|
1035
|
+
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
1036
|
+
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
1037
|
+
["asn", ["cloudfront-viewer-asn"]],
|
|
1038
|
+
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
1039
|
+
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
1040
|
+
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
1041
|
+
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
1042
|
+
// connection-layer truth — normalising them here is the permanent design.
|
|
1043
|
+
["tlsFingerprint", ["cf-ja3-hash"]],
|
|
1044
|
+
["ja4", ["cf-ja4"]]
|
|
1045
|
+
];
|
|
1046
|
+
function deriveConnectionFromHeaders(headers) {
|
|
1047
|
+
if (!headers) return void 0;
|
|
1048
|
+
const lower = {};
|
|
1049
|
+
for (const name of Object.keys(headers)) {
|
|
1050
|
+
const value = headers[name];
|
|
1051
|
+
if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
|
|
1052
|
+
}
|
|
1053
|
+
const connection = {};
|
|
1054
|
+
for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
|
|
1055
|
+
for (const source of sources) {
|
|
1056
|
+
const value = lower[source]?.trim();
|
|
1057
|
+
if (value) {
|
|
1058
|
+
connection[key] = value;
|
|
1059
|
+
break;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if (!connection.ip) {
|
|
1064
|
+
const xff = lower["x-forwarded-for"];
|
|
1065
|
+
const client = xff?.split(",")[0]?.trim();
|
|
1066
|
+
if (client) connection.ip = client;
|
|
1067
|
+
}
|
|
1068
|
+
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
1069
|
+
}
|
|
1070
|
+
function buildSdkObservedMetadata(rawHeaders) {
|
|
1071
|
+
const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
1072
|
+
const flat = {};
|
|
1073
|
+
if (rawHeaders) {
|
|
1074
|
+
for (const name of Object.keys(rawHeaders)) {
|
|
1075
|
+
const value = rawHeaders[name];
|
|
1076
|
+
if (value === void 0) continue;
|
|
1077
|
+
flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
const connection = deriveConnectionFromHeaders(flat);
|
|
1081
|
+
return {
|
|
1082
|
+
headers,
|
|
1083
|
+
...apiKeyFormat && { apiKeyFormat },
|
|
1084
|
+
...platformHeaders && { platformHeaders },
|
|
1085
|
+
...connection && { connection },
|
|
1086
|
+
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
// src/edge-config.ts
|
|
1091
|
+
var DEFAULT_EDGE_CONFIG = Object.freeze({
|
|
1092
|
+
version: 1,
|
|
1093
|
+
mode: "observe",
|
|
1094
|
+
depth: "classify",
|
|
1095
|
+
pathRules: [],
|
|
1096
|
+
sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
|
|
1097
|
+
failurePosture: "open"
|
|
1098
|
+
});
|
|
1099
|
+
var EDGE_MODES = ["observe", "enforce"];
|
|
1100
|
+
var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
|
|
1101
|
+
function isEdgeConfig(value) {
|
|
1102
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1103
|
+
const v = value;
|
|
1104
|
+
if (v.version !== 1) return false;
|
|
1105
|
+
if (!EDGE_MODES.includes(v.mode)) return false;
|
|
1106
|
+
if (!EDGE_DEPTHS.includes(v.depth)) return false;
|
|
1107
|
+
if (!Array.isArray(v.pathRules)) return false;
|
|
1108
|
+
for (const rule of v.pathRules) {
|
|
1109
|
+
if (typeof rule !== "object" || rule === null) return false;
|
|
1110
|
+
const r = rule;
|
|
1111
|
+
if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
|
|
1112
|
+
if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
|
|
1113
|
+
if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
|
|
1114
|
+
}
|
|
1115
|
+
const sampling = v.sampling;
|
|
1116
|
+
if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
|
|
1117
|
+
return false;
|
|
1118
|
+
}
|
|
1119
|
+
return v.failurePosture === "open";
|
|
1120
|
+
}
|
|
1121
|
+
async function fetchEdgeConfig(config, counterpartyId, opts) {
|
|
1122
|
+
if (!counterpartyId) return null;
|
|
1123
|
+
const headers = { Accept: "application/json" };
|
|
1124
|
+
if (config.apiKey) {
|
|
1125
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
1126
|
+
headers["X-API-Key"] = config.apiKey;
|
|
1127
|
+
}
|
|
1128
|
+
if (opts?.etag) headers["If-None-Match"] = opts.etag;
|
|
1129
|
+
try {
|
|
1130
|
+
const response = await fetch(
|
|
1131
|
+
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
|
|
1132
|
+
{ method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
|
|
1133
|
+
);
|
|
1134
|
+
if (response.status === 304) return { notModified: true };
|
|
1135
|
+
if (!response.ok) return null;
|
|
1136
|
+
const body = await response.json();
|
|
1137
|
+
const edgeConfig = body.data?.edgeConfig;
|
|
1138
|
+
if (!isEdgeConfig(edgeConfig)) return null;
|
|
1139
|
+
return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
|
|
1140
|
+
} catch {
|
|
1141
|
+
return null;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
var DEFAULT_TTL_MS = 60 * 1e3;
|
|
1145
|
+
var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
|
|
1146
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
1147
|
+
var inflight2 = /* @__PURE__ */ new Map();
|
|
1148
|
+
function cacheKey(apiBaseUrl, counterpartyId) {
|
|
1149
|
+
return `${apiBaseUrl}|${counterpartyId}`;
|
|
1150
|
+
}
|
|
1151
|
+
function degradeToObserve(config) {
|
|
1152
|
+
if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
|
|
1153
|
+
return config;
|
|
1154
|
+
}
|
|
1155
|
+
return {
|
|
1156
|
+
...config,
|
|
1157
|
+
mode: "observe",
|
|
1158
|
+
pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
async function revalidate(config, counterpartyId) {
|
|
1162
|
+
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
1163
|
+
const existing = inflight2.get(key);
|
|
1164
|
+
if (existing) return existing;
|
|
1165
|
+
const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
|
|
1166
|
+
if (result === null) return;
|
|
1167
|
+
const now = Date.now();
|
|
1168
|
+
if ("notModified" in result) {
|
|
1169
|
+
const entry = cache2.get(key);
|
|
1170
|
+
if (entry) entry.lastSuccessAt = now;
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
|
|
1174
|
+
}).finally(() => {
|
|
1175
|
+
inflight2.delete(key);
|
|
1176
|
+
});
|
|
1177
|
+
inflight2.set(key, promise);
|
|
1178
|
+
return promise;
|
|
1179
|
+
}
|
|
1180
|
+
async function getEdgeConfig(config, counterpartyId, opts) {
|
|
1181
|
+
const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
|
|
1182
|
+
const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
|
|
1183
|
+
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
1184
|
+
const entry = cache2.get(key);
|
|
1185
|
+
if (entry) {
|
|
1186
|
+
const age = Date.now() - entry.lastSuccessAt;
|
|
1187
|
+
if (age > ttlMs) {
|
|
1188
|
+
revalidate(config, counterpartyId).catch(() => {
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
|
|
1192
|
+
}
|
|
1193
|
+
await revalidate(config, counterpartyId).catch(() => {
|
|
1194
|
+
});
|
|
1195
|
+
return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// src/platform-signatures.ts
|
|
1199
|
+
var PLATFORM_AGENT_SIGNATURES = [
|
|
1200
|
+
{
|
|
1201
|
+
vendor: "claude",
|
|
1202
|
+
displayName: "Anthropic Claude",
|
|
1203
|
+
uaPatterns: [/claude/i, /anthropic/i],
|
|
1204
|
+
agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
|
|
1205
|
+
apiKeyFormatPatterns: [/^sk-ant/i],
|
|
1206
|
+
headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
|
|
1207
|
+
},
|
|
1208
|
+
{
|
|
1209
|
+
vendor: "chatgpt",
|
|
1210
|
+
displayName: "OpenAI ChatGPT",
|
|
1211
|
+
uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
|
|
1212
|
+
agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
|
|
1213
|
+
apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
|
|
1214
|
+
headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
|
|
1215
|
+
},
|
|
1216
|
+
{
|
|
1217
|
+
vendor: "gemini",
|
|
1218
|
+
displayName: "Google Gemini",
|
|
1219
|
+
uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
|
|
1220
|
+
agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
|
|
1221
|
+
apiKeyFormatPatterns: [/^aiza/i],
|
|
1222
|
+
headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
|
|
1223
|
+
},
|
|
1224
|
+
{
|
|
1225
|
+
vendor: "cursor",
|
|
1226
|
+
displayName: "Cursor",
|
|
1227
|
+
uaPatterns: [/cursor/i],
|
|
1228
|
+
agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
vendor: "goose",
|
|
1232
|
+
displayName: "Block Goose",
|
|
1233
|
+
uaPatterns: [/goose/i, /block-goose/i],
|
|
1234
|
+
agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
|
|
1235
|
+
},
|
|
1236
|
+
{
|
|
1237
|
+
vendor: "perplexity",
|
|
1238
|
+
displayName: "Perplexity",
|
|
1239
|
+
uaPatterns: [/perplexity/i],
|
|
1240
|
+
agentCardPatterns: [/perplexity\.ai/i],
|
|
1241
|
+
apiKeyFormatPatterns: [/^pplx-/i]
|
|
1242
|
+
}
|
|
1243
|
+
];
|
|
1244
|
+
function matchPlatformSignature(signatures, input) {
|
|
1245
|
+
const ua = input.userAgent ?? "";
|
|
1246
|
+
const cardUrl = input.agentCardUrl ?? "";
|
|
1247
|
+
const apiKeyFormat = input.apiKeyFormat ?? "";
|
|
1248
|
+
const headerLines = [];
|
|
1249
|
+
if (input.platformHeaders) {
|
|
1250
|
+
for (const [name, value] of Object.entries(input.platformHeaders)) {
|
|
1251
|
+
headerLines.push(name, `${name}: ${value}`);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
for (const sig of signatures) {
|
|
1255
|
+
const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
|
|
1256
|
+
const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
|
|
1257
|
+
const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
|
|
1258
|
+
const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
|
|
1259
|
+
if (uaMatch || cardMatch || keyMatch || headerMatch) {
|
|
1260
|
+
const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
|
|
1261
|
+
const cardHost = (() => {
|
|
1262
|
+
try {
|
|
1263
|
+
return cardUrl ? new URL(cardUrl).host : "";
|
|
1264
|
+
} catch {
|
|
1265
|
+
return "";
|
|
1266
|
+
}
|
|
1267
|
+
})();
|
|
1268
|
+
const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
|
|
1269
|
+
return {
|
|
1270
|
+
vendor: sig.vendor,
|
|
1271
|
+
fingerprintKey: `${sig.vendor}:${keyBasis}`,
|
|
1272
|
+
displayName: sig.displayName
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
return void 0;
|
|
1277
|
+
}
|
|
1278
|
+
function detectPlatformFingerprint(input) {
|
|
1279
|
+
return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
// src/edge-core/classify.ts
|
|
1283
|
+
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;
|
|
1284
|
+
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;
|
|
1285
|
+
var BROWSER_UA_PATTERN = /mozilla\/\d/i;
|
|
1286
|
+
var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN };
|
|
1287
|
+
|
|
1288
|
+
// src/edge-core/events.ts
|
|
1289
|
+
function sampled(rate, random = Math.random) {
|
|
1290
|
+
if (rate <= 0) return false;
|
|
1291
|
+
if (rate >= 1) return true;
|
|
1292
|
+
return random() < rate;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
// src/adapters/anonymous-beacon.ts
|
|
1296
|
+
function readHeader(raw, name) {
|
|
1297
|
+
const value = raw[name];
|
|
1298
|
+
if (typeof value === "string") return value;
|
|
1299
|
+
if (Array.isArray(value)) return value[0];
|
|
1300
|
+
return void 0;
|
|
1301
|
+
}
|
|
1302
|
+
function classifyPassThroughTraffic(path, rawHeaders) {
|
|
1303
|
+
if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: "never" };
|
|
1304
|
+
const credentials = extractCredentials(rawHeaders, {});
|
|
1305
|
+
if (credentials.astraId || credentials.apiKey || credentials.jwt) {
|
|
1306
|
+
return { kind: "never" };
|
|
1307
|
+
}
|
|
1308
|
+
const userAgent = readHeader(rawHeaders, "user-agent") ?? "";
|
|
1309
|
+
const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
1310
|
+
const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });
|
|
1311
|
+
if (fingerprint) {
|
|
1312
|
+
return {
|
|
1313
|
+
kind: "platform",
|
|
1314
|
+
protocol: "platform-ua",
|
|
1315
|
+
evidence: { vendor: fingerprint.vendor, userAgent: userAgent || "(none)" }
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
if (!userAgent || _patterns.BOT_UA_PATTERN.test(userAgent) || !_patterns.BROWSER_UA_PATTERN.test(userAgent)) {
|
|
1319
|
+
return {
|
|
1320
|
+
kind: "anonymous-bot",
|
|
1321
|
+
protocol: "ua-heuristic",
|
|
1322
|
+
evidence: { userAgent: userAgent || "(none)" }
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
if (!readHeader(rawHeaders, "sec-fetch-mode") && !readHeader(rawHeaders, "accept-language")) {
|
|
1326
|
+
return {
|
|
1327
|
+
kind: "anonymous-bot",
|
|
1328
|
+
protocol: "ua-heuristic",
|
|
1329
|
+
evidence: { userAgent, spoofedBrowser: true }
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
return { kind: "never" };
|
|
1333
|
+
}
|
|
1334
|
+
function createAnonymousBeacon(config, options) {
|
|
1335
|
+
const counterpartyId = config.counterpartyId;
|
|
1336
|
+
if (!counterpartyId) return () => {
|
|
1337
|
+
};
|
|
1338
|
+
const random = options?.random ?? Math.random;
|
|
1339
|
+
let edgeConfig;
|
|
1340
|
+
let refreshing = false;
|
|
1341
|
+
const refreshConfig = () => {
|
|
1342
|
+
if (refreshing) return;
|
|
1343
|
+
refreshing = true;
|
|
1344
|
+
getEdgeConfig(config, counterpartyId).then((cfg) => {
|
|
1345
|
+
edgeConfig = cfg;
|
|
1346
|
+
}).catch(() => {
|
|
1347
|
+
}).finally(() => {
|
|
1348
|
+
refreshing = false;
|
|
1349
|
+
});
|
|
1350
|
+
};
|
|
1351
|
+
refreshConfig();
|
|
1352
|
+
return (input) => {
|
|
1353
|
+
try {
|
|
1354
|
+
refreshConfig();
|
|
1355
|
+
const cfg = edgeConfig;
|
|
1356
|
+
if (!cfg) return;
|
|
1357
|
+
const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);
|
|
1358
|
+
if (traffic.kind === "never") return;
|
|
1359
|
+
if (traffic.kind === "anonymous-bot" && !sampled(cfg.sampling.anonymousBeaconRate, random)) {
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
const userAgent = readHeader(input.rawHeaders, "user-agent");
|
|
1363
|
+
const xff = input.rawHeaders["x-forwarded-for"];
|
|
1364
|
+
const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
|
|
1365
|
+
const sourceIp = input.sourceIp ?? xffStr?.split(",")[0]?.trim();
|
|
1366
|
+
reportUnregisteredAttempt(config, {
|
|
1367
|
+
...input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl },
|
|
1368
|
+
counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? "api",
|
|
1369
|
+
...sourceIp && { sourceIp },
|
|
1370
|
+
...userAgent && { userAgent },
|
|
1371
|
+
requestPath: input.requestPath,
|
|
1372
|
+
requestMethod: input.requestMethod,
|
|
1373
|
+
...traffic.protocol && { protocol: traffic.protocol },
|
|
1374
|
+
...traffic.evidence && { evidence: traffic.evidence },
|
|
1375
|
+
observedMetadata: buildSdkObservedMetadata(input.rawHeaders)
|
|
1376
|
+
}).catch(() => {
|
|
1377
|
+
});
|
|
1378
|
+
} catch {
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
950
1382
|
|
|
951
1383
|
// src/adapters/express.ts
|
|
952
1384
|
function defaultExtractCredentials(req) {
|
|
@@ -958,7 +1390,7 @@ function defaultExtractCredentials(req) {
|
|
|
958
1390
|
function extractAstraSyncCredentials(req) {
|
|
959
1391
|
return extractHttpCredentials(req.headers);
|
|
960
1392
|
}
|
|
961
|
-
function
|
|
1393
|
+
function headerValue2(value) {
|
|
962
1394
|
if (typeof value === "string") return value;
|
|
963
1395
|
if (Array.isArray(value)) return value[0];
|
|
964
1396
|
return void 0;
|
|
@@ -966,9 +1398,9 @@ function headerValue(value) {
|
|
|
966
1398
|
function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtractAction) {
|
|
967
1399
|
return resolveHttpPdlss({
|
|
968
1400
|
method: req.method,
|
|
969
|
-
astraPurpose:
|
|
970
|
-
astraAction:
|
|
971
|
-
legacyPurpose:
|
|
1401
|
+
astraPurpose: headerValue2(req.headers["x-astra-purpose"]),
|
|
1402
|
+
astraAction: headerValue2(req.headers["x-astra-action"]),
|
|
1403
|
+
legacyPurpose: headerValue2(req.headers["x-purpose"] ?? req.headers["X-Purpose"]),
|
|
972
1404
|
queryPurpose: typeof req.query.purpose === "string" ? req.query.purpose : void 0,
|
|
973
1405
|
routePurpose: routeConfig?.purpose,
|
|
974
1406
|
routeAction: routeConfig?.action,
|
|
@@ -1016,6 +1448,20 @@ function dedupeFailures(result) {
|
|
|
1016
1448
|
}
|
|
1017
1449
|
}
|
|
1018
1450
|
function defaultOnDenied(result, _req, res) {
|
|
1451
|
+
if (result.misconfigured) {
|
|
1452
|
+
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
1453
|
+
res.status(503).json({
|
|
1454
|
+
success: false,
|
|
1455
|
+
error: {
|
|
1456
|
+
code: "MERCHANT_VERIFICATION_MISCONFIGURED",
|
|
1457
|
+
message: result.denialReasons?.[0] || "This site's AstraSync integration is misconfigured",
|
|
1458
|
+
guidance: result.guidance,
|
|
1459
|
+
failures: result.failures,
|
|
1460
|
+
correlationId: result.correlationId
|
|
1461
|
+
}
|
|
1462
|
+
});
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1019
1465
|
const statusCode = !result.identityVerified ? 401 : 403;
|
|
1020
1466
|
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
1021
1467
|
res.status(statusCode).json({
|
|
@@ -1037,6 +1483,11 @@ function defaultOnDenied(result, _req, res) {
|
|
|
1037
1483
|
}
|
|
1038
1484
|
var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
|
|
1039
1485
|
function createMiddleware(options) {
|
|
1486
|
+
if ("routes" in options) {
|
|
1487
|
+
console.warn(
|
|
1488
|
+
"[VerificationGateway] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
|
|
1489
|
+
);
|
|
1490
|
+
}
|
|
1040
1491
|
const {
|
|
1041
1492
|
extractCredentials: customExtractCredentials,
|
|
1042
1493
|
extractPurpose: customExtractPurpose,
|
|
@@ -1048,12 +1499,25 @@ function createMiddleware(options) {
|
|
|
1048
1499
|
routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
|
|
1049
1500
|
failOnError = "open",
|
|
1050
1501
|
caseInsensitiveRouteMatch = false,
|
|
1502
|
+
anonymousBeacon = true,
|
|
1051
1503
|
...config
|
|
1052
1504
|
} = options;
|
|
1053
1505
|
if (config.apiBaseUrl) {
|
|
1054
1506
|
prefetchWellKnown(config.apiBaseUrl).catch(() => {
|
|
1055
1507
|
});
|
|
1056
1508
|
}
|
|
1509
|
+
const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "api" }) : void 0;
|
|
1510
|
+
const beaconPassThrough = emitAnonymousBeacon ? (req) => {
|
|
1511
|
+
const xff = req.headers["x-forwarded-for"];
|
|
1512
|
+
const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
|
|
1513
|
+
emitAnonymousBeacon({
|
|
1514
|
+
requestPath: req.path,
|
|
1515
|
+
requestMethod: req.method,
|
|
1516
|
+
counterpartyUrl: config.counterpartyUrl || `${req.protocol}://${req.get("host")}`,
|
|
1517
|
+
sourceIp: req.ip ?? (xffStr ? xffStr.split(",")[0].trim() : void 0),
|
|
1518
|
+
rawHeaders: req.headers
|
|
1519
|
+
});
|
|
1520
|
+
} : void 0;
|
|
1057
1521
|
let cachedRoutes = [];
|
|
1058
1522
|
let lastFetchAt = 0;
|
|
1059
1523
|
let refreshing = null;
|
|
@@ -1114,6 +1578,7 @@ function createMiddleware(options) {
|
|
|
1114
1578
|
cachedRoutes.length === 0 ? "no-policy" : "no-match"
|
|
1115
1579
|
);
|
|
1116
1580
|
}
|
|
1581
|
+
beaconPassThrough?.(req);
|
|
1117
1582
|
return next();
|
|
1118
1583
|
}
|
|
1119
1584
|
const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
|
|
@@ -1124,6 +1589,7 @@ function createMiddleware(options) {
|
|
|
1124
1589
|
res.setHeader("X-Astra-Gateway-Mode", "unenforced");
|
|
1125
1590
|
res.setHeader("X-Astra-Gateway-Reason", "route-none");
|
|
1126
1591
|
}
|
|
1592
|
+
beaconPassThrough?.(req);
|
|
1127
1593
|
return next();
|
|
1128
1594
|
}
|
|
1129
1595
|
const pdlssPair = resolveRequestPdlss(
|
|
@@ -1216,16 +1682,10 @@ function createMiddleware(options) {
|
|
|
1216
1682
|
forwardedFor: forwardedForStr,
|
|
1217
1683
|
agentCardUrl,
|
|
1218
1684
|
// Workstream D — capture EVERY inbound header (SDK-only merchants
|
|
1219
|
-
// have no edge to do it upstream)
|
|
1220
|
-
// stripped; out of the verify
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
return {
|
|
1224
|
-
headers,
|
|
1225
|
-
...apiKeyFormat && { apiKeyFormat },
|
|
1226
|
-
...platformHeaders && { platformHeaders }
|
|
1227
|
-
};
|
|
1228
|
-
})()
|
|
1685
|
+
// have no edge to do it upstream) plus the CDN-derived connection
|
|
1686
|
+
// block. Local string work, secrets stripped; out of the verify
|
|
1687
|
+
// cache key so it doesn't defeat caching.
|
|
1688
|
+
observedMetadata: buildSdkObservedMetadata(req.headers)
|
|
1229
1689
|
}
|
|
1230
1690
|
};
|
|
1231
1691
|
let result = await verify(config, verificationRequest);
|