@astrasyncai/verification-gateway 5.19.0 → 5.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +130 -0
- package/README.md +53 -4
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +65 -16
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +65 -16
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +23 -1
- package/dist/adapters/mcp.d.ts +23 -1
- package/dist/adapters/mcp.js +91 -16
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +91 -16
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +1 -1
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +57 -11
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +57 -11
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +35 -2
- package/dist/adapters/sdk.d.ts +35 -2
- package/dist/adapters/sdk.js +110 -11
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +110 -11
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +1 -1
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +50 -12
- package/dist/bin/astrasync-codex-hook.js +50 -12
- package/dist/bin/astrasync-guard.js +50 -12
- package/dist/bin/astrasync.js +65 -13
- package/dist/browser/background.js +50 -12
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +50 -12
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.js +50 -12
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +50 -12
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +50 -12
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +50 -12
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +1 -1
- package/dist/edge-config.d.ts +1 -1
- package/dist/edge-config.js +1 -1
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +1 -1
- package/dist/edge-core/index.d.ts +1 -1
- package/dist/edge-core/index.js +49 -11
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +49 -11
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +50 -12
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +50 -12
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +1 -1
- package/dist/git-trigger/git-hooks.d.ts +1 -1
- package/dist/index.d.mts +286 -8
- package/dist/index.d.ts +286 -8
- package/dist/index.js +532 -49
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +522 -49
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/registration/index.d.mts +11 -2
- package/dist/registration/index.d.ts +11 -2
- package/dist/registration/index.js +1 -1
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.d.mts +1 -1
- package/dist/transport/index.d.ts +1 -1
- package/dist/transport/index.js +1 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-BoGjyon0.d.mts → types-B4zhOAlq.d.mts} +30 -1
- package/dist/{types-BRz2U0Pn.d.ts → types-B_HLhZ9n.d.ts} +1 -1
- package/dist/{types-BfILnheI.d.mts → types-CU17R4Nr.d.mts} +11 -0
- package/dist/{types-BfILnheI.d.ts → types-CU17R4Nr.d.ts} +11 -0
- package/dist/{types-eWyZuz-3.d.ts → types-CtBXnWuV.d.ts} +30 -1
- package/dist/{types-DqWPkiYl.d.mts → types-DHHyXtuZ.d.mts} +30 -1
- package/dist/{types-DqWPkiYl.d.ts → types-DHHyXtuZ.d.ts} +30 -1
- package/dist/{types-CfBpm3w5.d.mts → types-Djpz-L0w.d.mts} +1 -1
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +28 -3
- package/dist/verify.d.ts +28 -3
- package/dist/verify.js +71 -11
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +69 -11
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,136 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
8
8
|
Full architectural context for each release lives in the platform spec at
|
|
9
9
|
`docs/research/adapter-architecture-technical-requirements.md`.
|
|
10
10
|
|
|
11
|
+
## [5.21.0] — 2026-10-26 — endpoint changes are dashboard-only, agent commerce studio rules
|
|
12
|
+
|
|
13
|
+
### Removed (breaking, security — shops' item 48)
|
|
14
|
+
|
|
15
|
+
- **`VerificationGatewayClient.updateEndpoint`** and the `EndpointOperationalPatch`
|
|
16
|
+
type. After registration, endpoint settings (checkout, catalogue, events,
|
|
17
|
+
skill and health check URLs) change in the dashboard only, behind the
|
|
18
|
+
owner's login and MFA; the platform now refuses API keys on
|
|
19
|
+
`PATCH /api/endpoints/:id` (403). Why: a merchant's API key lives in its
|
|
20
|
+
host's environment, and a host compromise must not let a leaked key point
|
|
21
|
+
agents at another checkout or catalogue under the merchant's verified
|
|
22
|
+
identity. Every dashboard change to one of these URLs alerts the owner.
|
|
23
|
+
- **`sendTestEvent(id, { approvalId })`.** From code the test event is
|
|
24
|
+
synthetic only (an `approvalId` is no longer sent; the platform answers 403
|
|
25
|
+
`dashboard_only` to an API key that sends one). A real held approval's
|
|
26
|
+
payload releases or re-drives that checkout, so it is sent from the
|
|
27
|
+
endpoint page in the dashboard.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **The default AstraSync API base is `https://astrasync.ai/api`** (gateway
|
|
32
|
+
online mode, the transport's default verify URL, README examples), the same
|
|
33
|
+
as `verify()`'s documented base. `api.astrasync.ai` still answers; pass
|
|
34
|
+
`apiBaseUrl` explicitly as before if you set one.
|
|
35
|
+
|
|
36
|
+
### Added — agent commerce studio rules
|
|
37
|
+
|
|
38
|
+
- **`createAgentCommerce({ apiBaseUrl, apiKey, counterpartyId })`** fetches
|
|
39
|
+
the rules you set in the dashboard (endpoint → Agent commerce) every 5
|
|
40
|
+
minutes and keeps the last good copy when a fetch fails: product
|
|
41
|
+
visibility, agent price, the image agents get, a verified-agent discount,
|
|
42
|
+
and card issuer offers. AstraSync stores rules only; it hosts nothing.
|
|
43
|
+
`report({ catalogUrl, checkoutUrl, eventsUrl })` tells the dashboard where
|
|
44
|
+
your kit lives — shown as suggestions you confirm; it never sets a URL.
|
|
45
|
+
- **`serveAgentCatalog({ commerce, products })`** serves your catalogue to
|
|
46
|
+
agents priced and filtered by those rules (`issuer_offer` marks a
|
|
47
|
+
cardholder-priced line). **`fromFeed(url)`** reads a Shopify
|
|
48
|
+
`products.json`, Google Merchant XML, CSV or JSON feed you already have.
|
|
49
|
+
- **Kits: `agentCommerce`.** The UCP and ACP kits price lines with the same
|
|
50
|
+
rules, so the agent's price is the price you charge. A cardholder price
|
|
51
|
+
applies on `X-Astra-Issuer-Program` (sent by the AstraSync bridge) and the
|
|
52
|
+
confirm carries `metadata.issuerProgram`; AstraSync refuses the purchase
|
|
53
|
+
unless the buyer is that programme's cardholder. Pass `metadata` through
|
|
54
|
+
in your `verifyPurchase`.
|
|
55
|
+
- `issuerOfferPrice` / `priceForAgent`: the shared price rule (percent off,
|
|
56
|
+
half up, clamped).
|
|
57
|
+
|
|
58
|
+
## [5.20.0] — 2026-10-19 — fewer backend calls, recoverable declined holds, endpoint ops from code
|
|
59
|
+
|
|
60
|
+
### Changed (behaviour)
|
|
61
|
+
|
|
62
|
+
- **Declined kit holds are `recoverable`.** After a `step_up.denied`,
|
|
63
|
+
`step_up.expired` or `step_up.lapsed` event the UCP kit's
|
|
64
|
+
`approval_<reason>` message has severity `recoverable` and the ACP kit's
|
|
65
|
+
resolution is `recoverable` (both were `requires_buyer_review`): the
|
|
66
|
+
session is back in `ready_for_complete` / `ready_for_payment` and payable
|
|
67
|
+
with no further buyer step, matching the 5.19.0 `payment_failed` fix. The
|
|
68
|
+
code is the signal — platforms must not auto-retry on `approval_denied`.
|
|
69
|
+
The held response keeps `requires_buyer_review`.
|
|
70
|
+
- **No decision POST on a shared verdict.** The express and MCP middlewares
|
|
71
|
+
no longer record a second decision when the verdict came from the cache or
|
|
72
|
+
from a concurrent identical call (the session already has its decision).
|
|
73
|
+
- **Single-flight verify.** Concurrent identical cache misses share one
|
|
74
|
+
verify-access call; followers get a copy with their own `attemptId`.
|
|
75
|
+
`bypassCache` re-verifies and uncacheable requests never join a flight.
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
|
|
79
|
+
- `createMcpMiddleware({ skipEvaluation: { tools?, methods? } })`: unenforced
|
|
80
|
+
listed tools / methods pass through with no verify-access call, even with
|
|
81
|
+
`evaluateAlwaysIfCredentialed` (handshake, listing, `resources/read`, and
|
|
82
|
+
observe tools that verify in their own handler).
|
|
83
|
+
- `createMcpMiddleware` warns once when its `counterpartyId` is not an
|
|
84
|
+
`mcp_server` endpoint (the routes fetch now carries the endpoint's
|
|
85
|
+
`counterpartyType`; `fetchRoutes(…, { onEndpointType })`). Tool rules need a
|
|
86
|
+
separate `mcp_server` endpoint for the site's MCP server.
|
|
87
|
+
- `isSharedVerdict(result)` and `onVerificationResult(listener)` (root
|
|
88
|
+
exports).
|
|
89
|
+
- **MCP middleware carries the attempt chain** (express / Next.js / edge
|
|
90
|
+
parity): `X-Astra-Attempt-Id`, else `params._meta.astrasync.attemptId`, is
|
|
91
|
+
sent as the verify `attemptId` (malformed values dropped). A tool call the
|
|
92
|
+
AstraSync bridge proved (acting proof bound to the attempt) is no longer
|
|
93
|
+
held at an `mcp_server` venue.
|
|
94
|
+
- `GatewayConfig.actingProof?: { connectorToken }` is sent as `actingProof`
|
|
95
|
+
in the verify-access body (honoured only from a first-party AstraSync
|
|
96
|
+
service caller; a verify carrying it is never cached).
|
|
97
|
+
- `VerificationGatewayClient.updateEndpoint(id, { eventsUrl, healthCheckUrl,
|
|
98
|
+
skillUrl, catalogUrl, checkoutUrl })` → `PATCH /api/endpoints/:id`
|
|
99
|
+
(operational URLs only, API key of the owner or an org member) and
|
|
100
|
+
`sendTestEvent(id, { type, approvalId? })` → `POST
|
|
101
|
+
/api/endpoints/:id/events/test` (one signed step-up event delivered now;
|
|
102
|
+
returns `{ delivered, status, responseCode, error, eventId, type,
|
|
103
|
+
approvalId }`). Types `EndpointOperationalPatch`, `TestEventType`,
|
|
104
|
+
`TestEventResult`.
|
|
105
|
+
- Kits' `pollHeldSessions` releases a `lapsed` approval (UCP and ACP);
|
|
106
|
+
`StepUpApprovalStatus` gains `'lapsed'`.
|
|
107
|
+
- ACP: `approval_required` / `approval_denied` / `approval_expired` /
|
|
108
|
+
`approval_lapsed` join the passthrough message codes.
|
|
109
|
+
- UCP profiles' `signing_keys` are accepted alongside `keys` (the kit's
|
|
110
|
+
platform-signature check and the profile parser read both, skipping
|
|
111
|
+
`use: "enc"` keys); `ucpProfileKeys(profile)` is exported from the root.
|
|
112
|
+
- **Kits' catalog item carries the product image.** `CatalogItem` (exported
|
|
113
|
+
as `UcpCatalogItem`) gains optional `image_url` (an absolute http(s) URL)
|
|
114
|
+
and `description`. The UCP kit keeps them on `line_items[].item`; the ACP
|
|
115
|
+
kit carries them on each line's `item` and on the order's line items. A
|
|
116
|
+
relative or invalid `image_url` is dropped when the kit prices the line.
|
|
117
|
+
- **`fetchRoutes` sends an `X-AstraSync-SDK-Version` header** on the routes
|
|
118
|
+
fetch, so the endpoint's SDK version on the dashboard updates from the
|
|
119
|
+
5-minute routes refresh (MCP traffic may never send a verify-access naming
|
|
120
|
+
the `mcp_server` endpoint). The URL is unchanged, so mocks matching
|
|
121
|
+
`…/routes` keep working. Round 29.1 backends also read the version from
|
|
122
|
+
the `User-Agent` for older SDKs.
|
|
123
|
+
- `VerificationWarning` type (root export) for the result's `warnings[]`.
|
|
124
|
+
|
|
125
|
+
### Fixed
|
|
126
|
+
|
|
127
|
+
- **The verification result carries verify-access `warnings[]`** (e.g.
|
|
128
|
+
`events_url_missing`). It reached the wire, but both result builders
|
|
129
|
+
dropped it.
|
|
130
|
+
- **The UCP kit verifies signed platform requests with `signing_keys` too.**
|
|
131
|
+
Only the mandate-key path read them, so a platform profile that published
|
|
132
|
+
only `signing_keys` got `key_not_found` on its request signatures.
|
|
133
|
+
|
|
134
|
+
### Changed (types)
|
|
135
|
+
|
|
136
|
+
- `registration/types.ts`: the trust-score fields on registration and
|
|
137
|
+
verification responses are optional — the platform no longer returns an
|
|
138
|
+
agent's score to the agent or the public (counterparties still see it in
|
|
139
|
+
verify-access).
|
|
140
|
+
|
|
11
141
|
## [5.19.0] — 2026-10-18 — approval events for held kit checkouts, MCP tool rules, fail-closed default
|
|
12
142
|
|
|
13
143
|
### Changed (behaviour)
|
package/README.md
CHANGED
|
@@ -73,7 +73,7 @@ import { createMiddleware } from '@astrasyncai/verification-gateway/nextjs';
|
|
|
73
73
|
// v2.3.7+ — per-route policy lives in the AstraSync dashboard.
|
|
74
74
|
// The SDK fetches it on init via counterpartyId; do NOT pass routes here.
|
|
75
75
|
export const middleware = createMiddleware({
|
|
76
|
-
apiBaseUrl: 'https://
|
|
76
|
+
apiBaseUrl: 'https://astrasync.ai/api', // always includes /api
|
|
77
77
|
apiKey: process.env.ASTRASYNC_API_KEY,
|
|
78
78
|
counterpartyId: 'ASTRAE-...',
|
|
79
79
|
showInterstitial: true,
|
|
@@ -90,7 +90,7 @@ export const config = {
|
|
|
90
90
|
import { createClient } from '@astrasyncai/verification-gateway/sdk';
|
|
91
91
|
|
|
92
92
|
const gateway = createClient({
|
|
93
|
-
apiBaseUrl: 'https://
|
|
93
|
+
apiBaseUrl: 'https://astrasync.ai/api', // always includes /api
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
// Verify another agent before interacting
|
|
@@ -439,6 +439,27 @@ refresh, with no deploy.
|
|
|
439
439
|
- The middleware sends its code-gated tool names on the fetch
|
|
440
440
|
(`?codeGates=a,b`), so the dashboard marks those tools "gated in code — a
|
|
441
441
|
rule here can only add checks".
|
|
442
|
+
- **One endpoint per surface (5.20.0).** Tool rules live on an `mcp_server`
|
|
443
|
+
endpoint. If your site and its MCP server share one (website) endpoint,
|
|
444
|
+
register a separate MCP endpoint for the MCP server — same owner; an API key
|
|
445
|
+
that operates your site endpoint may create it with `POST /api/endpoints` —
|
|
446
|
+
and use its id as the middleware's `counterpartyId`. The middleware warns
|
|
447
|
+
once (`console.warn`) when its `counterpartyId` is not an `mcp_server`
|
|
448
|
+
endpoint.
|
|
449
|
+
|
|
450
|
+
## Fewer backend calls (5.20.0)
|
|
451
|
+
|
|
452
|
+
- **Single-flight:** concurrent identical cache misses share one
|
|
453
|
+
verify-access call.
|
|
454
|
+
- **No decision POST on a shared verdict:** a cache hit (or a single-flight
|
|
455
|
+
follower) no longer re-records the decision for the original session
|
|
456
|
+
(`isSharedVerdict(result)`).
|
|
457
|
+
- **`skipEvaluation: { tools?, methods? }`** (MCP middleware): unenforced
|
|
458
|
+
listed calls pass through with no backend call — handshake / listing /
|
|
459
|
+
`resources/read`, and observe tools whose handler calls verify-access
|
|
460
|
+
itself.
|
|
461
|
+
- **`onVerificationResult(listener)`** observes each verdict this process
|
|
462
|
+
fetched (the AstraSync bridge sizes its per-agent rate limit from it).
|
|
442
463
|
|
|
443
464
|
## Route purpose on a paid leg (5.19.0)
|
|
444
465
|
|
|
@@ -766,7 +787,13 @@ falling back to `store.findByCheckoutSessionId(checkoutSessionId)`:
|
|
|
766
787
|
price change can't break the exact-value redemption), then settle → report
|
|
767
788
|
→ fulfil → order webhook. No agent call.
|
|
768
789
|
- **denied / expired / lapsed** → `kit.resumeDeclined(sessionId, reason)`:
|
|
769
|
-
back to `ready_for_complete` / `ready_for_payment` with
|
|
790
|
+
back to `ready_for_complete` / `ready_for_payment` with an
|
|
791
|
+
`approval_denied` / `approval_expired` / `approval_lapsed` message. 5.20.0:
|
|
792
|
+
the message is `recoverable` (UCP severity, ACP resolution) — the session
|
|
793
|
+
is payable with no further buyer step. **Platforms should not auto-retry
|
|
794
|
+
on `approval_denied`** (the buyer said no; the code is the signal); after
|
|
795
|
+
`approval_expired` / `approval_lapsed` completing again requests a new
|
|
796
|
+
approval. The held response itself keeps `requires_buyer_review`.
|
|
770
797
|
- **Card declined after redemption:** the session is payable again with the
|
|
771
798
|
decline message and the owner sees the failed outcome. Re-completing the
|
|
772
799
|
same cart at the same amount before the approval's `redeemBy` passes on the
|
|
@@ -784,7 +811,29 @@ checkout_awaiting_approval`), and held responses are never stored under an
|
|
|
784
811
|
`Idempotency-Key`, so a re-drive after the approval reaches the kit.
|
|
785
812
|
- `kit.pollHeldSessions({ sessionIds?, apiBaseUrl? })` polls held approvals
|
|
786
813
|
and resumes decided ones — a **fallback only** for merchants that can't
|
|
787
|
-
receive events (needs `store.listHeld()` when called without ids).
|
|
814
|
+
receive events (needs `store.listHeld()` when called without ids). 5.20.0:
|
|
815
|
+
a `lapsed` approval releases the session too.
|
|
816
|
+
- **Set the Events URL and test it from code (5.20.0).** With the endpoint's
|
|
817
|
+
API key (the owner's, or a personal key of a member of the owning
|
|
818
|
+
organisation):
|
|
819
|
+
|
|
820
|
+
```ts
|
|
821
|
+
import { createClient } from '@astrasyncai/verification-gateway/sdk';
|
|
822
|
+
const client = createClient({ apiBaseUrl, apiKey, counterpartyId: 'ASTRAE-…' });
|
|
823
|
+
await client.updateEndpoint(undefined, { eventsUrl: 'https://shop.example/astrasync/events' });
|
|
824
|
+
const r = await client.sendTestEvent(undefined, { type: 'step_up.lapsed' });
|
|
825
|
+
// r = { delivered, status: 'delivered'|'failed'|'not_configured', responseCode, error, eventId, … }
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
`updateEndpoint` (`PATCH /api/endpoints/:id`) changes only operational
|
|
829
|
+
URLs — `eventsUrl`, `healthCheckUrl`, `skillUrl`, `catalogUrl`,
|
|
830
|
+
`checkoutUrl` (`null` clears); rules and other policy stay in the
|
|
831
|
+
dashboard. The owner is alerted when the Events URL changes.
|
|
832
|
+
`sendTestEvent` (`POST /api/endpoints/:id/events/test`) delivers one signed
|
|
833
|
+
event now, outside the retrying outbox. Pass `approvalId` (a held kit
|
|
834
|
+
approval at this endpoint) to get that approval's real payload so your
|
|
835
|
+
resume path runs: `approved` re-confirms (and is held again — nothing is
|
|
836
|
+
charged); the others release the session.
|
|
788
837
|
|
|
789
838
|
**Agent attribution (5.19.0).** `verifyPurchase` receives `agentArtifacts`:
|
|
790
839
|
for a UCP request signed with RFC 9421, the covered headers (`signature`,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AstraSyncGateway } from '../gateway/gateway.mjs';
|
|
2
|
-
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-
|
|
3
|
-
import '../types-
|
|
2
|
+
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-Djpz-L0w.mjs';
|
|
3
|
+
import '../types-CU17R4Nr.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* PlatformAdapter Interface
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AstraSyncGateway } from '../gateway/gateway.js';
|
|
2
|
-
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-
|
|
3
|
-
import '../types-
|
|
2
|
+
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-B_HLhZ9n.js';
|
|
3
|
+
import '../types-CU17R4Nr.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* PlatformAdapter Interface
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequestHandler, Request } from 'express';
|
|
2
|
-
import { e as VerificationResult, E as ExpressMiddlewareOptions, b as AstraSyncCredentials } from '../types-
|
|
2
|
+
import { e as VerificationResult, E as ExpressMiddlewareOptions, b as AstraSyncCredentials } from '../types-DHHyXtuZ.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* AstraSync Universal Verification Gateway - Express Middleware
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequestHandler, Request } from 'express';
|
|
2
|
-
import { e as VerificationResult, E as ExpressMiddlewareOptions, b as AstraSyncCredentials } from '../types-
|
|
2
|
+
import { e as VerificationResult, E as ExpressMiddlewareOptions, b as AstraSyncCredentials } from '../types-DHHyXtuZ.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* AstraSync Universal Verification Gateway - Express Middleware
|
package/dist/adapters/express.js
CHANGED
|
@@ -479,7 +479,7 @@ function routePolicyOf(route) {
|
|
|
479
479
|
}
|
|
480
480
|
|
|
481
481
|
// src/version.ts
|
|
482
|
-
var SDK_VERSION = "5.
|
|
482
|
+
var SDK_VERSION = "5.21.0";
|
|
483
483
|
|
|
484
484
|
// src/http.ts
|
|
485
485
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -994,6 +994,9 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
994
994
|
if (requestData.enableRuntimeChallenge)
|
|
995
995
|
body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
|
|
996
996
|
if (requestData.routePolicy) body.routePolicy = requestData.routePolicy;
|
|
997
|
+
if (config.actingProof?.connectorToken) {
|
|
998
|
+
body.actingProof = { connectorToken: config.actingProof.connectorToken };
|
|
999
|
+
}
|
|
997
1000
|
if (requestData.approvalHeldByRoute) body.approvalHeldByRoute = true;
|
|
998
1001
|
if (requestData.createSession) body.createSession = requestData.createSession;
|
|
999
1002
|
if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
|
|
@@ -1161,22 +1164,46 @@ async function verify(config, request, options) {
|
|
|
1161
1164
|
"[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."
|
|
1162
1165
|
);
|
|
1163
1166
|
}
|
|
1164
|
-
const uncacheable = Boolean(request.commerceArtifacts);
|
|
1167
|
+
const uncacheable = Boolean(request.commerceArtifacts) || Boolean(mergedConfig.actingProof);
|
|
1165
1168
|
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
1166
1169
|
const cached = getCachedResult(request, mergedConfig.counterpartyId);
|
|
1167
1170
|
if (cached) {
|
|
1168
1171
|
if (mergedConfig.debug) {
|
|
1169
1172
|
console.log("[VerificationGateway] Returning cached result");
|
|
1170
1173
|
}
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1174
|
+
return sharedVerdict(cached, request);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
1178
|
+
const key = getCacheKey(request, mergedConfig.counterpartyId);
|
|
1179
|
+
const pending = inflightVerifies.get(key);
|
|
1180
|
+
if (pending) return sharedVerdict(await pending, request);
|
|
1181
|
+
const flight = verifyViaApi(mergedConfig, request, urls, uncacheable);
|
|
1182
|
+
inflightVerifies.set(key, flight);
|
|
1183
|
+
try {
|
|
1184
|
+
return await flight;
|
|
1185
|
+
} finally {
|
|
1186
|
+
inflightVerifies.delete(key);
|
|
1178
1187
|
}
|
|
1179
1188
|
}
|
|
1189
|
+
return verifyViaApi(mergedConfig, request, urls, uncacheable);
|
|
1190
|
+
}
|
|
1191
|
+
var inflightVerifies = /* @__PURE__ */ new Map();
|
|
1192
|
+
var sharedVerdicts = /* @__PURE__ */ new WeakSet();
|
|
1193
|
+
function isSharedVerdict(result) {
|
|
1194
|
+
return sharedVerdicts.has(result);
|
|
1195
|
+
}
|
|
1196
|
+
function sharedVerdict(source, request) {
|
|
1197
|
+
const hit = { ...source };
|
|
1198
|
+
if (request.attemptId) {
|
|
1199
|
+
hit.attemptId = request.attemptId;
|
|
1200
|
+
} else {
|
|
1201
|
+
delete hit.attemptId;
|
|
1202
|
+
}
|
|
1203
|
+
sharedVerdicts.add(hit);
|
|
1204
|
+
return hit;
|
|
1205
|
+
}
|
|
1206
|
+
async function verifyViaApi(mergedConfig, request, urls, uncacheable) {
|
|
1180
1207
|
const enrichedRequest = { ...request };
|
|
1181
1208
|
if (!enrichedRequest.counterpartyUrl && mergedConfig.counterpartyUrl) {
|
|
1182
1209
|
enrichedRequest.counterpartyUrl = mergedConfig.counterpartyUrl;
|
|
@@ -1255,7 +1282,9 @@ async function verify(config, request, options) {
|
|
|
1255
1282
|
fulfilment: apiResponse.fulfilment,
|
|
1256
1283
|
mandates: apiResponse.mandates,
|
|
1257
1284
|
kyaToken: apiResponse.kyaToken,
|
|
1258
|
-
aep: apiResponse.aep
|
|
1285
|
+
aep: apiResponse.aep,
|
|
1286
|
+
// 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
|
|
1287
|
+
warnings: apiResponse.warnings
|
|
1259
1288
|
};
|
|
1260
1289
|
return result2;
|
|
1261
1290
|
}
|
|
@@ -1323,7 +1352,9 @@ async function verify(config, request, options) {
|
|
|
1323
1352
|
// 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
|
|
1324
1353
|
mandates: apiResponse.mandates,
|
|
1325
1354
|
kyaToken: apiResponse.kyaToken,
|
|
1326
|
-
aep: apiResponse.aep
|
|
1355
|
+
aep: apiResponse.aep,
|
|
1356
|
+
// 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
|
|
1357
|
+
warnings: apiResponse.warnings
|
|
1327
1358
|
};
|
|
1328
1359
|
if (result.recommendation === "deny") {
|
|
1329
1360
|
result.policyAllowed = false;
|
|
@@ -1349,8 +1380,18 @@ async function verify(config, request, options) {
|
|
|
1349
1380
|
cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
|
|
1350
1381
|
}
|
|
1351
1382
|
}
|
|
1383
|
+
notifyVerificationListeners(request, result);
|
|
1352
1384
|
return result;
|
|
1353
1385
|
}
|
|
1386
|
+
var verificationListeners = /* @__PURE__ */ new Set();
|
|
1387
|
+
function notifyVerificationListeners(request, result) {
|
|
1388
|
+
for (const listener of verificationListeners) {
|
|
1389
|
+
try {
|
|
1390
|
+
listener(result, request);
|
|
1391
|
+
} catch {
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1354
1395
|
async function recordDecision(config, sessionId, decision, reason) {
|
|
1355
1396
|
const headers = { "Content-Type": "application/json" };
|
|
1356
1397
|
if (config.apiKey) {
|
|
@@ -1373,6 +1414,7 @@ async function fetchRoutes(config, counterpartyId, options = {}) {
|
|
|
1373
1414
|
headers["X-API-Key"] = config.apiKey;
|
|
1374
1415
|
}
|
|
1375
1416
|
try {
|
|
1417
|
+
headers["X-AstraSync-SDK-Version"] = SDK_VERSION;
|
|
1376
1418
|
const response = await sdkFetch(
|
|
1377
1419
|
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes` + (options.codeGates?.length ? `?codeGates=${options.codeGates.map(encodeURIComponent).join(",")}` : ""),
|
|
1378
1420
|
{ method: "GET", headers }
|
|
@@ -1387,6 +1429,13 @@ async function fetchRoutes(config, counterpartyId, options = {}) {
|
|
|
1387
1429
|
return null;
|
|
1388
1430
|
}
|
|
1389
1431
|
const body = await response.json();
|
|
1432
|
+
const type = body.data?.counterpartyType;
|
|
1433
|
+
if (typeof type === "string" && options.onEndpointType) {
|
|
1434
|
+
try {
|
|
1435
|
+
options.onEndpointType(type);
|
|
1436
|
+
} catch {
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1390
1439
|
return body.data?.routes ?? [];
|
|
1391
1440
|
} catch {
|
|
1392
1441
|
return null;
|
|
@@ -2665,14 +2714,14 @@ function createMiddleware(options) {
|
|
|
2665
2714
|
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
2666
2715
|
res.setHeader("X-Astra-Gateway-Reason", "evaluated-not-enforced");
|
|
2667
2716
|
}
|
|
2668
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2717
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2669
2718
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
2670
2719
|
});
|
|
2671
2720
|
}
|
|
2672
2721
|
return next();
|
|
2673
2722
|
}
|
|
2674
2723
|
if (!result.policyAllowed) {
|
|
2675
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2724
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2676
2725
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
2677
2726
|
});
|
|
2678
2727
|
}
|
|
@@ -2685,7 +2734,7 @@ function createMiddleware(options) {
|
|
|
2685
2734
|
}
|
|
2686
2735
|
if (requiresHumanApproval(result)) {
|
|
2687
2736
|
annotateApprovalRequired(result);
|
|
2688
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2737
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2689
2738
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
2690
2739
|
});
|
|
2691
2740
|
}
|
|
@@ -2710,7 +2759,7 @@ function createMiddleware(options) {
|
|
|
2710
2759
|
documentationUrl: wellKnownUrls.documentationUrl
|
|
2711
2760
|
};
|
|
2712
2761
|
}
|
|
2713
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2762
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2714
2763
|
recordDecision(config, sessionId, "denied", trustFailure.message).catch(() => {
|
|
2715
2764
|
});
|
|
2716
2765
|
}
|
|
@@ -2719,7 +2768,7 @@ function createMiddleware(options) {
|
|
|
2719
2768
|
return;
|
|
2720
2769
|
}
|
|
2721
2770
|
}
|
|
2722
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2771
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2723
2772
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
2724
2773
|
});
|
|
2725
2774
|
}
|