@absol-labs/agent 0.10.0 → 0.11.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/README.md +107 -23
- package/dist/capability/invocation-capability.d.ts +18 -6
- package/dist/capability/invocation-capability.d.ts.map +1 -1
- package/dist/capability/invocation-capability.js.map +1 -1
- package/dist/cli/commands/claim.d.ts.map +1 -1
- package/dist/cli/commands/claim.js +20 -4
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.d.ts.map +1 -1
- package/dist/cli/commands/close.js +16 -4
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/invoke.d.ts.map +1 -1
- package/dist/cli/commands/invoke.js +1 -0
- package/dist/cli/commands/invoke.js.map +1 -1
- package/dist/cli/commands/open.d.ts.map +1 -1
- package/dist/cli/commands/open.js +63 -11
- package/dist/cli/commands/open.js.map +1 -1
- package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -1
- package/dist/cli/commands/reclaim-unverified.js +12 -4
- package/dist/cli/commands/reclaim-unverified.js.map +1 -1
- package/dist/cli/commands/reclaim.d.ts.map +1 -1
- package/dist/cli/commands/reclaim.js +16 -5
- package/dist/cli/commands/reclaim.js.map +1 -1
- package/dist/cli/commands/streams.js +1 -1
- package/dist/cli/commands/streams.js.map +1 -1
- package/dist/cli/deps.d.ts +53 -7
- package/dist/cli/deps.d.ts.map +1 -1
- package/dist/cli/deps.js +65 -15
- package/dist/cli/deps.js.map +1 -1
- package/dist/cli/privy.d.ts +83 -0
- package/dist/cli/privy.d.ts.map +1 -0
- package/dist/cli/privy.js +230 -0
- package/dist/cli/privy.js.map +1 -0
- package/dist/cli/spend-policy.d.ts +60 -0
- package/dist/cli/spend-policy.d.ts.map +1 -0
- package/dist/cli/spend-policy.js +65 -0
- package/dist/cli/spend-policy.js.map +1 -0
- package/dist/cli/wallet.d.ts +108 -39
- package/dist/cli/wallet.d.ts.map +1 -1
- package/dist/cli/wallet.js +108 -43
- package/dist/cli/wallet.js.map +1 -1
- package/dist/gateway/caller-auth-gateway.d.ts +38 -3
- package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
- package/dist/gateway/caller-auth-gateway.js +25 -1
- package/dist/gateway/caller-auth-gateway.js.map +1 -1
- package/dist/gateway/http-server.d.ts +53 -0
- package/dist/gateway/http-server.d.ts.map +1 -1
- package/dist/gateway/http-server.js +189 -4
- package/dist/gateway/http-server.js.map +1 -1
- package/dist/gateway/x402-mode.d.ts +123 -0
- package/dist/gateway/x402-mode.d.ts.map +1 -0
- package/dist/gateway/x402-mode.js +212 -0
- package/dist/gateway/x402-mode.js.map +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/mandates/env.d.ts +3 -2
- package/dist/mandates/env.d.ts.map +1 -1
- package/dist/mandates/env.js +3 -2
- package/dist/mandates/env.js.map +1 -1
- package/dist/mcp/server.d.ts +49 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +513 -24
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/service-invoker.d.ts +97 -0
- package/dist/mcp/service-invoker.d.ts.map +1 -0
- package/dist/mcp/service-invoker.js +167 -0
- package/dist/mcp/service-invoker.js.map +1 -0
- package/dist/sdk/invoke.d.ts +19 -4
- package/dist/sdk/invoke.d.ts.map +1 -1
- package/dist/sdk/invoke.js +69 -5
- package/dist/sdk/invoke.js.map +1 -1
- package/dist/x402/delivery-oracle.d.ts +108 -0
- package/dist/x402/delivery-oracle.d.ts.map +1 -0
- package/dist/x402/delivery-oracle.js +174 -0
- package/dist/x402/delivery-oracle.js.map +1 -0
- package/dist/x402/facilitator-server-entry.d.ts +3 -0
- package/dist/x402/facilitator-server-entry.d.ts.map +1 -0
- package/dist/x402/facilitator-server-entry.js +27 -0
- package/dist/x402/facilitator-server-entry.js.map +1 -0
- package/dist/x402/facilitator-server.d.ts +73 -0
- package/dist/x402/facilitator-server.d.ts.map +1 -0
- package/dist/x402/facilitator-server.js +305 -0
- package/dist/x402/facilitator-server.js.map +1 -0
- package/dist/x402/facilitator.d.ts +69 -17
- package/dist/x402/facilitator.d.ts.map +1 -1
- package/dist/x402/facilitator.js +76 -33
- package/dist/x402/facilitator.js.map +1 -1
- package/dist/x402/payment-requirements.d.ts +106 -0
- package/dist/x402/payment-requirements.d.ts.map +1 -0
- package/dist/x402/payment-requirements.js +138 -0
- package/dist/x402/payment-requirements.js.map +1 -0
- package/dist/x402/relayer.d.ts +41 -0
- package/dist/x402/relayer.d.ts.map +1 -0
- package/dist/x402/relayer.js +64 -0
- package/dist/x402/relayer.js.map +1 -0
- package/dist/x402/resource-index.d.ts +75 -0
- package/dist/x402/resource-index.d.ts.map +1 -0
- package/dist/x402/resource-index.js +126 -0
- package/dist/x402/resource-index.js.map +1 -0
- package/dist/x402/verified-delivery-facilitator.d.ts +285 -0
- package/dist/x402/verified-delivery-facilitator.d.ts.map +1 -0
- package/dist/x402/verified-delivery-facilitator.js +423 -0
- package/dist/x402/verified-delivery-facilitator.js.map +1 -0
- package/dist/zktls/t2-delivery-proof.d.ts +6 -6
- package/docs/agent-layer.md +12 -8
- package/docs/cli.md +158 -22
- package/docs/mcp-hosted.md +4 -3
- package/docs/mcp-reference.md +175 -0
- package/docs/quickstart.md +18 -4
- package/docs/threat-model.md +4 -3
- package/docs/x402.md +648 -0
- package/package.json +18 -7
- package/src/capability/invocation-capability.ts +17 -1
- package/src/cli/commands/claim.ts +30 -4
- package/src/cli/commands/close.ts +20 -4
- package/src/cli/commands/invoke.ts +1 -0
- package/src/cli/commands/open.ts +76 -10
- package/src/cli/commands/reclaim-unverified.ts +16 -4
- package/src/cli/commands/reclaim.ts +22 -5
- package/src/cli/commands/streams.ts +1 -1
- package/src/cli/deps.ts +115 -24
- package/src/cli/privy.ts +396 -0
- package/src/cli/spend-policy.ts +139 -0
- package/src/cli/wallet.ts +188 -57
- package/src/gateway/caller-auth-gateway.ts +77 -6
- package/src/gateway/http-server.ts +280 -6
- package/src/gateway/x402-mode.ts +350 -0
- package/src/index.ts +40 -5
- package/src/mandates/env.ts +3 -2
- package/src/mcp/server.ts +681 -29
- package/src/mcp/service-invoker.ts +285 -0
- package/src/sdk/invoke.ts +90 -12
- package/src/x402/delivery-oracle.ts +285 -0
- package/src/x402/facilitator-server-entry.ts +35 -0
- package/src/x402/facilitator-server.ts +445 -0
- package/src/x402/facilitator.ts +125 -46
- package/src/x402/payment-requirements.ts +231 -0
- package/src/x402/relayer.ts +122 -0
- package/src/x402/resource-index.ts +228 -0
- package/src/x402/verified-delivery-facilitator.ts +744 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relayer.js","sourceRoot":"","sources":["../../src/x402/relayer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,IAAI,EACJ,aAAa,GAGd,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAa9E;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAoC,MAAM,CAAC,MAAM,CAAC;IACxE,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,WAAW;CACnB,CAAC,CAAC;AASH,SAAS,QAAQ,CAAC,OAAe;IAC/B,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAAyB;IAEzB,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,kBAAkB,CAAC;QAChC,KAAK;QACL,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;KAChC,CAAC,CAAC;IACH,OAAO;QACL,MAAM,CACJ,OAAuB,EACvB,YAAiC;YAEjC,OAAO,UAAU,CACf,MAA0C,EAC1C,OAAO,EACP,YAAY,CACb,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAYD;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAA2B;IAE3B,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,kBAAkB,CAAC;QAChC,OAAO;QACP,KAAK;QACL,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;KAChC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACzB,OAAO;QACL,MAAM,CACJ,OAAuB,EACvB,YAAiC;YAEjC,OAAO,UAAU,CACf,MAA0C,EAC1C,OAAO,EACP,YAAY,CACb,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,UAAe;IAC5C,OAAO,mBAAmB,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type DiscoverServicesOptions, type ServiceListing } from "../discovery/registry.js";
|
|
2
|
+
import type { SignedListingPayee } from "./payment-requirements.js";
|
|
3
|
+
/**
|
|
4
|
+
* Maps an x402 `PaymentRequirements.resource` URL onto the Metrik listing that
|
|
5
|
+
* serves it — the step that decides whether Metrik has any business having an
|
|
6
|
+
* opinion about a payment at all.
|
|
7
|
+
*
|
|
8
|
+
* ## Derived, never supplied
|
|
9
|
+
*
|
|
10
|
+
* The only thing taken from the request is the `resource` URL itself, because
|
|
11
|
+
* the x402 wire format gives the facilitator nothing else to key on. Everything
|
|
12
|
+
* the verdict is actually computed from — which listing that URL belongs to, the
|
|
13
|
+
* operator address on it, and the delivery record for it — is resolved HERE,
|
|
14
|
+
* from Metrik's own verified view of the registry. In particular the
|
|
15
|
+
* `extra.metrikServiceRef` hint that `buildMetrikPaymentRequirements` publishes
|
|
16
|
+
* is deliberately ignored: it rides inside a caller-supplied body, and reading
|
|
17
|
+
* it would let a caller choose which service's delivery record gets checked.
|
|
18
|
+
*
|
|
19
|
+
* ## Origin matching, and why not path matching
|
|
20
|
+
*
|
|
21
|
+
* A listing owns an ORIGIN (scheme + host + port). Matching on origin means a
|
|
22
|
+
* seller does not have to re-register every route, and it cannot over-reach: two
|
|
23
|
+
* listings never share an origin, because the origin is what the oracle probes
|
|
24
|
+
* and what `serviceRef` is derived from. A resource whose origin matches no
|
|
25
|
+
* listing is simply not ours.
|
|
26
|
+
*/
|
|
27
|
+
export interface ResolvedMetrikResource extends SignedListingPayee {
|
|
28
|
+
/** The listing, as verified by `discoverServices` (EIP-712 signer recovered). */
|
|
29
|
+
readonly listing: ServiceListing;
|
|
30
|
+
/** Which of the listing's signed origins the resource matched. */
|
|
31
|
+
readonly matchedOrigin: string;
|
|
32
|
+
}
|
|
33
|
+
export type ResourceIndexStatus = "resolved" | "not-listed"
|
|
34
|
+
/**
|
|
35
|
+
* Two or more signed listings claim this origin, so there is no single right
|
|
36
|
+
* answer about whose delivery record applies.
|
|
37
|
+
*
|
|
38
|
+
* Picking one — which "first claimant wins" did — is the origin-squatting
|
|
39
|
+
* primitive: a second listing claiming a victim's origin could take over the
|
|
40
|
+
* victim's gate and permanently refuse their payments. Not exploitable while
|
|
41
|
+
* listing insertion requires an operator-held key, but "unresolvable" costs
|
|
42
|
+
* nothing and removes the primitive before registration ever opens.
|
|
43
|
+
*/
|
|
44
|
+
| "ambiguous" | "registry-unavailable";
|
|
45
|
+
export interface ResourceLookup {
|
|
46
|
+
readonly status: ResourceIndexStatus;
|
|
47
|
+
readonly resource?: ResolvedMetrikResource;
|
|
48
|
+
}
|
|
49
|
+
export interface MetrikResourceIndex {
|
|
50
|
+
/** Never throws: an unreachable registry is a status, not an exception. */
|
|
51
|
+
lookup(resourceUrl: string): Promise<ResourceLookup>;
|
|
52
|
+
}
|
|
53
|
+
/** How long a registry snapshot is reused before a refresh is attempted. */
|
|
54
|
+
export declare const DEFAULT_RESOURCE_INDEX_REFRESH_MS = 60000;
|
|
55
|
+
/**
|
|
56
|
+
* How long a stale snapshot keeps being served after refreshes start failing.
|
|
57
|
+
* Serving a stale listing is safe in a way that serving a stale DELIVERY verdict
|
|
58
|
+
* is not: listings change on a human timescale (a new signed descriptor), and
|
|
59
|
+
* the fields used from them — `operator`, `serviceRef` — are the stable ones. The
|
|
60
|
+
* live verdict is always fetched fresh by the delivery oracle.
|
|
61
|
+
*/
|
|
62
|
+
export declare const DEFAULT_RESOURCE_INDEX_MAX_STALE_MS: number;
|
|
63
|
+
export interface RegistryResourceIndexOptions {
|
|
64
|
+
readonly discover?: () => Promise<readonly ServiceListing[]>;
|
|
65
|
+
readonly discoverOptions?: DiscoverServicesOptions;
|
|
66
|
+
readonly refreshMs?: number;
|
|
67
|
+
readonly maxStaleMs?: number;
|
|
68
|
+
readonly now?: () => number;
|
|
69
|
+
}
|
|
70
|
+
export declare function createRegistryResourceIndex(options?: RegistryResourceIndexOptions): MetrikResourceIndex;
|
|
71
|
+
/** Every origin the SIGNED record claims for a listing. */
|
|
72
|
+
export declare function signedOriginsOf(listing: ServiceListing): readonly string[];
|
|
73
|
+
/** Normalized `scheme://host[:port]`, or `undefined` if not a usable URL. */
|
|
74
|
+
export declare function originOf(url: string): string | undefined;
|
|
75
|
+
//# sourceMappingURL=resource-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-index.d.ts","sourceRoot":"","sources":["../../src/x402/resource-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;IAChE,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,kEAAkE;IAClE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,YAAY;AACd;;;;;;;;;GASG;GACD,WAAW,GACX,sBAAsB,CAAC;AAE3B,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACtD;AAED,4EAA4E;AAC5E,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAc,CAAC;AAE/D,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAC;IAC7D,QAAQ,CAAC,eAAe,CAAC,EAAE,uBAAuB,CAAC;IACnD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,4BAAiC,GACzC,mBAAmB,CA+FrB;AAED,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,MAAM,EAAE,CA6B1E;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUxD"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { discoverServices, } from "../discovery/registry.js";
|
|
2
|
+
/** How long a registry snapshot is reused before a refresh is attempted. */
|
|
3
|
+
export const DEFAULT_RESOURCE_INDEX_REFRESH_MS = 60_000;
|
|
4
|
+
/**
|
|
5
|
+
* How long a stale snapshot keeps being served after refreshes start failing.
|
|
6
|
+
* Serving a stale listing is safe in a way that serving a stale DELIVERY verdict
|
|
7
|
+
* is not: listings change on a human timescale (a new signed descriptor), and
|
|
8
|
+
* the fields used from them — `operator`, `serviceRef` — are the stable ones. The
|
|
9
|
+
* live verdict is always fetched fresh by the delivery oracle.
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_RESOURCE_INDEX_MAX_STALE_MS = 15 * 60_000;
|
|
12
|
+
export function createRegistryResourceIndex(options = {}) {
|
|
13
|
+
const refreshMs = options.refreshMs ?? DEFAULT_RESOURCE_INDEX_REFRESH_MS;
|
|
14
|
+
const maxStaleMs = options.maxStaleMs ?? DEFAULT_RESOURCE_INDEX_MAX_STALE_MS;
|
|
15
|
+
const now = options.now ?? (() => Date.now());
|
|
16
|
+
const discover = options.discover ??
|
|
17
|
+
(() => discoverServices(options.discoverOptions ?? {}));
|
|
18
|
+
let snapshot;
|
|
19
|
+
let inFlight;
|
|
20
|
+
async function refresh() {
|
|
21
|
+
try {
|
|
22
|
+
const listings = await discover();
|
|
23
|
+
const byOrigin = new Map();
|
|
24
|
+
const ambiguous = new Set();
|
|
25
|
+
for (const listing of listings) {
|
|
26
|
+
for (const origin of signedOriginsOf(listing)) {
|
|
27
|
+
const claimed = byOrigin.get(origin);
|
|
28
|
+
if (claimed === undefined) {
|
|
29
|
+
byOrigin.set(origin, {
|
|
30
|
+
serviceRef: listing.serviceRef,
|
|
31
|
+
operator: listing.operator,
|
|
32
|
+
listing,
|
|
33
|
+
matchedOrigin: origin,
|
|
34
|
+
});
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// A DIFFERENT service claiming an origin another already claims makes
|
|
38
|
+
// the origin unresolvable, not first-come-first-served. See the
|
|
39
|
+
// `ambiguous` doc on `ResourceIndexStatus`. A listing re-claiming its
|
|
40
|
+
// OWN origin (e.g. publicUrl and baseUrl agreeing) is not a conflict.
|
|
41
|
+
if (claimed.serviceRef.toLowerCase() !==
|
|
42
|
+
listing.serviceRef.toLowerCase()) {
|
|
43
|
+
ambiguous.add(origin);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
for (const origin of ambiguous) {
|
|
48
|
+
byOrigin.delete(origin);
|
|
49
|
+
}
|
|
50
|
+
return { loadedAtMs: now(), byOrigin, ambiguous };
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function currentSnapshot() {
|
|
57
|
+
const cached = snapshot;
|
|
58
|
+
if (cached !== undefined && now() - cached.loadedAtMs < refreshMs) {
|
|
59
|
+
return cached;
|
|
60
|
+
}
|
|
61
|
+
inFlight ??= refresh().finally(() => {
|
|
62
|
+
inFlight = undefined;
|
|
63
|
+
});
|
|
64
|
+
const loaded = await inFlight;
|
|
65
|
+
if (loaded !== undefined) {
|
|
66
|
+
snapshot = loaded;
|
|
67
|
+
return loaded;
|
|
68
|
+
}
|
|
69
|
+
if (cached !== undefined && now() - cached.loadedAtMs <= maxStaleMs) {
|
|
70
|
+
return cached;
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
async lookup(resourceUrl) {
|
|
76
|
+
const origin = originOf(resourceUrl);
|
|
77
|
+
if (origin === undefined) {
|
|
78
|
+
return { status: "not-listed" };
|
|
79
|
+
}
|
|
80
|
+
const loaded = await currentSnapshot();
|
|
81
|
+
if (loaded === undefined) {
|
|
82
|
+
return { status: "registry-unavailable" };
|
|
83
|
+
}
|
|
84
|
+
if (loaded.ambiguous.has(origin)) {
|
|
85
|
+
return { status: "ambiguous" };
|
|
86
|
+
}
|
|
87
|
+
const resource = loaded.byOrigin.get(origin);
|
|
88
|
+
return resource === undefined
|
|
89
|
+
? { status: "not-listed" }
|
|
90
|
+
: { status: "resolved", resource };
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** Every origin the SIGNED record claims for a listing. */
|
|
95
|
+
export function signedOriginsOf(listing) {
|
|
96
|
+
const candidates = [
|
|
97
|
+
listing.publicUrl,
|
|
98
|
+
listing.accessUrl,
|
|
99
|
+
];
|
|
100
|
+
const descriptor = listing.signed.descriptor;
|
|
101
|
+
if (descriptor !== undefined) {
|
|
102
|
+
candidates.push(descriptor.publicUrl, descriptor.interface?.baseUrl, descriptor.callerAuth?.accessUrl);
|
|
103
|
+
}
|
|
104
|
+
const origins = new Set();
|
|
105
|
+
for (const candidate of candidates) {
|
|
106
|
+
const origin = candidate === undefined ? undefined : originOf(candidate);
|
|
107
|
+
if (origin !== undefined) {
|
|
108
|
+
origins.add(origin);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return [...origins];
|
|
112
|
+
}
|
|
113
|
+
/** Normalized `scheme://host[:port]`, or `undefined` if not a usable URL. */
|
|
114
|
+
export function originOf(url) {
|
|
115
|
+
try {
|
|
116
|
+
const parsed = new URL(url);
|
|
117
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return `${parsed.protocol}//${parsed.host.toLowerCase()}`;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=resource-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-index.js","sourceRoot":"","sources":["../../src/x402/resource-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { type PaymentPayload, type PaymentRequirements, type SettleResponse, type VerifyResponse } from "x402/types";
|
|
2
|
+
import type { DeliveryVerdict, DeliveryVerdictReason, MetrikDeliveryOracle } from "./delivery-oracle.js";
|
|
3
|
+
import type { MetrikResourceIndex } from "./resource-index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Metrik's x402 facilitator: a fully conformant `exact` facilitator that ALSO
|
|
6
|
+
* refuses to settle payment for a service its own oracle says is not delivering.
|
|
7
|
+
*
|
|
8
|
+
* ## Why this is spec-legal
|
|
9
|
+
*
|
|
10
|
+
* `VerifyResponse` is `{ isValid: boolean, invalidReason?, payer? }`. Nothing in
|
|
11
|
+
* the x402 specification constrains WHY a facilitator answers `false`. A
|
|
12
|
+
* facilitator is the party a resource server delegates its "should this payment
|
|
13
|
+
* go through" decision to; Metrik simply knows one more thing than every other
|
|
14
|
+
* facilitator, because it runs a prober.
|
|
15
|
+
*
|
|
16
|
+
* ## What this is NOT
|
|
17
|
+
*
|
|
18
|
+
* **This is strictly weaker buyer protection than a Metrik escrow stream.** A
|
|
19
|
+
* stream holds the buyer's money and releases it only for intervals that
|
|
20
|
+
* verified, so money already spent on a service that stopped delivering is
|
|
21
|
+
* recoverable. This gate holds nothing. It can only prevent a payment that has
|
|
22
|
+
* not happened yet; it can never recover one that has. An `exact` payment that
|
|
23
|
+
* Metrik lets through is gone, exactly as it would be through any other
|
|
24
|
+
* facilitator.
|
|
25
|
+
*
|
|
26
|
+
* And `isValid: true` from this facilitator is NOT an endorsement. It means only
|
|
27
|
+
* "the payment is well-formed and Metrik has no fresh evidence that this service
|
|
28
|
+
* is failing". The gate subtracts; it never adds.
|
|
29
|
+
*
|
|
30
|
+
* ## Scope: only services Metrik actually tracks
|
|
31
|
+
*
|
|
32
|
+
* A resource that maps to no Metrik listing gets the ordinary facilitator
|
|
33
|
+
* answer, unchanged. Refusing payments for services Metrik has no opinion about
|
|
34
|
+
* would not be caution, it would be a broken facilitator.
|
|
35
|
+
*/
|
|
36
|
+
/** What the delivery gate did to a payment. */
|
|
37
|
+
export type MetrikGateOutcome =
|
|
38
|
+
/** The resource is not a Metrik listing — ordinary facilitator behaviour. */
|
|
39
|
+
"not-applicable"
|
|
40
|
+
/** Fresh evidence the service is delivering; payment allowed to proceed. */
|
|
41
|
+
| "passed"
|
|
42
|
+
/** Fresh evidence the service is failing; payment refused. */
|
|
43
|
+
| "refused"
|
|
44
|
+
/** No fresh evidence; `indeterminatePolicy` decided. */
|
|
45
|
+
| "indeterminate"
|
|
46
|
+
/** The resource's payee is not the operator who signed the listing. */
|
|
47
|
+
| "payee-mismatch"
|
|
48
|
+
/** Metrik could not tell whether the resource is one of its listings. */
|
|
49
|
+
| "registry-unavailable";
|
|
50
|
+
/** The delivery gate's own verdict, before settlement policy is applied. */
|
|
51
|
+
export interface MetrikGateVerdict {
|
|
52
|
+
readonly gate: MetrikGateOutcome;
|
|
53
|
+
/** Human-readable explanation. See "Where the explanation goes" below. */
|
|
54
|
+
readonly detail: string;
|
|
55
|
+
readonly serviceRef?: string;
|
|
56
|
+
readonly deliveryVerdict?: DeliveryVerdict;
|
|
57
|
+
readonly deliveryReason?: DeliveryVerdictReason;
|
|
58
|
+
readonly lastCheckedAt?: number | null;
|
|
59
|
+
readonly verdictAgeSeconds?: number | null;
|
|
60
|
+
readonly freshnessWindowSeconds?: number;
|
|
61
|
+
}
|
|
62
|
+
export interface MetrikGateAnnotation extends MetrikGateVerdict {
|
|
63
|
+
/**
|
|
64
|
+
* Whether THIS facilitator would broadcast this payment if asked.
|
|
65
|
+
*
|
|
66
|
+
* Distinct from `isValid`, and deliberately reported on `/verify`: a payment
|
|
67
|
+
* can be perfectly valid and still be one this relayer will not spend its own
|
|
68
|
+
* gas on (see {@link SettlementRefusalReason}). Reporting it up front lets a
|
|
69
|
+
* resource server refuse BEFORE it executes the request, instead of doing the
|
|
70
|
+
* work and then failing to get paid for it.
|
|
71
|
+
*/
|
|
72
|
+
readonly settleable: boolean;
|
|
73
|
+
/** Why `settleable` is false. Absent when it is true. */
|
|
74
|
+
readonly settlementRefusal?: SettlementRefusalReason;
|
|
75
|
+
}
|
|
76
|
+
export declare const SETTLEMENT_REFUSAL_DETAIL: Readonly<Record<SettlementRefusalReason, string>>;
|
|
77
|
+
/**
|
|
78
|
+
* A `VerifyResponse` with Metrik's reasoning attached.
|
|
79
|
+
*
|
|
80
|
+
* ### Where the explanation goes
|
|
81
|
+
*
|
|
82
|
+
* `invalidReason` is a CLOSED enum in the x402 spec and there is no member for
|
|
83
|
+
* "this service is not delivering". Inventing one would break every conformant
|
|
84
|
+
* client that parses the field. So the enum carries the closest honest member
|
|
85
|
+
* (see {@link DELIVERY_REFUSAL_REASON}) and the real explanation travels in a
|
|
86
|
+
* `metrik` object alongside it.
|
|
87
|
+
*
|
|
88
|
+
* `VerifyResponseSchema` is a `strip` (not `strict`) Zod object, so this extra
|
|
89
|
+
* key is spec-tolerated: a conformant client parses the response successfully
|
|
90
|
+
* and simply drops `metrik`. A client that wants the reason can read it off the
|
|
91
|
+
* raw body. Nothing about the standard fields changes.
|
|
92
|
+
*/
|
|
93
|
+
export type MetrikVerifyResponse = VerifyResponse & {
|
|
94
|
+
readonly metrik: MetrikGateAnnotation;
|
|
95
|
+
};
|
|
96
|
+
export type MetrikSettleResponse = SettleResponse & {
|
|
97
|
+
readonly metrik: MetrikGateAnnotation;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Why this facilitator will not BROADCAST a payment, independent of whether the
|
|
101
|
+
* payment is valid.
|
|
102
|
+
*
|
|
103
|
+
* `/settle` makes the operator's relayer sign and broadcast a call to
|
|
104
|
+
* `paymentRequirements.asset` and pay the gas for it. Every field of
|
|
105
|
+
* `PaymentRequirements` arrives in the request body, and `PaymentRequirementsSchema`
|
|
106
|
+
* accepts ANY `asset` address, ANY `payTo`, `maxAmountRequired: "0"`, and any
|
|
107
|
+
* valid-URL `resource`. The library's `verify` only checks the payload against
|
|
108
|
+
* those same caller-supplied requirements — signature recovers to
|
|
109
|
+
* `authorization.from`, `to === payTo`, window valid, and
|
|
110
|
+
* `balanceOf(from) >= maxAmountRequired` **on the caller-supplied asset**. An
|
|
111
|
+
* attacker signing from their own key to their own address satisfies all of it.
|
|
112
|
+
*
|
|
113
|
+
* Without the checks below, `/settle` is a permissionless "make the relayer
|
|
114
|
+
* broadcast a call to a contract of my choosing" endpoint: deploy something
|
|
115
|
+
* whose `balanceOf` returns a huge number and whose `transferWithAuthorization`
|
|
116
|
+
* burns gas, and drain the relayer until legitimate settlement stops. No funds
|
|
117
|
+
* are stolen — but it is the operator's money, and it induces the operator's key
|
|
118
|
+
* to sign transactions to contracts they never chose.
|
|
119
|
+
*
|
|
120
|
+
* The asset allowlist is the one that removes the arbitrary-contract-call
|
|
121
|
+
* primitive outright; the rest are defence in depth.
|
|
122
|
+
*/
|
|
123
|
+
export type SettlementRefusalReason =
|
|
124
|
+
/** `asset` is not an operator-approved settlement token. */
|
|
125
|
+
"asset-not-allowed"
|
|
126
|
+
/** The payload or the requirements name a chain this facilitator does not settle. */
|
|
127
|
+
| "network-mismatch"
|
|
128
|
+
/** A zero-value settlement moves nothing and only burns the relayer's gas. */
|
|
129
|
+
| "zero-amount"
|
|
130
|
+
/** The relayer only pays gas for resources Metrik actually tracks. */
|
|
131
|
+
| "resource-not-tracked";
|
|
132
|
+
/**
|
|
133
|
+
* Which resources this facilitator will spend the relayer's gas on.
|
|
134
|
+
*
|
|
135
|
+
* `tracked-resources` (default) is a deliberate ASYMMETRY with the delivery
|
|
136
|
+
* gate's allow-by-default policy, and the asymmetry is the point: an OPINION
|
|
137
|
+
* about a service costs nothing and should be given freely, so `/verify` stays
|
|
138
|
+
* universal and fails open. BROADCASTING costs the operator real gas, so
|
|
139
|
+
* `/settle` fails closed and is scoped to Metrik's own marketplace.
|
|
140
|
+
*
|
|
141
|
+
* This is not a censorship lever. Metrik declining to spend its own gas does
|
|
142
|
+
* not stop anyone being paid — any other facilitator (or the payer's own
|
|
143
|
+
* relayer) can settle the same payment.
|
|
144
|
+
*
|
|
145
|
+
* `any-resource` is for an operator deliberately running a general-purpose
|
|
146
|
+
* facilitator on a relayer they are content to fund for anyone's traffic. The
|
|
147
|
+
* asset allowlist still applies.
|
|
148
|
+
*/
|
|
149
|
+
export type SettlementScope = "tracked-resources" | "any-resource";
|
|
150
|
+
export declare const DEFAULT_SETTLEMENT_SCOPE: SettlementScope;
|
|
151
|
+
/**
|
|
152
|
+
* The `invalidReason` used when the delivery gate refuses.
|
|
153
|
+
*
|
|
154
|
+
* The enum has no member for "the resource is not delivering", so the choice is
|
|
155
|
+
* between members that are all imperfect. Every payer-side member
|
|
156
|
+
* (`invalid_payload`, `invalid_exact_evm_payload_signature`,
|
|
157
|
+
* `insufficient_funds`) would be an active lie: it sends the developer to debug
|
|
158
|
+
* a wallet that is working correctly. `unexpected_verify_error` is also false —
|
|
159
|
+
* this refusal is deliberate and expected, not an error.
|
|
160
|
+
*
|
|
161
|
+
* `invalid_payment_requirements` is the only member that points at the
|
|
162
|
+
* REQUIREMENTS side of the exchange, which is exactly where the problem is:
|
|
163
|
+
* Metrik will not settle a payment quoted for THIS resource to THIS payee right
|
|
164
|
+
* now. It is the honest member, and the `metrik.detail` string carries the rest.
|
|
165
|
+
*/
|
|
166
|
+
export declare const DELIVERY_REFUSAL_REASON: "invalid_payment_requirements";
|
|
167
|
+
/** What to do when Metrik has no fresh delivery evidence. */
|
|
168
|
+
export type IndeterminatePolicy = "allow" | "deny";
|
|
169
|
+
/**
|
|
170
|
+
* Default: `allow`.
|
|
171
|
+
*
|
|
172
|
+
* The standing Metrik rule is buyer-favouring, and it still is — but it applies
|
|
173
|
+
* where Metrik HOLDS the buyer's money and must decide whether to release it.
|
|
174
|
+
* Here Metrik holds nothing, so refusing does not protect a buyer's funds; it
|
|
175
|
+
* only denies them a service they asked to buy, on a rail that works fine
|
|
176
|
+
* without Metrik. Four things make `allow` the right default:
|
|
177
|
+
*
|
|
178
|
+
* 1. **Absent evidence is the normal case, not the exception.** The oracle's
|
|
179
|
+
* `/services` projection is built from ACTIVE STREAMS. A service with no live
|
|
180
|
+
* Metrik stream has no row at all — on the live oracle today that is every
|
|
181
|
+
* service. Failing closed would refuse 100% of payments, which is a broken
|
|
182
|
+
* facilitator rather than a careful one.
|
|
183
|
+
* 2. **Fail-closed is a censorship lever.** If "oracle down" meant "no payments",
|
|
184
|
+
* anyone who could degrade Metrik's oracle could block payments to a
|
|
185
|
+
* competitor listed on it. `allow` removes that lever entirely.
|
|
186
|
+
* 3. **The harms are asymmetric.** A wrong refusal denies a service outright. A
|
|
187
|
+
* wrong allowance passes one `exact` payment, at a price the buyer already
|
|
188
|
+
* agreed to, which by construction is one call's worth.
|
|
189
|
+
* 4. **A pass never claims anything.** `isValid: true` with
|
|
190
|
+
* `gate: "indeterminate"` says "no fresh evidence", and the annotation says
|
|
191
|
+
* so in the response. Nobody has to infer an endorsement that was not made.
|
|
192
|
+
*
|
|
193
|
+
* Set `indeterminatePolicy: "deny"` for a deployment that would rather refuse
|
|
194
|
+
* than proceed without positive fresh evidence. That is a real, supported
|
|
195
|
+
* choice — it is just not a safe default.
|
|
196
|
+
*/
|
|
197
|
+
export declare const DEFAULT_INDETERMINATE_POLICY: IndeterminatePolicy;
|
|
198
|
+
/** The payment-validity half of the facilitator (signature, amount, funds, window). */
|
|
199
|
+
export interface PaymentVerifier {
|
|
200
|
+
verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<VerifyResponse>;
|
|
201
|
+
}
|
|
202
|
+
/** The broadcast half. Requires a funded relayer wallet. */
|
|
203
|
+
export interface PaymentSettler {
|
|
204
|
+
settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
|
|
205
|
+
}
|
|
206
|
+
export declare class RelayerNotConfiguredError extends Error {
|
|
207
|
+
constructor();
|
|
208
|
+
}
|
|
209
|
+
export interface MetrikVerifiedDeliveryFacilitatorOptions {
|
|
210
|
+
readonly paymentVerifier: PaymentVerifier;
|
|
211
|
+
/** Omit to run a verify-only facilitator: `/settle` then fails loudly. */
|
|
212
|
+
readonly paymentSettler?: PaymentSettler;
|
|
213
|
+
readonly resourceIndex: MetrikResourceIndex;
|
|
214
|
+
readonly deliveryOracle: MetrikDeliveryOracle;
|
|
215
|
+
/** Default {@link DEFAULT_INDETERMINATE_POLICY}. */
|
|
216
|
+
readonly indeterminatePolicy?: IndeterminatePolicy;
|
|
217
|
+
/** Chain this facilitator settles on. Default `84532` (Base Sepolia). */
|
|
218
|
+
readonly chainId?: number;
|
|
219
|
+
/**
|
|
220
|
+
* Token contracts the relayer may be asked to call. Defaults to the single
|
|
221
|
+
* canonical USDC for `chainId`. An empty array is rejected: a settling
|
|
222
|
+
* facilitator with no allowed asset can never settle anything, and silently
|
|
223
|
+
* accepting that would hide a misconfiguration.
|
|
224
|
+
*
|
|
225
|
+
* THIS IS THE CONTROL that stops `/settle` being an arbitrary-contract-call
|
|
226
|
+
* primitive. See {@link SettlementRefusalReason}.
|
|
227
|
+
*/
|
|
228
|
+
readonly settlementAssetAllowlist?: readonly string[];
|
|
229
|
+
/** Default {@link DEFAULT_SETTLEMENT_SCOPE}. */
|
|
230
|
+
readonly settlementScope?: SettlementScope;
|
|
231
|
+
}
|
|
232
|
+
export interface FacilitatorSupported {
|
|
233
|
+
readonly x402Version: number;
|
|
234
|
+
readonly kind: readonly {
|
|
235
|
+
readonly scheme: string;
|
|
236
|
+
readonly networkId: string;
|
|
237
|
+
readonly extra: object;
|
|
238
|
+
}[];
|
|
239
|
+
}
|
|
240
|
+
export declare class MetrikVerifiedDeliveryFacilitator {
|
|
241
|
+
private readonly paymentVerifier;
|
|
242
|
+
private readonly paymentSettler;
|
|
243
|
+
private readonly resourceIndex;
|
|
244
|
+
private readonly deliveryOracle;
|
|
245
|
+
private readonly indeterminatePolicy;
|
|
246
|
+
private readonly network;
|
|
247
|
+
private readonly settlementAssets;
|
|
248
|
+
private readonly settlementScope;
|
|
249
|
+
constructor(options: MetrikVerifiedDeliveryFacilitatorOptions);
|
|
250
|
+
/** The assets this relayer may be asked to call, for logging at startup. */
|
|
251
|
+
get allowedSettlementAssets(): readonly string[];
|
|
252
|
+
supported(): FacilitatorSupported;
|
|
253
|
+
/** `POST /verify`. Takes an unvalidated body; never throws on bad input. */
|
|
254
|
+
verify(body: unknown): Promise<MetrikVerifyResponse>;
|
|
255
|
+
/**
|
|
256
|
+
* `POST /settle`. Re-runs the full gate before broadcasting: a facilitator
|
|
257
|
+
* must never settle something it would not verify, and `/settle` is reachable
|
|
258
|
+
* without `/verify` ever having been called.
|
|
259
|
+
*/
|
|
260
|
+
settle(body: unknown): Promise<MetrikSettleResponse>;
|
|
261
|
+
/**
|
|
262
|
+
* Settlement constraints checkable from the request alone — no RPC, no
|
|
263
|
+
* registry, no oracle. Returns the refusal, or `undefined` if the request
|
|
264
|
+
* clears them.
|
|
265
|
+
*/
|
|
266
|
+
private settlementPreflight;
|
|
267
|
+
/** Builds the standard-shaped refusal for a settlement the relayer declines. */
|
|
268
|
+
private refuseSettlement;
|
|
269
|
+
private evaluate;
|
|
270
|
+
/** Does this gate outcome name a resource the relayer will pay gas for? */
|
|
271
|
+
private scopeRefusal;
|
|
272
|
+
private evaluateGate;
|
|
273
|
+
private applyIndeterminate;
|
|
274
|
+
}
|
|
275
|
+
interface ParsedFacilitatorRequest {
|
|
276
|
+
readonly paymentPayload: PaymentPayload;
|
|
277
|
+
readonly paymentRequirements: PaymentRequirements;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Parses the facilitator wire body with the REAL x402 schemas. Both `/verify`
|
|
281
|
+
* and `/settle` take the same `{paymentPayload, paymentRequirements}` pair.
|
|
282
|
+
*/
|
|
283
|
+
export declare function parseFacilitatorRequest(body: unknown): ParsedFacilitatorRequest | undefined;
|
|
284
|
+
export {};
|
|
285
|
+
//# sourceMappingURL=verified-delivery-facilitator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verified-delivery-facilitator.d.ts","sourceRoot":"","sources":["../../src/x402/verified-delivery-facilitator.ts"],"names":[],"mappings":"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"}
|