@astrasyncai/verification-gateway 3.0.0 → 3.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.
Files changed (87) hide show
  1. package/dist/adapter-interface/interface.d.mts +2 -2
  2. package/dist/adapter-interface/interface.d.ts +2 -2
  3. package/dist/adapters/express.d.mts +2 -2
  4. package/dist/adapters/express.d.ts +2 -2
  5. package/dist/adapters/express.js +145 -93
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +145 -93
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/mcp.d.mts +29 -11
  10. package/dist/adapters/mcp.d.ts +29 -11
  11. package/dist/adapters/mcp.js +43 -102
  12. package/dist/adapters/mcp.js.map +1 -1
  13. package/dist/adapters/mcp.mjs +43 -102
  14. package/dist/adapters/mcp.mjs.map +1 -1
  15. package/dist/adapters/nextjs.d.mts +2 -2
  16. package/dist/adapters/nextjs.d.ts +2 -2
  17. package/dist/adapters/nextjs.js +126 -56
  18. package/dist/adapters/nextjs.js.map +1 -1
  19. package/dist/adapters/nextjs.mjs +126 -56
  20. package/dist/adapters/nextjs.mjs.map +1 -1
  21. package/dist/adapters/sdk.d.mts +2 -2
  22. package/dist/adapters/sdk.d.ts +2 -2
  23. package/dist/adapters/sdk.js +25 -14
  24. package/dist/adapters/sdk.js.map +1 -1
  25. package/dist/adapters/sdk.mjs +25 -14
  26. package/dist/adapters/sdk.mjs.map +1 -1
  27. package/dist/agent/index.d.mts +2 -2
  28. package/dist/agent/index.d.ts +2 -2
  29. package/dist/agent/index.js +3 -0
  30. package/dist/agent/index.js.map +1 -1
  31. package/dist/agent/index.mjs +3 -0
  32. package/dist/agent/index.mjs.map +1 -1
  33. package/dist/browser/background.js +18 -21
  34. package/dist/browser/background.js.map +1 -1
  35. package/dist/browser/background.mjs +18 -21
  36. package/dist/browser/background.mjs.map +1 -1
  37. package/dist/browser/browser-adapter.d.mts +2 -2
  38. package/dist/browser/browser-adapter.d.ts +2 -2
  39. package/dist/cli/index.d.mts +2 -2
  40. package/dist/cli/index.d.ts +2 -2
  41. package/dist/cursor/cursor-adapter.d.mts +2 -2
  42. package/dist/cursor/cursor-adapter.d.ts +2 -2
  43. package/dist/cursor/extension.d.mts +2 -2
  44. package/dist/cursor/extension.d.ts +2 -2
  45. package/dist/cursor/extension.js +18 -21
  46. package/dist/cursor/extension.js.map +1 -1
  47. package/dist/cursor/extension.mjs +18 -21
  48. package/dist/cursor/extension.mjs.map +1 -1
  49. package/dist/{express-CrfwoNAR.d.ts → express-BowlMHQF.d.ts} +1 -1
  50. package/dist/{express-ienhAXps.d.mts → express-CeoSdOAZ.d.mts} +1 -1
  51. package/dist/gateway/gateway.d.mts +2 -2
  52. package/dist/gateway/gateway.d.ts +2 -2
  53. package/dist/gateway/gateway.js +18 -21
  54. package/dist/gateway/gateway.js.map +1 -1
  55. package/dist/gateway/gateway.mjs +18 -21
  56. package/dist/gateway/gateway.mjs.map +1 -1
  57. package/dist/git-trigger/git-hooks.d.mts +2 -2
  58. package/dist/git-trigger/git-hooks.d.ts +2 -2
  59. package/dist/{index-CEg_WG6y.d.mts → index-B51W8gn8.d.mts} +1 -1
  60. package/dist/{index-DC5f8eoQ.d.ts → index-DBmlycVm.d.ts} +1 -1
  61. package/dist/{index-B5e2IDWU.d.mts → index-DtGziFEm.d.mts} +1 -1
  62. package/dist/{index-CCdZxvAr.d.ts → index-DzXXBuLm.d.ts} +1 -1
  63. package/dist/index.d.mts +7 -7
  64. package/dist/index.d.ts +7 -7
  65. package/dist/index.js +209 -191
  66. package/dist/index.js.map +1 -1
  67. package/dist/index.mjs +209 -191
  68. package/dist/index.mjs.map +1 -1
  69. package/dist/local-evaluator/evaluator.d.mts +2 -2
  70. package/dist/local-evaluator/evaluator.d.ts +2 -2
  71. package/dist/{nextjs-DSpisQst.d.mts → nextjs-BW1rzr1I.d.mts} +1 -1
  72. package/dist/{nextjs-66R1KW8e.d.ts → nextjs-V_K0qlAQ.d.ts} +1 -1
  73. package/dist/{sdk-5U_CBRpr.d.mts → sdk-ZYgI7G9f.d.ts} +14 -3
  74. package/dist/{sdk-Bm8np66n.d.ts → sdk-e5jg7sqW.d.mts} +14 -3
  75. package/dist/transport/index.d.mts +2 -2
  76. package/dist/transport/index.d.ts +2 -2
  77. package/dist/transport/index.js +10 -0
  78. package/dist/transport/index.js.map +1 -1
  79. package/dist/transport/index.mjs +10 -0
  80. package/dist/transport/index.mjs.map +1 -1
  81. package/dist/{types-CgDCUfo8.d.mts → types-BNiLZY0i.d.mts} +1 -1
  82. package/dist/{types-R5N4ET6x.d.ts → types-DJi-u3fz.d.ts} +1 -1
  83. package/dist/{types-B3USs-Kx.d.mts → types-rFh4VMH4.d.mts} +30 -2
  84. package/dist/{types-B3USs-Kx.d.ts → types-rFh4VMH4.d.ts} +30 -2
  85. package/dist/ui/index.d.mts +1 -1
  86. package/dist/ui/index.d.ts +1 -1
  87. package/package.json +1 -1
@@ -1,24 +1,13 @@
1
1
  // src/access-levels.ts
2
- var ACCESS_LEVEL_HIERARCHY = {
3
- none: 0,
4
- restricted: 1,
5
- "read-only": 2,
6
- standard: 3,
7
- full: 4,
8
- internal: 5
9
- };
10
2
  function getTrustLevel(score) {
11
3
  if (score >= 80) return "PLATINUM";
12
4
  if (score >= 60) return "GOLD";
13
5
  if (score >= 40) return "SILVER";
14
6
  return "BRONZE";
15
7
  }
16
- function hasMinimumAccess(actual, required) {
17
- return ACCESS_LEVEL_HIERARCHY[actual] >= ACCESS_LEVEL_HIERARCHY[required];
18
- }
19
8
 
20
9
  // src/version.ts
21
- var SDK_VERSION = "3.0.0";
10
+ var SDK_VERSION = "3.2.0";
22
11
 
23
12
  // src/well-known.ts
24
13
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -71,7 +60,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
71
60
  }
72
61
  }
73
62
  var verificationCache = /* @__PURE__ */ new Map();
74
- function getCacheKey(request) {
63
+ function getCacheKey(request, counterpartyId) {
75
64
  const c = request.credentials;
76
65
  return [
77
66
  c.astraId || "",
@@ -84,6 +73,14 @@ function getCacheKey(request) {
84
73
  request.jurisdiction || "",
85
74
  request.transactionValue ?? "",
86
75
  request.currency || "",
76
+ // SECURITY (cross-merchant cache leak): the merchant identity is sent via
77
+ // `config.counterpartyId`, NOT on the request, so it was previously absent
78
+ // from the key — two verifies for the SAME agent/purpose/action/value but
79
+ // DIFFERENT merchants collided, and a grant at a permissive merchant (low
80
+ // trust floor) was served for a stricter one. Same bug class as the
81
+ // duration omission (F-A1-07). counterpartyId affects the backend verdict
82
+ // (trust floor / per-route policy), so it MUST key the cache.
83
+ counterpartyId || "",
87
84
  request.counterpartyUrl || "",
88
85
  request.counterpartyType || "",
89
86
  request.isSubAgentRequest ? "1" : "0",
@@ -107,8 +104,8 @@ function getCacheKey(request) {
107
104
  request.callerMetadata?.agentCardUrl || ""
108
105
  ].join("|");
109
106
  }
110
- function getCachedResult(request) {
111
- const key = getCacheKey(request);
107
+ function getCachedResult(request, counterpartyId) {
108
+ const key = getCacheKey(request, counterpartyId);
112
109
  const cached = verificationCache.get(key);
113
110
  if (cached && cached.expiresAt > Date.now()) {
114
111
  return cached.result;
@@ -120,9 +117,9 @@ function getCachedResult(request) {
120
117
  }
121
118
  var DEFAULT_AUTONOMOUS_TTL_SECONDS = 60;
122
119
  var DEFAULT_STEP_UP_TTL_SECONDS = 300;
123
- function cacheResult(request, result, configuredTtl) {
120
+ function cacheResult(request, result, configuredTtl, counterpartyId) {
124
121
  const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : result.requiresStepUp ? DEFAULT_STEP_UP_TTL_SECONDS : DEFAULT_AUTONOMOUS_TTL_SECONDS;
125
- const key = getCacheKey(request);
122
+ const key = getCacheKey(request, counterpartyId);
126
123
  verificationCache.set(key, {
127
124
  result,
128
125
  expiresAt: Date.now() + ttlSeconds * 1e3
@@ -280,7 +277,7 @@ async function verify(config, request) {
280
277
  );
281
278
  }
282
279
  if (mergedConfig.cacheTtl !== 0) {
283
- const cached = getCachedResult(request);
280
+ const cached = getCachedResult(request, mergedConfig.counterpartyId);
284
281
  if (cached) {
285
282
  if (mergedConfig.debug) {
286
283
  console.log("[VerificationGateway] Returning cached result");
@@ -332,8 +329,8 @@ async function verify(config, request) {
332
329
  verifiedAt: /* @__PURE__ */ new Date(),
333
330
  // Extract sessionId so decisions can be recorded for denials too
334
331
  sessionId: apiResponse.sessionId,
335
- // v2.3.10 (defect #34, round-4): anonymous traffic has no session →
336
- // correlationId is the linking key for paired local_override events.
332
+ // Anonymous traffic has no session → correlationId is the per-attempt
333
+ // linking key (the sessionId-equivalent for anonymous callers).
337
334
  correlationId: apiResponse.correlationId,
338
335
  recommendation: apiResponse.recommendation,
339
336
  recommendationReasons: apiResponse.recommendationReasons
@@ -407,13 +404,10 @@ async function verify(config, request) {
407
404
  };
408
405
  } else if (result.recommendation === "step_up_required") {
409
406
  result.requiresStepUp = true;
410
- if (ACCESS_LEVEL_HIERARCHY[result.accessLevel] > ACCESS_LEVEL_HIERARCHY["read-only"]) {
411
- result.accessLevel = "read-only";
412
- }
413
407
  result.denialReasons = result.recommendationReasons || ["Step-up verification required"];
414
408
  }
415
409
  if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny") {
416
- cacheResult(request, result, mergedConfig.cacheTtl);
410
+ cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
417
411
  }
418
412
  return result;
419
413
  }
@@ -468,6 +462,13 @@ function extractHttpCredentials(headers) {
468
462
  purpose: { category, action }
469
463
  };
470
464
  }
465
+ const astraAction = getValue(`${HEADER_PREFIX}Action`) ?? getValue("x-astra-action");
466
+ if (astraAction) {
467
+ credentials.pdlss = {
468
+ ...credentials.pdlss,
469
+ purpose: { category: credentials.pdlss?.purpose?.category ?? "", action: astraAction }
470
+ };
471
+ }
471
472
  const duration = getValue(`${HEADER_PREFIX}Duration`) ?? getValue("x-astra-duration");
472
473
  if (duration) {
473
474
  credentials.pdlss = {
@@ -533,6 +534,85 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
533
534
  return failures;
534
535
  }
535
536
 
537
+ // src/adapters/http-pdlss.ts
538
+ var HTTP_METHOD_ACTION_TABLE = {
539
+ GET: "data.read",
540
+ HEAD: "data.read",
541
+ OPTIONS: "data.read",
542
+ POST: "data.write",
543
+ PUT: "data.write",
544
+ PATCH: "data.write",
545
+ DELETE: "data.delete"
546
+ };
547
+ var DEFAULT_HTTP_ACTION = "data.write";
548
+ var DEFAULT_HTTP_PURPOSE = "data";
549
+ function actionForHttpMethod(method) {
550
+ return HTTP_METHOD_ACTION_TABLE[method.toUpperCase()] ?? DEFAULT_HTTP_ACTION;
551
+ }
552
+ function normalizePurposeHeader(value) {
553
+ const colon = value.indexOf(":");
554
+ if (colon >= 0) {
555
+ return { purpose: value.slice(0, colon) };
556
+ }
557
+ const dot = value.indexOf(".");
558
+ if (dot > 0 && dot < value.length - 1) {
559
+ return { purpose: value.slice(0, dot), actionCandidate: value };
560
+ }
561
+ return { purpose: value };
562
+ }
563
+ function resolveHttpPdlss(input) {
564
+ const fromHeader = input.astraPurpose ? normalizePurposeHeader(input.astraPurpose) : void 0;
565
+ let action;
566
+ let actionSource;
567
+ if (input.routeAction) {
568
+ action = input.routeAction;
569
+ actionSource = "route_config";
570
+ } else if (input.hasCustomActionExtractor && input.customAction) {
571
+ action = input.customAction;
572
+ actionSource = "custom_extractor";
573
+ } else if (!input.hasCustomActionExtractor && input.astraAction) {
574
+ action = input.astraAction;
575
+ actionSource = "header";
576
+ } else if (!input.hasCustomActionExtractor && fromHeader?.actionCandidate) {
577
+ action = fromHeader.actionCandidate;
578
+ actionSource = "purpose_header_derived";
579
+ } else {
580
+ action = actionForHttpMethod(input.method);
581
+ actionSource = "method_table";
582
+ }
583
+ let purpose;
584
+ let purposeSource;
585
+ if (input.routePurpose) {
586
+ purpose = input.routePurpose;
587
+ purposeSource = "route_config";
588
+ } else if (input.hasCustomPurposeExtractor) {
589
+ if (input.customPurpose) {
590
+ purpose = input.customPurpose;
591
+ purposeSource = "custom_extractor";
592
+ }
593
+ } else if (fromHeader) {
594
+ purpose = fromHeader.purpose;
595
+ purposeSource = "header";
596
+ } else if (input.legacyPurpose) {
597
+ purpose = input.legacyPurpose;
598
+ purposeSource = "legacy_header";
599
+ } else if (input.queryPurpose) {
600
+ purpose = input.queryPurpose;
601
+ purposeSource = "query";
602
+ }
603
+ if (!purpose) {
604
+ const dot = action.indexOf(".");
605
+ if (dot > 0) {
606
+ purpose = action.slice(0, dot);
607
+ purposeSource = "action_derived";
608
+ } else {
609
+ purpose = DEFAULT_HTTP_PURPOSE;
610
+ purposeSource = "transport_default";
611
+ }
612
+ }
613
+ return { purpose, action, purposeSource, actionSource };
614
+ }
615
+
536
616
  // src/adapters/nextjs.ts
537
617
  function escapeHtml(value) {
538
618
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
@@ -593,28 +673,15 @@ function extractAstraSyncCredentialsFromNextRequest(request) {
593
673
  });
594
674
  return extractHttpCredentials(headers);
595
675
  }
596
- function extractPurpose(request) {
597
- const astraPurpose = request.headers.get("x-astra-purpose");
598
- if (astraPurpose) {
599
- return astraPurpose.split(":")[0];
600
- }
601
- const purposeHeader = request.headers.get("x-purpose");
602
- if (purposeHeader) {
603
- return purposeHeader;
604
- }
605
- switch (request.method.toUpperCase()) {
606
- case "GET":
607
- return "read_data";
608
- case "POST":
609
- return "write_data";
610
- case "PUT":
611
- case "PATCH":
612
- return "write_data";
613
- case "DELETE":
614
- return "delete_data";
615
- default:
616
- return "general";
617
- }
676
+ function resolveNextPdlss(request, routeConfig) {
677
+ return resolveHttpPdlss({
678
+ method: request.method,
679
+ astraPurpose: request.headers.get("x-astra-purpose") ?? void 0,
680
+ astraAction: request.headers.get("x-astra-action") ?? void 0,
681
+ legacyPurpose: request.headers.get("x-purpose") ?? void 0,
682
+ routePurpose: routeConfig?.purpose,
683
+ routeAction: routeConfig?.action
684
+ });
618
685
  }
619
686
  function generateCommerceShieldHtml(result, options) {
620
687
  const title = escapeHtml(options.commerceShield?.title || "AstraSync Agent Verification");
@@ -827,7 +894,16 @@ function createMiddleware(options) {
827
894
  }
828
895
  const credentials = extractCredentialsFromNextRequest(request);
829
896
  const counterpartyUrl = config.counterpartyUrl || request.nextUrl.origin;
830
- const purpose = extractPurpose(request);
897
+ const pdlssPair = resolveNextPdlss(request, routeConfig);
898
+ const purpose = pdlssPair.purpose;
899
+ if (config.debug) {
900
+ console.debug("[nextjs-middleware] pdlss resolved", {
901
+ purpose_source: pdlssPair.purposeSource,
902
+ resolved_purpose: pdlssPair.purpose,
903
+ action_source: pdlssPair.actionSource,
904
+ resolved_action: pdlssPair.action
905
+ });
906
+ }
831
907
  const astraCreds = extractAstraSyncCredentialsFromNextRequest(request);
832
908
  const preCheckFailures = performCounterpartyPreCheck(routeConfig, astraCreds, purpose);
833
909
  if (preCheckFailures.length > 0) {
@@ -881,10 +957,7 @@ function createMiddleware(options) {
881
957
  const result = await verify(config, {
882
958
  credentials,
883
959
  purpose,
884
- // RFC 7230 § 3.1.1 — HTTP method tokens uppercase by IANA convention.
885
- // Backend evaluator tolerates either case as defense-in-depth
886
- // (round-18.6 batch 2); SDK emits canonical form.
887
- action: request.method.toUpperCase(),
960
+ action: pdlssPair.action,
888
961
  resource: pathname,
889
962
  counterpartyUrl,
890
963
  counterpartyType: config.counterpartyType || "website",
@@ -899,7 +972,7 @@ function createMiddleware(options) {
899
972
  agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0
900
973
  }
901
974
  });
902
- if (!result.identityVerified || !result.policyAllowed || !hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
975
+ if (!result.identityVerified || !result.policyAllowed) {
903
976
  if (pathname.startsWith("/api/")) {
904
977
  return NextResponse.json(
905
978
  {
@@ -907,10 +980,8 @@ function createMiddleware(options) {
907
980
  error: {
908
981
  // Round-18 G4: 401 → identity missing (re-auth); 403 → identity
909
982
  // OK, policy denied (update PDLSS / step up).
910
- code: !result.identityVerified ? "UNAUTHORIZED" : "INSUFFICIENT_ACCESS",
983
+ code: !result.identityVerified ? "UNAUTHORIZED" : "POLICY_DENIED",
911
984
  message: result.denialReasons?.[0] || "Access denied",
912
- accessLevel: result.accessLevel,
913
- required: routeConfig.minAccessLevel,
914
985
  guidance: result.guidance
915
986
  }
916
987
  },
@@ -938,7 +1009,6 @@ function createMiddleware(options) {
938
1009
  response.headers.set("X-AstraSync-Access-Level", result.accessLevel);
939
1010
  if (result.agent) {
940
1011
  response.headers.set("X-AstraSync-Agent-Id", result.agent.astraId);
941
- response.headers.set("X-AstraSync-Trust-Score", result.agent.trustScore.toString());
942
1012
  }
943
1013
  return response;
944
1014
  };