@astrasyncai/verification-gateway 5.18.1 → 5.20.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 (129) hide show
  1. package/CHANGELOG.md +232 -0
  2. package/README.md +217 -4
  3. package/dist/adapter-interface/interface.d.mts +2 -2
  4. package/dist/adapter-interface/interface.d.ts +2 -2
  5. package/dist/adapters/express.d.mts +9 -1
  6. package/dist/adapters/express.d.ts +9 -1
  7. package/dist/adapters/express.js +160 -52
  8. package/dist/adapters/express.js.map +1 -1
  9. package/dist/adapters/express.mjs +160 -52
  10. package/dist/adapters/express.mjs.map +1 -1
  11. package/dist/adapters/http-pdlss.d.mts +7 -1
  12. package/dist/adapters/http-pdlss.d.ts +7 -1
  13. package/dist/adapters/http-pdlss.js +18 -2
  14. package/dist/adapters/http-pdlss.js.map +1 -1
  15. package/dist/adapters/http-pdlss.mjs +16 -1
  16. package/dist/adapters/http-pdlss.mjs.map +1 -1
  17. package/dist/adapters/kit-express.d.mts +93 -1
  18. package/dist/adapters/kit-express.d.ts +93 -1
  19. package/dist/adapters/kit-express.js +181 -2
  20. package/dist/adapters/kit-express.js.map +1 -1
  21. package/dist/adapters/kit-express.mjs +180 -2
  22. package/dist/adapters/kit-express.mjs.map +1 -1
  23. package/dist/adapters/mcp.d.mts +102 -9
  24. package/dist/adapters/mcp.d.ts +102 -9
  25. package/dist/adapters/mcp.js +242 -19
  26. package/dist/adapters/mcp.js.map +1 -1
  27. package/dist/adapters/mcp.mjs +240 -19
  28. package/dist/adapters/mcp.mjs.map +1 -1
  29. package/dist/adapters/nextjs.d.mts +1 -1
  30. package/dist/adapters/nextjs.d.ts +1 -1
  31. package/dist/adapters/nextjs.js +97 -14
  32. package/dist/adapters/nextjs.js.map +1 -1
  33. package/dist/adapters/nextjs.mjs +97 -14
  34. package/dist/adapters/nextjs.mjs.map +1 -1
  35. package/dist/adapters/sdk.d.mts +101 -2
  36. package/dist/adapters/sdk.d.ts +101 -2
  37. package/dist/adapters/sdk.js +199 -12
  38. package/dist/adapters/sdk.js.map +1 -1
  39. package/dist/adapters/sdk.mjs +199 -12
  40. package/dist/adapters/sdk.mjs.map +1 -1
  41. package/dist/agent/index.d.mts +1 -1
  42. package/dist/agent/index.d.ts +1 -1
  43. package/dist/agent/index.js +1 -1
  44. package/dist/agent/index.js.map +1 -1
  45. package/dist/agent/index.mjs +1 -1
  46. package/dist/agent/index.mjs.map +1 -1
  47. package/dist/bin/astrasync-claude-hook.js +94 -16
  48. package/dist/bin/astrasync-codex-hook.js +94 -16
  49. package/dist/bin/astrasync-guard.js +94 -16
  50. package/dist/bin/astrasync.js +127 -16
  51. package/dist/browser/background.js +94 -16
  52. package/dist/browser/background.js.map +1 -1
  53. package/dist/browser/background.mjs +94 -16
  54. package/dist/browser/background.mjs.map +1 -1
  55. package/dist/cli/index.js +1 -1
  56. package/dist/cli/index.js.map +1 -1
  57. package/dist/cli/index.mjs +1 -1
  58. package/dist/cli/index.mjs.map +1 -1
  59. package/dist/codex/index.js +94 -16
  60. package/dist/codex/index.js.map +1 -1
  61. package/dist/codex/index.mjs +94 -16
  62. package/dist/codex/index.mjs.map +1 -1
  63. package/dist/cursor/extension.js +94 -16
  64. package/dist/cursor/extension.js.map +1 -1
  65. package/dist/cursor/extension.mjs +94 -16
  66. package/dist/cursor/extension.mjs.map +1 -1
  67. package/dist/edge-config.d.mts +1 -1
  68. package/dist/edge-config.d.ts +1 -1
  69. package/dist/edge-config.js +1 -1
  70. package/dist/edge-config.js.map +1 -1
  71. package/dist/edge-config.mjs +1 -1
  72. package/dist/edge-config.mjs.map +1 -1
  73. package/dist/edge-core/index.d.mts +1 -1
  74. package/dist/edge-core/index.d.ts +1 -1
  75. package/dist/edge-core/index.js +69 -12
  76. package/dist/edge-core/index.js.map +1 -1
  77. package/dist/edge-core/index.mjs +69 -12
  78. package/dist/edge-core/index.mjs.map +1 -1
  79. package/dist/gateway/gateway.d.mts +2 -2
  80. package/dist/gateway/gateway.d.ts +2 -2
  81. package/dist/gateway/gateway.js +94 -16
  82. package/dist/gateway/gateway.js.map +1 -1
  83. package/dist/gateway/gateway.mjs +94 -16
  84. package/dist/gateway/gateway.mjs.map +1 -1
  85. package/dist/git-trigger/git-hooks.d.mts +1 -1
  86. package/dist/git-trigger/git-hooks.d.ts +1 -1
  87. package/dist/index.d.mts +706 -34
  88. package/dist/index.d.ts +706 -34
  89. package/dist/index.js +1391 -205
  90. package/dist/index.js.map +1 -1
  91. package/dist/index.mjs +1374 -195
  92. package/dist/index.mjs.map +1 -1
  93. package/dist/local-evaluator/evaluator.d.mts +2 -2
  94. package/dist/local-evaluator/evaluator.d.ts +2 -2
  95. package/dist/registration/index.d.mts +11 -2
  96. package/dist/registration/index.d.ts +11 -2
  97. package/dist/registration/index.js +1 -1
  98. package/dist/registration/index.js.map +1 -1
  99. package/dist/registration/index.mjs +1 -1
  100. package/dist/registration/index.mjs.map +1 -1
  101. package/dist/transport/index.d.mts +1 -1
  102. package/dist/transport/index.d.ts +1 -1
  103. package/dist/transport/index.js +3 -2
  104. package/dist/transport/index.js.map +1 -1
  105. package/dist/transport/index.mjs +3 -2
  106. package/dist/transport/index.mjs.map +1 -1
  107. package/dist/{types-BRz2U0Pn.d.ts → types-B_HLhZ9n.d.ts} +1 -1
  108. package/dist/{types-BfILnheI.d.mts → types-CU17R4Nr.d.mts} +11 -0
  109. package/dist/{types-BfILnheI.d.ts → types-CU17R4Nr.d.ts} +11 -0
  110. package/dist/{types-Cns4l8gX.d.mts → types-CxjqmPl-.d.mts} +115 -13
  111. package/dist/{types-Cns4l8gX.d.ts → types-CxjqmPl-.d.ts} +115 -13
  112. package/dist/{types-3ObBpsnf.d.mts → types-D37aSQ9c.d.mts} +106 -3
  113. package/dist/{types-CfBpm3w5.d.mts → types-Djpz-L0w.d.mts} +1 -1
  114. package/dist/{types-BoxZEYPS.d.ts → types-Dn8tXnei.d.ts} +106 -3
  115. package/dist/ui/index.d.mts +1 -1
  116. package/dist/ui/index.d.ts +1 -1
  117. package/dist/verify.d.mts +50 -4
  118. package/dist/verify.d.ts +50 -4
  119. package/dist/verify.js +93 -14
  120. package/dist/verify.js.map +1 -1
  121. package/dist/verify.mjs +91 -14
  122. package/dist/verify.mjs.map +1 -1
  123. package/dist/webhooks.d.mts +16 -3
  124. package/dist/webhooks.d.ts +16 -3
  125. package/dist/webhooks.js +24 -13
  126. package/dist/webhooks.js.map +1 -1
  127. package/dist/webhooks.mjs +24 -13
  128. package/dist/webhooks.mjs.map +1 -1
  129. package/package.json +1 -1
@@ -53,6 +53,17 @@ interface GatewayConfig {
53
53
  debug?: boolean;
54
54
  /** Custom headers to send with verification requests */
55
55
  customHeaders?: Record<string, string>;
56
+ /**
57
+ * 5.20.0: proof that this caller may act as the agent, sent as
58
+ * `actingProof` in the verify-access body. Honoured only from a
59
+ * first-party AstraSync service caller (the bridge): the backend checks the
60
+ * connector's OAuth access token and records a `connector_owner` proof when
61
+ * its owner owns the agent. Ignored for any other key. A verify carrying it
62
+ * is never served from, or written to, the verdict cache.
63
+ */
64
+ actingProof?: {
65
+ connectorToken: string;
66
+ };
56
67
  /** This counterparty's URL (sent with verify-access requests for analytics) */
57
68
  counterpartyUrl?: string;
58
69
  /** This counterparty's type (sent with verify-access requests for analytics) */
@@ -161,9 +172,15 @@ interface VerifiedAgent {
161
172
  astraId: string;
162
173
  /** Agent display name */
163
174
  name: string;
164
- /** Composite trust score (0-100) */
175
+ /**
176
+ * Composite trust score (0-100). 5.19.0: verify-access returns it to an
177
+ * authenticated counterparty (your API key) — counterparties may see an
178
+ * agent's score; the agent itself never does, so never relay it to the
179
+ * agent. It is withheld (undefined at runtime) for a keyless caller and when
180
+ * the caller is the agent itself; a route `minTrustScore` then fails closed.
181
+ */
165
182
  trustScore: number;
166
- /** Trust level tier */
183
+ /** Trust level tier (derived from `trustScore`) */
167
184
  trustLevel: TrustLevel;
168
185
  /** Whether the agent's identity record is anchored on-chain (5.9.0: was `blockchainVerified`) */
169
186
  blockchainAnchored: boolean;
@@ -297,7 +314,9 @@ interface StepUpApprovalInfo {
297
314
  * Lifecycle states of a step-up approval row (mirrors the backend's
298
315
  * step_up_approval_status_check constraint).
299
316
  */
300
- type StepUpApprovalStatus = 'pending' | 'approved' | 'denied' | 'expired' | 'consumed';
317
+ type StepUpApprovalStatus = 'pending' | 'approved' | 'denied' | 'expired' | 'consumed'
318
+ /** 5.20.0: approved but never redeemed inside the redemption window. */
319
+ | 'lapsed';
301
320
  /**
302
321
  * Terminal outcome of a hold-and-poll wait: any non-pending status, or
303
322
  * 'timeout' when the hold budget ran out while the approval was still pending.
@@ -359,6 +378,20 @@ interface SettlementArtifact {
359
378
  * - `counterparty.<allowlist|trust>`
360
379
  * - `attestation.<type>` (e.g. `attestation.verified_human_party`)
361
380
  * - `endpoint.<deactivated|trust|policy>`
381
+ * - `behaviour.<limit_probing|unattributed_limit_check>` (5.19.0) — the
382
+ * call is part of a sweep of unfinished attempts at rising values (quotes,
383
+ * held/denied confirms, orders that never settled) that maps the agent's
384
+ * spending limit. Completed purchases never count.
385
+ * - `behaviour.limit_probing`: the sweep is provably the agent's own
386
+ * (signed agent request, first-party bridge hop, runtime challenge or
387
+ * the agent's key). Denied with no new step-up approval; the agent's
388
+ * trust drops and its owner is alerted.
389
+ * - `behaviour.unattributed_limit_check`: the sweep can't be attributed
390
+ * to the agent (unsigned or direct merchant calls). Denied — it "needs
391
+ * a signed agent request" — with no agent trust penalty; owners are
392
+ * alerted with the evidence. A repeat of the merchant's own direct
393
+ * calls, or the same pattern across agents of two or more owners,
394
+ * reduces the endpoint owner's trust score.
362
395
  */
363
396
  interface AccessFailure {
364
397
  dimension: string;
@@ -475,6 +508,12 @@ interface VerificationResult {
475
508
  * (steer the user to add one via onboarding).
476
509
  */
477
510
  settlementOutcome?: SettlementOutcomeInfo;
511
+ /**
512
+ * 5.20.0 (round 29.1): non-fatal integration warnings for the caller —
513
+ * e.g. `events_url_missing` when a kit's held confirm is on an endpoint with
514
+ * no Events URL (the kit would never hear the owner's decision).
515
+ */
516
+ warnings?: VerificationWarning[];
478
517
  /**
479
518
  * Card settlement token. Present on a card purchase at a first-party
480
519
  * storefront (our Stripe tenant) — 5.14.1: always, there is no charge-here
@@ -638,6 +677,46 @@ interface CallerMetadata {
638
677
  */
639
678
  observedMetadata?: ObservedMetadata;
640
679
  }
680
+ /**
681
+ * 5.19.0 — the inbound agent request behind a kit confirm, forwarded so
682
+ * verify-access can tell whether the confirm is provably the agent's own
683
+ * (limit-probing attribution). The kits build it from `handle(req)`.
684
+ *
685
+ * - Signed (UCP, RFC 9421): the covered headers (`signature`,
686
+ * `signature-input`, `signature-agent`, `ucp-agent`, `content-digest` and
687
+ * every other header the signature covers — never `authorization` or
688
+ * `cookie`), the method, the PUBLIC request URL (your `publicOrigin` + the
689
+ * path and query, so `@target-uri` / `@authority` match what the agent
690
+ * signed behind a TLS-terminating proxy) and `contentDigest`, the
691
+ * `sha-256=:<base64>:` digest of the exact raw body.
692
+ * - `{ unsigned: true }`: the inbound request carried no signature, or it
693
+ * came over ACP (the ACP `Authorization` bearer is the platform's
694
+ * credential to you and is never forwarded, so ACP confirms are
695
+ * unattributable). Sent explicitly so the platform can tell a kit relay
696
+ * from a direct merchant call.
697
+ */
698
+ type AgentArtifacts = {
699
+ unsigned: true;
700
+ protocol?: 'ucp' | 'acp';
701
+ } | {
702
+ unsigned?: false;
703
+ protocol: 'ucp' | 'acp';
704
+ method: string;
705
+ /** Absolute public URL of the inbound request. */
706
+ url: string;
707
+ /** Lower-cased covered headers. */
708
+ headers: Record<string, string>;
709
+ /** `sha-256=:<base64>:` over the raw request body (absent for an empty body). */
710
+ contentDigest?: string;
711
+ };
712
+ /** 5.19.0 — kit context on a confirm (carried onto the approval and its events). */
713
+ interface CheckoutMetadata {
714
+ /** The kit's own checkout session id (`chk_…` / `cs_…`). */
715
+ kitSessionId?: string;
716
+ protocol?: 'ucp' | 'acp';
717
+ }
718
+ /** 5.19.0 — see {@link VerificationRequest.purposeSource}. */
719
+ type PurposeSource = 'route_config' | 'header' | 'body' | 'default';
641
720
  interface VerificationRequest {
642
721
  /** Agent credentials */
643
722
  credentials: AgentCredentials;
@@ -769,6 +848,25 @@ interface VerificationRequest {
769
848
  * from the verify cache key.
770
849
  */
771
850
  attemptId?: string;
851
+ /**
852
+ * 5.19.0 — where `purpose` came from: `'route_config'` (a dashboard route
853
+ * rule matched this request), `'header'` (the agent's X-Astra-Purpose /
854
+ * legacy header / query), `'body'` (request-derived by your own
855
+ * extractor), or `'default'` (derived from the action or the transport
856
+ * default). Set by the express and Next.js adapters. verify-access keeps a
857
+ * `'route_config'` purpose over a commerce-derived one (e.g. an MPP paid
858
+ * leg) only when a stored rule on the endpoint matches `requestMethod` +
859
+ * `requestPath` with the same purpose and action.
860
+ */
861
+ purposeSource?: PurposeSource;
862
+ /** 5.19.0 — the inbound agent request behind a kit confirm (see {@link AgentArtifacts}). */
863
+ agentArtifacts?: AgentArtifacts;
864
+ /** 5.19.0 — kit session id + protocol, stored on any approval this confirm creates. */
865
+ metadata?: CheckoutMetadata;
866
+ /** 5.19.0 — the inbound request's HTTP method (for the route-rule check above). */
867
+ requestMethod?: string;
868
+ /** 5.19.0 — the inbound request's path, without the query (for the route-rule check above). */
869
+ requestPath?: string;
772
870
  /**
773
871
  * 3.12.0 — first-party observational data: the
774
872
  * offers the agent evaluated at this checkpoint (catalog browse / intent
@@ -992,5 +1090,10 @@ interface AstraSyncAepEvidence {
992
1090
  platform_countersignature: string;
993
1091
  }>;
994
1092
  }
1093
+ /** 5.20.0: a non-fatal warning on a verify-access result (see `warnings`). */
1094
+ interface VerificationWarning {
1095
+ code: string;
1096
+ message: string;
1097
+ }
995
1098
 
996
1099
  export type { AgentCredentials as A, CommerceArtifactsPayload as C, GatewayConfig as G, TokenGuidance as T, VerificationRequest as V, AttemptReport as a, CounterpartyType as b, VerificationResult as c };
@@ -1,4 +1,4 @@
1
- import { V as VerificationInterstitialProps, d as VerificationResult, A as AgentCredentials, b as GuidanceInfo, T as TrustLevel } from '../types-Cns4l8gX.mjs';
1
+ import { V as VerificationInterstitialProps, e as VerificationResult, a as AgentCredentials, c as GuidanceInfo, T as TrustLevel } from '../types-CxjqmPl-.mjs';
2
2
 
3
3
  /**
4
4
  * AstraSync Verification Interstitial Component
@@ -1,4 +1,4 @@
1
- import { V as VerificationInterstitialProps, d as VerificationResult, A as AgentCredentials, b as GuidanceInfo, T as TrustLevel } from '../types-Cns4l8gX.js';
1
+ import { V as VerificationInterstitialProps, e as VerificationResult, a as AgentCredentials, c as GuidanceInfo, T as TrustLevel } from '../types-CxjqmPl-.js';
2
2
 
3
3
  /**
4
4
  * AstraSync Verification Interstitial Component
package/dist/verify.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AgentCredentials, G as GatewayConfig, a as AttemptReport, V as VerificationRequest, c as VerificationResult } from './types-3ObBpsnf.mjs';
1
+ import { A as AgentCredentials, G as GatewayConfig, c as VerificationResult, V as VerificationRequest, a as AttemptReport } from './types-D37aSQ9c.mjs';
2
2
  import { ObservedMetadata } from './metadata-capture.mjs';
3
3
 
4
4
  /**
@@ -11,7 +11,8 @@ import { ObservedMetadata } from './metadata-capture.mjs';
11
11
  /** Test-only: re-arm the one-time init self-check. */
12
12
  declare function _resetInitCheck(): void;
13
13
  /**
14
- * Clear the verification cache
14
+ * Clear the verification cache, and (5.20.0) forget in-flight single-flight
15
+ * calls so a later identical request reaches the backend on its own.
15
16
  */
16
17
  declare function clearCache(): void;
17
18
  /**
@@ -48,6 +49,24 @@ interface VerifyOptions {
48
49
  * Main verification function
49
50
  */
50
51
  declare function verify(config: GatewayConfig, request: VerificationRequest, options?: VerifyOptions): Promise<VerificationResult>;
52
+ /**
53
+ * Whether `result` was served from the verdict cache or shared from a
54
+ * concurrent identical call (5.20.0). The adapters skip the decision POST for
55
+ * these: the session already has its decision from the call that created it.
56
+ */
57
+ declare function isSharedVerdict(result: VerificationResult): boolean;
58
+ type VerificationListener = (result: VerificationResult, request: VerificationRequest) => void;
59
+ /**
60
+ * 5.20.0: observe every verdict this process fetched from verify-access
61
+ * (cache hits and single-flight followers are not repeated). Listeners run
62
+ * synchronously after the result is built and must not throw (a throw is
63
+ * swallowed). Returns an unsubscribe function.
64
+ *
65
+ * The MCP bridge uses it to size its per-agent rate limit from the trust
66
+ * score its tools' own verifies return, instead of paying for a second
67
+ * verify-access call in the gate.
68
+ */
69
+ declare function onVerificationResult(listener: VerificationListener): () => void;
51
70
  /**
52
71
  * Record a counterparty's grant/deny decision for a verification session.
53
72
  * Fire-and-forget — errors are silently swallowed.
@@ -79,15 +98,42 @@ interface ReportAttemptOptions {
79
98
  retried: boolean;
80
99
  }) => void;
81
100
  }
82
- declare function fetchRoutes(config: GatewayConfig, counterpartyId: string): Promise<RouteAccessConfigShape[] | null>;
101
+ declare function fetchRoutes(config: GatewayConfig, counterpartyId: string, options?: {
102
+ /**
103
+ * 5.19.0: tool names the MCP middleware gates in code, sent as
104
+ * `?codeGates=a,b` so the dashboard can mark them "gated in code — a rule
105
+ * here can only add checks".
106
+ */
107
+ codeGates?: string[];
108
+ /**
109
+ * 5.20.0: called with the endpoint's `counterpartyType` when the routes
110
+ * response carries it (backend round 29.1+). The MCP middleware uses it
111
+ * to warn when it is pointed at a non-`mcp_server` endpoint.
112
+ */
113
+ onEndpointType?: (counterpartyType: string) => void;
114
+ }): Promise<RouteAccessConfigShape[] | null>;
83
115
  /**
84
116
  * Minimal shape of an EndpointRoute as the SDK consumes it. Mirrors the
85
117
  * server's `EndpointRoute` type and the SDK's `RouteAccessConfig` — same
86
118
  * JSON moves between server and SDK unchanged.
87
119
  */
88
120
  interface RouteAccessConfigShape {
121
+ /** Path pattern (path rules). Absent on an MCP tool rule. */
89
122
  pattern: string;
90
123
  method: string;
124
+ /**
125
+ * 5.19.0: MCP tool rule — the `tools/call` tool name this rule governs
126
+ * (`mcp_server` endpoints store only tool rules: `{tool, purpose, action,
127
+ * resource?, observe?}`). Path-rule matchers skip rules carrying it.
128
+ */
129
+ tool?: string;
130
+ /** 5.19.0: a tool rule's resource override. */
131
+ resource?: string;
132
+ /**
133
+ * 5.19.0: a path rule stored on an `mcp_server` endpoint before tool rules
134
+ * existed. The MCP middleware ignores it (replace it with tool rules).
135
+ */
136
+ legacy?: boolean;
91
137
  /** Pass through unenforced (observe). Replaces `minAccessLevel: 'none'`. */
92
138
  observe?: boolean;
93
139
  minTrustScore?: number;
@@ -194,4 +240,4 @@ declare function quickVerify(config: GatewayConfig, credentials: AgentCredential
194
240
  retryAfterMs?: number;
195
241
  }>;
196
242
 
197
- export { type ReportAttemptOptions, type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, parseRetryAfterMs, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
243
+ export { type ReportAttemptOptions, type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, isSharedVerdict, onVerificationResult, parseRetryAfterMs, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
package/dist/verify.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AgentCredentials, G as GatewayConfig, a as AttemptReport, V as VerificationRequest, c as VerificationResult } from './types-BoxZEYPS.js';
1
+ import { A as AgentCredentials, G as GatewayConfig, c as VerificationResult, V as VerificationRequest, a as AttemptReport } from './types-Dn8tXnei.js';
2
2
  import { ObservedMetadata } from './metadata-capture.js';
3
3
 
4
4
  /**
@@ -11,7 +11,8 @@ import { ObservedMetadata } from './metadata-capture.js';
11
11
  /** Test-only: re-arm the one-time init self-check. */
12
12
  declare function _resetInitCheck(): void;
13
13
  /**
14
- * Clear the verification cache
14
+ * Clear the verification cache, and (5.20.0) forget in-flight single-flight
15
+ * calls so a later identical request reaches the backend on its own.
15
16
  */
16
17
  declare function clearCache(): void;
17
18
  /**
@@ -48,6 +49,24 @@ interface VerifyOptions {
48
49
  * Main verification function
49
50
  */
50
51
  declare function verify(config: GatewayConfig, request: VerificationRequest, options?: VerifyOptions): Promise<VerificationResult>;
52
+ /**
53
+ * Whether `result` was served from the verdict cache or shared from a
54
+ * concurrent identical call (5.20.0). The adapters skip the decision POST for
55
+ * these: the session already has its decision from the call that created it.
56
+ */
57
+ declare function isSharedVerdict(result: VerificationResult): boolean;
58
+ type VerificationListener = (result: VerificationResult, request: VerificationRequest) => void;
59
+ /**
60
+ * 5.20.0: observe every verdict this process fetched from verify-access
61
+ * (cache hits and single-flight followers are not repeated). Listeners run
62
+ * synchronously after the result is built and must not throw (a throw is
63
+ * swallowed). Returns an unsubscribe function.
64
+ *
65
+ * The MCP bridge uses it to size its per-agent rate limit from the trust
66
+ * score its tools' own verifies return, instead of paying for a second
67
+ * verify-access call in the gate.
68
+ */
69
+ declare function onVerificationResult(listener: VerificationListener): () => void;
51
70
  /**
52
71
  * Record a counterparty's grant/deny decision for a verification session.
53
72
  * Fire-and-forget — errors are silently swallowed.
@@ -79,15 +98,42 @@ interface ReportAttemptOptions {
79
98
  retried: boolean;
80
99
  }) => void;
81
100
  }
82
- declare function fetchRoutes(config: GatewayConfig, counterpartyId: string): Promise<RouteAccessConfigShape[] | null>;
101
+ declare function fetchRoutes(config: GatewayConfig, counterpartyId: string, options?: {
102
+ /**
103
+ * 5.19.0: tool names the MCP middleware gates in code, sent as
104
+ * `?codeGates=a,b` so the dashboard can mark them "gated in code — a rule
105
+ * here can only add checks".
106
+ */
107
+ codeGates?: string[];
108
+ /**
109
+ * 5.20.0: called with the endpoint's `counterpartyType` when the routes
110
+ * response carries it (backend round 29.1+). The MCP middleware uses it
111
+ * to warn when it is pointed at a non-`mcp_server` endpoint.
112
+ */
113
+ onEndpointType?: (counterpartyType: string) => void;
114
+ }): Promise<RouteAccessConfigShape[] | null>;
83
115
  /**
84
116
  * Minimal shape of an EndpointRoute as the SDK consumes it. Mirrors the
85
117
  * server's `EndpointRoute` type and the SDK's `RouteAccessConfig` — same
86
118
  * JSON moves between server and SDK unchanged.
87
119
  */
88
120
  interface RouteAccessConfigShape {
121
+ /** Path pattern (path rules). Absent on an MCP tool rule. */
89
122
  pattern: string;
90
123
  method: string;
124
+ /**
125
+ * 5.19.0: MCP tool rule — the `tools/call` tool name this rule governs
126
+ * (`mcp_server` endpoints store only tool rules: `{tool, purpose, action,
127
+ * resource?, observe?}`). Path-rule matchers skip rules carrying it.
128
+ */
129
+ tool?: string;
130
+ /** 5.19.0: a tool rule's resource override. */
131
+ resource?: string;
132
+ /**
133
+ * 5.19.0: a path rule stored on an `mcp_server` endpoint before tool rules
134
+ * existed. The MCP middleware ignores it (replace it with tool rules).
135
+ */
136
+ legacy?: boolean;
91
137
  /** Pass through unenforced (observe). Replaces `minAccessLevel: 'none'`. */
92
138
  observe?: boolean;
93
139
  minTrustScore?: number;
@@ -194,4 +240,4 @@ declare function quickVerify(config: GatewayConfig, credentials: AgentCredential
194
240
  retryAfterMs?: number;
195
241
  }>;
196
242
 
197
- export { type ReportAttemptOptions, type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, parseRetryAfterMs, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
243
+ export { type ReportAttemptOptions, type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, isSharedVerdict, onVerificationResult, parseRetryAfterMs, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
package/dist/verify.js CHANGED
@@ -25,6 +25,8 @@ __export(verify_exports, {
25
25
  extractCredentials: () => extractCredentials,
26
26
  fetchRoutes: () => fetchRoutes,
27
27
  hasCredentials: () => hasCredentials,
28
+ isSharedVerdict: () => isSharedVerdict,
29
+ onVerificationResult: () => onVerificationResult,
28
30
  parseRetryAfterMs: () => parseRetryAfterMs,
29
31
  quickVerify: () => quickVerify,
30
32
  recordDecision: () => recordDecision,
@@ -37,7 +39,7 @@ __export(verify_exports, {
37
39
  module.exports = __toCommonJS(verify_exports);
38
40
 
39
41
  // src/version.ts
40
- var SDK_VERSION = "5.18.1";
42
+ var SDK_VERSION = "5.20.0";
41
43
 
42
44
  // src/http.ts
43
45
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -218,7 +220,12 @@ function getCacheKey(request, counterpartyId) {
218
220
  // its start_checkout quote was served the cached quote-leg grant (no
219
221
  // settlementOutcome) and never reached the backend. Same F-A1-07 bug class.
220
222
  request.commercePhase || "",
221
- request.checkoutSessionId || ""
223
+ request.checkoutSessionId || "",
224
+ // 5.19.0: a route_config purpose claim is checked server-side against
225
+ // the stored rule for this method + path, so it changes the verdict.
226
+ request.purposeSource || "",
227
+ request.requestMethod || "",
228
+ request.requestPath || ""
222
229
  ].join("|");
223
230
  }
224
231
  function getCachedResult(request, counterpartyId) {
@@ -243,6 +250,7 @@ function cacheResult(request, result, configuredTtl, counterpartyId) {
243
250
  }
244
251
  function clearCache() {
245
252
  verificationCache.clear();
253
+ inflightVerifies.clear();
246
254
  }
247
255
  function extractCredentials(headers, query) {
248
256
  const credentials = {};
@@ -416,6 +424,9 @@ async function callVerifyAccessAPI(config, request) {
416
424
  if (requestData.enableRuntimeChallenge)
417
425
  body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
418
426
  if (requestData.routePolicy) body.routePolicy = requestData.routePolicy;
427
+ if (config.actingProof?.connectorToken) {
428
+ body.actingProof = { connectorToken: config.actingProof.connectorToken };
429
+ }
419
430
  if (requestData.approvalHeldByRoute) body.approvalHeldByRoute = true;
420
431
  if (requestData.createSession) body.createSession = requestData.createSession;
421
432
  if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
@@ -432,6 +443,11 @@ async function callVerifyAccessAPI(config, request) {
432
443
  if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
433
444
  if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
434
445
  if (requestData.attemptId) body.attemptId = requestData.attemptId;
446
+ if (requestData.purposeSource) body.purposeSource = requestData.purposeSource;
447
+ if (requestData.agentArtifacts) body.agentArtifacts = requestData.agentArtifacts;
448
+ if (requestData.metadata) body.metadata = requestData.metadata;
449
+ if (requestData.requestMethod) body.requestMethod = requestData.requestMethod;
450
+ if (requestData.requestPath) body.requestPath = requestData.requestPath;
435
451
  if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
436
452
  body.sdkVersion = SDK_VERSION;
437
453
  if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
@@ -578,22 +594,46 @@ async function verify(config, request, options) {
578
594
  "[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access decisions (verified ID + runtime challenge + PDLSS + trust score). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
579
595
  );
580
596
  }
581
- const uncacheable = Boolean(request.commerceArtifacts);
597
+ const uncacheable = Boolean(request.commerceArtifacts) || Boolean(mergedConfig.actingProof);
582
598
  if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
583
599
  const cached = getCachedResult(request, mergedConfig.counterpartyId);
584
600
  if (cached) {
585
601
  if (mergedConfig.debug) {
586
602
  console.log("[VerificationGateway] Returning cached result");
587
603
  }
588
- const hit = { ...cached };
589
- if (request.attemptId) {
590
- hit.attemptId = request.attemptId;
591
- } else {
592
- delete hit.attemptId;
593
- }
594
- return hit;
604
+ return sharedVerdict(cached, request);
605
+ }
606
+ }
607
+ if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
608
+ const key = getCacheKey(request, mergedConfig.counterpartyId);
609
+ const pending = inflightVerifies.get(key);
610
+ if (pending) return sharedVerdict(await pending, request);
611
+ const flight = verifyViaApi(mergedConfig, request, urls, uncacheable);
612
+ inflightVerifies.set(key, flight);
613
+ try {
614
+ return await flight;
615
+ } finally {
616
+ inflightVerifies.delete(key);
595
617
  }
596
618
  }
619
+ return verifyViaApi(mergedConfig, request, urls, uncacheable);
620
+ }
621
+ var inflightVerifies = /* @__PURE__ */ new Map();
622
+ var sharedVerdicts = /* @__PURE__ */ new WeakSet();
623
+ function isSharedVerdict(result) {
624
+ return sharedVerdicts.has(result);
625
+ }
626
+ function sharedVerdict(source, request) {
627
+ const hit = { ...source };
628
+ if (request.attemptId) {
629
+ hit.attemptId = request.attemptId;
630
+ } else {
631
+ delete hit.attemptId;
632
+ }
633
+ sharedVerdicts.add(hit);
634
+ return hit;
635
+ }
636
+ async function verifyViaApi(mergedConfig, request, urls, uncacheable) {
597
637
  const enrichedRequest = { ...request };
598
638
  if (!enrichedRequest.counterpartyUrl && mergedConfig.counterpartyUrl) {
599
639
  enrichedRequest.counterpartyUrl = mergedConfig.counterpartyUrl;
@@ -621,9 +661,18 @@ async function verify(config, request, options) {
621
661
  if (!apiResponse.access?.allowed) {
622
662
  const aggregatedFailures = apiResponse.access?.failures;
623
663
  const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
664
+ const denyAgent = idVerifiedFromBackend && apiResponse.agent ? {
665
+ astraId: apiResponse.agent.astraId,
666
+ name: apiResponse.agent.name,
667
+ trustScore: apiResponse.agent.trustScore,
668
+ trustLevel: getTrustLevel(apiResponse.agent.trustScore),
669
+ blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
670
+ status: apiResponse.agent.agentStatus
671
+ } : void 0;
624
672
  const result2 = {
625
673
  identityVerified: idVerifiedFromBackend,
626
674
  policyAllowed: false,
675
+ ...denyAgent && { agent: denyAgent },
627
676
  // 3.6.0: the server now emits top-level denialReasons on every deny
628
677
  // path — prefer it verbatim; the failure-message reconstruction remains
629
678
  // as the fallback for older backends.
@@ -663,7 +712,9 @@ async function verify(config, request, options) {
663
712
  fulfilment: apiResponse.fulfilment,
664
713
  mandates: apiResponse.mandates,
665
714
  kyaToken: apiResponse.kyaToken,
666
- aep: apiResponse.aep
715
+ aep: apiResponse.aep,
716
+ // 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
717
+ warnings: apiResponse.warnings
667
718
  };
668
719
  return result2;
669
720
  }
@@ -731,7 +782,9 @@ async function verify(config, request, options) {
731
782
  // 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
732
783
  mandates: apiResponse.mandates,
733
784
  kyaToken: apiResponse.kyaToken,
734
- aep: apiResponse.aep
785
+ aep: apiResponse.aep,
786
+ // 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
787
+ warnings: apiResponse.warnings
735
788
  };
736
789
  if (result.recommendation === "deny") {
737
790
  result.policyAllowed = false;
@@ -757,8 +810,24 @@ async function verify(config, request, options) {
757
810
  cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
758
811
  }
759
812
  }
813
+ notifyVerificationListeners(request, result);
760
814
  return result;
761
815
  }
816
+ var verificationListeners = /* @__PURE__ */ new Set();
817
+ function onVerificationResult(listener) {
818
+ verificationListeners.add(listener);
819
+ return () => {
820
+ verificationListeners.delete(listener);
821
+ };
822
+ }
823
+ function notifyVerificationListeners(request, result) {
824
+ for (const listener of verificationListeners) {
825
+ try {
826
+ listener(result, request);
827
+ } catch {
828
+ }
829
+ }
830
+ }
762
831
  async function recordDecision(config, sessionId, decision, reason) {
763
832
  const headers = { "Content-Type": "application/json" };
764
833
  if (config.apiKey) {
@@ -815,7 +884,7 @@ async function reportAttempt(config, report, options = {}) {
815
884
  }
816
885
  var ATTEMPT_REPORT_MAX_RETRY_DELAY_MS = 2e3;
817
886
  var refusedPolicyReads = /* @__PURE__ */ new Set();
818
- async function fetchRoutes(config, counterpartyId) {
887
+ async function fetchRoutes(config, counterpartyId, options = {}) {
819
888
  if (!counterpartyId) return null;
820
889
  const headers = { "Content-Type": "application/json" };
821
890
  if (config.apiKey) {
@@ -823,8 +892,9 @@ async function fetchRoutes(config, counterpartyId) {
823
892
  headers["X-API-Key"] = config.apiKey;
824
893
  }
825
894
  try {
895
+ headers["X-AstraSync-SDK-Version"] = SDK_VERSION;
826
896
  const response = await sdkFetch(
827
- `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
897
+ `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes` + (options.codeGates?.length ? `?codeGates=${options.codeGates.map(encodeURIComponent).join(",")}` : ""),
828
898
  { method: "GET", headers }
829
899
  );
830
900
  if (!response.ok) {
@@ -837,6 +907,13 @@ async function fetchRoutes(config, counterpartyId) {
837
907
  return null;
838
908
  }
839
909
  const body = await response.json();
910
+ const type = body.data?.counterpartyType;
911
+ if (typeof type === "string" && options.onEndpointType) {
912
+ try {
913
+ options.onEndpointType(type);
914
+ } catch {
915
+ }
916
+ }
840
917
  return body.data?.routes ?? [];
841
918
  } catch {
842
919
  return null;
@@ -906,6 +983,8 @@ async function quickVerify(config, credentials) {
906
983
  extractCredentials,
907
984
  fetchRoutes,
908
985
  hasCredentials,
986
+ isSharedVerdict,
987
+ onVerificationResult,
909
988
  parseRetryAfterMs,
910
989
  quickVerify,
911
990
  recordDecision,