@astrasyncai/verification-gateway 2.4.14 → 2.5.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/dist/adapters/express.js +107 -15
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +107 -15
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +75 -53
- package/dist/adapters/mcp.d.ts +75 -53
- package/dist/adapters/mcp.js +128 -23
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +128 -23
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.js +23 -13
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +23 -13
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.js +23 -13
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +23 -13
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/browser/background.js +23 -13
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +23 -13
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cursor/extension.js +23 -13
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +23 -13
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/gateway/gateway.js +23 -13
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +23 -13
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/index.d.mts +32 -2
- package/dist/index.d.ts +32 -2
- package/dist/index.js +172 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +169 -31
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/adapters/mcp.mjs
CHANGED
|
@@ -20,6 +20,65 @@ function hasMinimumAccess(actual, required) {
|
|
|
20
20
|
// src/version.ts
|
|
21
21
|
var SDK_VERSION = "2.4.13";
|
|
22
22
|
|
|
23
|
+
// src/well-known.ts
|
|
24
|
+
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
25
|
+
var cache = /* @__PURE__ */ new Map();
|
|
26
|
+
var inflight = /* @__PURE__ */ new Map();
|
|
27
|
+
function wellKnownUrl(apiBaseUrl) {
|
|
28
|
+
const base = apiBaseUrl.replace(/\/api\/?$/, "");
|
|
29
|
+
return `${base}/.well-known/agentic-commerce`;
|
|
30
|
+
}
|
|
31
|
+
async function fetchWellKnown(apiBaseUrl) {
|
|
32
|
+
const url = wellKnownUrl(apiBaseUrl);
|
|
33
|
+
const response = await fetch(url, {
|
|
34
|
+
method: "GET",
|
|
35
|
+
headers: { Accept: "application/json" },
|
|
36
|
+
signal: AbortSignal.timeout(5e3)
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`AstraSync platform must expose /.well-known/agentic-commerce; got ${response.status} from ${url}. SDK cannot initialise without it.`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const data = await response.json();
|
|
44
|
+
if (!data.registrationUrl || !data.documentationUrl || !data.verifyAccessUrl) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`/.well-known/agentic-commerce response missing required fields (registrationUrl, documentationUrl, verifyAccessUrl).`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return data;
|
|
50
|
+
}
|
|
51
|
+
function prefetchWellKnown(apiBaseUrl) {
|
|
52
|
+
const existing = inflight.get(apiBaseUrl);
|
|
53
|
+
if (existing) return existing;
|
|
54
|
+
const promise = fetchWellKnown(apiBaseUrl).then((data) => {
|
|
55
|
+
cache.set(apiBaseUrl, { data, fetchedAt: Date.now() });
|
|
56
|
+
inflight.delete(apiBaseUrl);
|
|
57
|
+
return data;
|
|
58
|
+
}).catch((err) => {
|
|
59
|
+
inflight.delete(apiBaseUrl);
|
|
60
|
+
throw err;
|
|
61
|
+
});
|
|
62
|
+
inflight.set(apiBaseUrl, promise);
|
|
63
|
+
return promise;
|
|
64
|
+
}
|
|
65
|
+
async function getWellKnownUrls(apiBaseUrl) {
|
|
66
|
+
const entry = cache.get(apiBaseUrl);
|
|
67
|
+
if (entry) {
|
|
68
|
+
if (Date.now() - entry.fetchedAt > CACHE_TTL_MS) {
|
|
69
|
+
prefetchWellKnown(apiBaseUrl).catch(() => {
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return entry.data;
|
|
73
|
+
}
|
|
74
|
+
const pending = inflight.get(apiBaseUrl);
|
|
75
|
+
if (pending) return pending;
|
|
76
|
+
return prefetchWellKnown(apiBaseUrl);
|
|
77
|
+
}
|
|
78
|
+
function getCachedWellKnownUrls(apiBaseUrl) {
|
|
79
|
+
return cache.get(apiBaseUrl)?.data;
|
|
80
|
+
}
|
|
81
|
+
|
|
23
82
|
// src/verify.ts
|
|
24
83
|
var DEFAULT_CONFIG = {
|
|
25
84
|
apiBaseUrl: "https://astrasync.ai/api",
|
|
@@ -155,21 +214,22 @@ function extractCredentials(headers, query) {
|
|
|
155
214
|
}
|
|
156
215
|
return credentials;
|
|
157
216
|
}
|
|
158
|
-
function createGuidanceResponse(
|
|
217
|
+
function createGuidanceResponse(_config, reason, options = {}) {
|
|
159
218
|
const source = options.source ?? "no_credentials";
|
|
160
219
|
const isApiError = source === "api_error";
|
|
220
|
+
const urls = options.urls;
|
|
161
221
|
const guidance = isApiError ? {
|
|
162
222
|
message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
|
|
163
|
-
registrationUrl:
|
|
164
|
-
documentationUrl:
|
|
223
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
224
|
+
documentationUrl: urls?.documentationUrl ?? "",
|
|
165
225
|
steps: [
|
|
166
226
|
"Retry the request with exponential backoff",
|
|
167
227
|
"If failures persist, share the correlationId with support"
|
|
168
228
|
]
|
|
169
229
|
} : {
|
|
170
230
|
message: "This service verifies AI agents before granting access. Please register your agent with AstraSync.",
|
|
171
|
-
registrationUrl:
|
|
172
|
-
documentationUrl:
|
|
231
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
232
|
+
documentationUrl: urls?.documentationUrl ?? "",
|
|
173
233
|
steps: [
|
|
174
234
|
"Register for an AstraSync account",
|
|
175
235
|
"Create and register your agent",
|
|
@@ -211,7 +271,7 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
211
271
|
const { credentials, ...requestData } = request;
|
|
212
272
|
const body = {
|
|
213
273
|
...credentials.astraId && { agentId: credentials.astraId },
|
|
214
|
-
purpose: requestData.purpose
|
|
274
|
+
...requestData.purpose && { purpose: requestData.purpose }
|
|
215
275
|
};
|
|
216
276
|
if (requestData.action) body.action = requestData.action;
|
|
217
277
|
if (requestData.resourceType) body.resourceType = requestData.resourceType;
|
|
@@ -291,6 +351,7 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
291
351
|
}
|
|
292
352
|
async function verify(config, request) {
|
|
293
353
|
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
354
|
+
const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
|
|
294
355
|
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
295
356
|
if (mergedConfig.strictInit) {
|
|
296
357
|
await performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, true);
|
|
@@ -327,7 +388,8 @@ async function verify(config, request) {
|
|
|
327
388
|
if (!apiResponse.success) {
|
|
328
389
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
329
390
|
source: "api_error",
|
|
330
|
-
correlationId: apiResponse.correlationId
|
|
391
|
+
correlationId: apiResponse.correlationId,
|
|
392
|
+
urls
|
|
331
393
|
});
|
|
332
394
|
}
|
|
333
395
|
if (!apiResponse.access?.allowed) {
|
|
@@ -350,8 +412,8 @@ async function verify(config, request) {
|
|
|
350
412
|
requiresApproval: apiResponse.access?.requiresApproval,
|
|
351
413
|
guidance: {
|
|
352
414
|
message: apiResponse.access?.reason || "Access denied by PDLSS policy",
|
|
353
|
-
registrationUrl:
|
|
354
|
-
documentationUrl:
|
|
415
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
416
|
+
documentationUrl: urls?.documentationUrl ?? ""
|
|
355
417
|
},
|
|
356
418
|
verifiedAt: /* @__PURE__ */ new Date(),
|
|
357
419
|
// Extract sessionId so decisions can be recorded for denials too
|
|
@@ -422,12 +484,12 @@ async function verify(config, request) {
|
|
|
422
484
|
];
|
|
423
485
|
result.guidance = result.runtimeChallenge ? {
|
|
424
486
|
message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
|
|
425
|
-
registrationUrl:
|
|
426
|
-
documentationUrl:
|
|
487
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
488
|
+
documentationUrl: urls?.documentationUrl ?? ""
|
|
427
489
|
} : {
|
|
428
490
|
message: result.recommendationReasons?.[0] || "Access denied by AstraSync recommendation",
|
|
429
|
-
registrationUrl:
|
|
430
|
-
documentationUrl:
|
|
491
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
492
|
+
documentationUrl: urls?.documentationUrl ?? ""
|
|
431
493
|
};
|
|
432
494
|
} else if (result.recommendation === "step_up_required") {
|
|
433
495
|
result.requiresStepUp = true;
|
|
@@ -563,19 +625,22 @@ function extractFromMcpBody(astrasyncMeta, args, key) {
|
|
|
563
625
|
}
|
|
564
626
|
return { value: void 0, source: void 0 };
|
|
565
627
|
}
|
|
566
|
-
function mcpToPdlss(parsed, headerPurpose, headerAction) {
|
|
567
|
-
const resource =
|
|
628
|
+
function mcpToPdlss(parsed, requestPath, headerPurpose, headerAction, toolGate) {
|
|
629
|
+
const resource = toolGate?.resource ?? requestPath;
|
|
568
630
|
let purpose;
|
|
569
631
|
let purposeSource;
|
|
570
|
-
if (
|
|
632
|
+
if (toolGate?.purpose !== void 0) {
|
|
633
|
+
purpose = toolGate.purpose;
|
|
634
|
+
purposeSource = "tool_gate";
|
|
635
|
+
} else if (headerPurpose) {
|
|
571
636
|
purpose = headerPurpose;
|
|
572
637
|
purposeSource = "header";
|
|
573
638
|
} else if (parsed.purposeFromBody && parsed.purposeSourceFromBody) {
|
|
574
639
|
purpose = parsed.purposeFromBody;
|
|
575
640
|
purposeSource = parsed.purposeSourceFromBody;
|
|
576
641
|
} else {
|
|
577
|
-
purpose =
|
|
578
|
-
purposeSource =
|
|
642
|
+
purpose = void 0;
|
|
643
|
+
purposeSource = void 0;
|
|
579
644
|
}
|
|
580
645
|
let action;
|
|
581
646
|
let actionSource;
|
|
@@ -600,6 +665,9 @@ function mcpRiskTier(parsed) {
|
|
|
600
665
|
}
|
|
601
666
|
|
|
602
667
|
// src/adapters/mcp.ts
|
|
668
|
+
function normalizeToolGate(gate) {
|
|
669
|
+
return typeof gate === "string" ? { minAccessLevel: gate } : gate;
|
|
670
|
+
}
|
|
603
671
|
function readSingleHeader(value) {
|
|
604
672
|
if (typeof value === "string") return value;
|
|
605
673
|
if (Array.isArray(value)) return value[0];
|
|
@@ -615,6 +683,9 @@ function dedupeFailures(result) {
|
|
|
615
683
|
return true;
|
|
616
684
|
});
|
|
617
685
|
}
|
|
686
|
+
if (result.denialReasons && result.denialReasons.length > 1) {
|
|
687
|
+
result.denialReasons = [...new Set(result.denialReasons)];
|
|
688
|
+
}
|
|
618
689
|
}
|
|
619
690
|
function defaultMcpDenied(result, req, res) {
|
|
620
691
|
const id = req.body?.id ?? null;
|
|
@@ -640,11 +711,17 @@ function defaultMcpDenied(result, req, res) {
|
|
|
640
711
|
});
|
|
641
712
|
}
|
|
642
713
|
function resolveMinAccessLevel(parsed, opts) {
|
|
643
|
-
if (parsed.toolName
|
|
644
|
-
|
|
714
|
+
if (!parsed.toolName) {
|
|
715
|
+
if (opts.methodGates && opts.methodGates[parsed.method] !== void 0) {
|
|
716
|
+
return { level: opts.methodGates[parsed.method], source: "methodGate" };
|
|
717
|
+
}
|
|
718
|
+
return { level: "none", source: "discovery_default" };
|
|
645
719
|
}
|
|
646
|
-
if (opts.
|
|
647
|
-
return {
|
|
720
|
+
if (opts.toolGates && opts.toolGates[parsed.toolName] !== void 0) {
|
|
721
|
+
return {
|
|
722
|
+
level: normalizeToolGate(opts.toolGates[parsed.toolName]).minAccessLevel,
|
|
723
|
+
source: "toolGate"
|
|
724
|
+
};
|
|
648
725
|
}
|
|
649
726
|
return { level: mcpRiskTier(parsed), source: "tier" };
|
|
650
727
|
}
|
|
@@ -662,6 +739,10 @@ function createMcpMiddleware(options) {
|
|
|
662
739
|
failOnError = "open",
|
|
663
740
|
...config
|
|
664
741
|
} = options;
|
|
742
|
+
if (config.apiBaseUrl) {
|
|
743
|
+
prefetchWellKnown(config.apiBaseUrl).catch(() => {
|
|
744
|
+
});
|
|
745
|
+
}
|
|
665
746
|
return async (req, res, next) => {
|
|
666
747
|
try {
|
|
667
748
|
if (skip) return next();
|
|
@@ -674,6 +755,7 @@ function createMcpMiddleware(options) {
|
|
|
674
755
|
return next();
|
|
675
756
|
}
|
|
676
757
|
req.mcpRequest = parsed;
|
|
758
|
+
const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
|
|
677
759
|
const headerRaw = req.headers["x-astra-id"] ?? req.headers["x-astra-agentid"];
|
|
678
760
|
const headerAstraId = typeof headerRaw === "string" ? headerRaw : Array.isArray(headerRaw) ? headerRaw[0] : void 0;
|
|
679
761
|
const bodyAstraId = parsed.agentIdFromBody;
|
|
@@ -727,9 +809,17 @@ function createMcpMiddleware(options) {
|
|
|
727
809
|
}
|
|
728
810
|
return next();
|
|
729
811
|
}
|
|
812
|
+
const rawGate = parsed.toolName && toolGates?.[parsed.toolName];
|
|
813
|
+
const gate = rawGate ? normalizeToolGate(rawGate) : void 0;
|
|
730
814
|
const headerPurpose = readSingleHeader(req.headers["x-astra-purpose"]);
|
|
731
815
|
const headerAction = readSingleHeader(req.headers["x-astra-action"]);
|
|
732
|
-
const pdlss = mcpToPdlss(
|
|
816
|
+
const pdlss = mcpToPdlss(
|
|
817
|
+
parsed,
|
|
818
|
+
req.path,
|
|
819
|
+
headerPurpose,
|
|
820
|
+
headerAction,
|
|
821
|
+
gate ? { purpose: gate.purpose, resource: gate.resource } : void 0
|
|
822
|
+
);
|
|
733
823
|
if (config.debug) {
|
|
734
824
|
console.debug("[mcp-middleware] pdlss resolved", {
|
|
735
825
|
purpose_source: pdlss.purposeSource,
|
|
@@ -790,6 +880,13 @@ function createMcpMiddleware(options) {
|
|
|
790
880
|
};
|
|
791
881
|
result.failures = [...result.failures ?? [], insufficientFailure];
|
|
792
882
|
result.denialReasons = [...result.denialReasons ?? [], insufficientFailure.message];
|
|
883
|
+
if (!result.guidance && wellKnownUrls) {
|
|
884
|
+
result.guidance = {
|
|
885
|
+
message: insufficientFailure.message,
|
|
886
|
+
registrationUrl: wellKnownUrls.registrationUrl,
|
|
887
|
+
documentationUrl: wellKnownUrls.documentationUrl
|
|
888
|
+
};
|
|
889
|
+
}
|
|
793
890
|
if (shouldRecordDecisions) {
|
|
794
891
|
const overrideKind = gateSource === "toolGate" ? "toolGate" : gateSource === "methodGate" ? "methodGate" : "other";
|
|
795
892
|
const override = {
|
|
@@ -858,6 +955,14 @@ function createMcpMiddleware(options) {
|
|
|
858
955
|
verifiedAt: /* @__PURE__ */ new Date(),
|
|
859
956
|
correlationId
|
|
860
957
|
};
|
|
958
|
+
const catchUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
|
|
959
|
+
if (catchUrls) {
|
|
960
|
+
result.guidance = {
|
|
961
|
+
message: `Middleware threw ${errorClass} \u2014 failing closed`,
|
|
962
|
+
registrationUrl: catchUrls.registrationUrl,
|
|
963
|
+
documentationUrl: catchUrls.documentationUrl
|
|
964
|
+
};
|
|
965
|
+
}
|
|
861
966
|
dedupeFailures(result);
|
|
862
967
|
return onDenied(result, req, res);
|
|
863
968
|
}
|