@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
package/dist/adapters/express.js
CHANGED
|
@@ -92,7 +92,7 @@ function getTrustLevel(score) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// src/version.ts
|
|
95
|
-
var SDK_VERSION = "
|
|
95
|
+
var SDK_VERSION = "4.1.0";
|
|
96
96
|
|
|
97
97
|
// src/well-known.ts
|
|
98
98
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -170,7 +170,7 @@ var DEFAULT_CONFIG = {
|
|
|
170
170
|
};
|
|
171
171
|
var initCheckPerformed = false;
|
|
172
172
|
var deprecationWarningShown = false;
|
|
173
|
-
async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
173
|
+
async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
174
174
|
initCheckPerformed = true;
|
|
175
175
|
try {
|
|
176
176
|
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
@@ -187,6 +187,28 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
|
187
187
|
`[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
|
|
188
188
|
);
|
|
189
189
|
}
|
|
190
|
+
if (apiKey) {
|
|
191
|
+
const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
|
|
192
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
193
|
+
});
|
|
194
|
+
if (selfCheck.status === 401) {
|
|
195
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
196
|
+
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}` : "") + `.`;
|
|
197
|
+
if (strictInit) {
|
|
198
|
+
throw new Error(`${message} (strictInit=true)`);
|
|
199
|
+
}
|
|
200
|
+
console.error(message);
|
|
201
|
+
} else if (selfCheck.ok) {
|
|
202
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
203
|
+
if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
|
|
204
|
+
console.warn(
|
|
205
|
+
`[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
|
|
206
|
+
);
|
|
207
|
+
} else if (debug) {
|
|
208
|
+
console.log("[VerificationGateway] API key self-check passed");
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
190
212
|
} catch (err) {
|
|
191
213
|
if (strictInit) {
|
|
192
214
|
throw err;
|
|
@@ -298,8 +320,17 @@ function extractCredentials(headers, query) {
|
|
|
298
320
|
function createGuidanceResponse(_config, reason, options = {}) {
|
|
299
321
|
const source = options.source ?? "no_credentials";
|
|
300
322
|
const isApiError = source === "api_error";
|
|
323
|
+
const isMisconfig = source === "merchant_misconfig";
|
|
301
324
|
const urls = options.urls;
|
|
302
|
-
const guidance =
|
|
325
|
+
const guidance = isMisconfig ? {
|
|
326
|
+
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.",
|
|
327
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
328
|
+
documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
|
|
329
|
+
steps: [
|
|
330
|
+
"Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
|
|
331
|
+
"Do not retry: the failure is deterministic until the operator updates their key"
|
|
332
|
+
]
|
|
333
|
+
} : isApiError ? {
|
|
303
334
|
message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
|
|
304
335
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
305
336
|
documentationUrl: urls?.documentationUrl ?? "",
|
|
@@ -337,13 +368,22 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
337
368
|
// partners (and their custom onDenied handlers) can branch on
|
|
338
369
|
// dimension. Without this, the synthesised stub was indistinguishable
|
|
339
370
|
// from a real policy deny.
|
|
340
|
-
failures:
|
|
371
|
+
failures: isMisconfig ? [
|
|
372
|
+
{
|
|
373
|
+
dimension: "verify_access.merchant_misconfigured",
|
|
374
|
+
message: reason ?? "The integration API key was rejected by AstraSync",
|
|
375
|
+
guidance: guidance.message
|
|
376
|
+
}
|
|
377
|
+
] : isApiError ? [
|
|
341
378
|
{
|
|
342
379
|
dimension: "verify_access.api_error",
|
|
343
380
|
message: reason ?? "Verification temporarily unavailable",
|
|
344
381
|
guidance: guidance.message
|
|
345
382
|
}
|
|
346
383
|
] : void 0,
|
|
384
|
+
// 4.0.0: typed marker so adapters render the misconfig envelope (503 +
|
|
385
|
+
// MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
|
|
386
|
+
...isMisconfig && { misconfigured: true },
|
|
347
387
|
correlationId: options.correlationId,
|
|
348
388
|
attemptId: options.attemptId,
|
|
349
389
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
@@ -398,7 +438,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
398
438
|
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
399
439
|
method: "POST",
|
|
400
440
|
headers,
|
|
401
|
-
body: JSON.stringify(body)
|
|
441
|
+
body: JSON.stringify(body),
|
|
442
|
+
signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
|
|
402
443
|
});
|
|
403
444
|
const data = await response.json();
|
|
404
445
|
if (response.status === 410) {
|
|
@@ -422,6 +463,17 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
422
463
|
};
|
|
423
464
|
}
|
|
424
465
|
if (!response.ok) {
|
|
466
|
+
if (response.status === 401) {
|
|
467
|
+
return {
|
|
468
|
+
success: false,
|
|
469
|
+
error: data.message || data.error || "Integration API key rejected",
|
|
470
|
+
misconfig: true,
|
|
471
|
+
misconfigCode: typeof data?.code === "string" ? data.code : void 0,
|
|
472
|
+
remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
|
|
473
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
474
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
475
|
+
};
|
|
476
|
+
}
|
|
425
477
|
return {
|
|
426
478
|
success: false,
|
|
427
479
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
@@ -443,9 +495,19 @@ async function verify(config, request, options) {
|
|
|
443
495
|
const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
|
|
444
496
|
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
445
497
|
if (mergedConfig.strictInit) {
|
|
446
|
-
await performInitCheck(
|
|
498
|
+
await performInitCheck(
|
|
499
|
+
mergedConfig.apiBaseUrl,
|
|
500
|
+
mergedConfig.debug,
|
|
501
|
+
true,
|
|
502
|
+
mergedConfig.apiKey
|
|
503
|
+
);
|
|
447
504
|
} else {
|
|
448
|
-
void performInitCheck(
|
|
505
|
+
void performInitCheck(
|
|
506
|
+
mergedConfig.apiBaseUrl,
|
|
507
|
+
mergedConfig.debug,
|
|
508
|
+
false,
|
|
509
|
+
mergedConfig.apiKey
|
|
510
|
+
);
|
|
449
511
|
}
|
|
450
512
|
}
|
|
451
513
|
if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
|
|
@@ -484,9 +546,10 @@ async function verify(config, request, options) {
|
|
|
484
546
|
const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
|
|
485
547
|
if (!apiResponse.success) {
|
|
486
548
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
487
|
-
source: "api_error",
|
|
549
|
+
source: apiResponse.misconfig ? "merchant_misconfig" : "api_error",
|
|
488
550
|
correlationId: apiResponse.correlationId,
|
|
489
551
|
attemptId: apiResponse.attemptId,
|
|
552
|
+
remediation: apiResponse.remediation,
|
|
490
553
|
urls
|
|
491
554
|
});
|
|
492
555
|
}
|
|
@@ -641,6 +704,21 @@ async function fetchRoutes(config, counterpartyId) {
|
|
|
641
704
|
return null;
|
|
642
705
|
}
|
|
643
706
|
}
|
|
707
|
+
async function reportUnregisteredAttempt(config, data) {
|
|
708
|
+
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
709
|
+
const { counterpartyUrl, ...rest } = data;
|
|
710
|
+
const body = {
|
|
711
|
+
...rest,
|
|
712
|
+
...counterpartyUrl && { counterpartyUrl },
|
|
713
|
+
...config.counterpartyId && { counterpartyId: config.counterpartyId }
|
|
714
|
+
};
|
|
715
|
+
await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
|
|
716
|
+
method: "POST",
|
|
717
|
+
headers: { "Content-Type": "application/json" },
|
|
718
|
+
body: JSON.stringify(body)
|
|
719
|
+
}).catch(() => {
|
|
720
|
+
});
|
|
721
|
+
}
|
|
644
722
|
async function reportCounterpartyPreCheckFailure(config, data) {
|
|
645
723
|
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
646
724
|
await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
|
|
@@ -838,6 +916,7 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
|
|
|
838
916
|
}
|
|
839
917
|
|
|
840
918
|
// src/metadata-capture.ts
|
|
919
|
+
var CAPTURE_SCHEMA_VERSION = 1;
|
|
841
920
|
var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
842
921
|
"cookie",
|
|
843
922
|
"set-cookie",
|
|
@@ -974,6 +1053,359 @@ function sanitizeHeaders(raw) {
|
|
|
974
1053
|
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
975
1054
|
return result;
|
|
976
1055
|
}
|
|
1056
|
+
var CONNECTION_HEADER_SOURCES = [
|
|
1057
|
+
["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
|
|
1058
|
+
[
|
|
1059
|
+
"country",
|
|
1060
|
+
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
1061
|
+
],
|
|
1062
|
+
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
1063
|
+
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
1064
|
+
["asn", ["cloudfront-viewer-asn"]],
|
|
1065
|
+
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
1066
|
+
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
1067
|
+
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
1068
|
+
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
1069
|
+
// connection-layer truth — normalising them here is the permanent design.
|
|
1070
|
+
["tlsFingerprint", ["cf-ja3-hash"]],
|
|
1071
|
+
["ja4", ["cf-ja4"]]
|
|
1072
|
+
];
|
|
1073
|
+
function deriveConnectionFromHeaders(headers) {
|
|
1074
|
+
if (!headers) return void 0;
|
|
1075
|
+
const lower = {};
|
|
1076
|
+
for (const name of Object.keys(headers)) {
|
|
1077
|
+
const value = headers[name];
|
|
1078
|
+
if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
|
|
1079
|
+
}
|
|
1080
|
+
const connection = {};
|
|
1081
|
+
for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
|
|
1082
|
+
for (const source of sources) {
|
|
1083
|
+
const value = lower[source]?.trim();
|
|
1084
|
+
if (value) {
|
|
1085
|
+
connection[key] = value;
|
|
1086
|
+
break;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
if (!connection.ip) {
|
|
1091
|
+
const xff = lower["x-forwarded-for"];
|
|
1092
|
+
const client = xff?.split(",")[0]?.trim();
|
|
1093
|
+
if (client) connection.ip = client;
|
|
1094
|
+
}
|
|
1095
|
+
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
1096
|
+
}
|
|
1097
|
+
function buildSdkObservedMetadata(rawHeaders) {
|
|
1098
|
+
const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
1099
|
+
const flat = {};
|
|
1100
|
+
if (rawHeaders) {
|
|
1101
|
+
for (const name of Object.keys(rawHeaders)) {
|
|
1102
|
+
const value = rawHeaders[name];
|
|
1103
|
+
if (value === void 0) continue;
|
|
1104
|
+
flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
const connection = deriveConnectionFromHeaders(flat);
|
|
1108
|
+
return {
|
|
1109
|
+
headers,
|
|
1110
|
+
...apiKeyFormat && { apiKeyFormat },
|
|
1111
|
+
...platformHeaders && { platformHeaders },
|
|
1112
|
+
...connection && { connection },
|
|
1113
|
+
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// src/edge-config.ts
|
|
1118
|
+
var DEFAULT_EDGE_CONFIG = Object.freeze({
|
|
1119
|
+
version: 1,
|
|
1120
|
+
mode: "observe",
|
|
1121
|
+
depth: "classify",
|
|
1122
|
+
pathRules: [],
|
|
1123
|
+
sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
|
|
1124
|
+
failurePosture: "open"
|
|
1125
|
+
});
|
|
1126
|
+
var EDGE_MODES = ["observe", "enforce"];
|
|
1127
|
+
var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
|
|
1128
|
+
function isEdgeConfig(value) {
|
|
1129
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1130
|
+
const v = value;
|
|
1131
|
+
if (v.version !== 1) return false;
|
|
1132
|
+
if (!EDGE_MODES.includes(v.mode)) return false;
|
|
1133
|
+
if (!EDGE_DEPTHS.includes(v.depth)) return false;
|
|
1134
|
+
if (!Array.isArray(v.pathRules)) return false;
|
|
1135
|
+
for (const rule of v.pathRules) {
|
|
1136
|
+
if (typeof rule !== "object" || rule === null) return false;
|
|
1137
|
+
const r = rule;
|
|
1138
|
+
if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
|
|
1139
|
+
if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
|
|
1140
|
+
if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
|
|
1141
|
+
}
|
|
1142
|
+
const sampling = v.sampling;
|
|
1143
|
+
if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
|
|
1144
|
+
return false;
|
|
1145
|
+
}
|
|
1146
|
+
return v.failurePosture === "open";
|
|
1147
|
+
}
|
|
1148
|
+
async function fetchEdgeConfig(config, counterpartyId, opts) {
|
|
1149
|
+
if (!counterpartyId) return null;
|
|
1150
|
+
const headers = { Accept: "application/json" };
|
|
1151
|
+
if (config.apiKey) {
|
|
1152
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
1153
|
+
headers["X-API-Key"] = config.apiKey;
|
|
1154
|
+
}
|
|
1155
|
+
if (opts?.etag) headers["If-None-Match"] = opts.etag;
|
|
1156
|
+
try {
|
|
1157
|
+
const response = await fetch(
|
|
1158
|
+
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
|
|
1159
|
+
{ method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
|
|
1160
|
+
);
|
|
1161
|
+
if (response.status === 304) return { notModified: true };
|
|
1162
|
+
if (!response.ok) return null;
|
|
1163
|
+
const body = await response.json();
|
|
1164
|
+
const edgeConfig = body.data?.edgeConfig;
|
|
1165
|
+
if (!isEdgeConfig(edgeConfig)) return null;
|
|
1166
|
+
return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
|
|
1167
|
+
} catch {
|
|
1168
|
+
return null;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
var DEFAULT_TTL_MS = 60 * 1e3;
|
|
1172
|
+
var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
|
|
1173
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
1174
|
+
var inflight2 = /* @__PURE__ */ new Map();
|
|
1175
|
+
function cacheKey(apiBaseUrl, counterpartyId) {
|
|
1176
|
+
return `${apiBaseUrl}|${counterpartyId}`;
|
|
1177
|
+
}
|
|
1178
|
+
function degradeToObserve(config) {
|
|
1179
|
+
if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
|
|
1180
|
+
return config;
|
|
1181
|
+
}
|
|
1182
|
+
return {
|
|
1183
|
+
...config,
|
|
1184
|
+
mode: "observe",
|
|
1185
|
+
pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
async function revalidate(config, counterpartyId) {
|
|
1189
|
+
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
1190
|
+
const existing = inflight2.get(key);
|
|
1191
|
+
if (existing) return existing;
|
|
1192
|
+
const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
|
|
1193
|
+
if (result === null) return;
|
|
1194
|
+
const now = Date.now();
|
|
1195
|
+
if ("notModified" in result) {
|
|
1196
|
+
const entry = cache2.get(key);
|
|
1197
|
+
if (entry) entry.lastSuccessAt = now;
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
|
|
1201
|
+
}).finally(() => {
|
|
1202
|
+
inflight2.delete(key);
|
|
1203
|
+
});
|
|
1204
|
+
inflight2.set(key, promise);
|
|
1205
|
+
return promise;
|
|
1206
|
+
}
|
|
1207
|
+
async function getEdgeConfig(config, counterpartyId, opts) {
|
|
1208
|
+
const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
|
|
1209
|
+
const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
|
|
1210
|
+
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
1211
|
+
const entry = cache2.get(key);
|
|
1212
|
+
if (entry) {
|
|
1213
|
+
const age = Date.now() - entry.lastSuccessAt;
|
|
1214
|
+
if (age > ttlMs) {
|
|
1215
|
+
revalidate(config, counterpartyId).catch(() => {
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
|
|
1219
|
+
}
|
|
1220
|
+
await revalidate(config, counterpartyId).catch(() => {
|
|
1221
|
+
});
|
|
1222
|
+
return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// src/platform-signatures.ts
|
|
1226
|
+
var PLATFORM_AGENT_SIGNATURES = [
|
|
1227
|
+
{
|
|
1228
|
+
vendor: "claude",
|
|
1229
|
+
displayName: "Anthropic Claude",
|
|
1230
|
+
uaPatterns: [/claude/i, /anthropic/i],
|
|
1231
|
+
agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
|
|
1232
|
+
apiKeyFormatPatterns: [/^sk-ant/i],
|
|
1233
|
+
headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
|
|
1234
|
+
},
|
|
1235
|
+
{
|
|
1236
|
+
vendor: "chatgpt",
|
|
1237
|
+
displayName: "OpenAI ChatGPT",
|
|
1238
|
+
uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
|
|
1239
|
+
agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
|
|
1240
|
+
apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
|
|
1241
|
+
headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
|
|
1242
|
+
},
|
|
1243
|
+
{
|
|
1244
|
+
vendor: "gemini",
|
|
1245
|
+
displayName: "Google Gemini",
|
|
1246
|
+
uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
|
|
1247
|
+
agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
|
|
1248
|
+
apiKeyFormatPatterns: [/^aiza/i],
|
|
1249
|
+
headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
|
|
1250
|
+
},
|
|
1251
|
+
{
|
|
1252
|
+
vendor: "cursor",
|
|
1253
|
+
displayName: "Cursor",
|
|
1254
|
+
uaPatterns: [/cursor/i],
|
|
1255
|
+
agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
|
|
1256
|
+
},
|
|
1257
|
+
{
|
|
1258
|
+
vendor: "goose",
|
|
1259
|
+
displayName: "Block Goose",
|
|
1260
|
+
uaPatterns: [/goose/i, /block-goose/i],
|
|
1261
|
+
agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
|
|
1262
|
+
},
|
|
1263
|
+
{
|
|
1264
|
+
vendor: "perplexity",
|
|
1265
|
+
displayName: "Perplexity",
|
|
1266
|
+
uaPatterns: [/perplexity/i],
|
|
1267
|
+
agentCardPatterns: [/perplexity\.ai/i],
|
|
1268
|
+
apiKeyFormatPatterns: [/^pplx-/i]
|
|
1269
|
+
}
|
|
1270
|
+
];
|
|
1271
|
+
function matchPlatformSignature(signatures, input) {
|
|
1272
|
+
const ua = input.userAgent ?? "";
|
|
1273
|
+
const cardUrl = input.agentCardUrl ?? "";
|
|
1274
|
+
const apiKeyFormat = input.apiKeyFormat ?? "";
|
|
1275
|
+
const headerLines = [];
|
|
1276
|
+
if (input.platformHeaders) {
|
|
1277
|
+
for (const [name, value] of Object.entries(input.platformHeaders)) {
|
|
1278
|
+
headerLines.push(name, `${name}: ${value}`);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
for (const sig of signatures) {
|
|
1282
|
+
const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
|
|
1283
|
+
const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
|
|
1284
|
+
const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
|
|
1285
|
+
const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
|
|
1286
|
+
if (uaMatch || cardMatch || keyMatch || headerMatch) {
|
|
1287
|
+
const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
|
|
1288
|
+
const cardHost = (() => {
|
|
1289
|
+
try {
|
|
1290
|
+
return cardUrl ? new URL(cardUrl).host : "";
|
|
1291
|
+
} catch {
|
|
1292
|
+
return "";
|
|
1293
|
+
}
|
|
1294
|
+
})();
|
|
1295
|
+
const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
|
|
1296
|
+
return {
|
|
1297
|
+
vendor: sig.vendor,
|
|
1298
|
+
fingerprintKey: `${sig.vendor}:${keyBasis}`,
|
|
1299
|
+
displayName: sig.displayName
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
return void 0;
|
|
1304
|
+
}
|
|
1305
|
+
function detectPlatformFingerprint(input) {
|
|
1306
|
+
return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// src/edge-core/classify.ts
|
|
1310
|
+
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;
|
|
1311
|
+
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;
|
|
1312
|
+
var BROWSER_UA_PATTERN = /mozilla\/\d/i;
|
|
1313
|
+
var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN };
|
|
1314
|
+
|
|
1315
|
+
// src/edge-core/events.ts
|
|
1316
|
+
function sampled(rate, random = Math.random) {
|
|
1317
|
+
if (rate <= 0) return false;
|
|
1318
|
+
if (rate >= 1) return true;
|
|
1319
|
+
return random() < rate;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
// src/adapters/anonymous-beacon.ts
|
|
1323
|
+
function readHeader(raw, name) {
|
|
1324
|
+
const value = raw[name];
|
|
1325
|
+
if (typeof value === "string") return value;
|
|
1326
|
+
if (Array.isArray(value)) return value[0];
|
|
1327
|
+
return void 0;
|
|
1328
|
+
}
|
|
1329
|
+
function classifyPassThroughTraffic(path, rawHeaders) {
|
|
1330
|
+
if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: "never" };
|
|
1331
|
+
const credentials = extractCredentials(rawHeaders, {});
|
|
1332
|
+
if (credentials.astraId || credentials.apiKey || credentials.jwt) {
|
|
1333
|
+
return { kind: "never" };
|
|
1334
|
+
}
|
|
1335
|
+
const userAgent = readHeader(rawHeaders, "user-agent") ?? "";
|
|
1336
|
+
const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
1337
|
+
const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });
|
|
1338
|
+
if (fingerprint) {
|
|
1339
|
+
return {
|
|
1340
|
+
kind: "platform",
|
|
1341
|
+
protocol: "platform-ua",
|
|
1342
|
+
evidence: { vendor: fingerprint.vendor, userAgent: userAgent || "(none)" }
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
if (!userAgent || _patterns.BOT_UA_PATTERN.test(userAgent) || !_patterns.BROWSER_UA_PATTERN.test(userAgent)) {
|
|
1346
|
+
return {
|
|
1347
|
+
kind: "anonymous-bot",
|
|
1348
|
+
protocol: "ua-heuristic",
|
|
1349
|
+
evidence: { userAgent: userAgent || "(none)" }
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
if (!readHeader(rawHeaders, "sec-fetch-mode") && !readHeader(rawHeaders, "accept-language")) {
|
|
1353
|
+
return {
|
|
1354
|
+
kind: "anonymous-bot",
|
|
1355
|
+
protocol: "ua-heuristic",
|
|
1356
|
+
evidence: { userAgent, spoofedBrowser: true }
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
return { kind: "never" };
|
|
1360
|
+
}
|
|
1361
|
+
function createAnonymousBeacon(config, options) {
|
|
1362
|
+
const counterpartyId = config.counterpartyId;
|
|
1363
|
+
if (!counterpartyId) return () => {
|
|
1364
|
+
};
|
|
1365
|
+
const random = options?.random ?? Math.random;
|
|
1366
|
+
let edgeConfig;
|
|
1367
|
+
let refreshing = false;
|
|
1368
|
+
const refreshConfig = () => {
|
|
1369
|
+
if (refreshing) return;
|
|
1370
|
+
refreshing = true;
|
|
1371
|
+
getEdgeConfig(config, counterpartyId).then((cfg) => {
|
|
1372
|
+
edgeConfig = cfg;
|
|
1373
|
+
}).catch(() => {
|
|
1374
|
+
}).finally(() => {
|
|
1375
|
+
refreshing = false;
|
|
1376
|
+
});
|
|
1377
|
+
};
|
|
1378
|
+
refreshConfig();
|
|
1379
|
+
return (input) => {
|
|
1380
|
+
try {
|
|
1381
|
+
refreshConfig();
|
|
1382
|
+
const cfg = edgeConfig;
|
|
1383
|
+
if (!cfg) return;
|
|
1384
|
+
const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);
|
|
1385
|
+
if (traffic.kind === "never") return;
|
|
1386
|
+
if (traffic.kind === "anonymous-bot" && !sampled(cfg.sampling.anonymousBeaconRate, random)) {
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
const userAgent = readHeader(input.rawHeaders, "user-agent");
|
|
1390
|
+
const xff = input.rawHeaders["x-forwarded-for"];
|
|
1391
|
+
const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
|
|
1392
|
+
const sourceIp = input.sourceIp ?? xffStr?.split(",")[0]?.trim();
|
|
1393
|
+
reportUnregisteredAttempt(config, {
|
|
1394
|
+
...input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl },
|
|
1395
|
+
counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? "api",
|
|
1396
|
+
...sourceIp && { sourceIp },
|
|
1397
|
+
...userAgent && { userAgent },
|
|
1398
|
+
requestPath: input.requestPath,
|
|
1399
|
+
requestMethod: input.requestMethod,
|
|
1400
|
+
...traffic.protocol && { protocol: traffic.protocol },
|
|
1401
|
+
...traffic.evidence && { evidence: traffic.evidence },
|
|
1402
|
+
observedMetadata: buildSdkObservedMetadata(input.rawHeaders)
|
|
1403
|
+
}).catch(() => {
|
|
1404
|
+
});
|
|
1405
|
+
} catch {
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
977
1409
|
|
|
978
1410
|
// src/adapters/express.ts
|
|
979
1411
|
function defaultExtractCredentials(req) {
|
|
@@ -985,7 +1417,7 @@ function defaultExtractCredentials(req) {
|
|
|
985
1417
|
function extractAstraSyncCredentials(req) {
|
|
986
1418
|
return extractHttpCredentials(req.headers);
|
|
987
1419
|
}
|
|
988
|
-
function
|
|
1420
|
+
function headerValue2(value) {
|
|
989
1421
|
if (typeof value === "string") return value;
|
|
990
1422
|
if (Array.isArray(value)) return value[0];
|
|
991
1423
|
return void 0;
|
|
@@ -993,9 +1425,9 @@ function headerValue(value) {
|
|
|
993
1425
|
function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtractAction) {
|
|
994
1426
|
return resolveHttpPdlss({
|
|
995
1427
|
method: req.method,
|
|
996
|
-
astraPurpose:
|
|
997
|
-
astraAction:
|
|
998
|
-
legacyPurpose:
|
|
1428
|
+
astraPurpose: headerValue2(req.headers["x-astra-purpose"]),
|
|
1429
|
+
astraAction: headerValue2(req.headers["x-astra-action"]),
|
|
1430
|
+
legacyPurpose: headerValue2(req.headers["x-purpose"] ?? req.headers["X-Purpose"]),
|
|
999
1431
|
queryPurpose: typeof req.query.purpose === "string" ? req.query.purpose : void 0,
|
|
1000
1432
|
routePurpose: routeConfig?.purpose,
|
|
1001
1433
|
routeAction: routeConfig?.action,
|
|
@@ -1043,6 +1475,20 @@ function dedupeFailures(result) {
|
|
|
1043
1475
|
}
|
|
1044
1476
|
}
|
|
1045
1477
|
function defaultOnDenied(result, _req, res) {
|
|
1478
|
+
if (result.misconfigured) {
|
|
1479
|
+
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
1480
|
+
res.status(503).json({
|
|
1481
|
+
success: false,
|
|
1482
|
+
error: {
|
|
1483
|
+
code: "MERCHANT_VERIFICATION_MISCONFIGURED",
|
|
1484
|
+
message: result.denialReasons?.[0] || "This site's AstraSync integration is misconfigured",
|
|
1485
|
+
guidance: result.guidance,
|
|
1486
|
+
failures: result.failures,
|
|
1487
|
+
correlationId: result.correlationId
|
|
1488
|
+
}
|
|
1489
|
+
});
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1046
1492
|
const statusCode = !result.identityVerified ? 401 : 403;
|
|
1047
1493
|
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
1048
1494
|
res.status(statusCode).json({
|
|
@@ -1064,6 +1510,11 @@ function defaultOnDenied(result, _req, res) {
|
|
|
1064
1510
|
}
|
|
1065
1511
|
var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
|
|
1066
1512
|
function createMiddleware(options) {
|
|
1513
|
+
if ("routes" in options) {
|
|
1514
|
+
console.warn(
|
|
1515
|
+
"[VerificationGateway] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1067
1518
|
const {
|
|
1068
1519
|
extractCredentials: customExtractCredentials,
|
|
1069
1520
|
extractPurpose: customExtractPurpose,
|
|
@@ -1075,12 +1526,25 @@ function createMiddleware(options) {
|
|
|
1075
1526
|
routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
|
|
1076
1527
|
failOnError = "open",
|
|
1077
1528
|
caseInsensitiveRouteMatch = false,
|
|
1529
|
+
anonymousBeacon = true,
|
|
1078
1530
|
...config
|
|
1079
1531
|
} = options;
|
|
1080
1532
|
if (config.apiBaseUrl) {
|
|
1081
1533
|
prefetchWellKnown(config.apiBaseUrl).catch(() => {
|
|
1082
1534
|
});
|
|
1083
1535
|
}
|
|
1536
|
+
const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "api" }) : void 0;
|
|
1537
|
+
const beaconPassThrough = emitAnonymousBeacon ? (req) => {
|
|
1538
|
+
const xff = req.headers["x-forwarded-for"];
|
|
1539
|
+
const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
|
|
1540
|
+
emitAnonymousBeacon({
|
|
1541
|
+
requestPath: req.path,
|
|
1542
|
+
requestMethod: req.method,
|
|
1543
|
+
counterpartyUrl: config.counterpartyUrl || `${req.protocol}://${req.get("host")}`,
|
|
1544
|
+
sourceIp: req.ip ?? (xffStr ? xffStr.split(",")[0].trim() : void 0),
|
|
1545
|
+
rawHeaders: req.headers
|
|
1546
|
+
});
|
|
1547
|
+
} : void 0;
|
|
1084
1548
|
let cachedRoutes = [];
|
|
1085
1549
|
let lastFetchAt = 0;
|
|
1086
1550
|
let refreshing = null;
|
|
@@ -1141,6 +1605,7 @@ function createMiddleware(options) {
|
|
|
1141
1605
|
cachedRoutes.length === 0 ? "no-policy" : "no-match"
|
|
1142
1606
|
);
|
|
1143
1607
|
}
|
|
1608
|
+
beaconPassThrough?.(req);
|
|
1144
1609
|
return next();
|
|
1145
1610
|
}
|
|
1146
1611
|
const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
|
|
@@ -1151,6 +1616,7 @@ function createMiddleware(options) {
|
|
|
1151
1616
|
res.setHeader("X-Astra-Gateway-Mode", "unenforced");
|
|
1152
1617
|
res.setHeader("X-Astra-Gateway-Reason", "route-none");
|
|
1153
1618
|
}
|
|
1619
|
+
beaconPassThrough?.(req);
|
|
1154
1620
|
return next();
|
|
1155
1621
|
}
|
|
1156
1622
|
const pdlssPair = resolveRequestPdlss(
|
|
@@ -1243,16 +1709,10 @@ function createMiddleware(options) {
|
|
|
1243
1709
|
forwardedFor: forwardedForStr,
|
|
1244
1710
|
agentCardUrl,
|
|
1245
1711
|
// Workstream D — capture EVERY inbound header (SDK-only merchants
|
|
1246
|
-
// have no edge to do it upstream)
|
|
1247
|
-
// stripped; out of the verify
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
return {
|
|
1251
|
-
headers,
|
|
1252
|
-
...apiKeyFormat && { apiKeyFormat },
|
|
1253
|
-
...platformHeaders && { platformHeaders }
|
|
1254
|
-
};
|
|
1255
|
-
})()
|
|
1712
|
+
// have no edge to do it upstream) plus the CDN-derived connection
|
|
1713
|
+
// block. Local string work, secrets stripped; out of the verify
|
|
1714
|
+
// cache key so it doesn't defeat caching.
|
|
1715
|
+
observedMetadata: buildSdkObservedMetadata(req.headers)
|
|
1256
1716
|
}
|
|
1257
1717
|
};
|
|
1258
1718
|
let result = await verify(config, verificationRequest);
|