@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,3 +1,3 @@
1
1
  import 'next/server';
2
- import '../types-B3USs-Kx.mjs';
3
- export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-DSpisQst.mjs';
2
+ import '../types-rFh4VMH4.mjs';
3
+ export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-BW1rzr1I.mjs';
@@ -1,3 +1,3 @@
1
1
  import 'next/server';
2
- import '../types-B3USs-Kx.js';
3
- export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-66R1KW8e.js';
2
+ import '../types-rFh4VMH4.js';
3
+ export { c as createMatcherConfig, a as createMiddleware } from '../nextjs-V_K0qlAQ.js';
@@ -36,26 +36,15 @@ __export(nextjs_exports, {
36
36
  module.exports = __toCommonJS(nextjs_exports);
37
37
 
38
38
  // src/access-levels.ts
39
- var ACCESS_LEVEL_HIERARCHY = {
40
- none: 0,
41
- restricted: 1,
42
- "read-only": 2,
43
- standard: 3,
44
- full: 4,
45
- internal: 5
46
- };
47
39
  function getTrustLevel(score) {
48
40
  if (score >= 80) return "PLATINUM";
49
41
  if (score >= 60) return "GOLD";
50
42
  if (score >= 40) return "SILVER";
51
43
  return "BRONZE";
52
44
  }
53
- function hasMinimumAccess(actual, required) {
54
- return ACCESS_LEVEL_HIERARCHY[actual] >= ACCESS_LEVEL_HIERARCHY[required];
55
- }
56
45
 
57
46
  // src/version.ts
58
- var SDK_VERSION = "3.0.0";
47
+ var SDK_VERSION = "3.2.0";
59
48
 
60
49
  // src/well-known.ts
61
50
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -108,7 +97,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
108
97
  }
109
98
  }
110
99
  var verificationCache = /* @__PURE__ */ new Map();
111
- function getCacheKey(request) {
100
+ function getCacheKey(request, counterpartyId) {
112
101
  const c = request.credentials;
113
102
  return [
114
103
  c.astraId || "",
@@ -121,6 +110,14 @@ function getCacheKey(request) {
121
110
  request.jurisdiction || "",
122
111
  request.transactionValue ?? "",
123
112
  request.currency || "",
113
+ // SECURITY (cross-merchant cache leak): the merchant identity is sent via
114
+ // `config.counterpartyId`, NOT on the request, so it was previously absent
115
+ // from the key — two verifies for the SAME agent/purpose/action/value but
116
+ // DIFFERENT merchants collided, and a grant at a permissive merchant (low
117
+ // trust floor) was served for a stricter one. Same bug class as the
118
+ // duration omission (F-A1-07). counterpartyId affects the backend verdict
119
+ // (trust floor / per-route policy), so it MUST key the cache.
120
+ counterpartyId || "",
124
121
  request.counterpartyUrl || "",
125
122
  request.counterpartyType || "",
126
123
  request.isSubAgentRequest ? "1" : "0",
@@ -144,8 +141,8 @@ function getCacheKey(request) {
144
141
  request.callerMetadata?.agentCardUrl || ""
145
142
  ].join("|");
146
143
  }
147
- function getCachedResult(request) {
148
- const key = getCacheKey(request);
144
+ function getCachedResult(request, counterpartyId) {
145
+ const key = getCacheKey(request, counterpartyId);
149
146
  const cached = verificationCache.get(key);
150
147
  if (cached && cached.expiresAt > Date.now()) {
151
148
  return cached.result;
@@ -157,9 +154,9 @@ function getCachedResult(request) {
157
154
  }
158
155
  var DEFAULT_AUTONOMOUS_TTL_SECONDS = 60;
159
156
  var DEFAULT_STEP_UP_TTL_SECONDS = 300;
160
- function cacheResult(request, result, configuredTtl) {
157
+ function cacheResult(request, result, configuredTtl, counterpartyId) {
161
158
  const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : result.requiresStepUp ? DEFAULT_STEP_UP_TTL_SECONDS : DEFAULT_AUTONOMOUS_TTL_SECONDS;
162
- const key = getCacheKey(request);
159
+ const key = getCacheKey(request, counterpartyId);
163
160
  verificationCache.set(key, {
164
161
  result,
165
162
  expiresAt: Date.now() + ttlSeconds * 1e3
@@ -317,7 +314,7 @@ async function verify(config, request) {
317
314
  );
318
315
  }
319
316
  if (mergedConfig.cacheTtl !== 0) {
320
- const cached = getCachedResult(request);
317
+ const cached = getCachedResult(request, mergedConfig.counterpartyId);
321
318
  if (cached) {
322
319
  if (mergedConfig.debug) {
323
320
  console.log("[VerificationGateway] Returning cached result");
@@ -369,8 +366,8 @@ async function verify(config, request) {
369
366
  verifiedAt: /* @__PURE__ */ new Date(),
370
367
  // Extract sessionId so decisions can be recorded for denials too
371
368
  sessionId: apiResponse.sessionId,
372
- // v2.3.10 (defect #34, round-4): anonymous traffic has no session →
373
- // correlationId is the linking key for paired local_override events.
369
+ // Anonymous traffic has no session → correlationId is the per-attempt
370
+ // linking key (the sessionId-equivalent for anonymous callers).
374
371
  correlationId: apiResponse.correlationId,
375
372
  recommendation: apiResponse.recommendation,
376
373
  recommendationReasons: apiResponse.recommendationReasons
@@ -444,13 +441,10 @@ async function verify(config, request) {
444
441
  };
445
442
  } else if (result.recommendation === "step_up_required") {
446
443
  result.requiresStepUp = true;
447
- if (ACCESS_LEVEL_HIERARCHY[result.accessLevel] > ACCESS_LEVEL_HIERARCHY["read-only"]) {
448
- result.accessLevel = "read-only";
449
- }
450
444
  result.denialReasons = result.recommendationReasons || ["Step-up verification required"];
451
445
  }
452
446
  if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny") {
453
- cacheResult(request, result, mergedConfig.cacheTtl);
447
+ cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
454
448
  }
455
449
  return result;
456
450
  }
@@ -505,6 +499,13 @@ function extractHttpCredentials(headers) {
505
499
  purpose: { category, action }
506
500
  };
507
501
  }
502
+ const astraAction = getValue(`${HEADER_PREFIX}Action`) ?? getValue("x-astra-action");
503
+ if (astraAction) {
504
+ credentials.pdlss = {
505
+ ...credentials.pdlss,
506
+ purpose: { category: credentials.pdlss?.purpose?.category ?? "", action: astraAction }
507
+ };
508
+ }
508
509
  const duration = getValue(`${HEADER_PREFIX}Duration`) ?? getValue("x-astra-duration");
509
510
  if (duration) {
510
511
  credentials.pdlss = {
@@ -570,6 +571,85 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
570
571
  return failures;
571
572
  }
572
573
 
574
+ // src/adapters/http-pdlss.ts
575
+ var HTTP_METHOD_ACTION_TABLE = {
576
+ GET: "data.read",
577
+ HEAD: "data.read",
578
+ OPTIONS: "data.read",
579
+ POST: "data.write",
580
+ PUT: "data.write",
581
+ PATCH: "data.write",
582
+ DELETE: "data.delete"
583
+ };
584
+ var DEFAULT_HTTP_ACTION = "data.write";
585
+ var DEFAULT_HTTP_PURPOSE = "data";
586
+ function actionForHttpMethod(method) {
587
+ return HTTP_METHOD_ACTION_TABLE[method.toUpperCase()] ?? DEFAULT_HTTP_ACTION;
588
+ }
589
+ function normalizePurposeHeader(value) {
590
+ const colon = value.indexOf(":");
591
+ if (colon >= 0) {
592
+ return { purpose: value.slice(0, colon) };
593
+ }
594
+ const dot = value.indexOf(".");
595
+ if (dot > 0 && dot < value.length - 1) {
596
+ return { purpose: value.slice(0, dot), actionCandidate: value };
597
+ }
598
+ return { purpose: value };
599
+ }
600
+ function resolveHttpPdlss(input) {
601
+ const fromHeader = input.astraPurpose ? normalizePurposeHeader(input.astraPurpose) : void 0;
602
+ let action;
603
+ let actionSource;
604
+ if (input.routeAction) {
605
+ action = input.routeAction;
606
+ actionSource = "route_config";
607
+ } else if (input.hasCustomActionExtractor && input.customAction) {
608
+ action = input.customAction;
609
+ actionSource = "custom_extractor";
610
+ } else if (!input.hasCustomActionExtractor && input.astraAction) {
611
+ action = input.astraAction;
612
+ actionSource = "header";
613
+ } else if (!input.hasCustomActionExtractor && fromHeader?.actionCandidate) {
614
+ action = fromHeader.actionCandidate;
615
+ actionSource = "purpose_header_derived";
616
+ } else {
617
+ action = actionForHttpMethod(input.method);
618
+ actionSource = "method_table";
619
+ }
620
+ let purpose;
621
+ let purposeSource;
622
+ if (input.routePurpose) {
623
+ purpose = input.routePurpose;
624
+ purposeSource = "route_config";
625
+ } else if (input.hasCustomPurposeExtractor) {
626
+ if (input.customPurpose) {
627
+ purpose = input.customPurpose;
628
+ purposeSource = "custom_extractor";
629
+ }
630
+ } else if (fromHeader) {
631
+ purpose = fromHeader.purpose;
632
+ purposeSource = "header";
633
+ } else if (input.legacyPurpose) {
634
+ purpose = input.legacyPurpose;
635
+ purposeSource = "legacy_header";
636
+ } else if (input.queryPurpose) {
637
+ purpose = input.queryPurpose;
638
+ purposeSource = "query";
639
+ }
640
+ if (!purpose) {
641
+ const dot = action.indexOf(".");
642
+ if (dot > 0) {
643
+ purpose = action.slice(0, dot);
644
+ purposeSource = "action_derived";
645
+ } else {
646
+ purpose = DEFAULT_HTTP_PURPOSE;
647
+ purposeSource = "transport_default";
648
+ }
649
+ }
650
+ return { purpose, action, purposeSource, actionSource };
651
+ }
652
+
573
653
  // src/adapters/nextjs.ts
574
654
  function escapeHtml(value) {
575
655
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
@@ -630,28 +710,15 @@ function extractAstraSyncCredentialsFromNextRequest(request) {
630
710
  });
631
711
  return extractHttpCredentials(headers);
632
712
  }
633
- function extractPurpose(request) {
634
- const astraPurpose = request.headers.get("x-astra-purpose");
635
- if (astraPurpose) {
636
- return astraPurpose.split(":")[0];
637
- }
638
- const purposeHeader = request.headers.get("x-purpose");
639
- if (purposeHeader) {
640
- return purposeHeader;
641
- }
642
- switch (request.method.toUpperCase()) {
643
- case "GET":
644
- return "read_data";
645
- case "POST":
646
- return "write_data";
647
- case "PUT":
648
- case "PATCH":
649
- return "write_data";
650
- case "DELETE":
651
- return "delete_data";
652
- default:
653
- return "general";
654
- }
713
+ function resolveNextPdlss(request, routeConfig) {
714
+ return resolveHttpPdlss({
715
+ method: request.method,
716
+ astraPurpose: request.headers.get("x-astra-purpose") ?? void 0,
717
+ astraAction: request.headers.get("x-astra-action") ?? void 0,
718
+ legacyPurpose: request.headers.get("x-purpose") ?? void 0,
719
+ routePurpose: routeConfig?.purpose,
720
+ routeAction: routeConfig?.action
721
+ });
655
722
  }
656
723
  function generateCommerceShieldHtml(result, options) {
657
724
  const title = escapeHtml(options.commerceShield?.title || "AstraSync Agent Verification");
@@ -864,7 +931,16 @@ function createMiddleware(options) {
864
931
  }
865
932
  const credentials = extractCredentialsFromNextRequest(request);
866
933
  const counterpartyUrl = config.counterpartyUrl || request.nextUrl.origin;
867
- const purpose = extractPurpose(request);
934
+ const pdlssPair = resolveNextPdlss(request, routeConfig);
935
+ const purpose = pdlssPair.purpose;
936
+ if (config.debug) {
937
+ console.debug("[nextjs-middleware] pdlss resolved", {
938
+ purpose_source: pdlssPair.purposeSource,
939
+ resolved_purpose: pdlssPair.purpose,
940
+ action_source: pdlssPair.actionSource,
941
+ resolved_action: pdlssPair.action
942
+ });
943
+ }
868
944
  const astraCreds = extractAstraSyncCredentialsFromNextRequest(request);
869
945
  const preCheckFailures = performCounterpartyPreCheck(routeConfig, astraCreds, purpose);
870
946
  if (preCheckFailures.length > 0) {
@@ -918,10 +994,7 @@ function createMiddleware(options) {
918
994
  const result = await verify(config, {
919
995
  credentials,
920
996
  purpose,
921
- // RFC 7230 § 3.1.1 — HTTP method tokens uppercase by IANA convention.
922
- // Backend evaluator tolerates either case as defense-in-depth
923
- // (round-18.6 batch 2); SDK emits canonical form.
924
- action: request.method.toUpperCase(),
997
+ action: pdlssPair.action,
925
998
  resource: pathname,
926
999
  counterpartyUrl,
927
1000
  counterpartyType: config.counterpartyType || "website",
@@ -936,7 +1009,7 @@ function createMiddleware(options) {
936
1009
  agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0
937
1010
  }
938
1011
  });
939
- if (!result.identityVerified || !result.policyAllowed || !hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
1012
+ if (!result.identityVerified || !result.policyAllowed) {
940
1013
  if (pathname.startsWith("/api/")) {
941
1014
  return NextResponse.json(
942
1015
  {
@@ -944,10 +1017,8 @@ function createMiddleware(options) {
944
1017
  error: {
945
1018
  // Round-18 G4: 401 → identity missing (re-auth); 403 → identity
946
1019
  // OK, policy denied (update PDLSS / step up).
947
- code: !result.identityVerified ? "UNAUTHORIZED" : "INSUFFICIENT_ACCESS",
1020
+ code: !result.identityVerified ? "UNAUTHORIZED" : "POLICY_DENIED",
948
1021
  message: result.denialReasons?.[0] || "Access denied",
949
- accessLevel: result.accessLevel,
950
- required: routeConfig.minAccessLevel,
951
1022
  guidance: result.guidance
952
1023
  }
953
1024
  },
@@ -975,7 +1046,6 @@ function createMiddleware(options) {
975
1046
  response.headers.set("X-AstraSync-Access-Level", result.accessLevel);
976
1047
  if (result.agent) {
977
1048
  response.headers.set("X-AstraSync-Agent-Id", result.agent.astraId);
978
- response.headers.set("X-AstraSync-Trust-Score", result.agent.trustScore.toString());
979
1049
  }
980
1050
  return response;
981
1051
  };