@astrasyncai/verification-gateway 5.17.2 → 5.18.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 +1849 -0
- package/README.md +141 -7
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +30 -12
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +30 -12
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/kit-express.d.mts +63 -0
- package/dist/adapters/kit-express.d.ts +63 -0
- package/dist/adapters/kit-express.js +88 -0
- package/dist/adapters/kit-express.js.map +1 -0
- package/dist/adapters/kit-express.mjs +61 -0
- package/dist/adapters/kit-express.mjs.map +1 -0
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +1 -1
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +1 -1
- 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 +18 -8
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +18 -8
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +1 -1
- package/dist/adapters/sdk.d.ts +1 -1
- package/dist/adapters/sdk.js +1 -1
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +1 -1
- package/dist/adapters/sdk.mjs.map +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 +1 -1
- package/dist/bin/astrasync-codex-hook.js +1 -1
- package/dist/bin/astrasync-guard.js +1 -1
- package/dist/bin/astrasync.js +19 -1
- package/dist/browser/background.js +1 -1
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +1 -1
- 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 +1 -1
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +1 -1
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +1 -1
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +1 -1
- 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 +5 -4
- package/dist/edge-core/index.d.ts +5 -4
- package/dist/edge-core/index.js +18 -8
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +18 -8
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +1 -1
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +1 -1
- 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 +390 -12
- package/dist/index.d.ts +390 -12
- package/dist/index.js +766 -230
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +749 -222
- package/dist/index.mjs.map +1 -1
- 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 +4 -3
- package/dist/transport/index.d.ts +4 -3
- 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-vNBvYD7Z.d.mts → types-3ObBpsnf.d.mts} +7 -0
- package/dist/{types-DA8LzAOB.d.ts → types-BoxZEYPS.d.ts} +7 -0
- package/dist/{types-DRb_plOh.d.mts → types-Cns4l8gX.d.mts} +17 -0
- package/dist/{types-DRb_plOh.d.ts → types-Cns4l8gX.d.ts} +17 -0
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +1 -1
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +1 -1
- package/dist/verify.mjs.map +1 -1
- package/package.json +8 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,1849 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@astrasyncai/verification-gateway` are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
6
|
+
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
Full architectural context for each release lives in the platform spec at
|
|
9
|
+
`docs/research/adapter-architecture-technical-requirements.md`.
|
|
10
|
+
|
|
11
|
+
## [5.18.0] — 2026-10-16 — checkout kit fixes, orders, Express mounting, MPP interop
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **A held purchase never settles (UCP + ACP kits).** The kits only treated a
|
|
16
|
+
`requires_approval` outcome or a `stepUpApproval` with `status: 'pending'`
|
|
17
|
+
as a hold, but verify-access step-up results carry `requiresStepUp`,
|
|
18
|
+
`requiresApproval`, `recommendation: 'step_up_required'` and
|
|
19
|
+
`policyAllowed: true` — so a held purchase reached `settle` and `fulfil`.
|
|
20
|
+
Any of those signals, or a `stepUpApproval` that isn't `consumed`, now holds:
|
|
21
|
+
UCP `requires_escalation` with `continue_url` = the approval page, ACP
|
|
22
|
+
`pending_approval`. A just-redeemed approval (`status: 'consumed'`) proceeds.
|
|
23
|
+
`StepUpApprovalInfo.status?: 'pending' | 'consumed'` is typed.
|
|
24
|
+
- **`settle` → `pending` no longer creates an order.** The session stays
|
|
25
|
+
`complete_in_progress` with no order until your processor confirms; see
|
|
26
|
+
`resolvePending` below.
|
|
27
|
+
- **Concurrent completes can't both charge.** `complete` claims
|
|
28
|
+
`complete_in_progress` before verifying (new optional
|
|
29
|
+
`CheckoutStore.claim(id, from, to)`, an atomic compare-and-set; the memory
|
|
30
|
+
stores implement it). The loser gets the session unchanged plus a
|
|
31
|
+
recoverable `checkout_in_progress` message (UCP) or `409
|
|
32
|
+
checkout_in_progress` (ACP). A store without `claim` logs a one-time warning.
|
|
33
|
+
- **Caller scoping.** Sessions and idempotency keys were scoped to the raw
|
|
34
|
+
`Authorization` header (ACP, `''` when absent — shared by every
|
|
35
|
+
unauthenticated caller) or to the `UCP-Agent` profile (UCP — shared by every
|
|
36
|
+
agent on a platform). They're now scoped to the verified ASTRA-id
|
|
37
|
+
(`kit.handle(req, { callerId })` / `resolveCallerId`), else `Authorization`,
|
|
38
|
+
else `X-Astra-Id`; UCP falls back to the platform profile, ACP refuses a
|
|
39
|
+
request with none (401). Scopes are stored hashed — no bearer token is
|
|
40
|
+
written to your store. Sessions created before the upgrade aren't found
|
|
41
|
+
afterwards. `beginIdempotent` has no shared `anon` scope any more: a request
|
|
42
|
+
with no caller isn't deduplicated, or gets `401 idempotency_caller_required`
|
|
43
|
+
when `required`; `idempotencyMiddleware` / `withIdempotency` also accept
|
|
44
|
+
`X-Astra-Id` as the caller.
|
|
45
|
+
- **UCP `complete` needs exactly one payment instrument** whose `handler_id`
|
|
46
|
+
is one of the profile's `payment_handlers` (handler `id` or name); anything
|
|
47
|
+
else is `payment_failed` and nothing is verified.
|
|
48
|
+
- **UCP `UCP-Agent` is bound to the verified agent.** `checkUcpAgentBinding`
|
|
49
|
+
was exported but unused: after `verifyPurchase` the kit now checks the
|
|
50
|
+
profile against `result.agent.protocolIdentities` (or
|
|
51
|
+
`resolveIdentities(req, result)`); a mismatch is `ucp_agent_mismatch` and
|
|
52
|
+
never settles. `ucpAgentBinding: 'registered'` (default) passes agents with
|
|
53
|
+
no registered profile (bridge-relayed calls); `'strict'` refuses them;
|
|
54
|
+
`'off'` skips it.
|
|
55
|
+
- **UCP GETs don't re-sign.** `render()` signed `ap2.merchant_authorization`
|
|
56
|
+
and wrote the session on every response, including GETs. A GET now returns
|
|
57
|
+
the stored authorization when it signs the same view.
|
|
58
|
+
- **Canceling a completed or canceled checkout is `405`** (UCP and ACP).
|
|
59
|
+
- **Express: credentialed callers on unmatched routes.** The no-match
|
|
60
|
+
pass-through ran before credentials were read, so
|
|
61
|
+
`evaluateAlwaysIfCredentialed` never applied to unmatched routes. Credentials
|
|
62
|
+
are read first; with the flag and an `X-Astra-Id` the request is evaluated in
|
|
63
|
+
observe mode (never vetoes, sets `req.agentVerification`).
|
|
64
|
+
- **`detectCommerce`: signed UCP requests are UCP.** The RFC 9421 branch ran
|
|
65
|
+
first, so a signed UCP call was labelled plain `rfc9421`. UCP is checked
|
|
66
|
+
first and carries the signature as its `rfc9421` artifact.
|
|
67
|
+
- **MPP challenge ids match mppx.** `buildMppChallenge` / `verifyMppChallenge`
|
|
68
|
+
bound a newline-joined `key=value` list; mppx binds pipe-joined positional
|
|
69
|
+
slots `realm|method|intent|request|expires|digest|opaque`. Ids now
|
|
70
|
+
interoperate both ways (ids issued by 5.15.0–5.17.2 no longer verify).
|
|
71
|
+
`buildMppChallenge` takes `meta` (encoded as `opaque`).
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- **`kit.resolvePending(sessionId, { status: 'settled' | 'failed', processorRef?, txHash?, chainId?, failureCode? })`**
|
|
76
|
+
(UCP + ACP): call it from your processor's webhook. Settled → reports the
|
|
77
|
+
settlement, runs `fulfil`, completes the session (and sends the UCP order
|
|
78
|
+
webhook); failed → reports it and returns the session to
|
|
79
|
+
`ready_for_complete` / `ready_for_payment`. A second call is a no-op. The
|
|
80
|
+
stored result excludes the settlement token, voucher, mandates and KYAPay
|
|
81
|
+
token. Type `PendingResolution`.
|
|
82
|
+
- **UCP `links`** (`{ type: 'terms_of_service' | 'privacy_policy' |
|
|
83
|
+
'refund_policy' | 'shipping_policy' | 'faq', url, title? }[]`), returned on
|
|
84
|
+
every checkout and covered by the merchant authorization.
|
|
85
|
+
- **UCP order capability:** `profile.orders: true` adds
|
|
86
|
+
`dev.ucp.shopping.order` (`UCP_ORDER_CAPABILITY`); `GET /orders/{id}`;
|
|
87
|
+
`buildUcpOrder(session)` (type `UcpOrder`); `webhook: { url?, privateKey?,
|
|
88
|
+
keyId?, businessProfileUrl?, attempts?, fetch?, onResult? }` sends the signed
|
|
89
|
+
order entity via `sendUcpWebhook` when an order is created (URL defaults to
|
|
90
|
+
the platform profile's order `config.webhook_url`, key to `signingKey`);
|
|
91
|
+
`kit.sendOrderWebhook(sessionId)` re-sends after an update. Optional
|
|
92
|
+
`CheckoutStore.findByOrderId(orderId)`.
|
|
93
|
+
- **`permalinkBase`** (UCP + ACP): `permalink_url` when `fulfil` returns none.
|
|
94
|
+
ACP `order.line_items` now mirrors the session's line items, plus
|
|
95
|
+
`checkout_session_id`.
|
|
96
|
+
- **ACP:** `API-Version` values are checked (`400 unsupported_api_version` with
|
|
97
|
+
`supported_versions`; `ACP_SUPPORTED_API_VERSIONS`); `Idempotency-Key` and
|
|
98
|
+
`Request-Id` are echoed on responses; `buildAcpWellKnown({ endpoint,
|
|
99
|
+
paymentHandlers, apiVersions?, links? })` and `acpPaymentHandlers()`;
|
|
100
|
+
`AcpCheckoutStore` type.
|
|
101
|
+
- **`expressHandler(kit, { callerId? })`** (root and
|
|
102
|
+
`@astrasyncai/verification-gateway/kit-express`): mounts a fetch-style kit on
|
|
103
|
+
Express and keeps the raw body (`express.raw()` or `req.rawBody`) for
|
|
104
|
+
signature checks; passes `req.agentVerification`'s verified ASTRA-id as the
|
|
105
|
+
caller.
|
|
106
|
+
- **`kit.handle(req, ctx?: KitRequestContext)`** and the `resolveCallerId`
|
|
107
|
+
option (UCP + ACP).
|
|
108
|
+
- **Express `defaultRoutePolicy: 'pass' | 'observe'`** (default `'pass'`):
|
|
109
|
+
`'observe'` evaluates unmatched routes in observe mode for any caller with
|
|
110
|
+
AstraSync credentials.
|
|
111
|
+
- **In-memory store warning:** the kits warn when they run on their in-memory
|
|
112
|
+
stores outside `NODE_ENV=test`.
|
|
113
|
+
- **MPP:** `buildMpp402Response(challenges, problem?)` (402, one
|
|
114
|
+
`WWW-Authenticate` per method, `Cache-Control: no-store`,
|
|
115
|
+
`application/problem+json`); `verifyMppChallenge(challenge, secret, { now?,
|
|
116
|
+
body?, store? })` → `Promise<MppVerifyResult>` checks the body against the
|
|
117
|
+
challenge `digest` and, with a `MppChallengeStore` (`MemoryMppChallengeStore`),
|
|
118
|
+
accepts each challenge once; `mppBodyDigest()`. The `(challenge, secret,
|
|
119
|
+
now?)` boolean form is unchanged.
|
|
120
|
+
- `CHANGELOG.md` ships in the package.
|
|
121
|
+
|
|
122
|
+
### Notes
|
|
123
|
+
|
|
124
|
+
- mppx stays pinned at 0.8.2. 0.13.x has the same challenge-id binding, but
|
|
125
|
+
installing it raises the monorepo's `viem` (peer `>=2.57.1`) and
|
|
126
|
+
`@x402/core`, and its `eventsource-parser` dependency needs Node 22.12+.
|
|
127
|
+
|
|
128
|
+
## [5.17.2] — 2026-10-15 — guard browse says where to approve
|
|
129
|
+
|
|
130
|
+
### Changed
|
|
131
|
+
|
|
132
|
+
- **`astrasync guard browse` prints the approval link** while it waits for the
|
|
133
|
+
owner's passkey (`Approve it at: https://…/activity/pending/<id>`), from the
|
|
134
|
+
sign-in route's new `approvalUrl`. There is no push notification: the owner
|
|
135
|
+
approves in the dashboard while signed in, and the link takes them there.
|
|
136
|
+
- **Fleet enrolment commands** in the docs name the binary:
|
|
137
|
+
`npx -y -p @astrasyncai/verification-gateway astrasync guard …`. The package
|
|
138
|
+
installs several commands, so `npx @astrasyncai/verification-gateway guard …`
|
|
139
|
+
fails with "could not determine executable to run".
|
|
140
|
+
|
|
141
|
+
## [5.17.1] — 2026-10-13 — one approval for a route that holds its own
|
|
142
|
+
|
|
143
|
+
### Added
|
|
144
|
+
|
|
145
|
+
- **`approvalHeldByRoute` (Express).** A function that returns true for
|
|
146
|
+
requests whose route asks the owner for approval itself — it creates its own
|
|
147
|
+
hold and answers `202` while it waits, as AstraSync's agent dashboard sign-in
|
|
148
|
+
does. For those requests a result that only needs the owner's approval is
|
|
149
|
+
passed to the route (`req.agentVerification` carries `requiresStepUp` and the
|
|
150
|
+
`failures` naming what needs approving) instead of refused, and verify-access
|
|
151
|
+
is told so it creates no approval of its own. The owner approves once. Any
|
|
152
|
+
deny is still refused, and so is a result that already carries a
|
|
153
|
+
`stepUpApproval`.
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
createMiddleware({
|
|
157
|
+
// …
|
|
158
|
+
approvalHeldByRoute: (req) => req.method === 'POST' && req.path === '/signin',
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Fixed
|
|
163
|
+
|
|
164
|
+
- **A hold on purpose, duration, scope or sub-agents is no longer described as
|
|
165
|
+
a spending limit.** The refusal now reads "The agent's owner asked to approve
|
|
166
|
+
this kind of request" and lists the server's `pdlss.<dimension>.approval_required`
|
|
167
|
+
entries; `commerce.intent.approval_required` and "Transaction is above the
|
|
168
|
+
autonomous limit" are kept for spending holds only.
|
|
169
|
+
- **Step-up results carry the server's `failures`.** An allowed-but-escalate
|
|
170
|
+
result now includes what needs approving, as a deny always has.
|
|
171
|
+
- **`astrasync guard browse` says why a sign-in was refused.** It read the
|
|
172
|
+
route error shape only, so a gateway refusal printed "no detail". A refused
|
|
173
|
+
status check (wrong device, unknown sign-in) now stops at once instead of
|
|
174
|
+
waiting 10 minutes for an approval that can't arrive.
|
|
175
|
+
|
|
176
|
+
## [5.17.0] — 2026-10-12 — `astrasync guard browse` (agent dashboard sign-in)
|
|
177
|
+
|
|
178
|
+
### Added
|
|
179
|
+
|
|
180
|
+
- **`astrasync guard browse`.** Signs an agent in to its owner's AstraSync
|
|
181
|
+
dashboard from this machine (round 28.5). It starts a local device proxy
|
|
182
|
+
for the AstraSync host, asks to sign in through the agent's Workforce Guard
|
|
183
|
+
checkpoint with this machine's Local Guard device credential, waits for the
|
|
184
|
+
owner's passkey approval when the agent's policy asks for it, and prints
|
|
185
|
+
the one-time sign-in URL to open through the proxy. The session is bound to
|
|
186
|
+
this machine: a copied cookie without the device is refused.
|
|
187
|
+
- The proxy carries WebSockets and tunnelled plain HTTP, and serves the
|
|
188
|
+
AstraSync host with a locally generated certificate.
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
astrasync guard browse --checkpoint <checkpoint-url> --slug <agent-slug> \
|
|
192
|
+
[--upstream astrasync-api] [--port <n>] [--host <extra-host>]
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- **Flags.** `--checkpoint` (required): the Workforce Guard checkpoint's base
|
|
196
|
+
URL. `--slug` (required): the agent's checkpoint slug. `--upstream`: the
|
|
197
|
+
checkpoint's upstream for the AstraSync API (default `astrasync-api`); the
|
|
198
|
+
sign-in goes to `<checkpoint>/a/<slug>/h/<upstream>/agent-sessions`.
|
|
199
|
+
`--port`: the local proxy port (default: any free port; it listens on
|
|
200
|
+
`127.0.0.1` only). `--host`: one extra hostname that also gets the device
|
|
201
|
+
credential (for example a separate app host); the enrolled AstraSync API
|
|
202
|
+
host always does.
|
|
203
|
+
- **Prerequisites.** The machine is enrolled in the organisation's fleet with
|
|
204
|
+
`astrasync guard enroll <token>` (user scope by default; `--system` enrols
|
|
205
|
+
the whole machine and needs administrator rights). The agent is linked to
|
|
206
|
+
a Workforce Guard checkpoint whose upstream for the AstraSync API forwards
|
|
207
|
+
the device credential, and the agent's policy allows the `dashboard.signin`
|
|
208
|
+
action (off for every agent until the owner allows it; put it on the
|
|
209
|
+
approval list to require the owner's passkey for each sign-in). The site's
|
|
210
|
+
route policy must allow the sign-in route, and the platform requires a
|
|
211
|
+
passed runtime challenge, which the checkpoint answers.
|
|
212
|
+
- **Certificate.** The proxy terminates TLS only for the AstraSync hosts,
|
|
213
|
+
with a self-signed ECDSA P-256 certificate generated in memory at start
|
|
214
|
+
(valid 30 days, never written to disk or added to a trust store). Point the
|
|
215
|
+
automation browser at the proxy and let it ignore certificate errors, e.g.
|
|
216
|
+
Playwright `chromium.launch({ proxy: { server: 'http://127.0.0.1:<port>' } })`
|
|
217
|
+
with `newContext({ ignoreHTTPSErrors: true })`. The proxy re-originates to
|
|
218
|
+
the real host over verified TLS. Every other host is a blind tunnel that
|
|
219
|
+
the proxy never inspects.
|
|
220
|
+
- **One-time code.** Once signed in (or once the owner approves), the command
|
|
221
|
+
prints `<site>/agent-session#code=…`. Open it once, through the proxy,
|
|
222
|
+
within 2 minutes: the code is single use, bound to this machine, and rides
|
|
223
|
+
in the URL fragment so it never reaches a server log or a Referer. The page
|
|
224
|
+
exchanges it for the session cookie and drops it from the address bar.
|
|
225
|
+
- **Session gate.** Every request in an agent session must carry the
|
|
226
|
+
machine's device credential (the proxy adds it; the browser never holds
|
|
227
|
+
it). A request without it, or from another device, ends the session. Each
|
|
228
|
+
request is checked against the agent's policy as `dashboard.read` or
|
|
229
|
+
`dashboard.change`. When the policy asks, or the area is admin, the owner
|
|
230
|
+
approves that exact request with a passkey (202 `OWNER_APPROVAL_REQUIRED`).
|
|
231
|
+
Ctrl-C stops the proxy.
|
|
232
|
+
|
|
233
|
+
## [5.16.0] — 2026-10-07 — Per-route owners + runtime challenge, governed git
|
|
234
|
+
|
|
235
|
+
### Fixed
|
|
236
|
+
|
|
237
|
+
- **UCP detection needs the `UCP-Agent` header.** A request to any
|
|
238
|
+
`/checkout-sessions` path was treated as a UCP checkout and verify-access
|
|
239
|
+
replaced the route's purpose with `commerce.unknown` — an ordinary API with
|
|
240
|
+
such a route was denied. UCP platforms always send `UCP-Agent`, so detection
|
|
241
|
+
now requires it.
|
|
242
|
+
|
|
243
|
+
### Changed (security — breaking for hand-rolled challenge responders)
|
|
244
|
+
|
|
245
|
+
- **`ChallengeHandler` no longer auto-includes.** Since 3.7.1, a handler with
|
|
246
|
+
nothing registered as pending answered with whatever counterparty the
|
|
247
|
+
challenge asked about. That made the runtime challenge prove only that the
|
|
248
|
+
agent's server was up: anyone presenting the agent's ASTRA-id passed. It
|
|
249
|
+
now answers only for counterparties registered with `registerPending()`
|
|
250
|
+
(counted, so concurrent calls to one counterparty don't clear each other).
|
|
251
|
+
- **`AgentClient` does the registering for you:** pass `challengeHandler` to
|
|
252
|
+
the client and each `fetch()` registers its destination (by origin, and by
|
|
253
|
+
`counterpartyId` when you pass the ASTRAE-id) for exactly as long as the
|
|
254
|
+
call is in flight.
|
|
255
|
+
- **Migration:** if you call counterparties without `AgentClient`, wrap each
|
|
256
|
+
call in `registerPending(id)` / `removePending(id)`. Endpoints that require
|
|
257
|
+
the challenge deny calls that aren't pending.
|
|
258
|
+
|
|
259
|
+
### Added
|
|
260
|
+
|
|
261
|
+
- **Per-route policy fields** (set on the endpoint's routes in the dashboard):
|
|
262
|
+
`allowedOwners` (only agents owned by the listed ASTRAO-/ASTRAD-/ASTRAI-ids
|
|
263
|
+
pass the route) and `requiresRuntimeChallenge` (the runtime challenge on
|
|
264
|
+
this route only). The Express and Next.js middleware forward the matched
|
|
265
|
+
route's values to verify-access as `routePolicy`, which enforces them — the
|
|
266
|
+
agent's owner is resolved by AstraSync and never disclosed to you. Routes
|
|
267
|
+
without them behave exactly as before. `routePolicyOf(route)` and the
|
|
268
|
+
`RoutePolicy` type are exported.
|
|
269
|
+
- **`astrasync guard git-route`**: routes this machine's `git fetch` / `git
|
|
270
|
+
push` to github.com through your organisation's Workforce Guard checkpoint
|
|
271
|
+
(`--checkpoint <url> --slug <connector> --agent <ASTRA-id>`, `--undo`).
|
|
272
|
+
`git commit` and its local hooks are unchanged. The checkpoint checks each
|
|
273
|
+
push against the agent's mandate (protected branches, deletions, repository
|
|
274
|
+
allow-list) and attaches the git host token from the AstraSync vault; the
|
|
275
|
+
machine authenticates with its Local Guard device credential via the new
|
|
276
|
+
`astrasync guard git-credential` helper. No git host token is stored on the
|
|
277
|
+
machine.
|
|
278
|
+
|
|
279
|
+
## [5.15.0] — 2026-10-06 — Agentic commerce protocols: AP2 mandates, UCP/ACP kits, KYAPay, signing
|
|
280
|
+
|
|
281
|
+
### Added
|
|
282
|
+
|
|
283
|
+
- **`reportSettlement()` errors:** throws `SettlementReportError` (`statusCode`,
|
|
284
|
+
`code`, `issues`). `isRetryableSettlementError(err)` is true for network
|
|
285
|
+
failures (`statusCode: 0`), 429 and 5xx; every other error is final.
|
|
286
|
+
- **Agent protocol identities:** `result.agent.protocolIdentities` (agent
|
|
287
|
+
signing key, UCP profile, Web Bot Auth key directory, A2A card, x402 wallet,
|
|
288
|
+
network agent ids, and which AstraSync verified).
|
|
289
|
+
- **`checkUcpAgentBinding(header, identities)`** / `parseUcpAgentHeader()`:
|
|
290
|
+
reject a `UCP-Agent` profile that isn't the agent's registered one
|
|
291
|
+
(`ucp_agent_mismatch`, `invalid_ucp_agent`).
|
|
292
|
+
- **Idempotency:** `idempotencyMiddleware()` (Express) and `withIdempotency()`
|
|
293
|
+
(fetch / Next.js) with `MemoryIdempotencyStore` / `RedisIdempotencyStore`.
|
|
294
|
+
Same key + same request replays the stored response
|
|
295
|
+
(`Idempotent-Replayed: true`); store down → 503 `idempotency_unavailable`;
|
|
296
|
+
5xx responses aren't stored. 24 h.
|
|
297
|
+
- **RFC 9421 signing:** `signHttpRequest()` (ES256 / Ed25519, `tag`, `nonce`,
|
|
298
|
+
RFC 9530 `Content-Digest`). Verification now also checks that a covered
|
|
299
|
+
`Content-Digest` matches the body.
|
|
300
|
+
- **Route patterns:** `:name` matches one path segment; `routePatternToRegExp()`
|
|
301
|
+
/ `matchRoutePattern()` are shared by the Express, Next.js and edge
|
|
302
|
+
matchers. Literal characters such as `.` are now escaped (previously `.`
|
|
303
|
+
matched any character).
|
|
304
|
+
- **`StepUpApprovalInfo.approvalUrl`:** the buyer-facing approval page. Return
|
|
305
|
+
it as UCP `continue_url` with `requires_escalation`.
|
|
306
|
+
- **`EdgeConfig.minTls`** (`'1.2' | '1.3'`): agent requests below it get 426 in
|
|
307
|
+
enforce mode and are logged in observe mode; browsers are never gated.
|
|
308
|
+
- **Express / Next.js adapters forward protocol artifacts** (VI, AP2, ACP, UCP,
|
|
309
|
+
MPP, x402 payloads; Visa TAP / Mastercard Agent Pay / Web Bot Auth
|
|
310
|
+
signatures) to verify-access, as the edge already did. Keep `req.rawBody` for
|
|
311
|
+
exact body-signature verification.
|
|
312
|
+
|
|
313
|
+
- **AP2 v0.2 mandates** (delegate SD-JWT, `~~` chains, exact `vct`s):
|
|
314
|
+
`verifyAp2Mandate()` (root signer by kid, KB hops against `cnf`,
|
|
315
|
+
`sd_hash` / `issuer_jwt_hash` binding, expiry, unknown constraints fail,
|
|
316
|
+
`checkout_hash` = SHA-256 of `checkout_jwt`), builders
|
|
317
|
+
(`closedCheckoutMandate`, `closedPaymentMandate`, `openCheckoutMandate`,
|
|
318
|
+
`openPaymentMandate`), `signRootMandate()`, and `createKbHop()` for agents
|
|
319
|
+
closing an open mandate.
|
|
320
|
+
- **`result.mandates`**: AP2 mandates AstraSync issued (merchant lane).
|
|
321
|
+
Pass your signed checkout as `checkoutJwt` (verify / `confirmCheckout`).
|
|
322
|
+
- **`result.kyaToken`**: a KYAPay `kya+jwt` for the agent at your endpoint
|
|
323
|
+
(`hid.email` = where to send the receipt). `verifyKyaPayTokens()` verifies
|
|
324
|
+
`KYAPay-Token` headers (identity tokens only unless you opt in to pay).
|
|
325
|
+
- **UCP 2026-08-25**: `createUcpCheckoutKit()` (create / get / update /
|
|
326
|
+
complete / cancel; negotiation, idempotency, optional signature checks,
|
|
327
|
+
AP2 merchant authorization + mandate checks, escalation →
|
|
328
|
+
`requires_escalation` with the approval URL), `buildUcpProfile()`,
|
|
329
|
+
`fetchUcpProfile()` (SSRF-guarded), `negotiateUcp()`, `signUcpRequest()` /
|
|
330
|
+
`verifyUcpRequest()` / `signUcpResponse()`, `sendUcpWebhook()`, message
|
|
331
|
+
builders.
|
|
332
|
+
- **ACP 2026-04-17**: `createAcpCheckoutKit()` (step-up → `pending_approval`
|
|
333
|
+
with the approval URL; API-Version and Idempotency-Key required).
|
|
334
|
+
- **A-Comm Evidence Protocol (AEP v1.0.3-rc.2):** `AepChain`,
|
|
335
|
+
`aepCanonicalJson`, `aepHash`, `aepSign`, `verifyAepChain`,
|
|
336
|
+
`aepPublicKeyDocument` — reproduces the published conformance vectors
|
|
337
|
+
byte for byte. `result.aep` (when your endpoint lists `aep`): AstraSync's
|
|
338
|
+
policy, delegation and platform-countersigned intent payloads to append to
|
|
339
|
+
your chain.
|
|
340
|
+
- **x402 v2 / MPP helpers** (`buildX402Challenge`, `parseX402Payment`,
|
|
341
|
+
`x402PaymentMatchesOffer`, `buildMppChallenge`, `verifyMppChallenge`,
|
|
342
|
+
`encodeMppReceipt`, …). The merchant's facilitator / processor settles.
|
|
343
|
+
|
|
344
|
+
### Changed
|
|
345
|
+
|
|
346
|
+
- **Idempotency** follows the spec of your protocol: `profile: 'ucp'`
|
|
347
|
+
(default; raw body, 409) or `'acp'` (canonical JSON, 422
|
|
348
|
+
`idempotency_conflict`; 409 `idempotency_in_flight` with `Retry-After`).
|
|
349
|
+
The key is echoed on responses.
|
|
350
|
+
- **x402 v2 is read from `PAYMENT-SIGNATURE` / `PAYMENT-REQUIRED`** (was the
|
|
351
|
+
body); v1 headers still work. MPP `Payment-Authorization` is detected.
|
|
352
|
+
ACP 2026-04-17 `payment_data.instrument.credential.token` is read.
|
|
353
|
+
- Requests carrying protocol artifacts are never served from or written to
|
|
354
|
+
the verify cache.
|
|
355
|
+
- `RegistryName` gains `'astrasync'` (the platform's composite resolver).
|
|
356
|
+
|
|
357
|
+
## [5.14.1] — 2026-10-05 — AstraSync never charges; runtime challenge is opt-in
|
|
358
|
+
|
|
359
|
+
### Changed
|
|
360
|
+
|
|
361
|
+
- **Every purchase is settled by the merchant.** The platform no longer
|
|
362
|
+
charges any card itself. A purchase grant records an order and returns
|
|
363
|
+
`settlementOutcome: { status: 'pending_merchant', orderId }` together with
|
|
364
|
+
the artifact the merchant settles: `settlementToken` for a card on the
|
|
365
|
+
first-party Stripe tenant, or the `settlement` voucher (stablecoin) for any
|
|
366
|
+
merchant. Redeem the voucher, then call `reportSettlement()`.
|
|
367
|
+
- **`reportSettlement()`** accepts `orderId` instead of `sessionId`, and a
|
|
368
|
+
stablecoin `txHash` (+ `chainId`) instead of a card `processorRef`. Every
|
|
369
|
+
merchant may report, not only first-party ones.
|
|
370
|
+
- **The voucher redeem response** no longer carries a `settlement` block (no
|
|
371
|
+
charge happens at redeem). It carries `order: { status: 'redeemed' }` when
|
|
372
|
+
the voucher funded a recorded order.
|
|
373
|
+
- **A voucher is minted only on a purchase leg**: the confirm leg, or an
|
|
374
|
+
unphased call that carries a value. Browse and quote calls no longer mint.
|
|
375
|
+
When the request's commerce protocol already carries the payment
|
|
376
|
+
credential (ACP / MPP token, x402 payment payload, AP2 payment mandate),
|
|
377
|
+
nothing is minted and the order settles by report-back.
|
|
378
|
+
- **Runtime challenge is opt-in.** `enableRuntimeChallenge` defaults to false
|
|
379
|
+
(backend and the Next.js adapter). Ask for it explicitly, or set the
|
|
380
|
+
endpoint's `requiresRuntimeChallenge`.
|
|
381
|
+
|
|
382
|
+
### Fixed
|
|
383
|
+
|
|
384
|
+
- **A dead agent callback no longer stalls verify.** A callback that times
|
|
385
|
+
out or can't be reached gives the same outcome for 60 seconds without being
|
|
386
|
+
called again, and at most 5 challenges are in flight to one host — the rest
|
|
387
|
+
resolve at once as `timeout`.
|
|
388
|
+
|
|
389
|
+
### Migration
|
|
390
|
+
|
|
391
|
+
- Merchants that relied on the platform charging first-party cards must now
|
|
392
|
+
charge the `settlementToken` and report back (the 5.5.0 self-settle flow).
|
|
393
|
+
|
|
394
|
+
## [5.14.0] — 2026-10-03 — edge beacons are no longer stranded in a reclaimed container
|
|
395
|
+
|
|
396
|
+
### Fixed
|
|
397
|
+
|
|
398
|
+
- **Repeat beacons are no longer held for 60 seconds.** The edge buffer used
|
|
399
|
+
to collect repeats of the same request (same caller, user agent and path)
|
|
400
|
+
into an aggregate that waited until its 60-second window closed. Lambda@Edge
|
|
401
|
+
has no `waitUntil`, so that aggregate was only sent if the same container
|
|
402
|
+
was invoked again after the window. When AWS reclaimed the container first,
|
|
403
|
+
the beacons were lost. On staging on 3 Oct, only ~68% of agent and script
|
|
404
|
+
requests were beaconed. Repeats now merge only into an item that is still
|
|
405
|
+
queued. Otherwise the repeat is a new item, sent on the same flush. Under
|
|
406
|
+
load, repeats still merge while a batch is in flight.
|
|
407
|
+
|
|
408
|
+
### Added
|
|
409
|
+
|
|
410
|
+
- **Batch metadata identifies the container.** Each batch's `meta` now
|
|
411
|
+
carries `containerId` (one per cold start) and the container's cumulative
|
|
412
|
+
`enqueuedTotal`, `deliveredTotal` and `droppedTotal`. The backend uses them
|
|
413
|
+
to count items left queued in a container that stops reporting, which the
|
|
414
|
+
container's own drop counter can't report.
|
|
415
|
+
|
|
416
|
+
## [5.13.0] — 2026-10-02 — a key that can't verify for its endpoint fails at deploy
|
|
417
|
+
|
|
418
|
+
### Added
|
|
419
|
+
|
|
420
|
+
- **The startup self-check names the endpoint.** When `counterpartyId` (or
|
|
421
|
+
`counterpartyUrl`) is configured, the one-time init check sends it to
|
|
422
|
+
`GET /agents/verify-access/self-check`. The backend answers whether this API
|
|
423
|
+
key may verify for that endpoint: verify-access now only accepts a key whose
|
|
424
|
+
account owns the endpoint, or an active member of the organisation that owns
|
|
425
|
+
it. A key from another account, or an unknown endpoint, is logged loudly at
|
|
426
|
+
startup (`strictInit: true` throws) instead of every inbound agent being
|
|
427
|
+
refused with `COUNTERPARTY_KEY_MISMATCH`.
|
|
428
|
+
|
|
429
|
+
- **A refused route-policy read is no longer silent.** When the Express or
|
|
430
|
+
Next.js middleware can't read its endpoint's route policy (HTTP 401/403/404:
|
|
431
|
+
a key from another account, or a wrong `counterpartyId`), it now logs one
|
|
432
|
+
loud error per endpoint saying the gateway is in pass-through mode and no
|
|
433
|
+
agent is being verified. It used to fall through quietly. Transient 5xx
|
|
434
|
+
failures stay quiet and are retried on refresh.
|
|
435
|
+
|
|
436
|
+
### Changed
|
|
437
|
+
|
|
438
|
+
- **A 403 `COUNTERPARTY_KEY_MISMATCH` is merchant misconfiguration**, like a
|
|
439
|
+
rejected key: `misconfigured: true`, `misconfigCode:
|
|
440
|
+
'counterparty_key_mismatch'`, failure dimension
|
|
441
|
+
`verify_access.merchant_misconfigured`, and the agent is told to contact the
|
|
442
|
+
site operator. It was previously a retryable `api_error` ("temporarily
|
|
443
|
+
unavailable — retry"), which retrying can never fix.
|
|
444
|
+
|
|
445
|
+
### Fixed
|
|
446
|
+
|
|
447
|
+
- **`viem` is a declared dependency.** `mppx` 0.8.2 imports `viem` when the
|
|
448
|
+
package loads but only lists it as a peer, so an install that skips peers
|
|
449
|
+
(`legacy-peer-deps`) failed at import with `Cannot find package 'viem'`.
|
|
450
|
+
|
|
451
|
+
### Notes
|
|
452
|
+
|
|
453
|
+
- Older backends ignore the query and return no `counterparty` block: silent,
|
|
454
|
+
as before.
|
|
455
|
+
|
|
456
|
+
## [5.12.0] — 2026-10-01 — verification outages are retryable, never an identity deny
|
|
457
|
+
|
|
458
|
+
### Changed
|
|
459
|
+
|
|
460
|
+
- **Outage posture in the Express, Next.js and MCP adapters and `quickVerify`.**
|
|
461
|
+
When verify-access is unreachable or rate-limited, an observe route or an
|
|
462
|
+
anonymous read (GET/HEAD; for MCP, anything other than `tools/call`) is
|
|
463
|
+
served and tagged `X-Astra-Verification: unavailable`. An enforced route
|
|
464
|
+
returns **503** with `Retry-After` (the backend's value, else 30 s) and
|
|
465
|
+
`VERIFICATION_UNAVAILABLE`. For MCP that is JSON-RPC `-32003`,
|
|
466
|
+
`recommendation: 'error'`, retryable. Previously an outage — including a
|
|
467
|
+
429 — produced **401 UNAUTHORIZED**, so anonymous catalog reads failed
|
|
468
|
+
closed.
|
|
469
|
+
- `failOnError: 'closed'` now fails with the same retryable 503 instead of an
|
|
470
|
+
identity-shaped 401.
|
|
471
|
+
- **Identity status mapping.** Missing credentials still get 401. A presented
|
|
472
|
+
identifier that is malformed or unknown now gets **403**
|
|
473
|
+
`AGENT_IDENTITY_REJECTED` with registration guidance. A 404 from
|
|
474
|
+
verify-access (unknown agent) is an identity deny, not an `api_error`.
|
|
475
|
+
- `VerificationResult` gains `httpStatus` and `retryAfterMs`. Non-JSON error
|
|
476
|
+
bodies (e.g. a proxy 429) keep their status and `Retry-After`.
|
|
477
|
+
- `reportAttempt(config, report, { onFailure })` checks the response status
|
|
478
|
+
and retries once on 429/5xx, honouring `Retry-After` (capped at 2 s). It
|
|
479
|
+
never throws. `AttemptReport.servedFrom` (`'bridge_cache' | 'merchant'`) is
|
|
480
|
+
new.
|
|
481
|
+
- **Edge beacons are buffered and batched.** The edge core queues beacons in
|
|
482
|
+
memory (up to 1,000 items, dropping the oldest first) and sends batches of
|
|
483
|
+
up to 100 to `/verification-activity/edge-events` with the endpoint's API
|
|
484
|
+
key. An in-flight send carries over to the next invocation. Failed batches
|
|
485
|
+
are retried up to 3 times, and a 429 is honoured. Identical requests within
|
|
486
|
+
60 s are collapsed into `repeatCount`. Each batch reports `droppedSinceLast`
|
|
487
|
+
and `queueDepth`. This fixes the ~60% beacon loss on Lambda@Edge, where a
|
|
488
|
+
300 ms budget used to drop single beacons.
|
|
489
|
+
- `reportUnregisteredAttempt` and the Express/Next anonymous beacon send the
|
|
490
|
+
API key when one is configured, so rows are attributed as verified.
|
|
491
|
+
- `confirmCheckout()` accepts `attemptId`.
|
|
492
|
+
- The ChatGPT platform signature now matches `GPTBot` and `OAI-SearchBot`.
|
|
493
|
+
- **A recognised but unregistered agent's read is served.** An allowed
|
|
494
|
+
verify-access response that says `step_up_required` for a caller with no
|
|
495
|
+
verified identity is treated as a grant. Step-up is for a registered
|
|
496
|
+
agent's owner to approve a valued action; an unregistered caller has no
|
|
497
|
+
owner. Older backends sent that verdict for recognised platform agents
|
|
498
|
+
(Claude-User, the AstraSync bridge) on plain reads, and every adapter
|
|
499
|
+
answered **401** "requires human approval" to an anonymous catalog GET
|
|
500
|
+
(since 5.0.0). A registered agent's valued step-up still fails closed.
|
|
501
|
+
- **An unknown agent id is an identity rejection.** The backend's 200
|
|
502
|
+
`agent.lookup` deny (a well-formed id that matches no registered agent) now
|
|
503
|
+
gets **403** `AGENT_IDENTITY_REJECTED` with registration guidance, like the
|
|
504
|
+
404 mapping, instead of a policy deny. It is never `identityVerified`.
|
|
505
|
+
- **`observe` never vetoes.** With `evaluateAlwaysIfCredentialed`, a
|
|
506
|
+
credentialed call to an `observe` tool (MCP) or route (Express) now passes
|
|
507
|
+
through whatever the verdict, as documented. It used to be denied (MCP:
|
|
508
|
+
403 / `-32001`, or 400 `PDLSS_PURPOSE_REQUIRED` with no purpose). Enforced
|
|
509
|
+
tools and routes are unchanged.
|
|
510
|
+
|
|
511
|
+
### Added
|
|
512
|
+
|
|
513
|
+
- `failure-posture` helpers: `isVerificationUnavailable`,
|
|
514
|
+
`unavailableRetryAfterSeconds`, `buildVerificationUnavailableBody`,
|
|
515
|
+
`denyStatusFor`, `isRejectedIdentityClaim`, `VERIFICATION_STATUS_HEADER`.
|
|
516
|
+
- `BeaconBuffer`, `getBeaconBuffer`, `resetBeaconBuffer` (edge core).
|
|
517
|
+
|
|
518
|
+
### Migration
|
|
519
|
+
|
|
520
|
+
- If you have a custom `onDenied` handler, branch on
|
|
521
|
+
`isVerificationUnavailable(result)` and return 503 + `Retry-After` rather
|
|
522
|
+
than 401.
|
|
523
|
+
- If your MCP host sits behind a proxy, set Express `trust proxy` so the
|
|
524
|
+
caller IP is correct.
|
|
525
|
+
|
|
526
|
+
## [5.11.0] — 2026-09-29 — Local Guard fleet mode (organisation-managed policy)
|
|
527
|
+
|
|
528
|
+
### Added
|
|
529
|
+
|
|
530
|
+
- **Fleet mode for Local Guard** (Workforce Guard / Enterprise Governance
|
|
531
|
+
orgs). `astrasync guard enroll <token> [--api-base-url <url>] [--system]`
|
|
532
|
+
enrols the machine with an org-minted token; from then on the Claude Code
|
|
533
|
+
hook, the Codex hook and the Cursor extension enforce the org's **central
|
|
534
|
+
signed policy** (ES256 JWS, `typ fleet-policy+jwt`, `aud
|
|
535
|
+
astrasync:fleet-policy`, verified against the org's own key, pinned at
|
|
536
|
+
enrolment).
|
|
537
|
+
- **Key rotation without re-enrolment.** When the org rotates its key, the
|
|
538
|
+
platform returns a signed rotation chain (`typ fleet-keys+jwt`, each new
|
|
539
|
+
key signed by the one it replaces). The guard follows the chain from its
|
|
540
|
+
pinned key, stops trusting the retired key, and caches the chain in
|
|
541
|
+
`~/.astrasync/fleet/keychain.json` (re-verified from the pin on every
|
|
542
|
+
load). A heartbeat reporting a new `activeKid` triggers the refresh.
|
|
543
|
+
- Enrolled machines **ignore** every local `policy.yaml` / `guard.json`,
|
|
544
|
+
`ASTRASYNC_GUARD_DISABLE`, `ASTRASYNC_GUARD_FAIL_OPEN`, guard.json
|
|
545
|
+
`failOpen` and the passive default — posture, failOpen, governMcp and
|
|
546
|
+
skipTools come only from the signed settings.
|
|
547
|
+
- Fail closed: a bad signature, wrong `aud`/`typ`/`iss`/`sub`, a policy hash
|
|
548
|
+
mismatch, a version rollback or an unreadable enrolment denies. A revoked
|
|
549
|
+
device keeps enforcing its last good policy.
|
|
550
|
+
- `ASTRASYNC_FLEET_REQUIRED=1` (set by managed settings) makes an
|
|
551
|
+
unenrolled machine deny with the enrol instruction.
|
|
552
|
+
- Heartbeat after each decision, at most once per interval with a 1.5 s
|
|
553
|
+
budget (never delays a decision); a changed active policy is fetched,
|
|
554
|
+
verified and swapped in for the next call.
|
|
555
|
+
- Machine-scope enrolment (`--system`: `/etc/astrasync`,
|
|
556
|
+
`/Library/Application Support/AstraSync`, `%ProgramData%\AstraSync`) wins
|
|
557
|
+
over user scope (`~/.astrasync/fleet/`, 0600).
|
|
558
|
+
- `astrasync guard fleet-status` and fleet lines in `astrasync guard status`.
|
|
559
|
+
- `astrasync guard managed-settings [--claude] [--codex] [--out <dir>]`: MDM
|
|
560
|
+
templates — Claude Code `managed-settings.json` (managed PreToolUse hook,
|
|
561
|
+
`allowManagedHooksOnly`, `env.ASTRASYNC_FLEET_REQUIRED`, guard-file deny
|
|
562
|
+
rules) and Codex `requirements.toml` (`allow_managed_hooks_only`,
|
|
563
|
+
`[[hooks.PreToolUse]]`), per OS.
|
|
564
|
+
- Root exports `parseLocalPolicyYaml` / `validateLocalPolicy` (+ result
|
|
565
|
+
types) so the platform validates fleet YAML with the guard's own parser.
|
|
566
|
+
- `resolveGuard()` / `resolveFleet()` (fleet-first resolution);
|
|
567
|
+
`resolveGuardConfig()` keeps its 5.10.0 signature.
|
|
568
|
+
- Claude Code permission deny rules now also cover the fleet enrolment paths
|
|
569
|
+
(`~/.astrasync/fleet/**` and the machine-scope directories).
|
|
570
|
+
|
|
571
|
+
### Removed
|
|
572
|
+
|
|
573
|
+
- `astrasync guard upgrade` no longer uploads the local policy to
|
|
574
|
+
`POST /api/v1/agents/policies/upload` — that route never existed, so the
|
|
575
|
+
upgrade always failed at that step. The flow now asks for the ASTRA- id of
|
|
576
|
+
an agent registered in the dashboard (optional) instead.
|
|
577
|
+
|
|
578
|
+
Unenrolled machines behave exactly as in 5.10.0.
|
|
579
|
+
|
|
580
|
+
## [5.10.0] — 2026-09-26 — only an ASTRA id is an agent claim at the edge
|
|
581
|
+
|
|
582
|
+
### Fixed
|
|
583
|
+
|
|
584
|
+
- **Edge classification: a bare `Authorization: Bearer` JWT (or a non-`kya_`
|
|
585
|
+
`x-api-key`) is no longer tiered `verified`.** verify-access is sent the ASTRA
|
|
586
|
+
id only, so such a request could never verify — under enforce it was always
|
|
587
|
+
denied ("Endpoint policy denies unverified agents"). That self-DoS'd any
|
|
588
|
+
property whose signed-in users call its own API with Bearer tokens (found on
|
|
589
|
+
AstraSync's own staging: first-party chat/OAuth sessions on `/api/*`). These
|
|
590
|
+
requests now classify on their other signals (UA / commerce protocol /
|
|
591
|
+
fingerprint) — a made-up token neither verifies nor bypasses the edge. An
|
|
592
|
+
`X-Astra-Id` (with or without a bearer) is still an agent claim.
|
|
593
|
+
- **A malformed agent id is a deny, not an outage.** A non-canonical id
|
|
594
|
+
(e.g. `ASTRA-bogus123`) makes verify-access answer `400 INVALID_AGENT_ID`;
|
|
595
|
+
the SDK treated that as a transient `verify_access.api_error`, so the edge
|
|
596
|
+
returned 503 "verification unavailable — retry" under enforce. It is now an
|
|
597
|
+
identity deny (`identity.invalid_agent_id`, backend message + guidance) →
|
|
598
|
+
the edge's 403 with registration guidance. Other 400s are unchanged.
|
|
599
|
+
|
|
600
|
+
## [5.9.0] — 2026-09-25 — `blockchainAnchored` (breaking rename)
|
|
601
|
+
|
|
602
|
+
### Changed (breaking)
|
|
603
|
+
|
|
604
|
+
- **`VerificationResult.agent.blockchainVerified` → `blockchainAnchored`.** The
|
|
605
|
+
server's `agent.blockchainStatus` values were renamed `verified` → `anchored`
|
|
606
|
+
and `unverified` → `not_anchored` (`pending` / `failed` unchanged). The flag
|
|
607
|
+
only ever meant "this agent's identity record is on-chain" — never an
|
|
608
|
+
identity-verification claim — and "verified" collided with the WHO axis
|
|
609
|
+
(`identityVerified`). Migration: replace `result.agent.blockchainVerified`
|
|
610
|
+
with `result.agent.blockchainAnchored`; direct-API consumers comparing
|
|
611
|
+
`blockchainStatus === 'verified'` compare against `'anchored'`.
|
|
612
|
+
|
|
613
|
+
## [5.8.0] — 2026-08-20 — attempt-chain redemption (X-Astra-Attempt-Id)
|
|
614
|
+
|
|
615
|
+
### Added
|
|
616
|
+
|
|
617
|
+
- **Express + Next.js middleware read `X-Astra-Attempt-Id`** (the bridge
|
|
618
|
+
stamps it on every delivered venue call; the edge pipeline already read it)
|
|
619
|
+
and thread the id into the verify-access body. Server-side, a step-up
|
|
620
|
+
approval the owner already granted for the same attempt chain now passes
|
|
621
|
+
every later hop carrying the id — bridge pre-verify, the venue middleware's
|
|
622
|
+
re-verify, and post-failure re-drives — instead of minting a fresh approval
|
|
623
|
+
each time (the Meridian two-hop approval-loop fix). Values not matching
|
|
624
|
+
`att_<32 hex>` are dropped, never forwarded.
|
|
625
|
+
- **README: bridge-fronted hold budgets** — documented the bridge's 30 s
|
|
626
|
+
default / 60 s max response budget (per-route `responseBudgetMs` override)
|
|
627
|
+
and the recommended venue `stepUpMaxWaitMs` posture behind the bridge, plus
|
|
628
|
+
the `X-Astra-Attempt-Id` wire contract for venue-side idempotency.
|
|
629
|
+
|
|
630
|
+
## [5.7.0] — 2026-08-20 — first-party account keys at the edge + runtimeChallenge not_configured
|
|
631
|
+
|
|
632
|
+
### Fixed
|
|
633
|
+
|
|
634
|
+
- **Edge classifier: account API keys are first-party, never an agent claim.**
|
|
635
|
+
`classify()` previously tiered ANY `Authorization: Bearer` / `x-api-key`
|
|
636
|
+
credential as a `verified` agent claim, so plain API clients (curl, Postman,
|
|
637
|
+
non-SDK backends) presenting a VALID `kya_…` account key were sent through
|
|
638
|
+
verify-access — which can never verify an account key as an agent — and
|
|
639
|
+
enforce mode 403'd them ("Endpoint policy denies unverified agents"),
|
|
640
|
+
masking key validity and creating a self-DoS vector. A bare account-key
|
|
641
|
+
credential now classifies `self` (pass-through, zero beacons; origin auth
|
|
642
|
+
stays authoritative). An explicit `X-Astra-Id` alongside still classifies
|
|
643
|
+
as an agent claim.
|
|
644
|
+
|
|
645
|
+
### Changed
|
|
646
|
+
|
|
647
|
+
- **`runtimeChallenge.status`: `not_supported` → `not_configured`** (contract
|
|
648
|
+
correction, matches the backend): the value means THIS agent registered
|
|
649
|
+
without a callback endpoint, not that the capability is unsupported.
|
|
650
|
+
|
|
651
|
+
## [5.6.0] — 2026-08-11 — fulfilment email: account default + agent override
|
|
652
|
+
|
|
653
|
+
Additive, non-breaking.
|
|
654
|
+
|
|
655
|
+
- **`fulfilment` on `VerificationResult`** (first-party confirm legs that
|
|
656
|
+
progressed — settled, pending_merchant, held, requires_action):
|
|
657
|
+
`{ email, emailSource }`. The platform now ALWAYS resolves a fulfilment
|
|
658
|
+
email for first-party orders: the agent-supplied `buyerEmail` when present
|
|
659
|
+
(`emailSource: 'agent_provided'`), else the buyer's account email
|
|
660
|
+
(`emailSource: 'account'`). Emails arrive canonicalized (trimmed,
|
|
661
|
+
lower-cased). Store it with the pending order; fulfil against it only once
|
|
662
|
+
the order is settled / pending_merchant. Merchant-only lane like
|
|
663
|
+
`settlementToken` — the bridge strips it from the agent plane.
|
|
664
|
+
`emailSource` is an open union: treat unknown sources like
|
|
665
|
+
`'agent_provided'`.
|
|
666
|
+
- **`buyerEmail` on `VerificationRequest`** + a `buyerEmail` option on
|
|
667
|
+
`confirmCheckout()`: transit-only forward of an alternate receipt/delivery
|
|
668
|
+
contact. You no longer need to require agents to collect an email — omit
|
|
669
|
+
it and `fulfilment.email` carries the account default. Precedence when
|
|
670
|
+
both exist: an explicit `buyerEmail` (bridge handoff body or your
|
|
671
|
+
`confirmCheckout` call) wins over the account default.
|
|
672
|
+
- Never emitted on quote legs or for non-first-party counterparties.
|
|
673
|
+
|
|
674
|
+
## [5.5.0] — 2026-08-09 — merchant self-settlement (interim), open outcome union, fulfilment PII lanes
|
|
675
|
+
|
|
676
|
+
Additive, non-breaking (one behavioral rule tightened — see the open union).
|
|
677
|
+
|
|
678
|
+
- **`settlementToken`** on `VerificationResult` (confirm leg, firstParty
|
|
679
|
+
merchants opted into `settlement_mode='self_settle'`): agent-blind
|
|
680
|
+
`{ stripeCustomerId, stripePaymentMethodId, amountMinor, currency,
|
|
681
|
+
sessionId, orderId, jti, statementSuffix, expiresAt }`. YOUR server charges
|
|
682
|
+
(Stripe idempotency key `voucher:<jti>` + `metadata.jti`) and reports back.
|
|
683
|
+
Merchant-only lane — never expose to the agent plane; the bridge strips it
|
|
684
|
+
defensively.
|
|
685
|
+
- **`client.reportSettlement({ sessionId, status, amountMinor, currency,
|
|
686
|
+
processorRef?, failureCode? })`** — reconciles the buyer dashboard,
|
|
687
|
+
/orders, and the agent's poll surface. Amounts must match the order
|
|
688
|
+
EXACTLY; replays of the same terminal state are safe.
|
|
689
|
+
- **`SettlementOutcomeInfo.status` is now an OPEN union** (`… | (string &
|
|
690
|
+
{})`). Contract rule, effective immediately: treat any status you do not
|
|
691
|
+
recognize (`pending_merchant` is the first) as **pending, never failed** —
|
|
692
|
+
the 5.4.1-era fail-close on an unknown status is what produced phantom
|
|
693
|
+
failed orders in the field.
|
|
694
|
+
- **`no_instrument` on a held/approved session is NON-terminal**: the
|
|
695
|
+
human's approval is NOT consumed; once a card is on file, a re-drive with
|
|
696
|
+
the same `checkoutSessionId` redeems the original approval and settles.
|
|
697
|
+
- **Fulfilment PII lanes** (bridge contract): optional `buyerEmail` rides
|
|
698
|
+
the checkout handoff transit-only (receipts / digital delivery — never
|
|
699
|
+
stored by AstraSync); shipping addresses go agent ↔ merchant DIRECT,
|
|
700
|
+
correlated by `sessionId`, never via AstraSync.
|
|
701
|
+
- `SDK_VERSION` constant re-lockstepped with package.json (had drifted at
|
|
702
|
+
5.4.1 through the 5.4.2 type-only release).
|
|
703
|
+
|
|
704
|
+
## [5.4.2] — 2026-08-08 — `requires_approval` settlement outcome (type-only)
|
|
705
|
+
|
|
706
|
+
Type-only, non-breaking at runtime. Held confirm legs now carry an explicit
|
|
707
|
+
`settlementOutcome: { status: 'requires_approval' }` alongside the pending
|
|
708
|
+
`stepUpApproval` — merchants must record the order as _pending approval_ and
|
|
709
|
+
expect a re-drive with the same `checkoutSessionId` (one order row per
|
|
710
|
+
session is normative). Platforms emitted this status ahead of some deployed
|
|
711
|
+
SDKs; if you are on 5.4.1, treat "absent outcome + pending stepUpApproval" —
|
|
712
|
+
and any unknown non-terminal status — identically to `requires_approval`.
|
|
713
|
+
|
|
714
|
+
## [5.4.1] — 2026-08-06 — confirm-leg cache correctness (UAT2 Bug B)
|
|
715
|
+
|
|
716
|
+
Bugfix, non-breaking. Staging UAT found an under-limit confirm could return
|
|
717
|
+
`unsettled_placeholder` non-deterministically: the verify cache key omitted
|
|
718
|
+
`commercePhase`/`checkoutSessionId`, so a confirm issued within the cache TTL
|
|
719
|
+
of its `start_checkout` quote was served the cached quote-leg grant (which
|
|
720
|
+
carries no `settlementOutcome`) and never reached the backend — settlement
|
|
721
|
+
silently did not run.
|
|
722
|
+
|
|
723
|
+
- **Cache key** now includes `commercePhase` and `checkoutSessionId` (same
|
|
724
|
+
F-A1-07 bug class as the earlier duration/counterparty omissions): a quote
|
|
725
|
+
and a confirm for the same cart can never collide, nor can two carts.
|
|
726
|
+
- **`confirmCheckout()` passes `bypassCache: true`** — belt-and-braces: the
|
|
727
|
+
confirm leg is the only leg that can settle, so it must always reach the
|
|
728
|
+
backend regardless of cache state.
|
|
729
|
+
- **`VerificationGatewayClient` now honors `counterpartyId`** — the
|
|
730
|
+
constructor silently dropped this typed, documented option, so a
|
|
731
|
+
client-driven confirm could only identify its endpoint by URL; with
|
|
732
|
+
multiple endpoints on one origin the first-party resolution was
|
|
733
|
+
non-deterministic and settlement could silently not run.
|
|
734
|
+
|
|
735
|
+
## [5.4.0] — 2026-08-05 — `confirmCheckout()` client method
|
|
736
|
+
|
|
737
|
+
Additive, non-breaking. Exposes the 5.3.0 confirm leg through the high-level
|
|
738
|
+
client so a first-party merchant no longer has to hand-roll `verify(config,
|
|
739
|
+
request)` or raw `POST /api/agents/verify-access` to drive charge-at-redeem.
|
|
740
|
+
|
|
741
|
+
- **`VerificationGatewayClient.confirmCheckout(options)`** — sends
|
|
742
|
+
`commercePhase: 'confirm'` with `checkoutSessionId` (per-cart idempotency),
|
|
743
|
+
`checkoutItems` (order/receipt plane), `transactionValue`/`currency`, and the
|
|
744
|
+
`counterpartyUrl`/`counterpartyType` that make the grant merchant-mediated.
|
|
745
|
+
`purpose`/`action` default to `shopping` / `shopping.purchase`. Returns the
|
|
746
|
+
full `VerificationResult`; read `.settlementOutcome`
|
|
747
|
+
(`settled` | `failed` | `requires_action` | `no_instrument`, + `orderId`).
|
|
748
|
+
Settlement fires only on this leg — `verify()` still cannot trigger it.
|
|
749
|
+
- **`SettlementOutcomeInfo`** is now exported so consumers can type the outcome.
|
|
750
|
+
|
|
751
|
+
No wire change: `commercePhase`/`checkoutSessionId`/`checkoutItems` were already
|
|
752
|
+
forwarded and `settlementOutcome` already read back in 5.3.0 — this is purely the
|
|
753
|
+
client convenience surface over them.
|
|
754
|
+
|
|
755
|
+
## [5.3.0] — 2026-08-05 — first-party checkout phase + charge-at-redeem settlement outcome
|
|
756
|
+
|
|
757
|
+
astra-pay card rail (PR #563). Additive, non-breaking: all new fields are
|
|
758
|
+
optional and older backends/agents that never send or read them are unaffected.
|
|
759
|
+
Builds on 5.2.0 (round-11, #564).
|
|
760
|
+
|
|
761
|
+
### Added
|
|
762
|
+
|
|
763
|
+
- **`VerificationRequest.commercePhase`** `'quote' | 'confirm'` — checkout-leg
|
|
764
|
+
discriminator. First-party settlement (charge-at-redeem on the owner's saved
|
|
765
|
+
instrument) fires ONLY on the `'confirm'` leg; quote/browse legs omit it (or
|
|
766
|
+
send `'quote'`) and never move money.
|
|
767
|
+
- **`VerificationRequest.checkoutSessionId`** — per-cart idempotency key
|
|
768
|
+
forwarded on the confirm leg, so two concurrent confirms for one cart charge
|
|
769
|
+
the owner's card at most once.
|
|
770
|
+
- **`VerificationRequest.checkoutItems`** — the checkout's authoritative line
|
|
771
|
+
items, forwarded on the confirm leg for the order plane (dashboard order
|
|
772
|
+
audit). Informational only — never the money authority (that remains
|
|
773
|
+
`transactionValue` bound into the settlement voucher).
|
|
774
|
+
- **`VerificationResult.settlementOutcome`** + **`SettlementOutcomeInfo`**
|
|
775
|
+
`{ status: 'settled' | 'failed' | 'requires_action' | 'no_instrument',
|
|
776
|
+
orderId?, failureCode? }` — sanitized first-party settlement result, present
|
|
777
|
+
INSTEAD of `settlement` when the counterparty is an AstraSync-operated
|
|
778
|
+
storefront and the backend redeemed the voucher + charged server-side. Carries
|
|
779
|
+
no voucher/instrument material — the settlement channel stays merchant-only.
|
|
780
|
+
|
|
781
|
+
## [5.1.0] — 2026-08-04 — MCP-connector steering in agent-facing guidance
|
|
782
|
+
|
|
783
|
+
Round-7 "kickstarting" fix: an anonymous agent reading a deny body was steered
|
|
784
|
+
to the human dashboard ("register the agent") even when it was running inside
|
|
785
|
+
an MCP host with the AstraSync connector installed. Guidance now offers the
|
|
786
|
+
connector as the agent-actionable path wherever the backend advertises a
|
|
787
|
+
hosted bridge.
|
|
788
|
+
|
|
789
|
+
### Added
|
|
790
|
+
|
|
791
|
+
- **`WellKnownAgenticCommerce.mcpEndpoint` / `.mcpDiscoveryUrl`** — optional
|
|
792
|
+
fields the backend's `/.well-known/agentic-commerce` doc emits on
|
|
793
|
+
astrasync.ai hosts (absent on self-hosted backends; validation unchanged, so
|
|
794
|
+
older backends keep working).
|
|
795
|
+
- **`GuidanceInfo.mcp`** `{ endpoint, discoveryUrl?, message? }` — attached to
|
|
796
|
+
registration-shaped guidance (server-denied and no-credentials templates)
|
|
797
|
+
when the well-known cache carries `mcpEndpoint`. The copy states that
|
|
798
|
+
registration through the connector is keyless and human-approved (in-chat
|
|
799
|
+
approval card; the agent never handles credentials). `merchant_misconfig` /
|
|
800
|
+
`api_error` guidance deliberately does NOT steer to the connector —
|
|
801
|
+
registration is not the remedy there — and the in-connector registration
|
|
802
|
+
envelope (`registration/guidance.ts`) is unchanged.
|
|
803
|
+
- **Edge deny body `error.guidance.mcp`** — threaded from `verify()` when the
|
|
804
|
+
well-known cache is warm, with a cold-cache fallback deriving
|
|
805
|
+
`https://mcp.<apex>/mcp` from `apiBaseUrl`, gated to astrasync.ai hosts so a
|
|
806
|
+
self-hosted deployment never advertises a dead endpoint.
|
|
807
|
+
|
|
808
|
+
## [5.0.0] — 2026-08-02 — remove the `accessLevel` band (breaking)
|
|
809
|
+
|
|
810
|
+
The access-level band (`none` / `restricted` / `read-only` / `standard` / `full`
|
|
811
|
+
/ `internal`) is removed entirely. It never gated the access **decision** — the
|
|
812
|
+
server does, resting on a **verified ID + runtime challenge + PDLSS match + trust
|
|
813
|
+
score**. The band had been inert in the adapters since 3.2.0; this release drops
|
|
814
|
+
it from the types, the result, the adapters, the edge core, and the UI so nothing
|
|
815
|
+
consumes or advertises an arbitrary tier.
|
|
816
|
+
|
|
817
|
+
### Removed (breaking)
|
|
818
|
+
|
|
819
|
+
- **`AccessLevel` type** and all band helpers (`ACCESS_LEVEL_HIERARCHY`,
|
|
820
|
+
`ACCESS_LEVEL_DESCRIPTIONS`, `DEFAULT_TRUST_THRESHOLDS`, `hasMinimumAccess`,
|
|
821
|
+
`getAccessLevelForScore`, `determineAccessLevel`, `getCapabilities`,
|
|
822
|
+
`AccessCapabilities`). `getTrustLevel` / `TRUST_LEVEL_RANGES` survive (moved to
|
|
823
|
+
`trust-levels`; the old `access-levels` module is gone).
|
|
824
|
+
- **`VerificationResult.accessLevel`** and `quickVerify().accessLevel`. Gate on
|
|
825
|
+
`identityVerified` + `policyAllowed` (+ `recommendation` / `stepUpApproval`).
|
|
826
|
+
- **`GatewayConfig.defaultAccessLevel`**, `RouteAccessConfig.minAccessLevel`,
|
|
827
|
+
`commerceShield.guestAccessLevel`.
|
|
828
|
+
- **`VerificationGatewayClient.hasAccess()` / `.getCapabilities()`** (the last
|
|
829
|
+
live band consumers).
|
|
830
|
+
- **`AccessLevelIndicator`** UI component + props.
|
|
831
|
+
- The `X-AstraSync-Access-Level` (Next.js) and `X-AstraSync-Permissions` (edge
|
|
832
|
+
ASAT) response headers.
|
|
833
|
+
|
|
834
|
+
### Changed (breaking)
|
|
835
|
+
|
|
836
|
+
- **MCP `toolGates` / `methodGates`** values are now `ToolGateConfig | 'observe'`
|
|
837
|
+
(`ToolGateConfig` drops `minAccessLevel`). A gate object is **enforced**; the
|
|
838
|
+
literal `'observe'` passes the tool through unenforced (still evaluated when
|
|
839
|
+
`evaluateAlwaysIfCredentialed`). Replaces the old band value / `'none'` sentinel
|
|
840
|
+
and the bare-string shorthand.
|
|
841
|
+
- **`mcpRiskTier(parsed): AccessLevel`** → **`mcpDefaultEnforced(parsed): boolean`**.
|
|
842
|
+
- **HTTP route gating.** `RouteAccessConfig` gains **`observe?: boolean`** to
|
|
843
|
+
replace the `minAccessLevel: 'none'` observe sentinel. A matched route with no
|
|
844
|
+
`observe` flag is enforced (server decision). Endpoint-level
|
|
845
|
+
`unverifiedAgentPolicy: audit` remains the endpoint-wide observe mechanism.
|
|
846
|
+
|
|
847
|
+
### Migration
|
|
848
|
+
|
|
849
|
+
- Delete any `accessLevel` / `minAccessLevel` / `defaultAccessLevel` reads — they
|
|
850
|
+
no longer exist. Gate on `identityVerified && policyAllowed`.
|
|
851
|
+
- MCP: `toolGates: { t: 'standard' }` → `{ t: { purpose: '…', action: '…' } }`;
|
|
852
|
+
`toolGates: { t: 'none' }` → `{ t: 'observe' }`.
|
|
853
|
+
- HTTP: a route previously `minAccessLevel: 'none'` → `observe: true`; any other
|
|
854
|
+
band value → drop it (tighten with `minTrustScore`).
|
|
855
|
+
|
|
856
|
+
## [4.6.0] — 2026-08-02 — canonical two-limit model in the LocalEvaluator
|
|
857
|
+
|
|
858
|
+
Aligns the offline `LocalEvaluator` spend-limit ladder with the backend
|
|
859
|
+
`checkWithinLimits` so a local policy pre-check and the cloud verdict agree.
|
|
860
|
+
|
|
861
|
+
### Changed (behaviour — review your local policies)
|
|
862
|
+
|
|
863
|
+
- **Two-limit ladder with fallback.** `limits` now has exactly two spend
|
|
864
|
+
thresholds — `autonomousThreshold` (Autonomous Limit) and the existing
|
|
865
|
+
`maxTransactionAmount` (now the **Hard Limit**). Evaluation:
|
|
866
|
+
- `value <= Autonomous Limit` → `ALLOW`
|
|
867
|
+
- `Autonomous Limit < value < Hard Limit` → `MANUAL_REVIEW` (human approval)
|
|
868
|
+
- `value >= Hard Limit` → `DENY`
|
|
869
|
+
The Hard Limit **falls back to the Autonomous Limit** when only the Autonomous
|
|
870
|
+
Limit is declared, and both default to `0`.
|
|
871
|
+
- **Hard-limit boundary is now inclusive (`>=`, was `>`).** A transaction
|
|
872
|
+
exactly at `maxTransactionAmount` is now denied, matching the backend.
|
|
873
|
+
- **A Hard-limit-only policy now steps up sub-cap spend.** Previously a policy
|
|
874
|
+
with only `maxTransactionAmount` allowed everything below it; now (Autonomous
|
|
875
|
+
Limit defaulting to `0`) any positive spend below the Hard Limit returns
|
|
876
|
+
`MANUAL_REVIEW`. **If you want the old auto-allow band, declare an
|
|
877
|
+
`autonomousThreshold`.**
|
|
878
|
+
|
|
879
|
+
### Added
|
|
880
|
+
|
|
881
|
+
- Optional `limits.autonomousThreshold` on the local policy schema, validated as
|
|
882
|
+
a number and required to be `<= maxTransactionAmount`.
|
|
883
|
+
- `retryable?: boolean` on the verification result — set `true` on a transient
|
|
884
|
+
`verify_access.api_error` (5xx / timeout / CSRF-403). Lets a consumer surface
|
|
885
|
+
an infra outage as error-and-retry instead of a policy denial. Not set on a
|
|
886
|
+
deterministic merchant misconfig (retrying won't help).
|
|
887
|
+
|
|
888
|
+
### Removed
|
|
889
|
+
|
|
890
|
+
- The enforcement-dead `stepUpThreshold` field is gone from the registration
|
|
891
|
+
`PDLSSLimits` type and the transport formatter (it never carried behaviour).
|
|
892
|
+
|
|
893
|
+
## [4.3.0] — 2026-07-16 — CloudFront fingerprints, verified-hop everywhere, capture-matrix truth
|
|
894
|
+
|
|
895
|
+
Partner-feedback round: maximal connection metadata on every adapter, the
|
|
896
|
+
cross-hop dedupe marker made real outside MCP, and the capture story
|
|
897
|
+
documented per who-operates-the-CDN. Additive connection keys throughout —
|
|
898
|
+
`schemaVersion` remains 1 per the frozen-capture doctrine.
|
|
899
|
+
|
|
900
|
+
### Added
|
|
901
|
+
|
|
902
|
+
- **CloudFront fingerprint + geo sources in the SDK derivation**
|
|
903
|
+
(`deriveConnectionFromHeaders`): `cloudfront-viewer-ja3-fingerprint` →
|
|
904
|
+
`tlsFingerprint`, `cloudfront-viewer-ja4-fingerprint` → `ja4`, plus
|
|
905
|
+
`headerOrder`/`headerCount` (header-structure fingerprint), `timeZone`,
|
|
906
|
+
`metroCode`, `countryRegionName`, and `cloudfront-viewer-address` as an
|
|
907
|
+
ip fallback (port-stripped, IPv6-safe). Connection values are truncated
|
|
908
|
+
to the new exported `MAX_CONNECTION_VALUE_CHARS` (256 — the platform's
|
|
909
|
+
hard zod bound; headerOrder routinely exceeds it).
|
|
910
|
+
- **Edge gateway emits `X-Astra-Verified-Hop` toward the origin** whenever
|
|
911
|
+
its verify-access call produced identity (authenticate/authorize depth) —
|
|
912
|
+
SDK-middleware origins behind the TAG no longer double-verify. Helpers
|
|
913
|
+
moved to a shared `verified-hop` module (transport re-exports unchanged).
|
|
914
|
+
- **`trustVerifiedHop` + `verifiedHopMaxAgeMs` on express AND nextjs
|
|
915
|
+
middleware options** (previously documented on express but implemented
|
|
916
|
+
only on MCP): a fresh marker matching the presented X-Astra-Id skips the
|
|
917
|
+
duplicate verify-access. Default off; unsigned dedupe advisory — enable
|
|
918
|
+
only behind a stripping gateway/trusted boundary (README trust-model note).
|
|
919
|
+
|
|
920
|
+
### Fixed / hardened
|
|
921
|
+
|
|
922
|
+
- Evaluated edge passes now strip an inbound spoofed `X-Astra-Verified-Hop`
|
|
923
|
+
(previously only `x-astrasync-*` was stripped — a spoofed marker could
|
|
924
|
+
reach an origin that trusted it).
|
|
925
|
+
- `x-astra-verified-hop` added to the metadata sanitiser's secret set: the
|
|
926
|
+
short-lived dedupe token never persists in stored metadata.
|
|
927
|
+
- Canonical capture matrix rewritten (README): edge adapter / SDK behind
|
|
928
|
+
own CDN / SDK behind **platform-managed** CDN (IP only — Railway, Render,
|
|
929
|
+
Fly, Heroku don't forward provider geo/TLS headers to customer origins) /
|
|
930
|
+
SDK no CDN, with a fingerprint-availability column.
|
|
931
|
+
|
|
932
|
+
## [4.2.1] — 2026-07-15 — dependency hygiene: @sd-jwt consolidation
|
|
933
|
+
|
|
934
|
+
### Changed
|
|
935
|
+
|
|
936
|
+
- Migrated `@sd-jwt/decode` + `@sd-jwt/utils` (both deprecated upstream —
|
|
937
|
+
merged into `@sd-jwt/core` ≥ 0.20.0; the decode deprecation notice cites
|
|
938
|
+
security reference GHSA-f9j6-8p6x-r9j6) to a single `@sd-jwt/core@^0.20.0`
|
|
939
|
+
dependency. Same two functions consumed (`decodeSdJwtSync`, `splitSdJwt`),
|
|
940
|
+
now imported from core; no behavior change (308 transport tests unchanged).
|
|
941
|
+
|
|
942
|
+
## [4.2.0] — 2026-07-15 — Local Guard: native permissions.deny self-protection
|
|
943
|
+
|
|
944
|
+
Closes the settings self-protection gap: Claude Code rejects schema-invalid
|
|
945
|
+
edits of its own `settings.json` without invoking PreToolUse hooks, and the
|
|
946
|
+
hook only blocks in active posture — so the hook alone cannot fully protect
|
|
947
|
+
the settings file it is registered in. The installer now also writes Claude
|
|
948
|
+
Code's native `permissions.deny` rules, which are evaluated before hooks,
|
|
949
|
+
apply regardless of guard posture, and cannot be removed by a governed agent
|
|
950
|
+
(the removal edit is itself denied — runtime-verified on Claude Code 2.1.210).
|
|
951
|
+
|
|
952
|
+
### Added
|
|
953
|
+
|
|
954
|
+
- `astrasync guard install-claude-code` now installs `permissions.deny`
|
|
955
|
+
self-protection rules (Edit rules for `.claude/settings.json`,
|
|
956
|
+
`.claude/settings.local.json`, and `.astrasync/**` in both `~/` and `**/`
|
|
957
|
+
anchored forms) alongside the PreToolUse hook; uninstall removes them.
|
|
958
|
+
Rules are Edit()-only — Claude Code's file permission checks match
|
|
959
|
+
`Edit(path)` rules against every file-editing tool and never match
|
|
960
|
+
`Write(path)` rules.
|
|
961
|
+
- New exports from the Claude Code settings installer:
|
|
962
|
+
`installClaudePermissionRules`, `uninstallClaudePermissionRules`,
|
|
963
|
+
`GUARD_PERMISSION_DENY_RULES`, `LEGACY_GUARD_PERMISSION_DENY_RULES`.
|
|
964
|
+
Claude-Code-only — the Codex installer intentionally does not write a
|
|
965
|
+
`permissions` block (hooks.json has no permissions concept).
|
|
966
|
+
- Rule ownership is exact-string match (deny entries carry no marker), so
|
|
967
|
+
uninstall also removes an identical rule the user added independently;
|
|
968
|
+
the CLI prints every removed rule so users can re-add their own.
|
|
969
|
+
|
|
970
|
+
## [4.1.0] — 2026-07-15 — Trusted Agent Gateway naming, edge core, published-docs fix
|
|
971
|
+
|
|
972
|
+
Naming split (an external product owns "Commerce Shield"): the edge product is
|
|
973
|
+
now the **Trusted Agent Gateway (TAG)**, the dashboard analytics product is
|
|
974
|
+
**Visit Intelligence**, and the unverified-agent overlay is the
|
|
975
|
+
**verification interstitial**. No breaking changes — deprecated aliases keep
|
|
976
|
+
every 4.0.0 import working.
|
|
977
|
+
|
|
978
|
+
### Added
|
|
979
|
+
|
|
980
|
+
- **`./edge-core` subpath**: the portable Trusted Agent Gateway pipeline
|
|
981
|
+
(request normalization contract, three-tier classification, protocol
|
|
982
|
+
detection, verify orchestration, observe/enforce outcome application) that
|
|
983
|
+
platform adapters compose — `@astrasyncai/adapter-lambda` (CloudFront) and
|
|
984
|
+
the new `@astrasyncai/adapter-edge` (Vercel Edge / Cloudflare Workers /
|
|
985
|
+
Fastly Compute) are thin request/response translators over it.
|
|
986
|
+
- **MCP adapter metadata capture**: `createMcpMiddleware` now captures
|
|
987
|
+
header-level ObservedMetadata automatically on every verify, matching the
|
|
988
|
+
Express and Next.js adapters (it previously captured none).
|
|
989
|
+
- `VerificationInterstitial` / `useVerificationInterstitial` /
|
|
990
|
+
`VerificationInterstitialProps` and the `showInterstitial` middleware
|
|
991
|
+
option — renamed from the Commerce Shield names, which remain as
|
|
992
|
+
`@deprecated` aliases until the next major.
|
|
993
|
+
- `check:dts-leaks` publish gate: built declaration files are scanned for
|
|
994
|
+
internal references before publishing.
|
|
995
|
+
- **CDN-header connection derivation** (`deriveConnectionFromHeaders` +
|
|
996
|
+
shared `buildSdkObservedMetadata`): the Express/Next.js/MCP adapters now
|
|
997
|
+
promote CDN-provided signals (Cloudflare, Fastly, Vercel, CloudFront —
|
|
998
|
+
client IP, geo, ASN, TLS/HTTP version, and Cloudflare JA3/JA4 TLS
|
|
999
|
+
fingerprints) into `ObservedMetadata.connection`. Merchants behind a CDN
|
|
1000
|
+
get the connection layer without an edge worker; edge adapters' native
|
|
1001
|
+
collectors remain authoritative where deployed.
|
|
1002
|
+
- **Dashboard-driven anonymous beacon** (Express + Next.js): pass-through
|
|
1003
|
+
traffic (unmatched routes / `none` routes) from non-browser callers is now
|
|
1004
|
+
beaconed fire-and-forget, sampled at the endpoint's dashboard EdgeConfig
|
|
1005
|
+
rate (platform-fingerprinted agents unsampled; humans and static assets
|
|
1006
|
+
never). Zero request-path latency; disable with `anonymousBeacon: false`.
|
|
1007
|
+
- **`ObservedMetadata.schemaVersion`** (`CAPTURE_SCHEMA_VERSION = 1`),
|
|
1008
|
+
stamped by every emitter: capture semantics are frozen within a major and
|
|
1009
|
+
the version travels with the payload, so mixed 4.x deployments cannot
|
|
1010
|
+
drift silently.
|
|
1011
|
+
|
|
1012
|
+
### Fixed
|
|
1013
|
+
|
|
1014
|
+
- **MCP tool names no longer travel as PDLSS actions**: a bare-string
|
|
1015
|
+
toolGate caused the raw MCP tool name to be sent as the PDLSS `action`,
|
|
1016
|
+
guaranteeing a policy denial. `tools/call` with no configured or declared
|
|
1017
|
+
action now evaluates purpose-only, and `createMcpMiddleware` warns at
|
|
1018
|
+
construction time about bare-string gates (use the object form with
|
|
1019
|
+
`purpose`/`action`).
|
|
1020
|
+
- **Stale `routes: [...]` example removed** from the Express adapter docs
|
|
1021
|
+
(per-route policy moved to the dashboard in v2.9.7); passing `routes` in
|
|
1022
|
+
middleware options now logs a one-time warning instead of being silently
|
|
1023
|
+
ignored.
|
|
1024
|
+
|
|
1025
|
+
### Changed
|
|
1026
|
+
|
|
1027
|
+
- README overhauled: Trusted Agent Gateway section with the capture-split
|
|
1028
|
+
matrix (edge = headers + connection layer; Express/Next.js = header-level
|
|
1029
|
+
automatic; MCP = header-level from 4.1.0), and documentation for the
|
|
1030
|
+
`./metadata-capture`, `./platform-signatures`, `./edge-config` exports.
|
|
1031
|
+
- Published doc comments rewritten to self-contained public language
|
|
1032
|
+
(internal spec/workstream/audit references removed from all declaration
|
|
1033
|
+
files).
|
|
1034
|
+
|
|
1035
|
+
## [4.0.0] — 2026-07-13 — Merchant-misconfig honesty + verify timeout
|
|
1036
|
+
|
|
1037
|
+
A rejected integration API key (revoked/expired/rotated) is now classified
|
|
1038
|
+
as **merchant misconfig**, not a transient `api_error`: inbound agents get
|
|
1039
|
+
an honest 503 instead of a misleading 401 blaming their own identity. Found
|
|
1040
|
+
live: a partner property silently 401'd every credentialed agent for six
|
|
1041
|
+
days on a rotated key.
|
|
1042
|
+
|
|
1043
|
+
### Breaking
|
|
1044
|
+
|
|
1045
|
+
- **Adapter deny contract for the dead-key class**: when the backend rejects
|
|
1046
|
+
the integration's OWN API key, express/nextjs(API-route)/mcp adapters now
|
|
1047
|
+
respond **503** with `error.code: 'MERCHANT_VERIFICATION_MISCONFIGURED'`
|
|
1048
|
+
(mcp: JSON-RPC code `-32002`) instead of 401 `UNAUTHORIZED`. Integrations
|
|
1049
|
+
matching on the old envelope must adapt. nextjs web pages keep the shield
|
|
1050
|
+
flow.
|
|
1051
|
+
- **`verify()` outbound call now has a hard timeout** (default 10s,
|
|
1052
|
+
`GatewayConfig.verifyTimeoutMs`). Previously a hanging backend hung the
|
|
1053
|
+
merchant's middleware (and every inbound agent behind it) indefinitely;
|
|
1054
|
+
timeouts now surface as the fail-closed `verify_access.api_error` result.
|
|
1055
|
+
|
|
1056
|
+
### Added
|
|
1057
|
+
|
|
1058
|
+
- **`VerificationResult.misconfigured`** typed marker + guidance source
|
|
1059
|
+
`merchant_misconfig` + failure dimension
|
|
1060
|
+
`verify_access.merchant_misconfigured` (guidance: "your identity and the
|
|
1061
|
+
AstraSync platform are fine — contact the site operator; retrying will not
|
|
1062
|
+
help"). Classified from the backend 401 (`code: api_key_*` when present —
|
|
1063
|
+
a verify-access 401 can only ever mean the caller's own key).
|
|
1064
|
+
- **Init self-check**: with an `apiKey` configured, the one-time init probe
|
|
1065
|
+
also calls `GET /agents/verify-access/self-check` — a dead key logs a loud
|
|
1066
|
+
`console.error` at startup (throws under `strictInit`); a key expiring
|
|
1067
|
+
within 7 days logs a rotation warning. 404 (older backend) is silent.
|
|
1068
|
+
|
|
1069
|
+
## [3.12.0] — 2026-07-11 — Trust Record capture (§33.5 #3)
|
|
1070
|
+
|
|
1071
|
+
Trust Record capture: attemptId chain correlation (request/response
|
|
1072
|
+
pass-through, excluded from the verdict cache key), considerationSet on
|
|
1073
|
+
verify, `reportAttempt()` for post-hoc consideration/outcome reporting. All
|
|
1074
|
+
fields optional; no behavioural change for existing callers.
|
|
1075
|
+
|
|
1076
|
+
### Added
|
|
1077
|
+
|
|
1078
|
+
- **`VerificationRequest.attemptId`** (`att_` + 32 lowercase hex): attempt-chain
|
|
1079
|
+
handle correlating the catalog → intent → settlement funnel into one attempt.
|
|
1080
|
+
Forwarded skip-when-undefined; the server mints one when absent and echoes it
|
|
1081
|
+
top-level on every response branch. **`VerificationResult.attemptId`** carries
|
|
1082
|
+
the echo (disjoint from `correlationId`/`sessionId` — an attempt CONTAINS
|
|
1083
|
+
events). On a cache hit the SDK rewrites the cached result's attemptId to the
|
|
1084
|
+
current request's own (or drops it) so a cached verdict never leaks a prior
|
|
1085
|
+
attempt's id.
|
|
1086
|
+
- **`VerificationRequest.considerationSet`** (`ConsiderationSet` /
|
|
1087
|
+
`ConsiderationItem` types): first-party observational data — the offers the
|
|
1088
|
+
agent evaluated at this checkpoint. Items capped at 50 server-side; order
|
|
1089
|
+
chosen-first so purchased counts survive truncation. Excluded from the
|
|
1090
|
+
verdict cache key alongside attemptId (observedMetadata precedent).
|
|
1091
|
+
- **`reportAttempt(config, report)`** → `POST /agents/verify-access/attempt-report`:
|
|
1092
|
+
post-hoc consideration/outcome reporting (`AttemptReport` / `AttemptOutcome`
|
|
1093
|
+
types) for signals that never reached verify-access (cache-served catalogs,
|
|
1094
|
+
transport-side denials, settled/blocked outcomes). Fire-and-forget — never
|
|
1095
|
+
throws; same credentials as verify().
|
|
1096
|
+
|
|
1097
|
+
## [3.10.0] — 2026-07-08 — Maximal metadata capture (Workstream D)
|
|
1098
|
+
|
|
1099
|
+
Total metadata capture folded into the Commerce Shield console round: every
|
|
1100
|
+
header and connection signal an inbound agent presents is captured (secrets
|
|
1101
|
+
stripped, credential headers reduced to a safe format prefix), forwarded, and
|
|
1102
|
+
used for platform attribution — without adding verify-access decision latency.
|
|
1103
|
+
|
|
1104
|
+
### Added
|
|
1105
|
+
|
|
1106
|
+
- **`./metadata-capture` module** (subpath + flat root re-exports):
|
|
1107
|
+
`sanitizeHeaders` (deny-lists genuine secrets — `Cookie`, `X-CSRF-Token`,
|
|
1108
|
+
our own `x-astrasync-*`/`kya` credentials, raw signatures; reduces
|
|
1109
|
+
`Authorization`/`X-Api-Key`/`X-Goog-Api-Key` to a NON-secret format prefix
|
|
1110
|
+
like `sk-ant-api03`; keeps everything else verbatim) with size caps (≤64
|
|
1111
|
+
headers, ≤1KB/value, ≤16KB total) that bound jsonb growth. Plus
|
|
1112
|
+
`extractPlatformHeaders`, `extractApiKeyFormat`, and the `ObservedMetadata`
|
|
1113
|
+
type. Pure/edge-safe (no Node built-ins).
|
|
1114
|
+
- **`CallerMetadata.observedMetadata`**: the express + nextjs adapters now
|
|
1115
|
+
forward the full sanitised header map on every verify-access call (local
|
|
1116
|
+
string work; kept OUT of the verify cache key so it doesn't defeat verdict
|
|
1117
|
+
caching). SDK-only merchants (no edge) get the same capture.
|
|
1118
|
+
- **Detection widened**: `PlatformDetectionInput` gains `apiKeyFormat` +
|
|
1119
|
+
`platformHeaders`; `PlatformSignatureDef` gains `apiKeyFormatPatterns` +
|
|
1120
|
+
`headerPatterns`; the seed signatures map `sk-ant`→claude, `sk-proj`→chatgpt,
|
|
1121
|
+
`aiza`/`x-goog-user-project`→gemini, `openai-organization`→chatgpt,
|
|
1122
|
+
`pplx-`→perplexity. A credential format / platform header is a stronger,
|
|
1123
|
+
less-spoofable signal than the User-Agent.
|
|
1124
|
+
|
|
1125
|
+
### Notes
|
|
1126
|
+
|
|
1127
|
+
Backward-compatible and additive: `observedMetadata` is optional everywhere and
|
|
1128
|
+
absent on pre-3.10.0 callers. `@astrasyncai/adapter-lambda` consumes the new
|
|
1129
|
+
surface to capture CloudFront-Viewer connection signals (IP/ASN/TLS/country).
|
|
1130
|
+
|
|
1131
|
+
## [3.9.0] — 2026-07-08 — Edge verification config + shared platform signatures (Commerce Shield edge adapter)
|
|
1132
|
+
|
|
1133
|
+
Foundation release for `@astrasyncai/adapter-lambda` (the Commerce Shield
|
|
1134
|
+
pathway-A edge shell, spec §7.4/§33.5 #1).
|
|
1135
|
+
|
|
1136
|
+
### Added
|
|
1137
|
+
|
|
1138
|
+
- **`EdgeConfig` + `edge-config` module** (`./edge-config` subpath and flat
|
|
1139
|
+
root re-exports): the per-endpoint policy the edge adapter fetches from the
|
|
1140
|
+
dashboard — `mode` (`observe`/`enforce`), `depth`
|
|
1141
|
+
(`classify`/`authenticate`/`authorize`), ordered first-match-wins `pathRules`
|
|
1142
|
+
(case-insensitive `*` globs, regex metachars escaped), anonymous-beacon
|
|
1143
|
+
sampling, and a v1 `failurePosture` locked to `'open'`.
|
|
1144
|
+
`fetchEdgeConfig()` (ETag/If-None-Match aware), `getEdgeConfig()` (60s TTL,
|
|
1145
|
+
stale-while-revalidate, never throws; enforce degrades to observe when the
|
|
1146
|
+
last successful fetch is older than 24h — a dead backend can never keep a
|
|
1147
|
+
site enforcing), `matchEdgePathRule()`, `DEFAULT_EDGE_CONFIG`.
|
|
1148
|
+
- **`platform-signatures` module** (`./platform-signatures` subpath + root
|
|
1149
|
+
re-exports): `PLATFORM_AGENT_SIGNATURES` + `detectPlatformFingerprint()`
|
|
1150
|
+
lifted from the backend's platform-agent detector so backend and edge
|
|
1151
|
+
classify identically (single source of truth).
|
|
1152
|
+
- **`./verify` subpath export** — `verify`, `extractCredentials`,
|
|
1153
|
+
`reportUnregisteredAttempt`, `fetchRoutes` etc. importable without the root
|
|
1154
|
+
barrel (whose `./registration` re-export drags `ethers`); this is the
|
|
1155
|
+
ethers-free surface the edge adapter bundles. `reportUnregisteredAttempt`
|
|
1156
|
+
and `fetchRoutes` also join the root barrel.
|
|
1157
|
+
|
|
1158
|
+
### Fixed
|
|
1159
|
+
|
|
1160
|
+
- **Version-constant drift**: `SDK_VERSION` (stamped on every verify call) was
|
|
1161
|
+
left at `3.7.1` by the 3.8.0 release, and the root barrel's `VERSION` had
|
|
1162
|
+
been frozen at `3.4.0`. Both now track the package version — `VERSION`
|
|
1163
|
+
re-exports `SDK_VERSION` instead of carrying its own literal.
|
|
1164
|
+
|
|
1165
|
+
## [3.8.0] — 2026-07-07 — Settlement voucher v2 (port to main)
|
|
1166
|
+
|
|
1167
|
+
_(Backfilled — this release shipped without a changelog entry.)_
|
|
1168
|
+
|
|
1169
|
+
### Changed
|
|
1170
|
+
|
|
1171
|
+
- **`SettlementArtifact.binding` becomes the v2 union**
|
|
1172
|
+
(`StablecoinSettlementBinding` — integer minor-units, asset-pinned — |
|
|
1173
|
+
`FiatSettlementBinding`). README Settlement Artifacts section rewritten with
|
|
1174
|
+
the voucher lifecycle and guarantee boundary (verify proves authenticity;
|
|
1175
|
+
redeem proves the authorization is live and single-use — it does not check
|
|
1176
|
+
or move funds).
|
|
1177
|
+
|
|
1178
|
+
## [3.7.1] — 2026-07-05 — ChallengeHandler auto-include (sandbox port)
|
|
1179
|
+
|
|
1180
|
+
### Changed
|
|
1181
|
+
|
|
1182
|
+
- **`ChallengeHandler` auto-includes the incoming counterparty.** When no
|
|
1183
|
+
counterparties have been pre-registered via `registerPending()`, a challenge
|
|
1184
|
+
response now echoes back the challenge payload's own `counterpartyId`/
|
|
1185
|
+
`counterpartyUrl` instead of an empty list — the correct default for agents
|
|
1186
|
+
that never call `registerPending()`. Pre-registered whitelists behave exactly
|
|
1187
|
+
as before. (Ported from the LMAX POC branch, where the empty default caused
|
|
1188
|
+
spurious challenge failures for agents without explicit pending lists.)
|
|
1189
|
+
- Runtime-challenge docs page: auto-include default documented, plus a warning
|
|
1190
|
+
for the double-appended challenge-path misconfiguration
|
|
1191
|
+
(`…/astrasync/astrasync/challenge`), pre-registration examples, and a raw-HTTP
|
|
1192
|
+
(no-SDK) example.
|
|
1193
|
+
|
|
1194
|
+
## [3.7.0] — 2026-07-04 — AstraSync Local Guard for Claude Code
|
|
1195
|
+
|
|
1196
|
+
### Added
|
|
1197
|
+
|
|
1198
|
+
- **`@astrasyncai/adapter-claude-code`** (subpath export `./claude-code`) — Layer 4
|
|
1199
|
+
Local Guard adapter for Anthropic's Claude Code CLI, intercepting tool calls via
|
|
1200
|
+
Claude Code's native PreToolUse hook. Strictly tightening decision mapping:
|
|
1201
|
+
DENY → hook `deny`, MANUAL_REVIEW → hook `ask` (Claude Code's own permission
|
|
1202
|
+
prompt is the human-in-the-loop), ALLOW → no hook output (the guard never emits
|
|
1203
|
+
`allow`, so it cannot bypass Claude Code's native permission system). MCP tools
|
|
1204
|
+
map `mcp__{server}__{tool}` → purpose `{server}.{tool}`, gated by `governMcp`.
|
|
1205
|
+
- **`astrasync-claude-hook` binary** — stateless per-tool-call hook entry.
|
|
1206
|
+
Policy resolution `$CLAUDE_PROJECT_DIR/.astrasync/policy.yaml` → payload cwd →
|
|
1207
|
+
`~/.astrasync/policy.yaml`; `guard.json` (`posture`, `failOpen`, `skipTools`,
|
|
1208
|
+
`governMcp`) beside the policy; JSONL traces beside the policy. Fail-closed on
|
|
1209
|
+
malformed payloads / invalid policy with `ASTRASYNC_GUARD_FAIL_OPEN=1` and
|
|
1210
|
+
`guard.json failOpen` opt-outs; `ASTRASYNC_GUARD_DISABLE=1` kill switch; missing
|
|
1211
|
+
policy anywhere = silent no-op.
|
|
1212
|
+
- **`astrasync guard install-claude-code` / `uninstall-claude-code`** — user-scope
|
|
1213
|
+
(`~/.claude/settings.json`, default) or `--project` install; merge-never-clobber
|
|
1214
|
+
settings editing (idempotent, preserves foreign hooks); generates a default
|
|
1215
|
+
coding-agent policy (permissive risk preset; recommended blocked commands and
|
|
1216
|
+
credential paths; guard self-protection patterns on `file.write`) and a passive
|
|
1217
|
+
`guard.json` for observe-then-enforce rollout. `astrasync guard status` reports
|
|
1218
|
+
Claude Code hook state.
|
|
1219
|
+
|
|
1220
|
+
### Fixed
|
|
1221
|
+
|
|
1222
|
+
- **Guard CLI was never shipped** — `cli/guard.ts` (`astrasync guard setup/start/…`,
|
|
1223
|
+
Phase A) was missing from tsup entries and the package `bin` map. It now ships as
|
|
1224
|
+
the `astrasync-guard` binary, and the main `astrasync` bin delegates
|
|
1225
|
+
`astrasync guard <cmd>`. Direct-bin argv parsing fixed so flags after the
|
|
1226
|
+
subcommand are not misread as the command.
|
|
1227
|
+
|
|
1228
|
+
## [3.6.0] — 2026-07-04 — step-up hold-and-poll + LMAX port alignment
|
|
1229
|
+
|
|
1230
|
+
### Added
|
|
1231
|
+
|
|
1232
|
+
- **Step-up hold-and-poll (opt-in)** — `stepUpMaxWaitMs` / `stepUpPollIntervalMs` on
|
|
1233
|
+
`GatewayConfig`. When enabled, the express/mcp/nextjs middleware holds a
|
|
1234
|
+
`step_up_required` request, polls the approval (`{success, data:{status}}` envelope,
|
|
1235
|
+
flat fallback), and on `approved` re-verifies once cache-bypassed so the backend
|
|
1236
|
+
redeems the single-use approval (server: approved → consumed). Non-approved outcomes
|
|
1237
|
+
fall into the existing fail-closed deny with a new `stepUpOutcome` field
|
|
1238
|
+
(`denied | expired | consumed | timeout`) and an `X-Astra-Step-Up` response header.
|
|
1239
|
+
OFF by default — existing integrations keep the instant-403 contract. Next.js edge
|
|
1240
|
+
runtimes: set a small `stepUpMaxWaitMs` (≤20s) or gate in a Node route handler.
|
|
1241
|
+
- **`verify(config, request, { bypassCache })`** — per-call cache-read bypass (Java
|
|
1242
|
+
SDK parity); also threaded through `verifyAndRecord`.
|
|
1243
|
+
- **Exports**: `awaitStepUpApproval`, `pollStepUpStatus`, `StepUpApprovalStatus`,
|
|
1244
|
+
`StepUpOutcome`, `VerifyOptions`.
|
|
1245
|
+
|
|
1246
|
+
### Changed
|
|
1247
|
+
|
|
1248
|
+
- **Step-up verdicts are never cached** (was: 300s TTL). A cached `step_up_required`
|
|
1249
|
+
result kept denying retries the owner had already approved and carried a stale
|
|
1250
|
+
pollUrl — the Java SDK 1.1.0 bug, now fixed here too. Not overridable via `cacheTtl`.
|
|
1251
|
+
Autonomous grants keep the 60s default.
|
|
1252
|
+
- **`denialReasons` server precedence** — the backend now emits top-level
|
|
1253
|
+
`denialReasons` on every deny path; the SDK prefers it verbatim and only falls back
|
|
1254
|
+
to client-side reconstruction (failures / recommendationReasons) for older backends.
|
|
1255
|
+
- **`reportUnregisteredAttempt`** — sends the configured `counterpartyId` and omits a
|
|
1256
|
+
null/undefined `counterpartyUrl` (backend attributes id-first and requires at least
|
|
1257
|
+
one of the two).
|
|
1258
|
+
|
|
1259
|
+
## [3.5.0] — 2026-06-30 — partner feedback round
|
|
1260
|
+
|
|
1261
|
+
### Added
|
|
1262
|
+
|
|
1263
|
+
- **`extractTransactionValue`** option on `ExpressMiddlewareOptions` — opt-in upfront value
|
|
1264
|
+
extraction so PDLSS limit evaluation runs at middleware time. Must return major units
|
|
1265
|
+
(dollars, not cents). `authorizeSettlement()` remains the required fail-closed settlement gate.
|
|
1266
|
+
|
|
1267
|
+
### Changed
|
|
1268
|
+
|
|
1269
|
+
- **Settlement architecture** — merchant-mediated grants now enforce voucher-primary: only
|
|
1270
|
+
crypto wallets (`stablecoin_voucher`) mint settlement artifacts; fiat instruments log a
|
|
1271
|
+
diagnostic and do not mint (fiat rails coming soon). Direct-charge adapters (Stripe
|
|
1272
|
+
PaymentIntent, PayPal Order) are never called on merchant-mediated paths.
|
|
1273
|
+
- **Owner-wallet fallback** — when agent's `individualUuid` is null (company-owned agents),
|
|
1274
|
+
settlement resolves wallets via the owner's individuals. Currency/asset hard filter prevents
|
|
1275
|
+
cross-asset-class funding.
|
|
1276
|
+
- **x402 decimal conversion** — `extractX402TransactionValue` converts known tokens (USDC/6,
|
|
1277
|
+
USDT/6, DAI/18, ETH/18, WETH/18) from atomic units to major units. Unknown tokens return
|
|
1278
|
+
`rawUnits: true` which the limit engine rejects fail-closed.
|
|
1279
|
+
- **Currency-formatted denial messages** — hard-limit and step-up messages now show formatted
|
|
1280
|
+
amounts (`$1,800.00 USD` instead of `1800`).
|
|
1281
|
+
- **Purpose dotted-token hint** — when a dotted action is sent as purpose (e.g.
|
|
1282
|
+
`shopping.purchase`), the denial message explains the canonical two-axis contract.
|
|
1283
|
+
- **Limits cross-validation** — `approvalThreshold` must be >= `autonomousThreshold` at
|
|
1284
|
+
registration. Equal values are valid (no HITL band).
|
|
1285
|
+
|
|
1286
|
+
### Fixed
|
|
1287
|
+
|
|
1288
|
+
- `SDK_VERSION` constant (was `3.3.0`, now `3.5.0`) — fixes drift from `package.json`.
|
|
1289
|
+
|
|
1290
|
+
### Docs
|
|
1291
|
+
|
|
1292
|
+
- Agent docs: field names corrected (`autonomousLimit` → `autonomousThreshold`, etc.),
|
|
1293
|
+
units/currency callout, settlement statement, registration guidance, purpose/action contract.
|
|
1294
|
+
- Fiat instrument UI (onboarding, profiles): replaced with "Fiat (coming soon)" label.
|
|
1295
|
+
|
|
1296
|
+
## [3.3.0] — 2026-06-16 — direct-path value enforcement (`authorizeSettlement`)
|
|
1297
|
+
|
|
1298
|
+
### Added
|
|
1299
|
+
|
|
1300
|
+
- **`authorizeSettlement(config, { agentId, value, currency, purpose?, action? })`** — the
|
|
1301
|
+
value-aware, FAIL-CLOSED gate a direct merchant MUST call before settling a priced cart.
|
|
1302
|
+
The request middleware verifies identity + access but never sends the transaction VALUE to
|
|
1303
|
+
verify-access, so a compliant merchant could settle past the agent's PDLSS spend limits.
|
|
1304
|
+
`authorizeSettlement` wraps `verify()` with the **merchant's authoritative priced total**
|
|
1305
|
+
(never an agent-supplied/spoofable amount) and returns `SettlementDecision { authorized, ... }`.
|
|
1306
|
+
`authorized` is true ONLY on a clean grant — a step-up/approval-band value, a value at/above the
|
|
1307
|
+
Hard Limit, a missing value, or a verify-access error all return `authorized: false`. Settle only
|
|
1308
|
+
when `authorized === true`. See `/docs/merchants#direct-path-settlement`.
|
|
1309
|
+
|
|
1310
|
+
> The request middleware's `requiresHumanApproval` fail-closed (3.2.1) only fires when verify-access
|
|
1311
|
+
> returns a step-up — which never happens without a value. Direct merchants MUST adopt
|
|
1312
|
+
> `authorizeSettlement`. A value-required-route tripwire (deny on missing value) follows as a
|
|
1313
|
+
> hard gate before broad direct-path GA.
|
|
1314
|
+
|
|
1315
|
+
## [3.2.1] — 2026-06-15 — direct-path step-up fail-closed; F5 guidance
|
|
1316
|
+
|
|
1317
|
+
### Fixed
|
|
1318
|
+
|
|
1319
|
+
- **Direct-path step-up fail-closed (F2).** The express / nextjs / mcp adapters
|
|
1320
|
+
gated on `identityVerified && policyAllowed` alone. A spending step-up is
|
|
1321
|
+
"allowed-but-escalate" (`policyAllowed: true` + `requiresApproval` /
|
|
1322
|
+
`requiresStepUp`), so the adapter would ADMIT a `[autonomous, hard)`-band
|
|
1323
|
+
purchase the bridge blocks — letting a direct merchant settle it via its own
|
|
1324
|
+
processor. The adapters now also deny when the outcome requires human approval
|
|
1325
|
+
(the approval mechanism is not yet wired), surfacing the
|
|
1326
|
+
`commerce.intent.approval_required` dimension. New shared `approval-gate.ts`;
|
|
1327
|
+
nextjs `/api/*` denials now include `failures[]`.
|
|
1328
|
+
- **Action-mismatch denial guidance (F5).** On the direct path the PDLSS action
|
|
1329
|
+
can resolve to the raw tool name; the guidance now points at configuring a
|
|
1330
|
+
`toolGates` tool→semantic-action mapping instead of telling operators to
|
|
1331
|
+
enumerate transport tool names in the agent's (immutable) PDLSS — which would
|
|
1332
|
+
pollute the semantic vocabulary (the retired-`mcp_invoke` class).
|
|
1333
|
+
|
|
1334
|
+
> Sequencing: direct merchants should adopt **3.2.1 before the backend
|
|
1335
|
+
> promotes**, or a 3.2.0 adapter still admits the step-up — a real-money bypass
|
|
1336
|
+
> window. See the platform spec's promotion gate.
|
|
1337
|
+
|
|
1338
|
+
## [3.2.0] — 2026-06-12 — access-level band no longer gates; step-up label-truth
|
|
1339
|
+
|
|
1340
|
+
Post-3.1.0 prod-feedback release. Non-breaking minor: the `AccessLevel` band,
|
|
1341
|
+
`RouteAccessConfig.minAccessLevel`, and `hasMinimumAccess` are **retained as
|
|
1342
|
+
informational/deprecated** — but the band **no longer gates** in any adapter.
|
|
1343
|
+
|
|
1344
|
+
### Changed — the access-level band is informational, not a gate
|
|
1345
|
+
|
|
1346
|
+
- **express / nextjs / mcp adapters:** removed the
|
|
1347
|
+
`hasMinimumAccess(result.accessLevel, route/tool minAccessLevel)` veto from
|
|
1348
|
+
the deny path. Gating is now purely the server-side decision
|
|
1349
|
+
(`identityVerified && policyAllowed`, which already encodes the endpoint
|
|
1350
|
+
trust-floor + PDLSS). The band mapped a trust score into an opaque tier and
|
|
1351
|
+
the per-route comparison duplicated the endpoint policy — and it manufactured
|
|
1352
|
+
the "read-only can't elevate to write" settlement wall. Per-route tightening
|
|
1353
|
+
now uses `route.minTrustScore` (express); explicit per-route/tool
|
|
1354
|
+
condition→constraint rules are the Phase-2 successor.
|
|
1355
|
+
- **MCP toolGate/methodGate:** these still decide _whether_ a tool is gated
|
|
1356
|
+
(any non-`none` tier → verify-access enforced) but **no longer differentiate
|
|
1357
|
+
tiers** — a tool gated above an agent's band is no longer denied on the band.
|
|
1358
|
+
- **`verify.ts` step-up label-truth:** a `step_up_required` recommendation no
|
|
1359
|
+
longer overwrites `accessLevel` to `'read-only'`. That masquerade made a
|
|
1360
|
+
step-up signal look like a low-trust band cap (it caused a downstream
|
|
1361
|
+
misdiagnosis). The real band is preserved; `requiresStepUp` carries the
|
|
1362
|
+
signal.
|
|
1363
|
+
- **Trust score redaction (#2):** agent-visible denial messages are now
|
|
1364
|
+
qualitative — the numeric trust score and the threshold are never embedded
|
|
1365
|
+
in a message returned toward the agent.
|
|
1366
|
+
- **`AstraSyncSDK.hasAccess()`** marked `@deprecated` — explicit opt-in band
|
|
1367
|
+
queries still work, but prefer the server-side policy decision /
|
|
1368
|
+
`minTrustScore`.
|
|
1369
|
+
- **MCP adapter — clear "purpose required" error.** A gated MCP tool call with
|
|
1370
|
+
no resolvable PDLSS purpose (none on the toolGate, no `X-Astra-Purpose`
|
|
1371
|
+
header, none in the body) now fails fast with a `400 PDLSS_PURPOSE_REQUIRED`
|
|
1372
|
+
(dimension `pdlss.purpose`) instead of forwarding an empty purpose to
|
|
1373
|
+
verify-access and surfacing an opaque `verify_access.api_error`. Post-3.2.0,
|
|
1374
|
+
prefer the object toolGate form (`{ purpose, action }`) over the deprecated
|
|
1375
|
+
band string — the band no longer gates and carries no vocabulary.
|
|
1376
|
+
|
|
1377
|
+
### Fixed — cross-merchant verification cache leak (security)
|
|
1378
|
+
|
|
1379
|
+
- **`verify()` result cache now keys on the merchant `counterpartyId`.** The
|
|
1380
|
+
cache key (`getCacheKey`) was built from the request only; the merchant
|
|
1381
|
+
identity travels via `config.counterpartyId`, so it was absent from the key.
|
|
1382
|
+
Two verifies for the SAME agent/purpose/action/value but DIFFERENT merchants
|
|
1383
|
+
collided — a grant cached at a permissive merchant (low/no trust floor) was
|
|
1384
|
+
served for a stricter merchant, bypassing its trust floor / per-route policy
|
|
1385
|
+
in any long-running consumer (the bridge). Same bug class as the earlier
|
|
1386
|
+
duration-omission fix (F-A1-07). `counterpartyId` now keys the cache.
|
|
1387
|
+
Surfaced by a cross-merchant live probe (a floor-0 grant leaking to a
|
|
1388
|
+
floor-50 merchant). Pre-existing; amplified by the 3.2.0 verify-before-act
|
|
1389
|
+
ordering (which adds a per-merchant `shopping.search` verify).
|
|
1390
|
+
|
|
1391
|
+
### Migration
|
|
1392
|
+
|
|
1393
|
+
No code change required to upgrade. If you relied on `route.minAccessLevel`
|
|
1394
|
+
to tighten a route, switch to `route.minTrustScore` (a number). Merchants on
|
|
1395
|
+
3.1.0 keep their band wall until they upgrade — upgrading removes it.
|
|
1396
|
+
|
|
1397
|
+
## [3.1.0] — 2026-06-11 — canonical PDLSS vocabulary (Bug 14)
|
|
1398
|
+
|
|
1399
|
+
The vocabulary-unification release. Partner prod testing proved **no agent
|
|
1400
|
+
registration shape could transact at an SDK-gated merchant**: the express/
|
|
1401
|
+
nextjs middleware sent `purpose: 'read_data'` (method inference) and
|
|
1402
|
+
`action: 'GET'` (the raw transport verb, with no override surface), while the
|
|
1403
|
+
platform evaluator and docs contract is two-axis — `purpose` = bare category
|
|
1404
|
+
noun (`shopping`), `action` = dotted verb (`shopping.search`). 3.1.0 pins
|
|
1405
|
+
every sender to that contract.
|
|
1406
|
+
|
|
1407
|
+
Retroactive context: 3.0.0's identity-forwarded catalog fetch (#437 B3/B5)
|
|
1408
|
+
moved merchant-side gating onto the bridge checkout critical path — the change
|
|
1409
|
+
that exposed this misalignment and motivates this release.
|
|
1410
|
+
|
|
1411
|
+
### Changed — middleware emits canonical vocabulary
|
|
1412
|
+
|
|
1413
|
+
- Express/Next.js adapters now resolve a canonical `{purpose, action}` pair.
|
|
1414
|
+
The **pinned method→action table** replaces both gen-1 inferences:
|
|
1415
|
+
GET/HEAD/OPTIONS → `data.read`; POST/PUT/PATCH → `data.write`; DELETE →
|
|
1416
|
+
`data.delete`; unknown → `data.write`. The transport verb is **never** sent
|
|
1417
|
+
as the PDLSS action, and `read_data`/`write_data`/`delete_data`/`general`
|
|
1418
|
+
are no longer emitted as purposes (unmapped fallback purpose is `data`).
|
|
1419
|
+
- A dotted `X-Astra-Purpose` (e.g. `shopping.purchase` — the shape older docs
|
|
1420
|
+
taught) is now normalized: category prefix → `purpose`, whole token →
|
|
1421
|
+
`action` candidate. The colon form (`category:action`) keeps its
|
|
1422
|
+
take-the-prefix behavior; the free-text remainder is still discarded.
|
|
1423
|
+
|
|
1424
|
+
### Added — config surfaces (both axes, finally symmetric)
|
|
1425
|
+
|
|
1426
|
+
- **Dashboard route send-mapping (the direct-path mechanism):**
|
|
1427
|
+
`RouteAccessConfig` gains optional `purpose` / `action` — the tokens the
|
|
1428
|
+
middleware STAMPS on verify-access calls for a matched route, fetched from
|
|
1429
|
+
`GET /endpoints/:id/routes` like the rest of route policy. Authoritative
|
|
1430
|
+
over agent headers (as MCP toolGates are). Domain merchants (e.g. a trading
|
|
1431
|
+
exchange mapping `/api/orders` → `trading`/`trading.execute`) configure this
|
|
1432
|
+
in the dashboard routes editor — an unmapped route falls to the generic
|
|
1433
|
+
`data`/`data.*` pair, which DENIES domain agents by design.
|
|
1434
|
+
- `X-Astra-Action` header: extracted by express/nextjs (parity with the MCP
|
|
1435
|
+
adapter) and emitted by `setHttpHeaders` alongside the back-compat colon
|
|
1436
|
+
form. `extractAction` middleware option added, symmetric with
|
|
1437
|
+
`extractPurpose`. `ToolGateConfig.action` override added for MCP.
|
|
1438
|
+
- Resolution telemetry: express/nextjs emit `purpose_source`/`action_source`
|
|
1439
|
+
debug lines (same shape as MCP) when `debug: true`.
|
|
1440
|
+
|
|
1441
|
+
### Breaking-by-policy (platform, not this package's code)
|
|
1442
|
+
|
|
1443
|
+
- **Gen-1 tokens are RETIRED, not aliased**: platform registration now
|
|
1444
|
+
rejects `read_data`/`write_data`/`execute_action`/`delete_data`/`general`
|
|
1445
|
+
with a pointed 400. Existing agents carrying them must retire +
|
|
1446
|
+
re-register (pre-launch posture: no production cohort to migrate).
|
|
1447
|
+
- Registration is now **action-primary**: `allowedActions` required (min 1 —
|
|
1448
|
+
the evaluator is fail-closed on actions), `categories` derived from
|
|
1449
|
+
dotted-action prefixes (explicit entries validated as a bare-noun
|
|
1450
|
+
superset). Dashboard `allowedPurposes` lists must hold bare nouns.
|
|
1451
|
+
|
|
1452
|
+
### Migration table
|
|
1453
|
+
|
|
1454
|
+
| You were sending/storing | Send/store instead |
|
|
1455
|
+
| --------------------------------------- | --------------------------------------------------------------- |
|
|
1456
|
+
| `purpose: 'read_data'`, `action: 'GET'` | `purpose: 'data'`, `action: 'data.read'` (automatic on upgrade) |
|
|
1457
|
+
| `purpose: 'shopping.purchase'` | `purpose: 'shopping'`, `action: 'shopping.purchase'` |
|
|
1458
|
+
| `categories: ['read_data', ...]` | `allowedActions: ['data.read', ...]` (categories derived) |
|
|
1459
|
+
| `allowedActions: ['GET', 'POST']` | `allowedActions: ['data.read', 'data.write']` or domain verbs |
|
|
1460
|
+
| route `allowedPurposes: ['read_data']` | `allowedPurposes: ['data']` (bare nouns) |
|
|
1461
|
+
|
|
1462
|
+
### Deprecated (removal in 4.0.0)
|
|
1463
|
+
|
|
1464
|
+
- `x-purpose` header and `?purpose` query param (express) — still resolved,
|
|
1465
|
+
scheduled for removal.
|
|
1466
|
+
- Colon-form `X-Astra-Purpose` (`category:action`) as an action channel — use
|
|
1467
|
+
the dedicated `X-Astra-Action` header.
|
|
1468
|
+
|
|
1469
|
+
## [3.0.0] — 2026-06-09 — migration guide (2.5 → 3.0)
|
|
1470
|
+
|
|
1471
|
+
Major bump consolidating the consumer-facing breaking changes accumulated across
|
|
1472
|
+
the PR #430 re-test, #437, and this follow-up. **No action is required to keep
|
|
1473
|
+
running 2.5.1** — these only matter when you upgrade or when you read responses
|
|
1474
|
+
from the hosted bridge. Read each item below.
|
|
1475
|
+
|
|
1476
|
+
### Breaking (SDK) — `buildGuidance` envelope: `registrationUrl` is now an action endpoint
|
|
1477
|
+
|
|
1478
|
+
The no-creds guidance `registrationUrl` was the human dashboard page
|
|
1479
|
+
(`/agents/register`), which an agent cannot use. It is now the **keyless action
|
|
1480
|
+
endpoint** an agent can POST to. The companion `documentationUrl` (the
|
|
1481
|
+
machine-readable contract) is unchanged.
|
|
1482
|
+
|
|
1483
|
+
```
|
|
1484
|
+
Before (2.5.x): { registrationUrl: ".../agents/register",
|
|
1485
|
+
documentationUrl: ".../docs/agent-access", steps: [...] }
|
|
1486
|
+
After (3.0.0): { registrationUrl: ".../api/agents/request-registration",
|
|
1487
|
+
documentationUrl: ".../docs/agent-access", steps: [...] }
|
|
1488
|
+
```
|
|
1489
|
+
|
|
1490
|
+
Migration:
|
|
1491
|
+
|
|
1492
|
+
- **POSTed to `registrationUrl` to register?** Keep doing that — it now points at
|
|
1493
|
+
the correct keyless action endpoint instead of an auth-walled HTML page.
|
|
1494
|
+
- **Displayed `registrationUrl` to a user as "where to learn"?** Switch to
|
|
1495
|
+
`documentationUrl`.
|
|
1496
|
+
- `/agents/register` is no longer surfaced by the SDK — it's a human-auth route.
|
|
1497
|
+
|
|
1498
|
+
### Breaking (hosted bridge, `mcp.astrasync.ai`) — affects callers, not this package's code
|
|
1499
|
+
|
|
1500
|
+
- **`lookup_agent` and `list_agents` removed** (tool count 11 → 9). The backend
|
|
1501
|
+
`GET /agents` and `GET /agents/:id` reject API-key auth (correct security — no
|
|
1502
|
+
cross-account or sibling-agent enumeration), so over the bridge's x-api-key
|
|
1503
|
+
credential these tools could only ever return a 403 deny envelope. Look up your
|
|
1504
|
+
own agent's public metadata via the dashboard or your known ASTRA-id.
|
|
1505
|
+
- **`verify_agent` now requires/defaults a `purpose`.** Pass a PDLSS purpose token
|
|
1506
|
+
(e.g. `shopping.purchase`); it defaults to `identity.verify`. (Previously the
|
|
1507
|
+
bridge omitted it and the backend rejected the call with 400.)
|
|
1508
|
+
- **Upstream failures are classified by status.** A reachable-but-rejecting
|
|
1509
|
+
platform now returns `upstream.validation_failed` (400/422),
|
|
1510
|
+
`upstream.auth_failed` (401), `upstream.access_denied` (403), or
|
|
1511
|
+
`upstream.unexpected_status` (other 4xx). `system.platform_unreachable` is now
|
|
1512
|
+
reserved for genuine reachability failures (5xx/network) — agents that retried
|
|
1513
|
+
on `platform_unreachable` should branch on the new dimensions (fix-input vs
|
|
1514
|
+
re-auth vs escalate).
|
|
1515
|
+
- **`request_registration` rejects secret-shaped fields** (`apiKey`/`privateKey`/
|
|
1516
|
+
`secret`/`token`/…) with a `-32602` validation error instead of silently
|
|
1517
|
+
stripping them.
|
|
1518
|
+
- **Per-email registration rate-limit** returns a structured `429`
|
|
1519
|
+
(`rate_limited` + `retryAfter`) instead of a `202` with a missing `requestId`.
|
|
1520
|
+
- **KYD is enforced at agent approval, per registration path.** API-key
|
|
1521
|
+
registrations on a no-KYD account now create a pending request (approved in the
|
|
1522
|
+
dashboard once KYD is complete) rather than failing at registration; an
|
|
1523
|
+
unapprovable backlog older than 24h returns `owner_kyd_required`.
|
|
1524
|
+
|
|
1525
|
+
## [2.5.0] — 2026-06-03
|
|
1526
|
+
|
|
1527
|
+
### Breaking — REST + MCP purpose default
|
|
1528
|
+
|
|
1529
|
+
The SDK no longer injects `'general'` as a default purpose when verify-access
|
|
1530
|
+
requests arrive without an explicit purpose. Undefined purpose now propagates
|
|
1531
|
+
to the backend evaluator, which applies skip-when-undefined per the round-18.6
|
|
1532
|
+
architectural posture.
|
|
1533
|
+
|
|
1534
|
+
Merchants with `allowedPurposes: ['general']` in endpoint policy: the entry
|
|
1535
|
+
continues to match callers that explicitly send `'general'`, but no longer
|
|
1536
|
+
matches callers who send nothing. If you relied on the auto-stamp as a
|
|
1537
|
+
catch-all, declare your intent explicitly or rely on skip-when-undefined.
|
|
1538
|
+
|
|
1539
|
+
### Breaking — MCP `mcp_invoke` purpose and `mcp:tool/` resource prefix removed
|
|
1540
|
+
|
|
1541
|
+
The MCP middleware no longer stamps transport-coupled defaults on the purpose
|
|
1542
|
+
and resource axes. `mcp_invoke` is removed; `mcp:tool/<name>` is replaced by
|
|
1543
|
+
the HTTP request path (e.g. `/mcp`).
|
|
1544
|
+
|
|
1545
|
+
Use the new `toolGates` object shape to declare per-tool purpose and resource:
|
|
1546
|
+
|
|
1547
|
+
```typescript
|
|
1548
|
+
toolGates: {
|
|
1549
|
+
list_products: { minAccessLevel: 'none', purpose: 'shopping.search', resource: '/api/catalog' },
|
|
1550
|
+
start_checkout: { minAccessLevel: 'standard', purpose: 'shopping.purchase', resource: '/api/checkout/*' },
|
|
1551
|
+
browse_catalog: 'read-only', // shorthand still works
|
|
1552
|
+
}
|
|
1553
|
+
```
|
|
1554
|
+
|
|
1555
|
+
See `docs/migration/2.5.0.md` for full before/after behaviour.
|
|
1556
|
+
|
|
1557
|
+
### Added — `ToolGateConfig` type for per-tool PDLSS mapping
|
|
1558
|
+
|
|
1559
|
+
`toolGates` now accepts both the existing `AccessLevel` shorthand and a new
|
|
1560
|
+
`ToolGateConfig` object with optional `purpose` and `resource` fields. When
|
|
1561
|
+
`purpose` is set on a tool gate, it is authoritative — the agent's
|
|
1562
|
+
`X-Astra-Purpose` header is ignored for that tool.
|
|
1563
|
+
|
|
1564
|
+
### Added — `/.well-known/agentic-commerce` URL discovery
|
|
1565
|
+
|
|
1566
|
+
The SDK now fetches canonical platform URLs from `/.well-known/agentic-commerce`
|
|
1567
|
+
at initialization (fire-and-forget pre-fetch, lazy await on first verify call).
|
|
1568
|
+
All guidance URLs in denial responses come from this endpoint instead of the
|
|
1569
|
+
previous `apiBaseUrl.replace('/api', '')` string manipulation.
|
|
1570
|
+
|
|
1571
|
+
Cache TTL is 60 minutes with stale-while-revalidate background refresh.
|
|
1572
|
+
|
|
1573
|
+
### Added — Non-tools/call methods default to `discovery_default` access level
|
|
1574
|
+
|
|
1575
|
+
`resolveMinAccessLevel()` now has an explicit branch for non-tools/call MCP
|
|
1576
|
+
methods (`initialize`, `tools/list`, etc.) returning `'none'` with source
|
|
1577
|
+
`'discovery_default'`. Use `methodGates` to override.
|
|
1578
|
+
|
|
1579
|
+
### Fixed — `result.guidance` populated on all adapter deny paths
|
|
1580
|
+
|
|
1581
|
+
Adapter-level deny paths (insufficient access level, insufficient trust score,
|
|
1582
|
+
middleware internal error) now backfill `result.guidance` with well-known URLs
|
|
1583
|
+
when the verify-access response didn't include guidance (e.g. success-path
|
|
1584
|
+
results that fail the local access-level gate).
|
|
1585
|
+
|
|
1586
|
+
### Fixed — `denialReasons` deduplication
|
|
1587
|
+
|
|
1588
|
+
`dedupeFailures()` now deduplicates the legacy `denialReasons` string array
|
|
1589
|
+
alongside the structured `failures` array.
|
|
1590
|
+
|
|
1591
|
+
## [2.4.0] — 2026-05-11
|
|
1592
|
+
|
|
1593
|
+
### Added — Agent registration absorbed into the gateway package
|
|
1594
|
+
|
|
1595
|
+
The previously separate agent-side SDK is now part of `@astrasyncai/verification-gateway`. One package, one version, one set of release notes. DevOps brief: stop maintaining two npm releases for what is effectively one platform SDK.
|
|
1596
|
+
|
|
1597
|
+
- **New `/registration` subpath** — `import { AstraSync } from '@astrasyncai/verification-gateway/registration'` exposes the registration client (`register()`, `verify()`, `health()`), config (`AstraSyncConfig`, `RegisterOptions`), error classes (`AstraSyncError`, `KYDRequiredError`, `AuthenticationError`), and the PDLSS declaration types. Class API and shapes are unchanged from the absorbed package — the only change for migrating callers is the import path.
|
|
1598
|
+
- **New `astrasync` CLI binary** — `npx astrasync register --name foo --pdlss ...`, `npx astrasync verify <id>`, `npx astrasync health`. Ships from this package's new `bin` field; no separate install.
|
|
1599
|
+
- **`ethers ^6.13.0` added as a direct dependency.** Powers secp256k1 request signing inside `/registration`. The lazy `await import('ethers')` in the signer is preserved; making ethers a hard dep makes it visible to `npm audit`, dependabot, and SBOM tooling rather than failing at runtime with a missing-module error.
|
|
1600
|
+
- **Subpath-by-role map** lives in `README.md` and `docs/research/adapter-architecture-technical-requirements.md` Appendix C round-8 entry. The round-3/round-7 two-package mnemonic ("verification-gateway = answers, agent-registration = asks") is retired.
|
|
1601
|
+
|
|
1602
|
+
### Added — `PDLSSConfig` type co-exists across subpaths by design
|
|
1603
|
+
|
|
1604
|
+
`/registration` exports a `PDLSSConfig` for the boundary declaration submitted at register time; `/agent` exports a different-shaped `PDLSSConfig` for the per-request runtime credential injection. Same name, different concept. The root export does not re-export either to keep the umbrella surface unambiguous. Disambiguate via subpath in imports.
|
|
1605
|
+
|
|
1606
|
+
### Rolled in from round-7 partner feedback (was PR #384 scope)
|
|
1607
|
+
|
|
1608
|
+
All 20 non-rename items from the 6 May onboarding test ship with this release. The package rename to `@astrasyncai/agent-registration` is superseded by the merge — that name was never published to npm.
|
|
1609
|
+
|
|
1610
|
+
- **Backend: typed errors replace opaque 500s.**
|
|
1611
|
+
- `POST /api/agents/register` is now `.strict()` on top-level fields: unknown keys return `400 unsupported_field` with the offending key list (B2). `metadata{}` stays passthrough.
|
|
1612
|
+
- `PUT /api/agents/{id}` detects mutation attempts on `pdlss`, `model`, `framework`, `agentType`, `apiEndpoint` and returns `409 pdlss_immutable` with `immutableFields[]` (B6). `apiEndpoint` removed from `updateAgentSchema`.
|
|
1613
|
+
- `GET /api/agents/{id}/chain-of-custody` resolves ASTRA-id ↔ UUID before querying (root cause of the 500: routes were passing ASTRA-id strings into UUID columns), checks ownership, returns `404`/`403`/typed envelopes (B7). New `agentsService.resolveAgentId()` helper covers both routes.
|
|
1614
|
+
- **Backend: new endpoints + first-class fields.**
|
|
1615
|
+
- `GET /api/agents/request-registration/{requestId}` polling endpoint (Doc5). Persistence reuses `platform_events.eventData` JSONB — no schema migration.
|
|
1616
|
+
- `protocols[]` promoted from `metadata.protocols[]` to a first-class field on `CreateAgentRequest` (Doc4). Backend mirrors top-level → `metadata.protocols` for back-compat.
|
|
1617
|
+
- **Hostname fix.** SDK default `baseUrl` changed from `https://api.kya.astrasync.ai` (NXDOMAIN since the rebrand) → `https://astrasync.ai`. Backend `kydUrl` in 403 responses changed from `https://app.kya.astrasync.ai/developer-profile` → `https://astrasync.ai/developer-profile`. Mechanical sweep across docs, KB articles, frontend doc routes, and the mcp-server agent resources.
|
|
1618
|
+
- **B5 audit confirmed there is NO register-time runtime challenge** — the tester's failure was at first verify-access, not at register. Documented explicitly in `/docs/agent-access`.
|
|
1619
|
+
- **Email template branching (B3).** `agent-outreach` template branches on `recipientHasAccount` — existing accounts get "Sign In to Accept" (links to `/dashboard/agents/pending`); new users get "Create Your Account" (links to `/auth/register`). Subject line, headline, body intro, and CTA all branch.
|
|
1620
|
+
- **Dashboard parity with the registration SDK (Doc8).** Agent-creation form at `/dashboard/agents/register` now exposes `model{}` and `framework{}` field groups in step 2, matching `RegisterOptions` from `/registration`. Dashboard-registered agents now hit the same trust-score baseline as SDK-registered ones.
|
|
1621
|
+
- **Trust score tooltip (D4).** `registration-success-dialog.tsx` adds a tooltip clarifying the score is recomputed at runtime on every request, improves with metadata completeness, and is intentionally opaque (anti-gaming).
|
|
1622
|
+
- **Customer-facing docs.** Six items (D1–D6) added across `/docs/pdlss` and the new `/docs/agent-access` section: anti-drift rationale, PDLSS immutability up-front, trust-score dynamics, self-instantiation clarification, step-up rules table, runtime-challenge timing callout. Plus Doc1 worked register-call example and Doc2 cross-links.
|
|
1623
|
+
|
|
1624
|
+
### Captured follow-ups (deferred to a separate feature-PR)
|
|
1625
|
+
|
|
1626
|
+
- B1 + B4 (paired): async owner-approval flow on API-key registrations + pending-approval inbox/banner. Needs a persistent approval-request table, magic-link handler, and dashboard inbox.
|
|
1627
|
+
- MFA implementation for API-key step-up.
|
|
1628
|
+
- `app.kya.astrasync.ai` references in env configs / Stripe webhooks / other places the in-repo grep doesn't catch.
|
|
1629
|
+
- Round-6 leftovers: `ENTERPRISE_ADMIN_EMAIL` env on staging, local-override row icon colour, `GET /api/version` endpoint.
|
|
1630
|
+
|
|
1631
|
+
### Post-merge actions (manual, not done by this PR)
|
|
1632
|
+
|
|
1633
|
+
- Push tag `@astrasyncai/verification-gateway@2.4.0` from `main` at the merge commit → existing `publish-gateway.yml` workflow validates and publishes via Trusted Publishing OIDC.
|
|
1634
|
+
- `npm deprecate "@astrasyncai/sdk@>=0.0.0" "Renamed to @astrasyncai/verification-gateway. See https://www.npmjs.com/package/@astrasyncai/verification-gateway"` — the legacy package on npm from before round-7.
|
|
1635
|
+
- `@astrasyncai/agent-registration` does NOT need deprecation; it was never published.
|
|
1636
|
+
|
|
1637
|
+
## [2.2.3] — 2026-05-05
|
|
1638
|
+
|
|
1639
|
+
### Changed — Server is the single source of truth for access decisions
|
|
1640
|
+
|
|
1641
|
+
This is the branch-validation release for the partner-feedback fixes. The same code ships as `2.3.0` on tag-publish once the verification matrix passes against UAT.
|
|
1642
|
+
|
|
1643
|
+
- **`apiBaseUrl` default corrected** (`src/verify.ts`) — was `https://api.astrasync.ai` which matched neither prod nor staging OpenAPI servers. Now `https://astrasync.ai/api`. Always include the `/api` path prefix when overriding; SDK derives registration / docs URLs by stripping it.
|
|
1644
|
+
- **Init self-test on first `verify()` call** — fires a HEAD probe to `${apiBaseUrl}/agents/verify-access` and warns once if the response content-type is `text/html` (the marketing-404 trap). Behind `disableInitChecks?: boolean` for tests.
|
|
1645
|
+
- **`access.accessLevel` read verbatim from server** (`src/verify.ts:418-425`) — the local `determineAccessLevel(...)` call is removed. The server's PDLSS engine resolves the level from endpoint policy + agent's live trust score using canonical thresholds; the SDK no longer diverges. Closes partner feedback #20.
|
|
1646
|
+
- **`minTrustScore` / `minTrustScoreForFull` config fields deprecated** (`src/types.ts`) — setting them no longer affects access decisions. A one-shot `console.warn` fires if either is set on a `verify()` call. To gate access, configure `trust_score_requirement` server-side via the endpoint registration.
|
|
1647
|
+
|
|
1648
|
+
### Added — Anonymous traffic + canonical-flow contract
|
|
1649
|
+
|
|
1650
|
+
- **Anonymous `verify()` calls forward to the server** — the SDK no longer short-circuits when credentials are missing. The server applies the endpoint's `unverifiedAgentPolicy` (deny / allow_partial / allow_full) and returns `{access, advisory, recommendation}`. Closes partner feedback #1 and #1b.
|
|
1651
|
+
- **`counterpartyId` config field** — your ASTRAE-id, issued at endpoint registration. Forwarded on every `verify-access` call so the server attributes traffic directly by endpoint rather than URL resolution. Closes partner feedback #3.
|
|
1652
|
+
- **Header aliases on `extractCredentials`** (`src/verify.ts:99`) — accepts `X-Astra-Id`, `X-Astra-AgentId`, `x-astra-agent-id`, plus their casing permutations. Closes partner feedback #9a.
|
|
1653
|
+
- **`AccessLevel` docstring rewritten** — references the canonical-flow §21 in the platform spec and lays out semantics for both anonymous (Branch A/B/C) and verified (Branch D) callers.
|
|
1654
|
+
|
|
1655
|
+
### Added — Webhook signature contract
|
|
1656
|
+
|
|
1657
|
+
- **`@astrasyncai/verification-gateway/webhooks`** (`src/webhooks.ts`) — new module with `verifyAstraSyncWebhook(rawBody, headers, secret, options?)` and `signAstraSyncWebhook(rawBody, secret, nowMs?)`. HMAC-SHA256 over `${unix_timestamp}.${rawBody}`, header format `X-AstraSync-Signature: t=<unix>,v1=<hex>`. Constant-time comparison; 5-minute replay window (configurable via `toleranceSeconds`).
|
|
1658
|
+
- 7/7 unit tests cover round-trip, wrong secret, tampered body, replay window, missing/malformed header, and header-case variants.
|
|
1659
|
+
- Closes partner feedback #4 (signature contract). Outbound webhook delivery system from AstraSync to merchant URLs is a separate engineering effort tracked in the platform spec §22 / §23.
|
|
1660
|
+
|
|
1661
|
+
### Fixed — Response field-name alignment
|
|
1662
|
+
|
|
1663
|
+
- **`agent.id` → `agent.astraId`, `agent.status` → `agent.agentStatus`, added `agent.blockchainStatus`** — read verbatim from the API response. The SDK type definitions and the OpenAPI schema both already declared the new names; the backend response is now in line. Closes partner feedback #21.
|
|
1664
|
+
|
|
1665
|
+
### Notes
|
|
1666
|
+
|
|
1667
|
+
- This release is paired with backend v2.9. The dual-perspective activity feed, orphan-identity tracking, Enterprise admin org pattern, and always-emit invariant on verification events all ship server-side; this SDK release is the corresponding client-side contract correction.
|
|
1668
|
+
- Activity-dashboard polish (per-row Step-up display, summary↔detail count consistency) is a NOT BUILT row in the platform spec — cosmetic only; does not affect the SDK contract.
|
|
1669
|
+
|
|
1670
|
+
## [2.2.0] — 2026-05-03
|
|
1671
|
+
|
|
1672
|
+
### Added — Ownership-bound agent client + caller metadata
|
|
1673
|
+
|
|
1674
|
+
- **`AgentClient.create()` async factory** (`src/agent/client.ts`) — validates
|
|
1675
|
+
the configured API key's account owns the supplied ASTRA-id by calling
|
|
1676
|
+
`GET /api/agents/:astraId/ownership` before returning a usable client. A
|
|
1677
|
+
stolen ASTRA-id paired with a different valid API key now fails closed at
|
|
1678
|
+
initialisation. Bypass in test environments with
|
|
1679
|
+
`ASTRASYNC_SKIP_OWNERSHIP_CHECK=true`.
|
|
1680
|
+
- **`OwnershipMismatchError`** (`src/agent/errors.ts`, exported from
|
|
1681
|
+
`src/agent/index.ts`) — typed error surfaced when ownership binding fails
|
|
1682
|
+
or no API key is configured. Extends a new base `AstraSyncSdkError` with a
|
|
1683
|
+
stable `code` field for downstream handling.
|
|
1684
|
+
- **`callerMetadata` on `verify()` requests** (`src/verify.ts`) — structured
|
|
1685
|
+
bag for `sourceIp`, `userAgent`, `referer`, `host`, `forwardedFor`, and
|
|
1686
|
+
`agentCardUrl`. Express + Next.js adapters now populate it from request
|
|
1687
|
+
headers (X-Forwarded-For first-hop resolution, `x-astrasync-agent-card`).
|
|
1688
|
+
Legacy top-level `clientIp` / `userAgent` fields continue to work.
|
|
1689
|
+
|
|
1690
|
+
### Changed
|
|
1691
|
+
|
|
1692
|
+
- Express + Next.js adapters forward the original client IP (first entry of
|
|
1693
|
+
`X-Forwarded-For`, falling back to `req.ip`) instead of the immediate
|
|
1694
|
+
proxy hop.
|
|
1695
|
+
- Internal formatting pass (Prettier) across adapters and `verify.ts` — no
|
|
1696
|
+
behavioural changes.
|
|
1697
|
+
|
|
1698
|
+
### Tests
|
|
1699
|
+
|
|
1700
|
+
- New `src/agent/__tests__/ownership.test.ts` covering the ownership-binding
|
|
1701
|
+
factory: success, `owned=false`, non-2xx, missing API key, and the
|
|
1702
|
+
`ASTRASYNC_SKIP_OWNERSHIP_CHECK` bypass.
|
|
1703
|
+
|
|
1704
|
+
## [2.1.0] — 2026-04-18
|
|
1705
|
+
|
|
1706
|
+
### Added — Commerce Transport Verification Engine (spec v2.7)
|
|
1707
|
+
|
|
1708
|
+
Runtime verification layer covering all 10 registered commerce/agent protocols.
|
|
1709
|
+
Library-first design; no hand-rolled cryptography.
|
|
1710
|
+
|
|
1711
|
+
**New `src/transport/` modules (21 source files):**
|
|
1712
|
+
|
|
1713
|
+
- **Extractors** — `vi.ts` (VI SD-JWT via `@sd-jwt/decode`), `ap2.ts` (AP2 mandate
|
|
1714
|
+
triple), `ucp.ts` (checkout session + AJV manifest), `acp.ts` (multi-header parse
|
|
1715
|
+
- payment-token prefix detection), `rfc9421.ts` (`structured-headers`), `mpp.ts`
|
|
1716
|
+
(Challenge/Credential/Receipt via `mppx`), `x402.ts` (v1 + v2 via `@x402/core`).
|
|
1717
|
+
- **Verifiers** — `vi-verify.ts` (3-layer SD-JWT chain + RFC 7638 JWK thumbprint
|
|
1718
|
+
bindings + VI constraint type 8 hash binding), `ap2-verify.ts` (mandate chain
|
|
1719
|
+
cross-ref + totals monotonicity), `acp-verify.ts` (detached JSON sig, Ed25519 +
|
|
1720
|
+
ES256 candidates, Timestamp freshness), `rfc9421-verify.ts` (wraps
|
|
1721
|
+
`http-message-signatures` + `RegistryResolver`), `mpp-verify.ts`
|
|
1722
|
+
(expiry + BodyDigest + source extraction), `stripe-webhook.ts` (inline
|
|
1723
|
+
HMAC-SHA256 via `node:crypto`).
|
|
1724
|
+
- **Registry resolvers** — `registry/visa.ts` (JWKS at `mcp.visa.com/.well-known/
|
|
1725
|
+
jwks` via `jose.createRemoteJWKSet`), `registry/mastercard.ts` (partnership-gated
|
|
1726
|
+
stub), `registry/web-bot-auth.ts` (IETF `draft-meunier-web-bot-auth-architecture-05`
|
|
1727
|
+
directory fetch, Ed25519).
|
|
1728
|
+
- **Orchestration** — `commerce-pipeline.ts` (extract→verify→identity-bind→
|
|
1729
|
+
constraint-eval→CommerceContext with hard-deny/trust-signal policy +
|
|
1730
|
+
per-phase timings), `identity-binding.ts` (cross-protocol agent identity
|
|
1731
|
+
mapping), `constraint-eval.ts` (VI types 1/2/3/4 + MPP/x402 payment-method
|
|
1732
|
+
allowlist + spending-limit), `extractor-registry.ts`
|
|
1733
|
+
(`registerTransportExtractor()` SDK hook for Lambda adapters),
|
|
1734
|
+
`purpose-mapping.ts` (20 commerce purpose mappings), `transaction-value.ts`
|
|
1735
|
+
(per-protocol amount normalization).
|
|
1736
|
+
|
|
1737
|
+
**New peer-dep-compatible runtime dependencies:**
|
|
1738
|
+
|
|
1739
|
+
- `@sd-jwt/core` ^0.19.0 + `@sd-jwt/decode` + `@sd-jwt/utils` (Apache-2.0)
|
|
1740
|
+
- `http-message-signatures` ^1.0.5 (ISC)
|
|
1741
|
+
- `mppx` 0.5.13 pinned (MIT, pre-1.0 API churn expected — wrapped in adapter)
|
|
1742
|
+
- `@x402/core` ^2.10.0 (Apache-2.0)
|
|
1743
|
+
- `web-bot-auth` ^0.1.3 (Apache-2.0)
|
|
1744
|
+
- `jose` ^5.9.6 (MIT)
|
|
1745
|
+
- `ajv` ^8.17.1 (MIT)
|
|
1746
|
+
- `structured-headers` ^2.0.1 (MIT)
|
|
1747
|
+
|
|
1748
|
+
**Exports added** — import from `@astrasyncai/verification-gateway`:
|
|
1749
|
+
|
|
1750
|
+
```ts
|
|
1751
|
+
import {
|
|
1752
|
+
transport, // namespace containing all new modules
|
|
1753
|
+
} from '@astrasyncai/verification-gateway';
|
|
1754
|
+
|
|
1755
|
+
// Or from the transport subpath:
|
|
1756
|
+
import {
|
|
1757
|
+
// Extractors
|
|
1758
|
+
extractVIClaims,
|
|
1759
|
+
extractAP2Mandates,
|
|
1760
|
+
extractUCPContext,
|
|
1761
|
+
extractACPContext,
|
|
1762
|
+
parseRFC9421,
|
|
1763
|
+
extractMPPContext,
|
|
1764
|
+
extractX402Context,
|
|
1765
|
+
// Verifiers
|
|
1766
|
+
verifyVIChain,
|
|
1767
|
+
verifyAP2Chain,
|
|
1768
|
+
verifyACPSignature,
|
|
1769
|
+
verifyRFC9421,
|
|
1770
|
+
verifyMPP,
|
|
1771
|
+
verifyStripeWebhook,
|
|
1772
|
+
// Registry resolvers
|
|
1773
|
+
createVisaRegistry,
|
|
1774
|
+
createMastercardRegistry,
|
|
1775
|
+
createWebBotAuthRegistry,
|
|
1776
|
+
// Orchestration
|
|
1777
|
+
runCommercePipeline,
|
|
1778
|
+
evaluateVIConstraints,
|
|
1779
|
+
evaluatePaymentMethodAllowlist,
|
|
1780
|
+
evaluateSpendingLimit,
|
|
1781
|
+
bindIdentity,
|
|
1782
|
+
registerTransportExtractor,
|
|
1783
|
+
// Types
|
|
1784
|
+
type CommerceContext,
|
|
1785
|
+
type CommercePipelineInput,
|
|
1786
|
+
type VIExtractedClaims,
|
|
1787
|
+
type AP2MandateTriple,
|
|
1788
|
+
type ACPRequestContext,
|
|
1789
|
+
type MPPRequestContext,
|
|
1790
|
+
type X402RequestContext,
|
|
1791
|
+
type UCPCheckoutContext,
|
|
1792
|
+
type RegistryResolver,
|
|
1793
|
+
type IdentityClaim,
|
|
1794
|
+
type TransactionValueContext,
|
|
1795
|
+
} from '@astrasyncai/verification-gateway/transport';
|
|
1796
|
+
```
|
|
1797
|
+
|
|
1798
|
+
**Tests** — 545 unit tests across 42 test files in this package. 13 additional
|
|
1799
|
+
integration tests in the backend exercise the full pipeline end-to-end via
|
|
1800
|
+
`POST /agents/verify-access` with a `commerceArtifacts` payload.
|
|
1801
|
+
|
|
1802
|
+
### Added — Publishing hygiene
|
|
1803
|
+
|
|
1804
|
+
- `prepublishOnly` script runs `clean` + `typecheck` + `build` before any
|
|
1805
|
+
`npm publish`, so no one can publish from a stale dist or without a
|
|
1806
|
+
passing typecheck.
|
|
1807
|
+
|
|
1808
|
+
### Notes
|
|
1809
|
+
|
|
1810
|
+
- Nothing is removed or renamed from the `2.0.x` API surface. Existing
|
|
1811
|
+
middleware (`createMiddleware` on Express / Next.js), the agent-side client
|
|
1812
|
+
(`AgentClient`), `verify()`, `quickVerify()`, `extractCredentials()`, and
|
|
1813
|
+
all adapter registries continue to work unchanged.
|
|
1814
|
+
- The orphaned `2.0.1` publish (2026-03-09) was a snapshot published directly
|
|
1815
|
+
from a local working copy without a matching git commit. Its code surface
|
|
1816
|
+
is a strict subset of `2.0.0`'s source-with-fixes and has since been
|
|
1817
|
+
superseded by content in `main`. All runtime behaviour from `2.0.1` is
|
|
1818
|
+
preserved in `2.1.0`.
|
|
1819
|
+
|
|
1820
|
+
## [2.0.1] — 2026-03-09 (orphaned)
|
|
1821
|
+
|
|
1822
|
+
Published directly from a local working copy. No matching git commit or
|
|
1823
|
+
tag. Code surface is a strict subset of `2.1.0`. Included early SDK fixes
|
|
1824
|
+
(`durationRequired` forwarding, unregistered-attempt + counterparty
|
|
1825
|
+
pre-check activity reporting) plus `browser/background` and `cursor/extension`
|
|
1826
|
+
dist chunks; all of these are now in `2.1.0`.
|
|
1827
|
+
|
|
1828
|
+
## [2.0.0] — 2026-03-08
|
|
1829
|
+
|
|
1830
|
+
Universal Verification Gateway launch:
|
|
1831
|
+
|
|
1832
|
+
- SDK handshake + PDLSS pre-check
|
|
1833
|
+
- Agent-side SDK: `AgentClient`, transport adapters (HTTP / A2A / MCP),
|
|
1834
|
+
challenge handler
|
|
1835
|
+
- Counterparty-side SDK: `verify()`, `quickVerify()`, `verifyAndRecord()`,
|
|
1836
|
+
`recordDecision()`
|
|
1837
|
+
- Adapter exports: `/express`, `/nextjs`, `/sdk`, `/agent`, `/transport`,
|
|
1838
|
+
`/gateway`, `/local-evaluator`, `/adapter-interface`, `/cli`, `/cursor`,
|
|
1839
|
+
`/browser`, `/git-trigger`
|
|
1840
|
+
- Local PDLSS evaluator (YAML + constraint checker)
|
|
1841
|
+
- AstraSyncGateway class (online / local / hybrid modes)
|
|
1842
|
+
- Hybrid sync queue (disk-backed, retry, status visibility)
|
|
1843
|
+
- Layer-4 adapters: OpenClaw CLI, Cursor, Browser
|
|
1844
|
+
|
|
1845
|
+
## [1.1.0] — 2026-03-02
|
|
1846
|
+
|
|
1847
|
+
## [1.0.0] — 2026-03-02
|
|
1848
|
+
|
|
1849
|
+
Initial release.
|