@astrasyncai/verification-gateway 5.19.0 → 5.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +83 -0
- package/README.md +51 -2
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +65 -16
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +65 -16
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +23 -1
- package/dist/adapters/mcp.d.ts +23 -1
- package/dist/adapters/mcp.js +91 -16
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +91 -16
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +1 -1
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +57 -11
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +57 -11
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +58 -2
- package/dist/adapters/sdk.d.ts +58 -2
- package/dist/adapters/sdk.js +124 -11
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +124 -11
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +1 -1
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +49 -11
- package/dist/bin/astrasync-codex-hook.js +49 -11
- package/dist/bin/astrasync-guard.js +49 -11
- package/dist/bin/astrasync.js +51 -12
- package/dist/browser/background.js +49 -11
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +49 -11
- 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 +49 -11
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +49 -11
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +49 -11
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +49 -11
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +1 -1
- package/dist/edge-config.d.ts +1 -1
- package/dist/edge-config.js +1 -1
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +1 -1
- package/dist/edge-core/index.d.ts +1 -1
- package/dist/edge-core/index.js +49 -11
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +49 -11
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +49 -11
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +49 -11
- 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 +168 -8
- package/dist/index.d.ts +168 -8
- package/dist/index.js +229 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +226 -31
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/registration/index.d.mts +11 -2
- package/dist/registration/index.d.ts +11 -2
- package/dist/registration/index.js +1 -1
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.d.mts +1 -1
- package/dist/transport/index.d.ts +1 -1
- package/dist/transport/index.js +1 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-BRz2U0Pn.d.ts → types-B_HLhZ9n.d.ts} +1 -1
- package/dist/{types-BfILnheI.d.mts → types-CU17R4Nr.d.mts} +11 -0
- package/dist/{types-BfILnheI.d.ts → types-CU17R4Nr.d.ts} +11 -0
- package/dist/{types-DqWPkiYl.d.mts → types-CxjqmPl-.d.mts} +25 -1
- package/dist/{types-DqWPkiYl.d.ts → types-CxjqmPl-.d.ts} +25 -1
- package/dist/{types-BoGjyon0.d.mts → types-D37aSQ9c.d.mts} +25 -1
- package/dist/{types-CfBpm3w5.d.mts → types-Djpz-L0w.d.mts} +1 -1
- package/dist/{types-eWyZuz-3.d.ts → types-Dn8tXnei.d.ts} +25 -1
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +28 -3
- package/dist/verify.d.ts +28 -3
- package/dist/verify.js +71 -11
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +69 -11
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -30,7 +30,7 @@ function getTrustLevel(score) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// src/version.ts
|
|
33
|
-
var SDK_VERSION = "5.
|
|
33
|
+
var SDK_VERSION = "5.20.0";
|
|
34
34
|
|
|
35
35
|
// src/http.ts
|
|
36
36
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -312,6 +312,7 @@ function cacheResult(request, result, configuredTtl, counterpartyId) {
|
|
|
312
312
|
}
|
|
313
313
|
function clearCache() {
|
|
314
314
|
verificationCache.clear();
|
|
315
|
+
inflightVerifies.clear();
|
|
315
316
|
}
|
|
316
317
|
function extractCredentials(headers, query) {
|
|
317
318
|
const credentials = {};
|
|
@@ -485,6 +486,9 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
485
486
|
if (requestData.enableRuntimeChallenge)
|
|
486
487
|
body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
|
|
487
488
|
if (requestData.routePolicy) body.routePolicy = requestData.routePolicy;
|
|
489
|
+
if (config.actingProof?.connectorToken) {
|
|
490
|
+
body.actingProof = { connectorToken: config.actingProof.connectorToken };
|
|
491
|
+
}
|
|
488
492
|
if (requestData.approvalHeldByRoute) body.approvalHeldByRoute = true;
|
|
489
493
|
if (requestData.createSession) body.createSession = requestData.createSession;
|
|
490
494
|
if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
|
|
@@ -652,22 +656,46 @@ async function verify(config, request, options) {
|
|
|
652
656
|
"[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access decisions (verified ID + runtime challenge + PDLSS + trust score). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
|
|
653
657
|
);
|
|
654
658
|
}
|
|
655
|
-
const uncacheable = Boolean(request.commerceArtifacts);
|
|
659
|
+
const uncacheable = Boolean(request.commerceArtifacts) || Boolean(mergedConfig.actingProof);
|
|
656
660
|
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
657
661
|
const cached = getCachedResult(request, mergedConfig.counterpartyId);
|
|
658
662
|
if (cached) {
|
|
659
663
|
if (mergedConfig.debug) {
|
|
660
664
|
console.log("[VerificationGateway] Returning cached result");
|
|
661
665
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
666
|
+
return sharedVerdict(cached, request);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
670
|
+
const key = getCacheKey(request, mergedConfig.counterpartyId);
|
|
671
|
+
const pending = inflightVerifies.get(key);
|
|
672
|
+
if (pending) return sharedVerdict(await pending, request);
|
|
673
|
+
const flight = verifyViaApi(mergedConfig, request, urls, uncacheable);
|
|
674
|
+
inflightVerifies.set(key, flight);
|
|
675
|
+
try {
|
|
676
|
+
return await flight;
|
|
677
|
+
} finally {
|
|
678
|
+
inflightVerifies.delete(key);
|
|
669
679
|
}
|
|
670
680
|
}
|
|
681
|
+
return verifyViaApi(mergedConfig, request, urls, uncacheable);
|
|
682
|
+
}
|
|
683
|
+
var inflightVerifies = /* @__PURE__ */ new Map();
|
|
684
|
+
var sharedVerdicts = /* @__PURE__ */ new WeakSet();
|
|
685
|
+
function isSharedVerdict(result) {
|
|
686
|
+
return sharedVerdicts.has(result);
|
|
687
|
+
}
|
|
688
|
+
function sharedVerdict(source, request) {
|
|
689
|
+
const hit = { ...source };
|
|
690
|
+
if (request.attemptId) {
|
|
691
|
+
hit.attemptId = request.attemptId;
|
|
692
|
+
} else {
|
|
693
|
+
delete hit.attemptId;
|
|
694
|
+
}
|
|
695
|
+
sharedVerdicts.add(hit);
|
|
696
|
+
return hit;
|
|
697
|
+
}
|
|
698
|
+
async function verifyViaApi(mergedConfig, request, urls, uncacheable) {
|
|
671
699
|
const enrichedRequest = { ...request };
|
|
672
700
|
if (!enrichedRequest.counterpartyUrl && mergedConfig.counterpartyUrl) {
|
|
673
701
|
enrichedRequest.counterpartyUrl = mergedConfig.counterpartyUrl;
|
|
@@ -746,7 +774,9 @@ async function verify(config, request, options) {
|
|
|
746
774
|
fulfilment: apiResponse.fulfilment,
|
|
747
775
|
mandates: apiResponse.mandates,
|
|
748
776
|
kyaToken: apiResponse.kyaToken,
|
|
749
|
-
aep: apiResponse.aep
|
|
777
|
+
aep: apiResponse.aep,
|
|
778
|
+
// 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
|
|
779
|
+
warnings: apiResponse.warnings
|
|
750
780
|
};
|
|
751
781
|
return result2;
|
|
752
782
|
}
|
|
@@ -814,7 +844,9 @@ async function verify(config, request, options) {
|
|
|
814
844
|
// 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
|
|
815
845
|
mandates: apiResponse.mandates,
|
|
816
846
|
kyaToken: apiResponse.kyaToken,
|
|
817
|
-
aep: apiResponse.aep
|
|
847
|
+
aep: apiResponse.aep,
|
|
848
|
+
// 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
|
|
849
|
+
warnings: apiResponse.warnings
|
|
818
850
|
};
|
|
819
851
|
if (result.recommendation === "deny") {
|
|
820
852
|
result.policyAllowed = false;
|
|
@@ -840,8 +872,24 @@ async function verify(config, request, options) {
|
|
|
840
872
|
cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
|
|
841
873
|
}
|
|
842
874
|
}
|
|
875
|
+
notifyVerificationListeners(request, result);
|
|
843
876
|
return result;
|
|
844
877
|
}
|
|
878
|
+
var verificationListeners = /* @__PURE__ */ new Set();
|
|
879
|
+
function onVerificationResult(listener) {
|
|
880
|
+
verificationListeners.add(listener);
|
|
881
|
+
return () => {
|
|
882
|
+
verificationListeners.delete(listener);
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
function notifyVerificationListeners(request, result) {
|
|
886
|
+
for (const listener of verificationListeners) {
|
|
887
|
+
try {
|
|
888
|
+
listener(result, request);
|
|
889
|
+
} catch {
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
845
893
|
async function recordDecision(config, sessionId, decision, reason) {
|
|
846
894
|
const headers = { "Content-Type": "application/json" };
|
|
847
895
|
if (config.apiKey) {
|
|
@@ -906,6 +954,7 @@ async function fetchRoutes(config, counterpartyId, options = {}) {
|
|
|
906
954
|
headers["X-API-Key"] = config.apiKey;
|
|
907
955
|
}
|
|
908
956
|
try {
|
|
957
|
+
headers["X-AstraSync-SDK-Version"] = SDK_VERSION;
|
|
909
958
|
const response = await sdkFetch(
|
|
910
959
|
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes` + (options.codeGates?.length ? `?codeGates=${options.codeGates.map(encodeURIComponent).join(",")}` : ""),
|
|
911
960
|
{ method: "GET", headers }
|
|
@@ -920,6 +969,13 @@ async function fetchRoutes(config, counterpartyId, options = {}) {
|
|
|
920
969
|
return null;
|
|
921
970
|
}
|
|
922
971
|
const body = await response.json();
|
|
972
|
+
const type2 = body.data?.counterpartyType;
|
|
973
|
+
if (typeof type2 === "string" && options.onEndpointType) {
|
|
974
|
+
try {
|
|
975
|
+
options.onEndpointType(type2);
|
|
976
|
+
} catch {
|
|
977
|
+
}
|
|
978
|
+
}
|
|
923
979
|
return body.data?.routes ?? [];
|
|
924
980
|
} catch {
|
|
925
981
|
return null;
|
|
@@ -2843,14 +2899,14 @@ function createMiddleware(options) {
|
|
|
2843
2899
|
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
2844
2900
|
res.setHeader("X-Astra-Gateway-Reason", "evaluated-not-enforced");
|
|
2845
2901
|
}
|
|
2846
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2902
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2847
2903
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
2848
2904
|
});
|
|
2849
2905
|
}
|
|
2850
2906
|
return next();
|
|
2851
2907
|
}
|
|
2852
2908
|
if (!result.policyAllowed) {
|
|
2853
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2909
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2854
2910
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
2855
2911
|
});
|
|
2856
2912
|
}
|
|
@@ -2863,7 +2919,7 @@ function createMiddleware(options) {
|
|
|
2863
2919
|
}
|
|
2864
2920
|
if (requiresHumanApproval(result)) {
|
|
2865
2921
|
annotateApprovalRequired(result);
|
|
2866
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2922
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2867
2923
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
2868
2924
|
});
|
|
2869
2925
|
}
|
|
@@ -2888,7 +2944,7 @@ function createMiddleware(options) {
|
|
|
2888
2944
|
documentationUrl: wellKnownUrls.documentationUrl
|
|
2889
2945
|
};
|
|
2890
2946
|
}
|
|
2891
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2947
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2892
2948
|
recordDecision(config, sessionId, "denied", trustFailure.message).catch(() => {
|
|
2893
2949
|
});
|
|
2894
2950
|
}
|
|
@@ -2897,7 +2953,7 @@ function createMiddleware(options) {
|
|
|
2897
2953
|
return;
|
|
2898
2954
|
}
|
|
2899
2955
|
}
|
|
2900
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2956
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2901
2957
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
2902
2958
|
});
|
|
2903
2959
|
}
|
|
@@ -3745,6 +3801,80 @@ var VerificationGatewayClient = class {
|
|
|
3745
3801
|
}
|
|
3746
3802
|
return json4.data;
|
|
3747
3803
|
}
|
|
3804
|
+
/**
|
|
3805
|
+
* 5.20.0 (round 29.1): change an endpoint's OPERATIONAL URLs with this
|
|
3806
|
+
* client's API key — `PATCH /api/endpoints/:id`. Accepts the key of the
|
|
3807
|
+
* endpoint's owner, or a personal key of an individual with an active seat
|
|
3808
|
+
* in the owning organisation. Policy (rules, trust floor, challenge, edge
|
|
3809
|
+
* config) stays dashboard-only. `null` clears a field. The owner is alerted
|
|
3810
|
+
* when `eventsUrl` changes.
|
|
3811
|
+
*
|
|
3812
|
+
* @param endpointId the ASTRAE id (defaults to the client's `counterpartyId`)
|
|
3813
|
+
* @returns the endpoint as stored, plus `changed` (the fields that changed)
|
|
3814
|
+
* @throws AstraSyncError — 400 `UNKNOWN_FIELDS` / validation, 401/403, 404
|
|
3815
|
+
*/
|
|
3816
|
+
async updateEndpoint(endpointId, patch) {
|
|
3817
|
+
return this.endpointCall("PATCH", endpointId, "", patch);
|
|
3818
|
+
}
|
|
3819
|
+
/**
|
|
3820
|
+
* 5.20.0 (round 29.1): ask AstraSync to send ONE signed step-up event to the
|
|
3821
|
+
* endpoint's Events URL now — `POST /api/endpoints/:id/events/test`.
|
|
3822
|
+
* Delivered synchronously, outside the event outbox (random `eventId`, no
|
|
3823
|
+
* retries), signed with the endpoint's webhook secret like a real event.
|
|
3824
|
+
* Without `approvalId` the payload is synthetic (a kit acknowledges and
|
|
3825
|
+
* ignores it). With the id of a held kit approval at this endpoint the
|
|
3826
|
+
* payload is the real one, so your resume path runs: `approved` makes the
|
|
3827
|
+
* kit re-confirm (held again — nothing is charged); `denied` / `expired` /
|
|
3828
|
+
* `lapsed` release the session.
|
|
3829
|
+
*
|
|
3830
|
+
* Resolves even when your endpoint refused the event (`delivered: false`,
|
|
3831
|
+
* with `responseCode` / `error`).
|
|
3832
|
+
*/
|
|
3833
|
+
async sendTestEvent(endpointId, options) {
|
|
3834
|
+
return this.endpointCall("POST", endpointId, "/events/test", options);
|
|
3835
|
+
}
|
|
3836
|
+
async endpointCall(method, endpointId, suffix, body) {
|
|
3837
|
+
const id = endpointId ?? this.config.counterpartyId;
|
|
3838
|
+
if (!id) {
|
|
3839
|
+
throw new AstraSyncError(
|
|
3840
|
+
"An endpoint id (ASTRAE-\u2026) is required: pass it, or set counterpartyId on the client",
|
|
3841
|
+
400,
|
|
3842
|
+
"VALIDATION"
|
|
3843
|
+
);
|
|
3844
|
+
}
|
|
3845
|
+
if (!this.config.apiKey) {
|
|
3846
|
+
throw new AstraSyncError("This call needs the client apiKey", 401, "AUTH_REQUIRED");
|
|
3847
|
+
}
|
|
3848
|
+
const base = this.config.apiBaseUrl.replace(/\/+$/, "");
|
|
3849
|
+
const url = `${base}/endpoints/${encodeURIComponent(id)}${suffix}`;
|
|
3850
|
+
let res;
|
|
3851
|
+
try {
|
|
3852
|
+
res = await sdkFetch(url, {
|
|
3853
|
+
method,
|
|
3854
|
+
headers: {
|
|
3855
|
+
"Content-Type": "application/json",
|
|
3856
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
3857
|
+
"X-API-Key": this.config.apiKey
|
|
3858
|
+
},
|
|
3859
|
+
body: JSON.stringify(body),
|
|
3860
|
+
signal: AbortSignal.timeout(Math.max(this.timeout, 15e3))
|
|
3861
|
+
});
|
|
3862
|
+
} catch (err) {
|
|
3863
|
+
throw new AstraSyncError(
|
|
3864
|
+
`${method} ${suffix || "/endpoints/:id"} failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
3865
|
+
0,
|
|
3866
|
+
"network_error"
|
|
3867
|
+
);
|
|
3868
|
+
}
|
|
3869
|
+
const json4 = await res.json().catch(() => ({}));
|
|
3870
|
+
if (!res.ok || json4.success === false || json4.data === void 0) {
|
|
3871
|
+
const errObj = typeof json4.error === "object" ? json4.error : void 0;
|
|
3872
|
+
const code = json4.code ?? errObj?.code ?? (typeof json4.error === "string" ? json4.error : "unknown_error");
|
|
3873
|
+
const message = json4.message ?? errObj?.message ?? `HTTP ${res.status}`;
|
|
3874
|
+
throw new AstraSyncError(`${message} (${code})`, res.status, code);
|
|
3875
|
+
}
|
|
3876
|
+
return json4.data;
|
|
3877
|
+
}
|
|
3748
3878
|
/**
|
|
3749
3879
|
* Quick verification — checks credentials and policy in one call.
|
|
3750
3880
|
*
|
|
@@ -6709,16 +6839,30 @@ function createMcpMiddleware(options) {
|
|
|
6709
6839
|
failOnError = "closed",
|
|
6710
6840
|
toolGatePrecedence = "code",
|
|
6711
6841
|
routesRefreshMs,
|
|
6842
|
+
skipEvaluation,
|
|
6712
6843
|
...config
|
|
6713
6844
|
} = options;
|
|
6845
|
+
const skipTools = new Set(skipEvaluation?.tools ?? []);
|
|
6846
|
+
const skipMethods = new Set(skipEvaluation?.methods ?? []);
|
|
6714
6847
|
if (config.apiBaseUrl) {
|
|
6715
6848
|
prefetchWellKnown(config.apiBaseUrl).catch(() => {
|
|
6716
6849
|
});
|
|
6717
6850
|
}
|
|
6718
6851
|
const codeGatedTools = Object.entries(toolGates ?? {}).filter(([, g]) => g !== "observe").map(([name]) => name);
|
|
6852
|
+
let warnedEndpointType = false;
|
|
6853
|
+
const onEndpointType = (counterpartyType) => {
|
|
6854
|
+
if (counterpartyType === "mcp_server" || warnedEndpointType) return;
|
|
6855
|
+
warnedEndpointType = true;
|
|
6856
|
+
console.warn(
|
|
6857
|
+
`[VerificationGateway/MCP] counterpartyId ${config.counterpartyId} is a '${counterpartyType}' endpoint, not an 'mcp_server' endpoint. Dashboard tool rules are read from an mcp_server endpoint only: register a separate MCP endpoint for this server (same owner) and use its id here. See https://astrasync.ai/docs/mcp-integration#tool-rules.`
|
|
6858
|
+
);
|
|
6859
|
+
};
|
|
6719
6860
|
const rulesCache = config.apiKey && config.counterpartyId ? createRoutesCache(config, {
|
|
6720
6861
|
...routesRefreshMs !== void 0 && { refreshMs: routesRefreshMs },
|
|
6721
|
-
|
|
6862
|
+
fetchOptions: {
|
|
6863
|
+
...codeGatedTools.length && { codeGates: codeGatedTools },
|
|
6864
|
+
onEndpointType
|
|
6865
|
+
}
|
|
6722
6866
|
}) : void 0;
|
|
6723
6867
|
return async (req, res, next) => {
|
|
6724
6868
|
try {
|
|
@@ -6768,6 +6912,9 @@ function createMcpMiddleware(options) {
|
|
|
6768
6912
|
return next();
|
|
6769
6913
|
}
|
|
6770
6914
|
}
|
|
6915
|
+
if (!parsed.toolName && skipMethods.has(parsed.method) && methodGates?.[parsed.method] === void 0) {
|
|
6916
|
+
return next();
|
|
6917
|
+
}
|
|
6771
6918
|
const dashboardRules = rulesCache ? dashboardToolRules(await rulesCache.current()) : void 0;
|
|
6772
6919
|
const gateDecision = resolveGate(parsed, {
|
|
6773
6920
|
toolGates,
|
|
@@ -6775,6 +6922,9 @@ function createMcpMiddleware(options) {
|
|
|
6775
6922
|
dashboardRules,
|
|
6776
6923
|
toolGatePrecedence
|
|
6777
6924
|
});
|
|
6925
|
+
if (!gateDecision.enforce && (parsed.toolName && skipTools.has(parsed.toolName) || !parsed.toolName && skipMethods.has(parsed.method))) {
|
|
6926
|
+
return next();
|
|
6927
|
+
}
|
|
6778
6928
|
const credentials = extractCredentials(
|
|
6779
6929
|
req.headers,
|
|
6780
6930
|
req.query
|
|
@@ -6831,8 +6981,14 @@ function createMcpMiddleware(options) {
|
|
|
6831
6981
|
const forwardedFor = req.headers["x-forwarded-for"];
|
|
6832
6982
|
const forwardedForStr = Array.isArray(forwardedFor) ? forwardedFor.join(", ") : forwardedFor;
|
|
6833
6983
|
const sourceIp = req.ip ?? (forwardedForStr ? forwardedForStr.split(",")[0].trim() : void 0);
|
|
6984
|
+
const attemptRaw = readSingleHeader(req.headers["x-astra-attempt-id"]);
|
|
6985
|
+
const metaAttempt = req.body?.params?._meta?.astrasync?.attemptId;
|
|
6986
|
+
const attemptId = [attemptRaw, metaAttempt].find(
|
|
6987
|
+
(v) => typeof v === "string" && /^att_[0-9a-f]{32}$/.test(v)
|
|
6988
|
+
);
|
|
6834
6989
|
const verificationRequest = {
|
|
6835
6990
|
credentials,
|
|
6991
|
+
...attemptId && { attemptId },
|
|
6836
6992
|
purpose: pdlss.purpose,
|
|
6837
6993
|
action: pdlss.action,
|
|
6838
6994
|
resource: pdlss.resource,
|
|
@@ -6894,14 +7050,14 @@ function createMcpMiddleware(options) {
|
|
|
6894
7050
|
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
6895
7051
|
res.setHeader("X-Astra-Gateway-Reason", "evaluated-not-enforced");
|
|
6896
7052
|
}
|
|
6897
|
-
if (shouldRecordDecisions && sessionId) {
|
|
7053
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
6898
7054
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
6899
7055
|
});
|
|
6900
7056
|
}
|
|
6901
7057
|
return next();
|
|
6902
7058
|
}
|
|
6903
7059
|
if (!result.policyAllowed) {
|
|
6904
|
-
if (shouldRecordDecisions && sessionId) {
|
|
7060
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
6905
7061
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
6906
7062
|
});
|
|
6907
7063
|
}
|
|
@@ -6911,7 +7067,7 @@ function createMcpMiddleware(options) {
|
|
|
6911
7067
|
}
|
|
6912
7068
|
if (requiresHumanApproval(result)) {
|
|
6913
7069
|
annotateApprovalRequired(result);
|
|
6914
|
-
if (shouldRecordDecisions && sessionId) {
|
|
7070
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
6915
7071
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
6916
7072
|
});
|
|
6917
7073
|
}
|
|
@@ -6929,7 +7085,7 @@ function createMcpMiddleware(options) {
|
|
|
6929
7085
|
})
|
|
6930
7086
|
);
|
|
6931
7087
|
}
|
|
6932
|
-
if (shouldRecordDecisions && sessionId) {
|
|
7088
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
6933
7089
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
6934
7090
|
});
|
|
6935
7091
|
}
|
|
@@ -10938,6 +11094,16 @@ function checkUcpAgentBinding(header, identities) {
|
|
|
10938
11094
|
|
|
10939
11095
|
// src/ucp/profile.ts
|
|
10940
11096
|
var UCP_VERSION = "2026-08-25";
|
|
11097
|
+
function ucpProfileKeys(profile) {
|
|
11098
|
+
const out = [];
|
|
11099
|
+
for (const list of [profile?.keys, profile?.signing_keys]) {
|
|
11100
|
+
if (!Array.isArray(list)) continue;
|
|
11101
|
+
for (const k of list) {
|
|
11102
|
+
if (k && typeof k === "object" && k.use !== "enc") out.push(k);
|
|
11103
|
+
}
|
|
11104
|
+
}
|
|
11105
|
+
return out;
|
|
11106
|
+
}
|
|
10941
11107
|
var SPEC = `https://ucp.dev/${UCP_VERSION}/specification`;
|
|
10942
11108
|
var SCHEMAS = `https://ucp.dev/${UCP_VERSION}/schemas`;
|
|
10943
11109
|
function astrasyncPaymentHandlers(handlers, specBase = "https://astrasync.ai/ucp/handlers") {
|
|
@@ -12102,6 +12268,19 @@ var resumeResult = (outcome, session) => ({
|
|
|
12102
12268
|
});
|
|
12103
12269
|
|
|
12104
12270
|
// src/ucp/checkout-kit.ts
|
|
12271
|
+
function withValidImageUrl(item) {
|
|
12272
|
+
if (item.image_url === void 0) return item;
|
|
12273
|
+
let ok = false;
|
|
12274
|
+
try {
|
|
12275
|
+
const u = new URL(item.image_url);
|
|
12276
|
+
ok = u.protocol === "https:" || u.protocol === "http:";
|
|
12277
|
+
} catch {
|
|
12278
|
+
ok = false;
|
|
12279
|
+
}
|
|
12280
|
+
if (ok) return item;
|
|
12281
|
+
const { image_url: _drop, ...rest } = item;
|
|
12282
|
+
return rest;
|
|
12283
|
+
}
|
|
12105
12284
|
var MemoryCheckoutStore = class {
|
|
12106
12285
|
constructor() {
|
|
12107
12286
|
this.m = /* @__PURE__ */ new Map();
|
|
@@ -12385,7 +12564,8 @@ function createUcpCheckoutKit(opts) {
|
|
|
12385
12564
|
const messages = [];
|
|
12386
12565
|
for (const [i, l] of lines.entries()) {
|
|
12387
12566
|
const q = Math.max(1, Math.floor(l.quantity ?? 1));
|
|
12388
|
-
const
|
|
12567
|
+
const found = l.item?.id ? await opts.catalog(l.item.id, q) : null;
|
|
12568
|
+
const item = found && withValidImageUrl(found);
|
|
12389
12569
|
if (!item) {
|
|
12390
12570
|
messages.push(
|
|
12391
12571
|
ucpError(
|
|
@@ -12474,7 +12654,7 @@ function createUcpCheckoutKit(opts) {
|
|
|
12474
12654
|
{ method: req.method, url: req.url, headers, body: body || void 0 },
|
|
12475
12655
|
async (fresh) => {
|
|
12476
12656
|
const pp = fresh ? await fetchProfile(profileUrl, true) : plat;
|
|
12477
|
-
return "
|
|
12657
|
+
return "ucp" in pp ? ucpProfileKeys(pp) : [];
|
|
12478
12658
|
}
|
|
12479
12659
|
);
|
|
12480
12660
|
if (!sig.ok) return { error: json2(sig.status, { code: sig.code, content: sig.content }) };
|
|
@@ -12770,7 +12950,7 @@ function createUcpCheckoutKit(opts) {
|
|
|
12770
12950
|
ucpError(
|
|
12771
12951
|
`approval_${reason}`,
|
|
12772
12952
|
reason === "denied" ? "The buyer declined this purchase." : "The approval for this purchase is no longer valid. Complete the checkout again to request a new one.",
|
|
12773
|
-
"
|
|
12953
|
+
"recoverable"
|
|
12774
12954
|
)
|
|
12775
12955
|
];
|
|
12776
12956
|
await store.put(s);
|
|
@@ -12805,7 +12985,7 @@ function createUcpCheckoutKit(opts) {
|
|
|
12805
12985
|
});
|
|
12806
12986
|
if (status === "approved" || status === "consumed") {
|
|
12807
12987
|
out.push({ sessionId: s.id, outcome: (await resumeApproved(s.id)).outcome });
|
|
12808
|
-
} else if (status === "denied" || status === "expired") {
|
|
12988
|
+
} else if (status === "denied" || status === "expired" || status === "lapsed") {
|
|
12809
12989
|
out.push({ sessionId: s.id, outcome: (await resumeDeclined(s.id, status)).outcome });
|
|
12810
12990
|
} else {
|
|
12811
12991
|
out.push({ sessionId: s.id, outcome: "pending" });
|
|
@@ -12848,7 +13028,7 @@ function createUcpCheckoutKit(opts) {
|
|
|
12848
13028
|
_caller: caller,
|
|
12849
13029
|
_platformProfile: ctx.profileUrl,
|
|
12850
13030
|
_ap2: ctx.ap2,
|
|
12851
|
-
_platformKeys: ctx.plat
|
|
13031
|
+
_platformKeys: ucpProfileKeys(ctx.plat),
|
|
12852
13032
|
...typeof webhookUrl === "string" && /^https:\/\//.test(webhookUrl) && { _webhookUrl: webhookUrl },
|
|
12853
13033
|
...req.headers.get("x-astra-checkout-session") && {
|
|
12854
13034
|
_astraCheckoutSessionId: req.headers.get("x-astra-checkout-session").slice(0, 64)
|
|
@@ -13540,7 +13720,12 @@ var ACP_CODES = /* @__PURE__ */ new Set([
|
|
|
13540
13720
|
"out_of_stock",
|
|
13541
13721
|
"payment_declined",
|
|
13542
13722
|
"requires_sign_in",
|
|
13543
|
-
"requires_3ds"
|
|
13723
|
+
"requires_3ds",
|
|
13724
|
+
// 5.20.0: the owner-approval codes the kit itself emits.
|
|
13725
|
+
"approval_required",
|
|
13726
|
+
"approval_denied",
|
|
13727
|
+
"approval_expired",
|
|
13728
|
+
"approval_lapsed"
|
|
13544
13729
|
]);
|
|
13545
13730
|
function heldBody2(text) {
|
|
13546
13731
|
try {
|
|
@@ -13607,7 +13792,8 @@ function createAcpCheckoutKit(opts) {
|
|
|
13607
13792
|
const messages = [];
|
|
13608
13793
|
for (const [i, it] of items.entries()) {
|
|
13609
13794
|
const q = Math.max(1, Math.floor(it.quantity ?? 1));
|
|
13610
|
-
const
|
|
13795
|
+
const found = it.id ? await opts.catalog(it.id, q) : null;
|
|
13796
|
+
const c = found && withValidImageUrl(found);
|
|
13611
13797
|
if (!c) {
|
|
13612
13798
|
messages.push({
|
|
13613
13799
|
type: "error",
|
|
@@ -13621,7 +13807,13 @@ function createAcpCheckoutKit(opts) {
|
|
|
13621
13807
|
const amount = c.price * q;
|
|
13622
13808
|
lines.push({
|
|
13623
13809
|
id: `li_${i + 1}`,
|
|
13624
|
-
item: {
|
|
13810
|
+
item: {
|
|
13811
|
+
id: c.id,
|
|
13812
|
+
name: c.title,
|
|
13813
|
+
unit_amount: c.price,
|
|
13814
|
+
...c.image_url && { image_url: c.image_url },
|
|
13815
|
+
...typeof c.description === "string" && { description: c.description }
|
|
13816
|
+
},
|
|
13625
13817
|
quantity: q,
|
|
13626
13818
|
name: c.title,
|
|
13627
13819
|
unit_amount: c.price,
|
|
@@ -13968,7 +14160,7 @@ function createAcpCheckoutKit(opts) {
|
|
|
13968
14160
|
code: `approval_${reason}`,
|
|
13969
14161
|
content: reason === "denied" ? "The buyer declined this purchase." : "The approval for this purchase is no longer valid. Complete the session again to request a new one.",
|
|
13970
14162
|
severity: "medium",
|
|
13971
|
-
resolution: "
|
|
14163
|
+
resolution: "recoverable"
|
|
13972
14164
|
}
|
|
13973
14165
|
];
|
|
13974
14166
|
await store.put(s);
|
|
@@ -14003,7 +14195,7 @@ function createAcpCheckoutKit(opts) {
|
|
|
14003
14195
|
});
|
|
14004
14196
|
if (status === "approved" || status === "consumed") {
|
|
14005
14197
|
out.push({ sessionId: s.id, outcome: (await resumeApproved(s.id)).outcome });
|
|
14006
|
-
} else if (status === "denied" || status === "expired") {
|
|
14198
|
+
} else if (status === "denied" || status === "expired" || status === "lapsed") {
|
|
14007
14199
|
out.push({ sessionId: s.id, outcome: (await resumeDeclined(s.id, status)).outcome });
|
|
14008
14200
|
} else {
|
|
14009
14201
|
out.push({ sessionId: s.id, outcome: "pending" });
|
|
@@ -14320,6 +14512,7 @@ export {
|
|
|
14320
14512
|
isEdgeConfig,
|
|
14321
14513
|
isRejectedIdentityClaim,
|
|
14322
14514
|
isRetryableSettlementError,
|
|
14515
|
+
isSharedVerdict,
|
|
14323
14516
|
isSpecialUseIp,
|
|
14324
14517
|
isVerificationUnavailable,
|
|
14325
14518
|
isVerifiedHopValidFor,
|
|
@@ -14331,6 +14524,7 @@ export {
|
|
|
14331
14524
|
negotiateUcp,
|
|
14332
14525
|
nextjs_exports as nextjs,
|
|
14333
14526
|
normalizeDeclaredSource,
|
|
14527
|
+
onVerificationResult,
|
|
14334
14528
|
openCheckoutMandate,
|
|
14335
14529
|
openPaymentMandate,
|
|
14336
14530
|
parseYaml as parseLocalPolicyYaml,
|
|
@@ -14364,6 +14558,7 @@ export {
|
|
|
14364
14558
|
ucpEscalation,
|
|
14365
14559
|
ucpFailure,
|
|
14366
14560
|
ucpProfileHandler,
|
|
14561
|
+
ucpProfileKeys,
|
|
14367
14562
|
ucpRequiredComponents,
|
|
14368
14563
|
unavailableRetryAfterSeconds,
|
|
14369
14564
|
validatePolicy as validateLocalPolicy,
|