@astrasyncai/verification-gateway 4.0.0 → 4.2.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 +100 -13
- package/dist/bin/astrasync.js +168 -27
- 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 +24 -13
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +24 -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
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'next/server';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-
|
|
2
|
+
import '../types-r850cOt0.mjs';
|
|
3
|
+
export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-WyeVr2Kp.mjs';
|
|
4
4
|
import '../metadata-capture.mjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'next/server';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-
|
|
2
|
+
import '../types-sMxBT-nM.js';
|
|
3
|
+
export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-w7RTbP1P.js';
|
|
4
4
|
import '../metadata-capture.js';
|
package/dist/adapters/nextjs.js
CHANGED
|
@@ -102,7 +102,7 @@ function getTrustLevel(score) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// src/version.ts
|
|
105
|
-
var SDK_VERSION = "4.
|
|
105
|
+
var SDK_VERSION = "4.1.0";
|
|
106
106
|
|
|
107
107
|
// src/well-known.ts
|
|
108
108
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -241,6 +241,40 @@ function cacheResult(request, result, configuredTtl, counterpartyId) {
|
|
|
241
241
|
expiresAt: Date.now() + ttlSeconds * 1e3
|
|
242
242
|
});
|
|
243
243
|
}
|
|
244
|
+
function extractCredentials(headers, query) {
|
|
245
|
+
const credentials = {};
|
|
246
|
+
const ASTRA_ID_PATTERN = /^ASTRAE?-[A-Za-z0-9_-]{1,64}$/;
|
|
247
|
+
const astraIdHeader = headers["x-astra-id"] || headers["X-Astra-Id"] || headers["X-ASTRA-ID"] || headers["x-astra-agentid"] || headers["X-Astra-AgentId"] || headers["x-astra-agent-id"] || headers["X-Astra-Agent-Id"] || headers["X-ASTRA-AGENT-ID"];
|
|
248
|
+
if (astraIdHeader) {
|
|
249
|
+
const raw = Array.isArray(astraIdHeader) ? astraIdHeader[0] : typeof astraIdHeader === "string" ? astraIdHeader : void 0;
|
|
250
|
+
if (typeof raw === "string" && ASTRA_ID_PATTERN.test(raw)) {
|
|
251
|
+
credentials.astraId = raw;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const apiKeyHeader = headers["x-api-key"] || headers["X-Api-Key"] || headers["X-API-KEY"];
|
|
255
|
+
if (apiKeyHeader) {
|
|
256
|
+
credentials.apiKey = Array.isArray(apiKeyHeader) ? apiKeyHeader[0] : apiKeyHeader;
|
|
257
|
+
}
|
|
258
|
+
const authHeader = headers["authorization"] || headers["Authorization"];
|
|
259
|
+
if (authHeader) {
|
|
260
|
+
const authValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;
|
|
261
|
+
if (typeof authValue === "string") {
|
|
262
|
+
credentials.authorizationHeader = authValue;
|
|
263
|
+
if (authValue.startsWith("Bearer ")) {
|
|
264
|
+
credentials.jwt = authValue.slice(7);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (query) {
|
|
269
|
+
if (query.astraId && !credentials.astraId) {
|
|
270
|
+
credentials.astraId = query.astraId;
|
|
271
|
+
}
|
|
272
|
+
if (query.apiKey && !credentials.apiKey) {
|
|
273
|
+
credentials.apiKey = query.apiKey;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return credentials;
|
|
277
|
+
}
|
|
244
278
|
function createGuidanceResponse(_config, reason, options = {}) {
|
|
245
279
|
const source = options.source ?? "no_credentials";
|
|
246
280
|
const isApiError = source === "api_error";
|
|
@@ -615,6 +649,21 @@ async function fetchRoutes(config, counterpartyId) {
|
|
|
615
649
|
return null;
|
|
616
650
|
}
|
|
617
651
|
}
|
|
652
|
+
async function reportUnregisteredAttempt(config, data) {
|
|
653
|
+
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
654
|
+
const { counterpartyUrl, ...rest } = data;
|
|
655
|
+
const body = {
|
|
656
|
+
...rest,
|
|
657
|
+
...counterpartyUrl && { counterpartyUrl },
|
|
658
|
+
...config.counterpartyId && { counterpartyId: config.counterpartyId }
|
|
659
|
+
};
|
|
660
|
+
await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
|
|
661
|
+
method: "POST",
|
|
662
|
+
headers: { "Content-Type": "application/json" },
|
|
663
|
+
body: JSON.stringify(body)
|
|
664
|
+
}).catch(() => {
|
|
665
|
+
});
|
|
666
|
+
}
|
|
618
667
|
async function reportCounterpartyPreCheckFailure(config, data) {
|
|
619
668
|
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
620
669
|
await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
|
|
@@ -720,6 +769,7 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
|
|
|
720
769
|
}
|
|
721
770
|
|
|
722
771
|
// src/metadata-capture.ts
|
|
772
|
+
var CAPTURE_SCHEMA_VERSION = 1;
|
|
723
773
|
var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
724
774
|
"cookie",
|
|
725
775
|
"set-cookie",
|
|
@@ -856,6 +906,359 @@ function sanitizeHeaders(raw) {
|
|
|
856
906
|
if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
|
|
857
907
|
return result;
|
|
858
908
|
}
|
|
909
|
+
var CONNECTION_HEADER_SOURCES = [
|
|
910
|
+
["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
|
|
911
|
+
[
|
|
912
|
+
"country",
|
|
913
|
+
["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
|
|
914
|
+
],
|
|
915
|
+
["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
|
|
916
|
+
["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
|
|
917
|
+
["asn", ["cloudfront-viewer-asn"]],
|
|
918
|
+
["tlsVersion", ["cloudfront-viewer-tls"]],
|
|
919
|
+
["httpVersion", ["cloudfront-viewer-http-version"]],
|
|
920
|
+
// TLS fingerprints can only be computed where TLS terminates. When a CDN
|
|
921
|
+
// terminates TLS in front of the merchant, its fingerprint headers ARE the
|
|
922
|
+
// connection-layer truth — normalising them here is the permanent design.
|
|
923
|
+
["tlsFingerprint", ["cf-ja3-hash"]],
|
|
924
|
+
["ja4", ["cf-ja4"]]
|
|
925
|
+
];
|
|
926
|
+
function deriveConnectionFromHeaders(headers) {
|
|
927
|
+
if (!headers) return void 0;
|
|
928
|
+
const lower = {};
|
|
929
|
+
for (const name of Object.keys(headers)) {
|
|
930
|
+
const value = headers[name];
|
|
931
|
+
if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
|
|
932
|
+
}
|
|
933
|
+
const connection = {};
|
|
934
|
+
for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
|
|
935
|
+
for (const source of sources) {
|
|
936
|
+
const value = lower[source]?.trim();
|
|
937
|
+
if (value) {
|
|
938
|
+
connection[key] = value;
|
|
939
|
+
break;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
if (!connection.ip) {
|
|
944
|
+
const xff = lower["x-forwarded-for"];
|
|
945
|
+
const client = xff?.split(",")[0]?.trim();
|
|
946
|
+
if (client) connection.ip = client;
|
|
947
|
+
}
|
|
948
|
+
return Object.keys(connection).length > 0 ? connection : void 0;
|
|
949
|
+
}
|
|
950
|
+
function buildSdkObservedMetadata(rawHeaders) {
|
|
951
|
+
const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
952
|
+
const flat = {};
|
|
953
|
+
if (rawHeaders) {
|
|
954
|
+
for (const name of Object.keys(rawHeaders)) {
|
|
955
|
+
const value = rawHeaders[name];
|
|
956
|
+
if (value === void 0) continue;
|
|
957
|
+
flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
const connection = deriveConnectionFromHeaders(flat);
|
|
961
|
+
return {
|
|
962
|
+
headers,
|
|
963
|
+
...apiKeyFormat && { apiKeyFormat },
|
|
964
|
+
...platformHeaders && { platformHeaders },
|
|
965
|
+
...connection && { connection },
|
|
966
|
+
schemaVersion: CAPTURE_SCHEMA_VERSION
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// src/edge-config.ts
|
|
971
|
+
var DEFAULT_EDGE_CONFIG = Object.freeze({
|
|
972
|
+
version: 1,
|
|
973
|
+
mode: "observe",
|
|
974
|
+
depth: "classify",
|
|
975
|
+
pathRules: [],
|
|
976
|
+
sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
|
|
977
|
+
failurePosture: "open"
|
|
978
|
+
});
|
|
979
|
+
var EDGE_MODES = ["observe", "enforce"];
|
|
980
|
+
var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
|
|
981
|
+
function isEdgeConfig(value) {
|
|
982
|
+
if (typeof value !== "object" || value === null) return false;
|
|
983
|
+
const v = value;
|
|
984
|
+
if (v.version !== 1) return false;
|
|
985
|
+
if (!EDGE_MODES.includes(v.mode)) return false;
|
|
986
|
+
if (!EDGE_DEPTHS.includes(v.depth)) return false;
|
|
987
|
+
if (!Array.isArray(v.pathRules)) return false;
|
|
988
|
+
for (const rule of v.pathRules) {
|
|
989
|
+
if (typeof rule !== "object" || rule === null) return false;
|
|
990
|
+
const r = rule;
|
|
991
|
+
if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
|
|
992
|
+
if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
|
|
993
|
+
if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
|
|
994
|
+
}
|
|
995
|
+
const sampling = v.sampling;
|
|
996
|
+
if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
|
|
997
|
+
return false;
|
|
998
|
+
}
|
|
999
|
+
return v.failurePosture === "open";
|
|
1000
|
+
}
|
|
1001
|
+
async function fetchEdgeConfig(config, counterpartyId, opts) {
|
|
1002
|
+
if (!counterpartyId) return null;
|
|
1003
|
+
const headers = { Accept: "application/json" };
|
|
1004
|
+
if (config.apiKey) {
|
|
1005
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
1006
|
+
headers["X-API-Key"] = config.apiKey;
|
|
1007
|
+
}
|
|
1008
|
+
if (opts?.etag) headers["If-None-Match"] = opts.etag;
|
|
1009
|
+
try {
|
|
1010
|
+
const response = await fetch(
|
|
1011
|
+
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
|
|
1012
|
+
{ method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
|
|
1013
|
+
);
|
|
1014
|
+
if (response.status === 304) return { notModified: true };
|
|
1015
|
+
if (!response.ok) return null;
|
|
1016
|
+
const body = await response.json();
|
|
1017
|
+
const edgeConfig = body.data?.edgeConfig;
|
|
1018
|
+
if (!isEdgeConfig(edgeConfig)) return null;
|
|
1019
|
+
return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
|
|
1020
|
+
} catch {
|
|
1021
|
+
return null;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
var DEFAULT_TTL_MS = 60 * 1e3;
|
|
1025
|
+
var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
|
|
1026
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
1027
|
+
var inflight = /* @__PURE__ */ new Map();
|
|
1028
|
+
function cacheKey(apiBaseUrl, counterpartyId) {
|
|
1029
|
+
return `${apiBaseUrl}|${counterpartyId}`;
|
|
1030
|
+
}
|
|
1031
|
+
function degradeToObserve(config) {
|
|
1032
|
+
if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
|
|
1033
|
+
return config;
|
|
1034
|
+
}
|
|
1035
|
+
return {
|
|
1036
|
+
...config,
|
|
1037
|
+
mode: "observe",
|
|
1038
|
+
pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
async function revalidate(config, counterpartyId) {
|
|
1042
|
+
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
1043
|
+
const existing = inflight.get(key);
|
|
1044
|
+
if (existing) return existing;
|
|
1045
|
+
const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
|
|
1046
|
+
if (result === null) return;
|
|
1047
|
+
const now = Date.now();
|
|
1048
|
+
if ("notModified" in result) {
|
|
1049
|
+
const entry = cache2.get(key);
|
|
1050
|
+
if (entry) entry.lastSuccessAt = now;
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
|
|
1054
|
+
}).finally(() => {
|
|
1055
|
+
inflight.delete(key);
|
|
1056
|
+
});
|
|
1057
|
+
inflight.set(key, promise);
|
|
1058
|
+
return promise;
|
|
1059
|
+
}
|
|
1060
|
+
async function getEdgeConfig(config, counterpartyId, opts) {
|
|
1061
|
+
const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
|
|
1062
|
+
const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
|
|
1063
|
+
const key = cacheKey(config.apiBaseUrl, counterpartyId);
|
|
1064
|
+
const entry = cache2.get(key);
|
|
1065
|
+
if (entry) {
|
|
1066
|
+
const age = Date.now() - entry.lastSuccessAt;
|
|
1067
|
+
if (age > ttlMs) {
|
|
1068
|
+
revalidate(config, counterpartyId).catch(() => {
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
|
|
1072
|
+
}
|
|
1073
|
+
await revalidate(config, counterpartyId).catch(() => {
|
|
1074
|
+
});
|
|
1075
|
+
return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// src/platform-signatures.ts
|
|
1079
|
+
var PLATFORM_AGENT_SIGNATURES = [
|
|
1080
|
+
{
|
|
1081
|
+
vendor: "claude",
|
|
1082
|
+
displayName: "Anthropic Claude",
|
|
1083
|
+
uaPatterns: [/claude/i, /anthropic/i],
|
|
1084
|
+
agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
|
|
1085
|
+
apiKeyFormatPatterns: [/^sk-ant/i],
|
|
1086
|
+
headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
vendor: "chatgpt",
|
|
1090
|
+
displayName: "OpenAI ChatGPT",
|
|
1091
|
+
uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
|
|
1092
|
+
agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
|
|
1093
|
+
apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
|
|
1094
|
+
headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
vendor: "gemini",
|
|
1098
|
+
displayName: "Google Gemini",
|
|
1099
|
+
uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
|
|
1100
|
+
agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
|
|
1101
|
+
apiKeyFormatPatterns: [/^aiza/i],
|
|
1102
|
+
headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
|
|
1103
|
+
},
|
|
1104
|
+
{
|
|
1105
|
+
vendor: "cursor",
|
|
1106
|
+
displayName: "Cursor",
|
|
1107
|
+
uaPatterns: [/cursor/i],
|
|
1108
|
+
agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
vendor: "goose",
|
|
1112
|
+
displayName: "Block Goose",
|
|
1113
|
+
uaPatterns: [/goose/i, /block-goose/i],
|
|
1114
|
+
agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
|
|
1115
|
+
},
|
|
1116
|
+
{
|
|
1117
|
+
vendor: "perplexity",
|
|
1118
|
+
displayName: "Perplexity",
|
|
1119
|
+
uaPatterns: [/perplexity/i],
|
|
1120
|
+
agentCardPatterns: [/perplexity\.ai/i],
|
|
1121
|
+
apiKeyFormatPatterns: [/^pplx-/i]
|
|
1122
|
+
}
|
|
1123
|
+
];
|
|
1124
|
+
function matchPlatformSignature(signatures, input) {
|
|
1125
|
+
const ua = input.userAgent ?? "";
|
|
1126
|
+
const cardUrl = input.agentCardUrl ?? "";
|
|
1127
|
+
const apiKeyFormat = input.apiKeyFormat ?? "";
|
|
1128
|
+
const headerLines = [];
|
|
1129
|
+
if (input.platformHeaders) {
|
|
1130
|
+
for (const [name, value] of Object.entries(input.platformHeaders)) {
|
|
1131
|
+
headerLines.push(name, `${name}: ${value}`);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
for (const sig of signatures) {
|
|
1135
|
+
const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
|
|
1136
|
+
const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
|
|
1137
|
+
const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
|
|
1138
|
+
const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
|
|
1139
|
+
if (uaMatch || cardMatch || keyMatch || headerMatch) {
|
|
1140
|
+
const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
|
|
1141
|
+
const cardHost = (() => {
|
|
1142
|
+
try {
|
|
1143
|
+
return cardUrl ? new URL(cardUrl).host : "";
|
|
1144
|
+
} catch {
|
|
1145
|
+
return "";
|
|
1146
|
+
}
|
|
1147
|
+
})();
|
|
1148
|
+
const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
|
|
1149
|
+
return {
|
|
1150
|
+
vendor: sig.vendor,
|
|
1151
|
+
fingerprintKey: `${sig.vendor}:${keyBasis}`,
|
|
1152
|
+
displayName: sig.displayName
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
return void 0;
|
|
1157
|
+
}
|
|
1158
|
+
function detectPlatformFingerprint(input) {
|
|
1159
|
+
return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// src/edge-core/classify.ts
|
|
1163
|
+
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;
|
|
1164
|
+
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;
|
|
1165
|
+
var BROWSER_UA_PATTERN = /mozilla\/\d/i;
|
|
1166
|
+
var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN };
|
|
1167
|
+
|
|
1168
|
+
// src/edge-core/events.ts
|
|
1169
|
+
function sampled(rate, random = Math.random) {
|
|
1170
|
+
if (rate <= 0) return false;
|
|
1171
|
+
if (rate >= 1) return true;
|
|
1172
|
+
return random() < rate;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// src/adapters/anonymous-beacon.ts
|
|
1176
|
+
function readHeader(raw, name) {
|
|
1177
|
+
const value = raw[name];
|
|
1178
|
+
if (typeof value === "string") return value;
|
|
1179
|
+
if (Array.isArray(value)) return value[0];
|
|
1180
|
+
return void 0;
|
|
1181
|
+
}
|
|
1182
|
+
function classifyPassThroughTraffic(path, rawHeaders) {
|
|
1183
|
+
if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: "never" };
|
|
1184
|
+
const credentials = extractCredentials(rawHeaders, {});
|
|
1185
|
+
if (credentials.astraId || credentials.apiKey || credentials.jwt) {
|
|
1186
|
+
return { kind: "never" };
|
|
1187
|
+
}
|
|
1188
|
+
const userAgent = readHeader(rawHeaders, "user-agent") ?? "";
|
|
1189
|
+
const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
|
|
1190
|
+
const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });
|
|
1191
|
+
if (fingerprint) {
|
|
1192
|
+
return {
|
|
1193
|
+
kind: "platform",
|
|
1194
|
+
protocol: "platform-ua",
|
|
1195
|
+
evidence: { vendor: fingerprint.vendor, userAgent: userAgent || "(none)" }
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
if (!userAgent || _patterns.BOT_UA_PATTERN.test(userAgent) || !_patterns.BROWSER_UA_PATTERN.test(userAgent)) {
|
|
1199
|
+
return {
|
|
1200
|
+
kind: "anonymous-bot",
|
|
1201
|
+
protocol: "ua-heuristic",
|
|
1202
|
+
evidence: { userAgent: userAgent || "(none)" }
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
if (!readHeader(rawHeaders, "sec-fetch-mode") && !readHeader(rawHeaders, "accept-language")) {
|
|
1206
|
+
return {
|
|
1207
|
+
kind: "anonymous-bot",
|
|
1208
|
+
protocol: "ua-heuristic",
|
|
1209
|
+
evidence: { userAgent, spoofedBrowser: true }
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
return { kind: "never" };
|
|
1213
|
+
}
|
|
1214
|
+
function createAnonymousBeacon(config, options) {
|
|
1215
|
+
const counterpartyId = config.counterpartyId;
|
|
1216
|
+
if (!counterpartyId) return () => {
|
|
1217
|
+
};
|
|
1218
|
+
const random = options?.random ?? Math.random;
|
|
1219
|
+
let edgeConfig;
|
|
1220
|
+
let refreshing = false;
|
|
1221
|
+
const refreshConfig = () => {
|
|
1222
|
+
if (refreshing) return;
|
|
1223
|
+
refreshing = true;
|
|
1224
|
+
getEdgeConfig(config, counterpartyId).then((cfg) => {
|
|
1225
|
+
edgeConfig = cfg;
|
|
1226
|
+
}).catch(() => {
|
|
1227
|
+
}).finally(() => {
|
|
1228
|
+
refreshing = false;
|
|
1229
|
+
});
|
|
1230
|
+
};
|
|
1231
|
+
refreshConfig();
|
|
1232
|
+
return (input) => {
|
|
1233
|
+
try {
|
|
1234
|
+
refreshConfig();
|
|
1235
|
+
const cfg = edgeConfig;
|
|
1236
|
+
if (!cfg) return;
|
|
1237
|
+
const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);
|
|
1238
|
+
if (traffic.kind === "never") return;
|
|
1239
|
+
if (traffic.kind === "anonymous-bot" && !sampled(cfg.sampling.anonymousBeaconRate, random)) {
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
const userAgent = readHeader(input.rawHeaders, "user-agent");
|
|
1243
|
+
const xff = input.rawHeaders["x-forwarded-for"];
|
|
1244
|
+
const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
|
|
1245
|
+
const sourceIp = input.sourceIp ?? xffStr?.split(",")[0]?.trim();
|
|
1246
|
+
reportUnregisteredAttempt(config, {
|
|
1247
|
+
...input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl },
|
|
1248
|
+
counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? "api",
|
|
1249
|
+
...sourceIp && { sourceIp },
|
|
1250
|
+
...userAgent && { userAgent },
|
|
1251
|
+
requestPath: input.requestPath,
|
|
1252
|
+
requestMethod: input.requestMethod,
|
|
1253
|
+
...traffic.protocol && { protocol: traffic.protocol },
|
|
1254
|
+
...traffic.evidence && { evidence: traffic.evidence },
|
|
1255
|
+
observedMetadata: buildSdkObservedMetadata(input.rawHeaders)
|
|
1256
|
+
}).catch(() => {
|
|
1257
|
+
});
|
|
1258
|
+
} catch {
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
859
1262
|
|
|
860
1263
|
// src/adapters/http-pdlss.ts
|
|
861
1264
|
var HTTP_METHOD_ACTION_TABLE = {
|
|
@@ -1019,7 +1422,7 @@ function resolveNextPdlss(request, routeConfig) {
|
|
|
1019
1422
|
routeAction: routeConfig?.action
|
|
1020
1423
|
});
|
|
1021
1424
|
}
|
|
1022
|
-
function
|
|
1425
|
+
function generateInterstitialHtml(result, options) {
|
|
1023
1426
|
const title = escapeHtml(options.commerceShield?.title || "AstraSync Agent Verification");
|
|
1024
1427
|
const message = escapeHtml(
|
|
1025
1428
|
options.commerceShield?.message || result.guidance?.message || "This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials."
|
|
@@ -1175,13 +1578,31 @@ function generateCommerceShieldHtml(result, options) {
|
|
|
1175
1578
|
}
|
|
1176
1579
|
var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
|
|
1177
1580
|
function createMiddleware(options) {
|
|
1581
|
+
if ("routes" in options) {
|
|
1582
|
+
console.warn(
|
|
1583
|
+
"[VerificationGateway/Next.js] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
|
|
1584
|
+
);
|
|
1585
|
+
}
|
|
1178
1586
|
const {
|
|
1179
1587
|
skipPaths = [],
|
|
1180
|
-
|
|
1588
|
+
showInterstitial,
|
|
1589
|
+
showCommerceShield,
|
|
1181
1590
|
enableRuntimeChallenge = true,
|
|
1182
1591
|
routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
|
|
1592
|
+
anonymousBeacon = true,
|
|
1183
1593
|
...config
|
|
1184
1594
|
} = options;
|
|
1595
|
+
const interstitialEnabled = showInterstitial ?? showCommerceShield ?? true;
|
|
1596
|
+
const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "website" }) : void 0;
|
|
1597
|
+
const beaconPassThrough = emitAnonymousBeacon ? (request, pathname) => {
|
|
1598
|
+
emitAnonymousBeacon({
|
|
1599
|
+
requestPath: pathname,
|
|
1600
|
+
requestMethod: request.method,
|
|
1601
|
+
counterpartyUrl: config.counterpartyUrl || request.nextUrl.origin,
|
|
1602
|
+
sourceIp: request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || void 0,
|
|
1603
|
+
rawHeaders: Object.fromEntries(request.headers.entries())
|
|
1604
|
+
});
|
|
1605
|
+
} : void 0;
|
|
1185
1606
|
let cachedRoutes = [];
|
|
1186
1607
|
let lastFetchAt = 0;
|
|
1187
1608
|
let refreshing = null;
|
|
@@ -1223,9 +1644,11 @@ function createMiddleware(options) {
|
|
|
1223
1644
|
}
|
|
1224
1645
|
const routeConfig = findRouteConfig(cachedRoutes, pathname, request.method);
|
|
1225
1646
|
if (!routeConfig) {
|
|
1647
|
+
beaconPassThrough?.(request, pathname);
|
|
1226
1648
|
return NextResponse.next();
|
|
1227
1649
|
}
|
|
1228
1650
|
if (routeConfig.minAccessLevel === "none") {
|
|
1651
|
+
beaconPassThrough?.(request, pathname);
|
|
1229
1652
|
return NextResponse.next();
|
|
1230
1653
|
}
|
|
1231
1654
|
const credentials = extractCredentialsFromNextRequest(request);
|
|
@@ -1277,8 +1700,8 @@ function createMiddleware(options) {
|
|
|
1277
1700
|
{ status: 403 }
|
|
1278
1701
|
);
|
|
1279
1702
|
}
|
|
1280
|
-
if (
|
|
1281
|
-
return new NextResponse(
|
|
1703
|
+
if (interstitialEnabled) {
|
|
1704
|
+
return new NextResponse(generateInterstitialHtml(preCheckResult, options), {
|
|
1282
1705
|
status: 200,
|
|
1283
1706
|
headers: {
|
|
1284
1707
|
"Content-Type": "text/html",
|
|
@@ -1306,17 +1729,9 @@ function createMiddleware(options) {
|
|
|
1306
1729
|
host: request.headers.get("host") || void 0,
|
|
1307
1730
|
forwardedFor,
|
|
1308
1731
|
agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0,
|
|
1309
|
-
// Workstream D — full sanitised header capture
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
Object.fromEntries(request.headers.entries())
|
|
1313
|
-
);
|
|
1314
|
-
return {
|
|
1315
|
-
headers,
|
|
1316
|
-
...apiKeyFormat && { apiKeyFormat },
|
|
1317
|
-
...platformHeaders && { platformHeaders }
|
|
1318
|
-
};
|
|
1319
|
-
})()
|
|
1732
|
+
// Workstream D — full sanitised header capture + CDN-derived
|
|
1733
|
+
// connection block (Web Headers → plain map).
|
|
1734
|
+
observedMetadata: buildSdkObservedMetadata(Object.fromEntries(request.headers.entries()))
|
|
1320
1735
|
}
|
|
1321
1736
|
};
|
|
1322
1737
|
let result = await verify(config, verificationRequest);
|
|
@@ -1371,8 +1786,8 @@ function createMiddleware(options) {
|
|
|
1371
1786
|
}
|
|
1372
1787
|
);
|
|
1373
1788
|
}
|
|
1374
|
-
if (
|
|
1375
|
-
return new NextResponse(
|
|
1789
|
+
if (interstitialEnabled) {
|
|
1790
|
+
return new NextResponse(generateInterstitialHtml(result, options), {
|
|
1376
1791
|
status: 200,
|
|
1377
1792
|
headers: {
|
|
1378
1793
|
"Content-Type": "text/html",
|