@kya-os/agentshield-nextjs 0.2.12 → 0.3.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.
Files changed (74) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/api-client.d.mts +6 -1
  3. package/dist/api-client.d.ts +6 -1
  4. package/dist/api-client.js +1 -1
  5. package/dist/api-client.js.map +1 -1
  6. package/dist/api-client.mjs +1 -1
  7. package/dist/api-client.mjs.map +1 -1
  8. package/dist/api-middleware.d.mts +13 -0
  9. package/dist/api-middleware.d.ts +13 -0
  10. package/dist/api-middleware.js +146 -24
  11. package/dist/api-middleware.js.map +1 -1
  12. package/dist/api-middleware.mjs +146 -24
  13. package/dist/api-middleware.mjs.map +1 -1
  14. package/dist/create-middleware.js +565 -487
  15. package/dist/create-middleware.js.map +1 -1
  16. package/dist/create-middleware.mjs +565 -487
  17. package/dist/create-middleware.mjs.map +1 -1
  18. package/dist/edge/index.js +69 -46
  19. package/dist/edge/index.js.map +1 -1
  20. package/dist/edge/index.mjs +69 -46
  21. package/dist/edge/index.mjs.map +1 -1
  22. package/dist/edge-detector-wrapper.js +9 -1
  23. package/dist/edge-detector-wrapper.js.map +1 -1
  24. package/dist/edge-detector-wrapper.mjs +9 -1
  25. package/dist/edge-detector-wrapper.mjs.map +1 -1
  26. package/dist/edge-runtime-loader.d.mts +1 -0
  27. package/dist/edge-runtime-loader.d.ts +1 -0
  28. package/dist/edge-runtime-loader.js +19 -3
  29. package/dist/edge-runtime-loader.js.map +1 -1
  30. package/dist/edge-runtime-loader.mjs +19 -3
  31. package/dist/edge-runtime-loader.mjs.map +1 -1
  32. package/dist/edge-wasm-middleware.d.mts +1 -0
  33. package/dist/edge-wasm-middleware.d.ts +1 -0
  34. package/dist/edge-wasm-middleware.js +10 -2
  35. package/dist/edge-wasm-middleware.js.map +1 -1
  36. package/dist/edge-wasm-middleware.mjs +11 -3
  37. package/dist/edge-wasm-middleware.mjs.map +1 -1
  38. package/dist/enhanced-middleware.js +48 -20
  39. package/dist/enhanced-middleware.js.map +1 -1
  40. package/dist/enhanced-middleware.mjs +49 -21
  41. package/dist/enhanced-middleware.mjs.map +1 -1
  42. package/dist/index.d.mts +1 -1
  43. package/dist/index.d.ts +1 -1
  44. package/dist/index.js +260 -107
  45. package/dist/index.js.map +1 -1
  46. package/dist/index.mjs +261 -108
  47. package/dist/index.mjs.map +1 -1
  48. package/dist/middleware.js +565 -487
  49. package/dist/middleware.js.map +1 -1
  50. package/dist/middleware.mjs +565 -487
  51. package/dist/middleware.mjs.map +1 -1
  52. package/dist/policy.d.mts +16 -4
  53. package/dist/policy.d.ts +16 -4
  54. package/dist/policy.js +14 -10
  55. package/dist/policy.js.map +1 -1
  56. package/dist/policy.mjs +14 -10
  57. package/dist/policy.mjs.map +1 -1
  58. package/dist/session-tracker.js +13 -19
  59. package/dist/session-tracker.js.map +1 -1
  60. package/dist/session-tracker.mjs +13 -19
  61. package/dist/session-tracker.mjs.map +1 -1
  62. package/dist/signature-verifier.js +9 -1
  63. package/dist/signature-verifier.js.map +1 -1
  64. package/dist/signature-verifier.mjs +9 -1
  65. package/dist/signature-verifier.mjs.map +1 -1
  66. package/dist/wasm-middleware.d.mts +1 -0
  67. package/dist/wasm-middleware.d.ts +1 -0
  68. package/dist/wasm-middleware.js +15 -15
  69. package/dist/wasm-middleware.js.map +1 -1
  70. package/dist/wasm-middleware.mjs +15 -15
  71. package/dist/wasm-middleware.mjs.map +1 -1
  72. package/package.json +5 -5
  73. package/wasm/agentshield_wasm.d.ts +2 -2
  74. package/wasm/agentshield_wasm_bg.wasm +0 -0
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { loadRulesSync, mapVerificationMethod, createEvaluationContext, evaluatePolicy, ENFORCEMENT_ACTIONS, PolicyConfigSchema, DEFAULT_POLICY, matchPath as matchPath$1, createPolicyFetcher } from '@kya-os/agentshield-shared';
1
+ import { loadRulesSync, shouldEnforce, evaluateEnforcement, createEvaluationContext, evaluatePolicy, ENFORCEMENT_ACTIONS, PolicyConfigSchema, DEFAULT_POLICY, matchPath as matchPath$1, createPolicyFetcher, mapVerificationMethod } from '@kya-os/agentshield-shared';
2
2
  export { DEFAULT_POLICY, ENFORCEMENT_ACTIONS, createEvaluationContext, evaluatePolicy } from '@kya-os/agentshield-shared';
3
3
  import { NextResponse } from 'next/server';
4
4
  import * as ed25519 from '@noble/ed25519';
@@ -232,7 +232,15 @@ var init_edge_detector_with_wasm = __esm({
232
232
  }
233
233
  const signaturePresent = !!(normalizedHeaders["signature"] || normalizedHeaders["signature-input"]);
234
234
  const signatureAgent = normalizedHeaders["signature-agent"];
235
- if (signatureAgent?.includes("chatgpt.com")) {
235
+ const isChatGPT = (() => {
236
+ try {
237
+ const url = new URL(signatureAgent?.replace(/^"|"$/g, "") || "");
238
+ return url.hostname === "chatgpt.com" || url.hostname.endsWith(".chatgpt.com");
239
+ } catch {
240
+ return false;
241
+ }
242
+ })();
243
+ if (isChatGPT) {
236
244
  confidence = 85;
237
245
  reasons.push("signature_agent:chatgpt");
238
246
  detectedAgent = { type: "chatgpt", name: "ChatGPT" };
@@ -759,7 +767,15 @@ async function verifyAgentSignature(method, path, headers) {
759
767
  }
760
768
  let agent;
761
769
  let agentKey;
762
- if (signatureAgent === '"https://chatgpt.com"' || signatureAgent?.includes("chatgpt.com")) {
770
+ const isChatGPT = signatureAgent === '"https://chatgpt.com"' || (() => {
771
+ try {
772
+ const url = new URL(signatureAgent?.replace(/^"|"$/g, "") || "");
773
+ return url.hostname === "chatgpt.com" || url.hostname.endsWith(".chatgpt.com");
774
+ } catch {
775
+ return false;
776
+ }
777
+ })();
778
+ if (isChatGPT) {
763
779
  agent = "ChatGPT";
764
780
  agentKey = "chatgpt";
765
781
  }
@@ -1056,11 +1072,6 @@ var EdgeAgentDetectorWrapper = class {
1056
1072
  return;
1057
1073
  }
1058
1074
  };
1059
-
1060
- // src/middleware.ts
1061
- init_edge_detector_with_wasm();
1062
-
1063
- // src/session-tracker.ts
1064
1075
  var EdgeSessionTracker = class {
1065
1076
  config;
1066
1077
  constructor(config) {
@@ -1077,7 +1088,7 @@ var EdgeSessionTracker = class {
1077
1088
  */
1078
1089
  async track(_request, response, result) {
1079
1090
  try {
1080
- if (!this.config.enabled || !result.isAgent) {
1091
+ if (!this.config.enabled || !shouldEnforce(result)) {
1081
1092
  return response;
1082
1093
  }
1083
1094
  const sessionData = {
@@ -1152,9 +1163,7 @@ var EdgeSessionTracker = class {
1152
1163
  for (let i = 0; i < encoded.length; i++) {
1153
1164
  obfuscated[i] = (encoded[i] || 0) ^ key.charCodeAt(i % key.length);
1154
1165
  }
1155
- return btoa(
1156
- Array.from(obfuscated, (byte) => String.fromCharCode(byte)).join("")
1157
- );
1166
+ return btoa(Array.from(obfuscated, (byte) => String.fromCharCode(byte)).join(""));
1158
1167
  } catch (error) {
1159
1168
  return btoa(data);
1160
1169
  }
@@ -1179,9 +1188,9 @@ var EdgeSessionTracker = class {
1179
1188
  var StatelessSessionChecker = class {
1180
1189
  static check(headers) {
1181
1190
  try {
1182
- const agent = headers["x-agentshield-session-agent"];
1183
- const confidence = headers["x-agentshield-session-confidence"];
1184
- const sessionId = headers["x-agentshield-session-id"];
1191
+ const agent = headers["kya-session-agent"];
1192
+ const confidence = headers["kya-session-confidence"];
1193
+ const sessionId = headers["kya-session-id"];
1185
1194
  if (agent && confidence && sessionId) {
1186
1195
  return {
1187
1196
  id: sessionId,
@@ -1211,33 +1220,49 @@ var StatelessSessionChecker = class {
1211
1220
  static setHeaders(response, session) {
1212
1221
  try {
1213
1222
  if (response.setHeader) {
1214
- response.setHeader("X-AgentShield-Session-Agent", session.agent);
1215
- response.setHeader(
1216
- "X-AgentShield-Session-Confidence",
1217
- session.confidence.toString()
1218
- );
1219
- response.setHeader("X-AgentShield-Session-Id", session.id);
1223
+ response.setHeader("KYA-Session-Agent", session.agent);
1224
+ response.setHeader("KYA-Session-Confidence", session.confidence.toString());
1225
+ response.setHeader("KYA-Session-Id", session.id);
1220
1226
  } else if (response.headers && response.headers.set) {
1221
- response.headers.set("x-agentshield-session-agent", session.agent);
1222
- response.headers.set(
1223
- "x-agentshield-session-confidence",
1224
- session.confidence.toString()
1225
- );
1226
- response.headers.set("x-agentshield-session-id", session.id);
1227
+ response.headers.set("kya-session-agent", session.agent);
1228
+ response.headers.set("kya-session-confidence", session.confidence.toString());
1229
+ response.headers.set("kya-session-id", session.id);
1227
1230
  }
1228
1231
  } catch {
1229
1232
  }
1230
1233
  }
1231
1234
  };
1232
1235
 
1233
- // src/middleware.ts
1236
+ // src/utils.ts
1237
+ function getClientIp(request) {
1238
+ const forwardedFor = request.headers.get("x-forwarded-for");
1239
+ if (forwardedFor) {
1240
+ const ip = forwardedFor.split(",")[0]?.trim();
1241
+ if (ip) return ip;
1242
+ }
1243
+ const realIp = request.headers.get("x-real-ip");
1244
+ if (realIp) return realIp;
1245
+ const cfIp = request.headers.get("cf-connecting-ip");
1246
+ if (cfIp) return cfIp;
1247
+ const clientIp = request.headers.get("x-client-ip");
1248
+ if (clientIp) return clientIp;
1249
+ return void 0;
1250
+ }
1251
+ function safeHostname(url) {
1252
+ try {
1253
+ return new URL(url).hostname;
1254
+ } catch {
1255
+ return "this site";
1256
+ }
1257
+ }
1234
1258
  function createAgentShieldMiddleware(config = {}) {
1235
- const detector = config.enableWasm ? new EdgeAgentDetectorWrapperWithWasm({ enableWasm: true }) : new EdgeAgentDetectorWrapper(config);
1259
+ let detector = config.enableWasm ? null : new EdgeAgentDetectorWrapper(config);
1260
+ let detectorInitPromise = null;
1236
1261
  const sessionTracker = config.sessionTracking?.enabled || config.enableWasm ? new EdgeSessionTracker({
1237
1262
  enabled: true,
1238
1263
  ...config.sessionTracking
1239
1264
  }) : null;
1240
- if (config.events) {
1265
+ if (detector && config.events) {
1241
1266
  Object.entries(config.events).forEach(([event, handler]) => {
1242
1267
  if (handler) {
1243
1268
  detector.on(event, handler);
@@ -1258,6 +1283,23 @@ function createAgentShieldMiddleware(config = {}) {
1258
1283
  } = config;
1259
1284
  return async (request) => {
1260
1285
  try {
1286
+ if (!detector) {
1287
+ if (!detectorInitPromise) {
1288
+ detectorInitPromise = (async () => {
1289
+ const { EdgeAgentDetectorWrapperWithWasm: EdgeAgentDetectorWrapperWithWasm2 } = await Promise.resolve().then(() => (init_edge_detector_with_wasm(), edge_detector_with_wasm_exports));
1290
+ detector = new EdgeAgentDetectorWrapperWithWasm2({ enableWasm: true });
1291
+ if (config.events) {
1292
+ Object.entries(config.events).forEach(([event, handler]) => {
1293
+ if (handler) {
1294
+ detector.on(event, handler);
1295
+ }
1296
+ });
1297
+ }
1298
+ })();
1299
+ }
1300
+ await detectorInitPromise;
1301
+ }
1302
+ const activeDetector = detector;
1261
1303
  const shouldSkip = skipPaths.some((pattern) => {
1262
1304
  if (typeof pattern === "string") {
1263
1305
  return request.nextUrl.pathname.startsWith(pattern);
@@ -1271,11 +1313,11 @@ function createAgentShieldMiddleware(config = {}) {
1271
1313
  const existingSession = sessionTracker ? await sessionTracker.check(request) : null;
1272
1314
  if (existingSession) {
1273
1315
  const response2 = NextResponse.next();
1274
- response2.headers.set("x-agentshield-detected", "true");
1275
- response2.headers.set("x-agentshield-agent", existingSession.agent);
1276
- response2.headers.set("x-agentshield-confidence", existingSession.confidence.toString());
1277
- response2.headers.set("x-agentshield-session", "continued");
1278
- response2.headers.set("x-agentshield-session-id", existingSession.id);
1316
+ response2.headers.set("kya-detected", "true");
1317
+ response2.headers.set("kya-agent", existingSession.agent);
1318
+ response2.headers.set("kya-confidence", existingSession.confidence.toString());
1319
+ response2.headers.set("kya-session", "continued");
1320
+ response2.headers.set("kya-session-id", existingSession.id);
1279
1321
  request.agentShield = {
1280
1322
  result: {
1281
1323
  isAgent: true,
@@ -1295,17 +1337,17 @@ function createAgentShieldMiddleware(config = {}) {
1295
1337
  };
1296
1338
  const context2 = {
1297
1339
  userAgent: request.headers.get("user-agent") || "",
1298
- ipAddress: (request.ip ?? request.headers.get("x-forwarded-for")) || "",
1340
+ ipAddress: getClientIp(request) || "",
1299
1341
  headers: Object.fromEntries(request.headers.entries()),
1300
1342
  url: request.url,
1301
1343
  method: request.method,
1302
1344
  timestamp: /* @__PURE__ */ new Date()
1303
1345
  };
1304
- detector.emit("agent.session.continued", existingSession, context2);
1346
+ activeDetector.emit("agent.session.continued", existingSession, context2);
1305
1347
  return response2;
1306
1348
  }
1307
1349
  const userAgent = request.headers.get("user-agent");
1308
- const ipAddress = request.ip ?? request.headers.get("x-forwarded-for");
1350
+ const ipAddress = getClientIp(request);
1309
1351
  const url = new URL(request.url);
1310
1352
  const pathWithQuery = url.pathname + url.search;
1311
1353
  const context = {
@@ -1317,15 +1359,19 @@ function createAgentShieldMiddleware(config = {}) {
1317
1359
  method: request.method,
1318
1360
  timestamp: /* @__PURE__ */ new Date()
1319
1361
  };
1320
- const result = await detector.analyze(context);
1321
- if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 70)) {
1362
+ const result = await activeDetector.analyze(context);
1363
+ const decision = evaluateEnforcement(result, {
1364
+ confidenceThreshold: config.confidenceThreshold,
1365
+ defaultAction: onAgentDetected
1366
+ });
1367
+ if (decision.shouldNotify) {
1322
1368
  if (onDetection) {
1323
1369
  const customResponse = await onDetection(request, result);
1324
1370
  if (customResponse) {
1325
1371
  return customResponse;
1326
1372
  }
1327
1373
  }
1328
- switch (onAgentDetected) {
1374
+ switch (decision.action) {
1329
1375
  case "block": {
1330
1376
  const response2 = NextResponse.json(
1331
1377
  {
@@ -1341,11 +1387,17 @@ function createAgentShieldMiddleware(config = {}) {
1341
1387
  response2.headers.set(key, value);
1342
1388
  });
1343
1389
  }
1344
- detector.emit("agent.blocked", result, context);
1390
+ activeDetector.emit("agent.blocked", result, context);
1345
1391
  return response2;
1346
1392
  }
1347
- case "redirect":
1348
- return NextResponse.redirect(new URL(redirectUrl, request.url));
1393
+ case "redirect": {
1394
+ const redirectTarget = new URL(redirectUrl, request.url);
1395
+ const agentName = result.detectedAgent?.name;
1396
+ if (agentName && !redirectTarget.searchParams.has("agent")) {
1397
+ redirectTarget.searchParams.set("agent", agentName.toLowerCase());
1398
+ }
1399
+ return NextResponse.redirect(redirectTarget);
1400
+ }
1349
1401
  case "rewrite":
1350
1402
  return NextResponse.rewrite(new URL(rewriteUrl, request.url));
1351
1403
  case "log":
@@ -1361,9 +1413,7 @@ function createAgentShieldMiddleware(config = {}) {
1361
1413
  break;
1362
1414
  case "allow":
1363
1415
  default:
1364
- if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 70)) {
1365
- detector.emit("agent.allowed", result, context);
1366
- }
1416
+ activeDetector.emit("agent.allowed", result, context);
1367
1417
  break;
1368
1418
  }
1369
1419
  }
@@ -1372,15 +1422,15 @@ function createAgentShieldMiddleware(config = {}) {
1372
1422
  skipped: false
1373
1423
  };
1374
1424
  let response = NextResponse.next();
1375
- response.headers.set("x-agentshield-detected", result.isAgent.toString());
1376
- response.headers.set("x-agentshield-confidence", result.confidence.toString());
1425
+ response.headers.set("kya-detected", result.isAgent.toString());
1426
+ response.headers.set("kya-confidence", result.confidence.toString());
1377
1427
  if (result.detectedAgent?.name) {
1378
- response.headers.set("x-agentshield-agent", result.detectedAgent.name);
1428
+ response.headers.set("kya-agent", result.detectedAgent.name);
1379
1429
  }
1380
- if (sessionTracker && result.isAgent && result.confidence >= (config.confidenceThreshold ?? 70)) {
1430
+ if (sessionTracker && decision.shouldNotify) {
1381
1431
  response = await sessionTracker.track(request, response, result);
1382
- response.headers.set("x-agentshield-session", "new");
1383
- detector.emit("agent.session.started", result, context);
1432
+ response.headers.set("kya-session", "new");
1433
+ activeDetector.emit("agent.session.started", result, context);
1384
1434
  }
1385
1435
  return response;
1386
1436
  } catch (error) {
@@ -1721,8 +1771,6 @@ async function createStorageAdapter(config) {
1721
1771
  }
1722
1772
  return new MemoryStorageAdapter();
1723
1773
  }
1724
-
1725
- // src/enhanced-middleware.ts
1726
1774
  var SessionManager = class {
1727
1775
  sessionLastActivity = /* @__PURE__ */ new Map();
1728
1776
  generateSessionId(ipAddress, userAgent) {
@@ -1829,7 +1877,7 @@ function createEnhancedAgentShieldMiddleware(config = {}) {
1829
1877
  return NextResponse.next();
1830
1878
  }
1831
1879
  const userAgent = request.headers.get("user-agent");
1832
- const ipAddress = request.ip ?? request.headers.get("x-forwarded-for");
1880
+ const ipAddress = getClientIp(request);
1833
1881
  const url = new URL(request.url);
1834
1882
  const pathWithQuery = url.pathname + url.search;
1835
1883
  const context = {
@@ -1844,14 +1892,21 @@ function createEnhancedAgentShieldMiddleware(config = {}) {
1844
1892
  const result = await activeDetector.analyze(context);
1845
1893
  let finalConfidence = result.confidence;
1846
1894
  let verificationMethod = result.verificationMethod || "pattern";
1847
- if (result.isAgent && wasmConfidenceUtils) {
1895
+ if (shouldEnforce(result) && wasmConfidenceUtils) {
1848
1896
  const reasons = result.reasons || [];
1849
1897
  if (wasmConfidenceUtils.shouldIndicateWasmVerification(result.confidence)) {
1850
1898
  finalConfidence = wasmConfidenceUtils.getWasmConfidenceBoost(result.confidence, reasons);
1851
1899
  verificationMethod = wasmConfidenceUtils.getVerificationMethod(finalConfidence, reasons);
1852
1900
  }
1853
1901
  }
1854
- if (result.isAgent && finalConfidence >= (config.confidenceThreshold ?? 0.7)) {
1902
+ const decision = evaluateEnforcement(
1903
+ { ...result, confidence: finalConfidence },
1904
+ {
1905
+ confidenceThreshold: config.confidenceThreshold,
1906
+ defaultAction: config.onAgentDetected
1907
+ }
1908
+ );
1909
+ if (decision.shouldNotify) {
1855
1910
  if (sessionTrackingEnabled) {
1856
1911
  const storage = await getStorage();
1857
1912
  const sessionId = sessionManager.generateSessionId(
@@ -1915,26 +1970,23 @@ function createEnhancedAgentShieldMiddleware(config = {}) {
1915
1970
  if (config.onDetection) {
1916
1971
  await config.onDetection(result, context);
1917
1972
  }
1918
- switch (config.onAgentDetected) {
1973
+ switch (decision.action) {
1919
1974
  case "block": {
1920
1975
  const { status = 403, message = "Access denied: AI agent detected" } = config.blockedResponse || {};
1921
1976
  const response2 = NextResponse.json(
1922
1977
  { error: message, detected: true, confidence: finalConfidence },
1923
1978
  { status }
1924
1979
  );
1925
- response2.headers.set("x-agentshield-detected", "true");
1926
- response2.headers.set(
1927
- "x-agentshield-confidence",
1928
- String(Math.round(finalConfidence * 100))
1929
- );
1930
- response2.headers.set("x-agentshield-agent", result.detectedAgent?.name || "Unknown");
1931
- response2.headers.set("x-agentshield-verification", verificationMethod);
1980
+ response2.headers.set("kya-detected", "true");
1981
+ response2.headers.set("kya-confidence", String(Math.round(finalConfidence * 100)));
1982
+ response2.headers.set("kya-agent", result.detectedAgent?.name || "Unknown");
1983
+ response2.headers.set("kya-verification", verificationMethod);
1932
1984
  return response2;
1933
1985
  }
1934
1986
  case "log": {
1935
1987
  const isInteresting = finalConfidence >= 0.9 || result.detectedAgent?.name?.toLowerCase().includes("chatgpt") || result.detectedAgent?.name?.toLowerCase().includes("perplexity") || verificationMethod === "signature";
1936
1988
  if (isInteresting && process.env.NODE_ENV !== "production") {
1937
- console.debug(`[AgentShield] \u{1F916} AI Agent detected (${verificationMethod}):`, {
1989
+ console.debug(`[AgentShield] AI Agent detected (${verificationMethod}):`, {
1938
1990
  agent: result.detectedAgent?.name,
1939
1991
  confidence: `${(finalConfidence * 100).toFixed(0)}%`,
1940
1992
  path: pathWithQuery,
@@ -1947,14 +1999,14 @@ function createEnhancedAgentShieldMiddleware(config = {}) {
1947
1999
  }
1948
2000
  const response = NextResponse.next();
1949
2001
  if (result.isAgent) {
1950
- response.headers.set("x-agentshield-detected", "true");
1951
- response.headers.set("x-agentshield-confidence", String(Math.round(finalConfidence * 100)));
1952
- response.headers.set("x-agentshield-agent", result.detectedAgent?.name || "Unknown");
1953
- response.headers.set("x-agentshield-verification", verificationMethod);
2002
+ response.headers.set("kya-detected", "true");
2003
+ response.headers.set("kya-confidence", String(Math.round(finalConfidence * 100)));
2004
+ response.headers.set("kya-agent", result.detectedAgent?.name || "Unknown");
2005
+ response.headers.set("kya-verification", verificationMethod);
1954
2006
  if (finalConfidence > 0.9) {
1955
- response.headers.set("x-ai-visitor", "true");
1956
- response.headers.set("x-ai-confidence", finalConfidence.toString());
1957
- response.headers.set("x-ai-verification", verificationMethod);
2007
+ response.headers.set("kya-ai-visitor", "true");
2008
+ response.headers.set("kya-ai-confidence", finalConfidence.toString());
2009
+ response.headers.set("kya-ai-verification", verificationMethod);
1958
2010
  }
1959
2011
  }
1960
2012
  return response;
@@ -1963,7 +2015,7 @@ function createEnhancedAgentShieldMiddleware(config = {}) {
1963
2015
 
1964
2016
  // src/api-client.ts
1965
2017
  var DEFAULT_BASE_URL = "https://kya.vouched.id";
1966
- var EDGE_DETECT_URL = "https://detect.kya-os.ai";
2018
+ var EDGE_DETECT_URL = "https://detect.checkpoint-gateway.ai";
1967
2019
  var DEFAULT_TIMEOUT = 5e3;
1968
2020
  var AgentShieldClient = class {
1969
2021
  apiKey;
@@ -2153,6 +2205,80 @@ function getAgentShieldClient(config) {
2153
2205
  function resetAgentShieldClient() {
2154
2206
  clientInstance = null;
2155
2207
  }
2208
+ var MCP_I_DOCS_URL = "https://docs.knowthat.ai/mcp-i/getting-started";
2209
+ var DEFAULT_CONNECT_PATH = "/connect";
2210
+ function buildAgentInstructionResponse(request, decision, redirectUrl) {
2211
+ const resolved = resolveUrl(redirectUrl ?? DEFAULT_CONNECT_PATH, request.url);
2212
+ const agentName = decision.agentName || decision.agentType || "unknown";
2213
+ if (!resolved.searchParams.has("agent")) {
2214
+ resolved.searchParams.set("agent", agentName.toLowerCase());
2215
+ }
2216
+ const authUrl = resolved.toString();
2217
+ const hostname = safeHostname(request.url);
2218
+ const body = {
2219
+ // Markdown-formatted so clients that render markdown (Claude Desktop,
2220
+ // ChatGPT web) surface the URL as a clickable link. Tone mirrors the
2221
+ // gateway response so messaging stays consistent across platforms.
2222
+ message: `I can't access ${hostname} yet \u2014 this site checks AI assistants at the front door.
2223
+
2224
+ **To give me access, open this link:**
2225
+ [Connect securely to ${hostname}](${authUrl})
2226
+
2227
+ It only takes a moment and you won't need to do it again. Once you're done, ask me to try again and I'll connect through the verified channel automatically.`,
2228
+ user_action_required: {
2229
+ action: `Connect securely to ${hostname}`,
2230
+ url: authUrl,
2231
+ reason: `${hostname} checks AI assistants before they connect. Open the link to give your assistant a verified key.`
2232
+ },
2233
+ mcp_i: {
2234
+ version: "1.0",
2235
+ action: "authenticate",
2236
+ authorization_url: authUrl,
2237
+ flow: {
2238
+ type: "oauth2_delegation",
2239
+ steps: [
2240
+ "1. Direct your user to the authorization_url",
2241
+ "2. User reviews requested scopes and grants consent",
2242
+ "3. Receive delegation credential (JWT)",
2243
+ "4. Include credential in KYA-Delegation header",
2244
+ "5. Retry this request with the proof"
2245
+ ]
2246
+ },
2247
+ retry_instructions: {
2248
+ header: "KYA-Delegation",
2249
+ format: "JWT delegation credential from authorization flow"
2250
+ },
2251
+ documentation: MCP_I_DOCS_URL
2252
+ },
2253
+ error: "mcp_authentication_required",
2254
+ code: "AGENT_REQUIRES_DELEGATION",
2255
+ detection: {
2256
+ agent_type: decision.agentType || "ai_agent",
2257
+ agent_name: decision.agentName || "Unknown Agent",
2258
+ confidence: decision.confidence
2259
+ }
2260
+ };
2261
+ const response = NextResponse.json(body, { status: 401 });
2262
+ response.headers.set("WWW-Authenticate", `KYA realm="api", authorization_uri="${authUrl}"`);
2263
+ response.headers.set(
2264
+ "Link",
2265
+ `<${authUrl}>; rel="kya-authorize", <${MCP_I_DOCS_URL}>; rel="help"`
2266
+ );
2267
+ response.headers.set("KYA-Auth-Required", "true");
2268
+ response.headers.set("KYA-Auth-Url", authUrl);
2269
+ response.headers.set("KYA-Action", "instruct");
2270
+ response.headers.set("KYA-Detected-Agent", agentName);
2271
+ response.headers.set("KYA-Confidence", decision.confidence.toString());
2272
+ response.headers.set("Cache-Control", "no-store");
2273
+ return response;
2274
+ }
2275
+ function resolveUrl(target, baseUrl2) {
2276
+ try {
2277
+ return new URL(target, baseUrl2);
2278
+ } catch {
2279
+ return new URL(DEFAULT_CONNECT_PATH, baseUrl2);
2280
+ }
2281
+ }
2156
2282
 
2157
2283
  // src/api-middleware.ts
2158
2284
  function matchPath(path, pattern) {
@@ -2173,35 +2299,52 @@ function shouldIncludePath(path, includePaths) {
2173
2299
  if (!includePaths || includePaths.length === 0) return true;
2174
2300
  return includePaths.some((pattern) => matchPath(path, pattern));
2175
2301
  }
2176
- function buildBlockedResponse(decision, config) {
2302
+ function buildBlockedResponse(request, decision, config) {
2177
2303
  const status = config.blockedResponse?.status ?? 403;
2178
- const redirectUrl = config.redirectUrl || decision.redirectUrl;
2179
- const baseMessage = config.blockedResponse?.message ?? decision.message ?? "Access denied";
2180
- const errorMessage = redirectUrl ? `${baseMessage}. Please go to ${redirectUrl}` : baseMessage;
2181
- const message = config.blockedResponse?.message ?? decision.message ?? (redirectUrl ? `AI agents are not permitted on this resource. Please go to ${redirectUrl} for more information.` : "AI agents are not permitted on this resource.");
2182
- const responseBody = {
2183
- error: errorMessage,
2304
+ const message = config.blockedResponse?.message ?? decision.message ?? "Access denied";
2305
+ const recoveryUrl = resolveRecoveryUrl(request, config.redirectUrl || decision.redirectUrl);
2306
+ const body = {
2307
+ error: message,
2184
2308
  code: "AGENT_BLOCKED",
2185
2309
  reason: decision.reason,
2186
- agentType: decision.agentType,
2187
- message
2310
+ agentType: decision.agentType
2188
2311
  };
2189
- if (redirectUrl) {
2190
- responseBody.redirectUrl = redirectUrl;
2312
+ if (recoveryUrl) {
2313
+ const hostname = safeHostname(request.url);
2314
+ body.user_action_required = {
2315
+ action: `Connect securely to ${hostname}`,
2316
+ url: recoveryUrl,
2317
+ reason: `${hostname} blocks unverified AI assistants. Open the link to give your assistant a verified key and try again.`
2318
+ };
2319
+ body.message = `I can't access ${hostname} \u2014 this site blocks unverified AI assistants.
2320
+
2321
+ **To give me access, open this link:**
2322
+ [Connect securely to ${hostname}](${recoveryUrl})
2323
+
2324
+ Once you're done, ask me to try again.`;
2191
2325
  }
2192
- const response = NextResponse.json(responseBody, { status });
2326
+ const response = NextResponse.json(body, { status });
2193
2327
  if (config.blockedResponse?.headers) {
2194
2328
  for (const [key, value] of Object.entries(config.blockedResponse.headers)) {
2195
2329
  response.headers.set(key, value);
2196
2330
  }
2197
2331
  }
2198
- response.headers.set("X-AgentShield-Action", decision.action);
2199
- response.headers.set("X-AgentShield-Reason", decision.reason);
2200
- if (redirectUrl) {
2201
- response.headers.set("X-AgentShield-Redirect", redirectUrl);
2332
+ if (recoveryUrl) {
2333
+ response.headers.set("Link", `<${recoveryUrl}>; rel="kya-authorize"`);
2334
+ response.headers.set("KYA-Auth-Url", recoveryUrl);
2202
2335
  }
2336
+ response.headers.set("KYA-Action", decision.action);
2337
+ response.headers.set("KYA-Reason", decision.reason);
2203
2338
  return response;
2204
2339
  }
2340
+ function resolveRecoveryUrl(request, target) {
2341
+ if (!target) return void 0;
2342
+ try {
2343
+ return new URL(target, request.url).toString();
2344
+ } catch {
2345
+ return void 0;
2346
+ }
2347
+ }
2205
2348
  function buildRedirectResponse(request, decision, config) {
2206
2349
  const redirectUrl = config.redirectUrl || decision.redirectUrl || "/blocked";
2207
2350
  const url = new URL(redirectUrl, request.url);
@@ -2246,7 +2389,7 @@ function withAgentShield(config = {}) {
2246
2389
  try {
2247
2390
  const client2 = getClient();
2248
2391
  const userAgent = request.headers.get("user-agent") || void 0;
2249
- const ipAddress = request.ip || request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || request.headers.get("x-real-ip") || void 0;
2392
+ const ipAddress = getClientIp(request);
2250
2393
  const result = await client2.enforce({
2251
2394
  headers: Object.fromEntries(request.headers.entries()),
2252
2395
  userAgent,
@@ -2297,6 +2440,7 @@ function withAgentShield(config = {}) {
2297
2440
  if (decision.isAgent && config.onAgentDetected) {
2298
2441
  await config.onAgentDetected(request, decision);
2299
2442
  }
2443
+ const redirectMode = config.redirectMode ?? "instruct";
2300
2444
  switch (decision.action) {
2301
2445
  case "block": {
2302
2446
  if (config.customBlockedResponse) {
@@ -2305,10 +2449,15 @@ function withAgentShield(config = {}) {
2305
2449
  if (config.onBlock === "redirect") {
2306
2450
  return buildRedirectResponse(request, decision, config);
2307
2451
  }
2308
- return buildBlockedResponse(decision, config);
2452
+ return buildBlockedResponse(request, decision, config);
2309
2453
  }
2310
- case "redirect": {
2311
- return buildRedirectResponse(request, decision, config);
2454
+ case "redirect":
2455
+ case "instruct": {
2456
+ if (redirectMode === "http" && decision.action === "redirect") {
2457
+ return buildRedirectResponse(request, decision, config);
2458
+ }
2459
+ const targetUrl = config.redirectUrl || decision.redirectUrl;
2460
+ return buildAgentInstructionResponse(request, decision, targetUrl);
2312
2461
  }
2313
2462
  case "challenge": {
2314
2463
  return buildRedirectResponse(request, decision, config);
@@ -2318,10 +2467,10 @@ function withAgentShield(config = {}) {
2318
2467
  default: {
2319
2468
  const response = NextResponse.next();
2320
2469
  if (decision.isAgent) {
2321
- response.headers.set("X-AgentShield-Detected", "true");
2322
- response.headers.set("X-AgentShield-Confidence", decision.confidence.toString());
2470
+ response.headers.set("KYA-Detected", "true");
2471
+ response.headers.set("KYA-Confidence", decision.confidence.toString());
2323
2472
  if (decision.agentName) {
2324
- response.headers.set("X-AgentShield-Agent", decision.agentName);
2473
+ response.headers.set("KYA-Agent", decision.agentName);
2325
2474
  }
2326
2475
  }
2327
2476
  return response;
@@ -2379,24 +2528,28 @@ function buildBlockedResponse2(decision, config) {
2379
2528
  response.headers.set(key, value);
2380
2529
  }
2381
2530
  }
2382
- response.headers.set("X-AgentShield-Action", decision.action);
2383
- response.headers.set("X-AgentShield-Reason", decision.reason);
2384
- response.headers.set("X-AgentShield-MatchType", decision.matchType);
2531
+ response.headers.set("KYA-Action", decision.action);
2532
+ response.headers.set("KYA-Reason", decision.reason);
2533
+ response.headers.set("KYA-Match-Type", decision.matchType);
2385
2534
  return response;
2386
2535
  }
2387
- function buildRedirectResponse2(request, decision, config) {
2536
+ function buildRedirectResponse2(request, decision, config, detection) {
2388
2537
  const redirectUrl = decision.redirectUrl || config.redirectUrl || "/blocked";
2389
2538
  const url = new URL(redirectUrl, request.url);
2390
2539
  url.searchParams.set("reason", decision.reason);
2391
2540
  if (decision.ruleId) {
2392
2541
  url.searchParams.set("ruleId", decision.ruleId);
2393
2542
  }
2543
+ const agentName = detection?.detectedAgent?.name;
2544
+ if (agentName && !url.searchParams.has("agent")) {
2545
+ url.searchParams.set("agent", agentName.toLowerCase());
2546
+ }
2394
2547
  return NextResponse.redirect(url);
2395
2548
  }
2396
- function buildChallengeResponse(request, decision, config) {
2397
- return buildRedirectResponse2(request, decision, config);
2549
+ function buildChallengeResponse(request, decision, config, detection) {
2550
+ return buildRedirectResponse2(request, decision, config, detection);
2398
2551
  }
2399
- async function handlePolicyDecision(request, decision, config) {
2552
+ async function handlePolicyDecision(request, decision, config, detection) {
2400
2553
  switch (decision.action) {
2401
2554
  case ENFORCEMENT_ACTIONS.BLOCK:
2402
2555
  if (config.customBlockedResponse) {
@@ -2404,9 +2557,9 @@ async function handlePolicyDecision(request, decision, config) {
2404
2557
  }
2405
2558
  return buildBlockedResponse2(decision, config);
2406
2559
  case ENFORCEMENT_ACTIONS.REDIRECT:
2407
- return buildRedirectResponse2(request, decision, config);
2560
+ return buildRedirectResponse2(request, decision, config, detection);
2408
2561
  case ENFORCEMENT_ACTIONS.CHALLENGE:
2409
- return buildChallengeResponse(request, decision, config);
2562
+ return buildChallengeResponse(request, decision, config, detection);
2410
2563
  case ENFORCEMENT_ACTIONS.LOG:
2411
2564
  console.log("[AgentShield] Policy decision (log):", {
2412
2565
  path: request.nextUrl.pathname,
@@ -2480,7 +2633,7 @@ async function applyPolicy(request, detection, config) {
2480
2633
  if (config.onPolicyDecision) {
2481
2634
  await config.onPolicyDecision(request, decision, context);
2482
2635
  }
2483
- return await handlePolicyDecision(request, decision, config);
2636
+ return await handlePolicyDecision(request, decision, config, detection);
2484
2637
  } catch (error) {
2485
2638
  if (config.debug) {
2486
2639
  console.error("[AgentShield] Policy evaluation error:", error);