@absol-labs/agent 0.10.0 → 0.12.0-rc.1
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 +106 -30
- package/dist/capability/invocation-capability.d.ts +20 -8
- package/dist/capability/invocation-capability.d.ts.map +1 -1
- package/dist/capability/invocation-capability.js.map +1 -1
- package/dist/capability/probe-capability.d.ts +225 -0
- package/dist/capability/probe-capability.d.ts.map +1 -0
- package/dist/capability/probe-capability.js +248 -0
- package/dist/capability/probe-capability.js.map +1 -0
- package/dist/cli/args.d.ts +11 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +23 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands/claim.d.ts.map +1 -1
- package/dist/cli/commands/claim.js +21 -5
- 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 +51 -7
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/invoke.d.ts +2 -0
- package/dist/cli/commands/invoke.d.ts.map +1 -1
- package/dist/cli/commands/invoke.js +3 -2
- package/dist/cli/commands/invoke.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +15 -2
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/open.d.ts.map +1 -1
- package/dist/cli/commands/open.js +121 -15
- package/dist/cli/commands/open.js.map +1 -1
- package/dist/cli/commands/pay.d.ts +19 -0
- package/dist/cli/commands/pay.d.ts.map +1 -0
- package/dist/cli/commands/pay.js +355 -0
- package/dist/cli/commands/pay.js.map +1 -0
- package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -1
- package/dist/cli/commands/reclaim-unverified.js +15 -6
- package/dist/cli/commands/reclaim-unverified.js.map +1 -1
- package/dist/cli/commands/reclaim.d.ts +23 -2
- package/dist/cli/commands/reclaim.d.ts.map +1 -1
- package/dist/cli/commands/reclaim.js +200 -21
- package/dist/cli/commands/reclaim.js.map +1 -1
- package/dist/cli/commands/refund.d.ts +13 -0
- package/dist/cli/commands/refund.d.ts.map +1 -0
- package/dist/cli/commands/refund.js +224 -0
- package/dist/cli/commands/refund.js.map +1 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +10 -1
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/streams.js +9 -13
- package/dist/cli/commands/streams.js.map +1 -1
- package/dist/cli/commands/watch.d.ts.map +1 -1
- package/dist/cli/commands/watch.js +2 -1
- package/dist/cli/commands/watch.js.map +1 -1
- package/dist/cli/config.d.ts +44 -26
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +88 -38
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/deps.d.ts +86 -7
- package/dist/cli/deps.d.ts.map +1 -1
- package/dist/cli/deps.js +102 -16
- package/dist/cli/deps.js.map +1 -1
- package/dist/cli/errors.d.ts.map +1 -1
- package/dist/cli/errors.js +21 -1
- package/dist/cli/errors.js.map +1 -1
- package/dist/cli/escape-hatch.d.ts +6 -4
- package/dist/cli/escape-hatch.d.ts.map +1 -1
- package/dist/cli/escape-hatch.js +6 -2
- package/dist/cli/escape-hatch.js.map +1 -1
- package/dist/cli/listings.d.ts +18 -0
- package/dist/cli/listings.d.ts.map +1 -1
- package/dist/cli/listings.js +22 -12
- package/dist/cli/listings.js.map +1 -1
- package/dist/cli/preflight.d.ts +20 -14
- package/dist/cli/preflight.d.ts.map +1 -1
- package/dist/cli/preflight.js +34 -20
- package/dist/cli/preflight.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 +232 -0
- package/dist/cli/privy.js.map +1 -0
- package/dist/cli/reclaimability.d.ts +82 -0
- package/dist/cli/reclaimability.d.ts.map +1 -0
- package/dist/cli/reclaimability.js +80 -0
- package/dist/cli/reclaimability.js.map +1 -0
- package/dist/cli/run.d.ts +2 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +40 -11
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/scan-range.d.ts +2 -2
- package/dist/cli/scan-range.js +2 -2
- 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/status.d.ts +3 -1
- package/dist/cli/status.d.ts.map +1 -1
- package/dist/cli/status.js +15 -3
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/wallet.d.ts +109 -40
- package/dist/cli/wallet.d.ts.map +1 -1
- package/dist/cli/wallet.js +109 -44
- package/dist/cli/wallet.js.map +1 -1
- package/dist/discovery/rate-band.d.ts +74 -0
- package/dist/discovery/rate-band.d.ts.map +1 -0
- package/dist/discovery/rate-band.js +114 -0
- package/dist/discovery/rate-band.js.map +1 -0
- package/dist/escrow-generation.d.ts +81 -0
- package/dist/escrow-generation.d.ts.map +1 -0
- package/dist/escrow-generation.js +76 -0
- package/dist/escrow-generation.js.map +1 -0
- package/dist/frameworks/agentkit.d.ts +8 -4
- package/dist/frameworks/agentkit.d.ts.map +1 -1
- package/dist/frameworks/agentkit.js +27 -10
- package/dist/frameworks/agentkit.js.map +1 -1
- package/dist/frameworks/eliza.d.ts +3 -3
- package/dist/frameworks/eliza.d.ts.map +1 -1
- package/dist/frameworks/eliza.js +15 -6
- package/dist/frameworks/eliza.js.map +1 -1
- package/dist/frameworks/langchain.d.ts.map +1 -1
- package/dist/frameworks/langchain.js +8 -0
- package/dist/frameworks/langchain.js.map +1 -1
- package/dist/gateway/caller-auth-gateway.d.ts +91 -4
- package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
- package/dist/gateway/caller-auth-gateway.js +184 -7
- package/dist/gateway/caller-auth-gateway.js.map +1 -1
- package/dist/gateway/http-server.d.ts +121 -1
- package/dist/gateway/http-server.d.ts.map +1 -1
- package/dist/gateway/http-server.js +474 -5
- package/dist/gateway/http-server.js.map +1 -1
- package/dist/gateway/probe-auth.d.ts +112 -0
- package/dist/gateway/probe-auth.d.ts.map +1 -0
- package/dist/gateway/probe-auth.js +127 -0
- package/dist/gateway/probe-auth.js.map +1 -0
- package/dist/gateway/signed-rate-bounds.d.ts +51 -0
- package/dist/gateway/signed-rate-bounds.d.ts.map +1 -0
- package/dist/gateway/signed-rate-bounds.js +94 -0
- package/dist/gateway/signed-rate-bounds.js.map +1 -0
- package/dist/gateway/x402-opener-mode.d.ts +215 -0
- package/dist/gateway/x402-opener-mode.d.ts.map +1 -0
- package/dist/gateway/x402-opener-mode.js +639 -0
- package/dist/gateway/x402-opener-mode.js.map +1 -0
- package/dist/index.d.ts +11 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -5
- 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 +100 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +719 -39
- 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/mcp/x402-tools.d.ts +104 -0
- package/dist/mcp/x402-tools.d.ts.map +1 -0
- package/dist/mcp/x402-tools.js +434 -0
- package/dist/mcp/x402-tools.js.map +1 -0
- package/dist/network.d.ts +119 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +199 -0
- package/dist/network.js.map +1 -0
- package/dist/sdk/invoke.d.ts +23 -4
- package/dist/sdk/invoke.d.ts.map +1 -1
- package/dist/sdk/invoke.js +71 -10
- package/dist/sdk/invoke.js.map +1 -1
- package/dist/wallet/autonomous-wallet-broker.d.ts +3 -0
- package/dist/wallet/autonomous-wallet-broker.d.ts.map +1 -1
- package/dist/wallet/autonomous-wallet-broker.js +27 -23
- package/dist/wallet/autonomous-wallet-broker.js.map +1 -1
- package/dist/wallet/autonomous-wallet-protocol.d.ts +8 -2
- package/dist/wallet/autonomous-wallet-protocol.d.ts.map +1 -1
- package/dist/wallet/autonomous-wallet-protocol.js +9 -2
- package/dist/wallet/autonomous-wallet-protocol.js.map +1 -1
- package/dist/wallet/autonomous-wallet.d.ts.map +1 -1
- package/dist/wallet/autonomous-wallet.js +3 -2
- package/dist/wallet/autonomous-wallet.js.map +1 -1
- package/dist/wallet/broker-escrows.d.ts +222 -0
- package/dist/wallet/broker-escrows.d.ts.map +1 -0
- package/dist/wallet/broker-escrows.js +36 -0
- package/dist/wallet/broker-escrows.js.map +1 -0
- package/dist/wallet/lifecycle.d.ts +21 -5
- package/dist/wallet/lifecycle.d.ts.map +1 -1
- package/dist/wallet/lifecycle.js +32 -12
- package/dist/wallet/lifecycle.js.map +1 -1
- package/dist/wallet/privy-broker-server.d.ts.map +1 -1
- package/dist/wallet/privy-broker-server.js +31 -26
- package/dist/wallet/privy-broker-server.js.map +1 -1
- package/dist/wallet/privy-session-broker.d.ts +14 -5
- package/dist/wallet/privy-session-broker.d.ts.map +1 -1
- package/dist/wallet/privy-session-broker.js +29 -17
- package/dist/wallet/privy-session-broker.js.map +1 -1
- package/dist/wallet/privy-session-provider.d.ts +3 -1
- package/dist/wallet/privy-session-provider.d.ts.map +1 -1
- package/dist/wallet/privy-session-provider.js +5 -3
- package/dist/wallet/privy-session-provider.js.map +1 -1
- package/dist/wallet/provider.d.ts.map +1 -1
- package/dist/wallet/provider.js +15 -8
- package/dist/wallet/provider.js.map +1 -1
- package/dist/x402/facilitator.d.ts +42 -17
- package/dist/x402/facilitator.d.ts.map +1 -1
- package/dist/x402/facilitator.js +49 -33
- package/dist/x402/facilitator.js.map +1 -1
- package/dist/x402-buyer/guarded-fetch.d.ts +51 -0
- package/dist/x402-buyer/guarded-fetch.d.ts.map +1 -0
- package/dist/x402-buyer/guarded-fetch.js +147 -0
- package/dist/x402-buyer/guarded-fetch.js.map +1 -0
- package/dist/x402-buyer/index.d.ts +10 -0
- package/dist/x402-buyer/index.d.ts.map +1 -0
- package/dist/x402-buyer/index.js +10 -0
- package/dist/x402-buyer/index.js.map +1 -0
- package/dist/x402-buyer/pay.d.ts +135 -0
- package/dist/x402-buyer/pay.d.ts.map +1 -0
- package/dist/x402-buyer/pay.js +336 -0
- package/dist/x402-buyer/pay.js.map +1 -0
- package/dist/x402-opener/abi.d.ts +684 -0
- package/dist/x402-opener/abi.d.ts.map +1 -0
- package/dist/x402-opener/abi.js +880 -0
- package/dist/x402-opener/abi.js.map +1 -0
- package/dist/x402-opener/facilitator-entry.d.ts +3 -0
- package/dist/x402-opener/facilitator-entry.d.ts.map +1 -0
- package/dist/x402-opener/facilitator-entry.js +37 -0
- package/dist/x402-opener/facilitator-entry.js.map +1 -0
- package/dist/x402-opener/facilitator-server.d.ts +180 -0
- package/dist/x402-opener/facilitator-server.d.ts.map +1 -0
- package/dist/x402-opener/facilitator-server.js +696 -0
- package/dist/x402-opener/facilitator-server.js.map +1 -0
- package/dist/x402-opener/index.d.ts +14 -0
- package/dist/x402-opener/index.d.ts.map +1 -0
- package/dist/x402-opener/index.js +14 -0
- package/dist/x402-opener/index.js.map +1 -0
- package/dist/x402-opener/listing-resolver.d.ts +55 -0
- package/dist/x402-opener/listing-resolver.d.ts.map +1 -0
- package/dist/x402-opener/listing-resolver.js +125 -0
- package/dist/x402-opener/listing-resolver.js.map +1 -0
- package/dist/x402-opener/refund-relay.d.ts +240 -0
- package/dist/x402-opener/refund-relay.d.ts.map +1 -0
- package/dist/x402-opener/refund-relay.js +1240 -0
- package/dist/x402-opener/refund-relay.js.map +1 -0
- package/dist/x402-opener/relayer-queue.d.ts +14 -0
- package/dist/x402-opener/relayer-queue.d.ts.map +1 -0
- package/dist/x402-opener/relayer-queue.js +18 -0
- package/dist/x402-opener/relayer-queue.js.map +1 -0
- package/dist/x402-opener/scheme.d.ts +217 -0
- package/dist/x402-opener/scheme.d.ts.map +1 -0
- package/dist/x402-opener/scheme.js +749 -0
- package/dist/x402-opener/scheme.js.map +1 -0
- package/dist/x402-opener/terms.d.ts +105 -0
- package/dist/x402-opener/terms.d.ts.map +1 -0
- package/dist/x402-opener/terms.js +212 -0
- package/dist/x402-opener/terms.js.map +1 -0
- package/dist/zktls/reclaim.d.ts +2 -2
- package/docs/agent-layer.md +13 -8
- package/docs/autonomous-privy-wallet.md +188 -0
- package/docs/cli.md +342 -53
- package/docs/langchain.md +5 -0
- package/docs/mcp-hosted.md +4 -3
- package/docs/mcp-reference.md +245 -0
- package/docs/probe-capability.md +191 -0
- package/docs/quickstart.md +54 -5
- package/docs/threat-model.md +24 -3
- package/docs/x402.md +681 -0
- package/package.json +19 -6
- package/src/capability/invocation-capability.ts +17 -1
- package/src/capability/probe-capability.ts +355 -0
- package/src/cli/args.ts +29 -0
- package/src/cli/commands/claim.ts +31 -5
- package/src/cli/commands/close.ts +56 -7
- package/src/cli/commands/invoke.ts +6 -2
- package/src/cli/commands/mcp.ts +18 -2
- package/src/cli/commands/open.ts +151 -14
- package/src/cli/commands/pay.ts +442 -0
- package/src/cli/commands/reclaim-unverified.ts +24 -6
- package/src/cli/commands/reclaim.ts +274 -19
- package/src/cli/commands/refund.ts +277 -0
- package/src/cli/commands/status.ts +17 -1
- package/src/cli/commands/streams.ts +11 -15
- package/src/cli/commands/watch.ts +7 -1
- package/src/cli/config.ts +139 -52
- package/src/cli/deps.ts +189 -25
- package/src/cli/errors.ts +24 -1
- package/src/cli/escape-hatch.ts +19 -5
- package/src/cli/listings.ts +43 -10
- package/src/cli/preflight.ts +36 -21
- package/src/cli/privy.ts +398 -0
- package/src/cli/reclaimability.ts +154 -0
- package/src/cli/run.ts +54 -11
- package/src/cli/scan-range.ts +2 -2
- package/src/cli/spend-policy.ts +139 -0
- package/src/cli/status.ts +14 -1
- package/src/cli/wallet.ts +189 -58
- package/src/discovery/rate-band.ts +172 -0
- package/src/escrow-generation.ts +135 -0
- package/src/frameworks/agentkit.ts +45 -11
- package/src/frameworks/eliza.ts +27 -5
- package/src/frameworks/langchain.ts +14 -0
- package/src/gateway/caller-auth-gateway.ts +336 -13
- package/src/gateway/http-server.ts +690 -7
- package/src/gateway/probe-auth.ts +191 -0
- package/src/gateway/signed-rate-bounds.ts +164 -0
- package/src/gateway/x402-opener-mode.ts +974 -0
- package/src/index.ts +112 -14
- package/src/mandates/env.ts +3 -2
- package/src/mcp/server.ts +973 -44
- package/src/mcp/service-invoker.ts +285 -0
- package/src/mcp/x402-tools.ts +621 -0
- package/src/network.ts +302 -0
- package/src/sdk/invoke.ts +96 -17
- package/src/wallet/autonomous-wallet-broker.ts +46 -20
- package/src/wallet/autonomous-wallet-protocol.ts +11 -2
- package/src/wallet/autonomous-wallet.ts +4 -2
- package/src/wallet/broker-escrows.ts +66 -0
- package/src/wallet/lifecycle.ts +53 -18
- package/src/wallet/privy-broker-server.ts +35 -25
- package/src/wallet/privy-session-broker.ts +58 -25
- package/src/wallet/privy-session-provider.ts +7 -3
- package/src/wallet/provider.ts +20 -15
- package/src/x402/facilitator.ts +85 -46
- package/src/x402-buyer/guarded-fetch.ts +213 -0
- package/src/x402-buyer/index.ts +9 -0
- package/src/x402-buyer/pay.ts +517 -0
- package/src/x402-opener/abi.ts +881 -0
- package/src/x402-opener/facilitator-entry.ts +45 -0
- package/src/x402-opener/facilitator-server.ts +1014 -0
- package/src/x402-opener/index.ts +13 -0
- package/src/x402-opener/listing-resolver.ts +202 -0
- package/src/x402-opener/refund-relay.ts +1743 -0
- package/src/x402-opener/relayer-queue.ts +18 -0
- package/src/x402-opener/scheme.ts +1133 -0
- package/src/x402-opener/terms.ts +300 -0
package/src/x402/facilitator.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrik-native HTTP `402` challenge flow.
|
|
3
|
+
*
|
|
4
|
+
* This is NOT an implementation of the x402 protocol. It uses its own scheme
|
|
5
|
+
* string (`streamproof-verified-stream`), its own wire format, and its own
|
|
6
|
+
* request header (`x-metrik-payment`). It does not interoperate with
|
|
7
|
+
* `x402-fetch`, `x402-axios`, `x402-express`, or any other x402 client or
|
|
8
|
+
* facilitator. See `docs/x402.md` for the full explanation of why Metrik's
|
|
9
|
+
* metered-stream settlement does not fit any shipped x402 scheme.
|
|
10
|
+
*
|
|
11
|
+
* The directory name is historical. The deprecated `X402*` / `x402*` alias
|
|
12
|
+
* exports that used to live here were removed with the x402 v1 integration
|
|
13
|
+
* (metrik-agent#115); only the canonical names below are exported.
|
|
14
|
+
*/
|
|
1
15
|
import type { StreamProofClientConfig } from "@absol-labs/sdk";
|
|
2
16
|
import { z } from "zod";
|
|
3
17
|
|
|
@@ -16,7 +30,19 @@ import {
|
|
|
16
30
|
type VerifiedConsumedHttpsResponseProof,
|
|
17
31
|
} from "../zktls/reclaim.js";
|
|
18
32
|
|
|
19
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Immutable wire constant for the Metrik-native 402 scheme. The value is
|
|
35
|
+
* historical (`streamproof-*` predates the Metrik rename) and MUST NOT change:
|
|
36
|
+
* the live gateway and deployed callers depend on it.
|
|
37
|
+
*/
|
|
38
|
+
export const METRIK_STREAM_SCHEME = "streamproof-verified-stream" as const;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Request header carrying the Metrik verified-stream payload. Deliberately NOT
|
|
42
|
+
* `x-payment`: that header belongs to the x402 protocol, which this flow does
|
|
43
|
+
* not implement.
|
|
44
|
+
*/
|
|
45
|
+
export const METRIK_PAYMENT_HEADER = "x-metrik-payment" as const;
|
|
20
46
|
|
|
21
47
|
const addressSchema = z.string().regex(/^0x[0-9a-fA-F]{40}$/);
|
|
22
48
|
const bytes32Schema = z.string().regex(/^0x[0-9a-fA-F]{64}$/);
|
|
@@ -35,36 +61,36 @@ export interface VerifiedStreamRequirements extends z.infer<
|
|
|
35
61
|
typeof verifiedStreamRequirementsSchema
|
|
36
62
|
> {}
|
|
37
63
|
|
|
38
|
-
export const
|
|
39
|
-
scheme: z.literal(
|
|
64
|
+
export const streamChallengeSchema = z.object({
|
|
65
|
+
scheme: z.literal(METRIK_STREAM_SCHEME),
|
|
40
66
|
requirements: verifiedStreamRequirementsSchema,
|
|
41
67
|
});
|
|
42
68
|
|
|
43
|
-
export interface
|
|
44
|
-
typeof
|
|
69
|
+
export interface StreamChallenge extends z.infer<
|
|
70
|
+
typeof streamChallengeSchema
|
|
45
71
|
> {}
|
|
46
72
|
|
|
47
|
-
export const
|
|
48
|
-
challenge:
|
|
73
|
+
export const streamOpenPayloadSchema = z.object({
|
|
74
|
+
challenge: streamChallengeSchema,
|
|
49
75
|
signedMandate: signedSpendMandateSchema,
|
|
50
76
|
});
|
|
51
77
|
|
|
52
|
-
export interface
|
|
53
|
-
typeof
|
|
78
|
+
export interface StreamOpenPayload extends z.infer<
|
|
79
|
+
typeof streamOpenPayloadSchema
|
|
54
80
|
> {}
|
|
55
81
|
|
|
56
|
-
export interface
|
|
82
|
+
export interface StreamFacilitator {
|
|
57
83
|
/** Build the 402 challenge a server returns to prompt a verified stream. */
|
|
58
|
-
challenge(req: VerifiedStreamRequirements):
|
|
84
|
+
challenge(req: VerifiedStreamRequirements): StreamChallenge;
|
|
59
85
|
/** Verify + open the stream from an agent's signed payment payload. */
|
|
60
86
|
open(payloadHeader: string): Promise<{ streamId: `0x${string}` }>;
|
|
61
87
|
/** Prove the HTTPS response consumed after opening a verified stream. */
|
|
62
88
|
proveConsumedHttpsResponse(
|
|
63
|
-
input:
|
|
89
|
+
input: ConsumedHttpsResponseProofInput,
|
|
64
90
|
): Promise<VerifiedConsumedHttpsResponseProof>;
|
|
65
91
|
}
|
|
66
92
|
|
|
67
|
-
export interface
|
|
93
|
+
export interface ConsumedHttpsResponseProofInput {
|
|
68
94
|
readonly signedMandate: SignedSpendMandate;
|
|
69
95
|
readonly streamId?: `0x${string}`;
|
|
70
96
|
readonly operator?: `0x${string}`;
|
|
@@ -109,9 +135,11 @@ function warnFacilitatorOnce(key: string, message: string): void {
|
|
|
109
135
|
console.error(message);
|
|
110
136
|
}
|
|
111
137
|
|
|
112
|
-
export class
|
|
138
|
+
export class StreamPayloadError extends Error {
|
|
113
139
|
constructor(message: string) {
|
|
114
140
|
super(message);
|
|
141
|
+
// Unchanged on purpose: `error.name` is an observable value that existing
|
|
142
|
+
// consumers may match on. The class was renamed; its `name` was not.
|
|
115
143
|
this.name = "X402PayloadError";
|
|
116
144
|
}
|
|
117
145
|
}
|
|
@@ -137,14 +165,15 @@ export class DeliveryProofUnavailableError extends Error {
|
|
|
137
165
|
* facilitator denies the open in this case (fail-closed, buyer-favoring) rather
|
|
138
166
|
* than proceeding on an unverified assumption of "0 spent / none revoked".
|
|
139
167
|
*/
|
|
140
|
-
export class
|
|
168
|
+
export class SpendControlUnavailableError extends Error {
|
|
141
169
|
constructor(message: string) {
|
|
142
170
|
super(message);
|
|
171
|
+
// Unchanged on purpose: see StreamPayloadError above.
|
|
143
172
|
this.name = "X402SpendControlUnavailableError";
|
|
144
173
|
}
|
|
145
174
|
}
|
|
146
175
|
|
|
147
|
-
export class
|
|
176
|
+
export class VerifiedStreamFacilitator implements StreamFacilitator {
|
|
148
177
|
private readonly agentClient: VerifiedStreamAgentOpener;
|
|
149
178
|
private readonly deliveryProofs: ConsumerDeliveryProofService | undefined;
|
|
150
179
|
private readonly sdkConfig: StreamProofClientConfig;
|
|
@@ -181,26 +210,26 @@ export class VerifiedStreamX402Facilitator implements X402Facilitator {
|
|
|
181
210
|
// both resolvers are wired; warn once so the reason is visible at deploy time.
|
|
182
211
|
if (options.resolveSpentSoFarUsdc === undefined) {
|
|
183
212
|
warnFacilitatorOnce(
|
|
184
|
-
"
|
|
185
|
-
"[metrik]
|
|
213
|
+
"metrik-stream-spent",
|
|
214
|
+
"[metrik] Metrik verified-stream facilitator: no resolveSpentSoFarUsdc wired — the mandate cumulative cap (maxTotalUsdc) cannot be verified, so open() will DENY every spend (fail-closed) until a resolver is wired.",
|
|
186
215
|
);
|
|
187
216
|
}
|
|
188
217
|
if (options.resolveRevokedMandateIds === undefined) {
|
|
189
218
|
warnFacilitatorOnce(
|
|
190
|
-
"
|
|
191
|
-
"[metrik]
|
|
219
|
+
"metrik-stream-revocation",
|
|
220
|
+
"[metrik] Metrik verified-stream facilitator: no resolveRevokedMandateIds wired — revocation state cannot be verified, so open() will DENY every spend (fail-closed) until a resolver is wired.",
|
|
192
221
|
);
|
|
193
222
|
}
|
|
194
223
|
}
|
|
195
224
|
|
|
196
|
-
challenge(req: VerifiedStreamRequirements):
|
|
225
|
+
challenge(req: VerifiedStreamRequirements): StreamChallenge {
|
|
197
226
|
const requirements = verifiedStreamRequirementsSchema.parse(req);
|
|
198
227
|
assertSettlementTarget(requirements, this.sdkConfig);
|
|
199
|
-
return { scheme:
|
|
228
|
+
return { scheme: METRIK_STREAM_SCHEME, requirements };
|
|
200
229
|
}
|
|
201
230
|
|
|
202
231
|
async open(payloadHeader: string): Promise<{ streamId: `0x${string}` }> {
|
|
203
|
-
const payload =
|
|
232
|
+
const payload = parseStreamPayloadHeader(payloadHeader);
|
|
204
233
|
assertSettlementTarget(payload.challenge.requirements, this.sdkConfig);
|
|
205
234
|
|
|
206
235
|
// FAIL-CLOSED fund safety (B6). Both the cumulative-cap accounting and the
|
|
@@ -209,12 +238,12 @@ export class VerifiedStreamX402Facilitator implements X402Facilitator {
|
|
|
209
238
|
// returns a non-bigint/negative spend is treated as "state cannot be
|
|
210
239
|
// verified" and DENIES the open — never a silent fail-open to 0/none.
|
|
211
240
|
if (this.resolveSpentSoFarUsdc === undefined) {
|
|
212
|
-
throw new
|
|
241
|
+
throw new SpendControlUnavailableError(
|
|
213
242
|
"cannot open verified stream: no resolveSpentSoFarUsdc wired — the mandate cumulative cap (maxTotalUsdc) cannot be verified (fail-closed)",
|
|
214
243
|
);
|
|
215
244
|
}
|
|
216
245
|
if (this.resolveRevokedMandateIds === undefined) {
|
|
217
|
-
throw new
|
|
246
|
+
throw new SpendControlUnavailableError(
|
|
218
247
|
"cannot open verified stream: no resolveRevokedMandateIds wired — mandate revocation state cannot be verified (fail-closed)",
|
|
219
248
|
);
|
|
220
249
|
}
|
|
@@ -223,14 +252,14 @@ export class VerifiedStreamX402Facilitator implements X402Facilitator {
|
|
|
223
252
|
try {
|
|
224
253
|
spentSoFarUsdc = await this.resolveSpentSoFarUsdc(payload.signedMandate);
|
|
225
254
|
} catch (error) {
|
|
226
|
-
throw new
|
|
255
|
+
throw new SpendControlUnavailableError(
|
|
227
256
|
`cannot verify mandate cumulative cap (maxTotalUsdc): ${
|
|
228
257
|
error instanceof Error ? error.message : String(error)
|
|
229
258
|
} (fail-closed)`,
|
|
230
259
|
);
|
|
231
260
|
}
|
|
232
261
|
if (typeof spentSoFarUsdc !== "bigint" || spentSoFarUsdc < 0n) {
|
|
233
|
-
throw new
|
|
262
|
+
throw new SpendControlUnavailableError(
|
|
234
263
|
"cannot verify mandate cumulative cap (maxTotalUsdc): resolver returned an invalid spent-so-far value (fail-closed)",
|
|
235
264
|
);
|
|
236
265
|
}
|
|
@@ -241,7 +270,7 @@ export class VerifiedStreamX402Facilitator implements X402Facilitator {
|
|
|
241
270
|
payload.signedMandate,
|
|
242
271
|
);
|
|
243
272
|
} catch (error) {
|
|
244
|
-
throw new
|
|
273
|
+
throw new SpendControlUnavailableError(
|
|
245
274
|
`cannot verify mandate revocation state: ${
|
|
246
275
|
error instanceof Error ? error.message : String(error)
|
|
247
276
|
} (fail-closed)`,
|
|
@@ -254,7 +283,7 @@ export class VerifiedStreamX402Facilitator implements X402Facilitator {
|
|
|
254
283
|
Symbol.iterator
|
|
255
284
|
] !== "function"
|
|
256
285
|
) {
|
|
257
|
-
throw new
|
|
286
|
+
throw new SpendControlUnavailableError(
|
|
258
287
|
"cannot verify mandate revocation state: resolver returned a non-iterable value (fail-closed)",
|
|
259
288
|
);
|
|
260
289
|
}
|
|
@@ -275,11 +304,11 @@ export class VerifiedStreamX402Facilitator implements X402Facilitator {
|
|
|
275
304
|
}
|
|
276
305
|
|
|
277
306
|
async proveConsumedHttpsResponse(
|
|
278
|
-
input:
|
|
307
|
+
input: ConsumedHttpsResponseProofInput,
|
|
279
308
|
): Promise<VerifiedConsumedHttpsResponseProof> {
|
|
280
309
|
if (this.deliveryProofs === undefined) {
|
|
281
310
|
throw new DeliveryProofUnavailableError(
|
|
282
|
-
"zkTLS delivery proofs are not configured on this
|
|
311
|
+
"zkTLS delivery proofs are not configured on this Metrik verified-stream facilitator",
|
|
283
312
|
);
|
|
284
313
|
}
|
|
285
314
|
|
|
@@ -317,42 +346,52 @@ export class VerifiedStreamX402Facilitator implements X402Facilitator {
|
|
|
317
346
|
}
|
|
318
347
|
}
|
|
319
348
|
|
|
320
|
-
export function
|
|
321
|
-
const parsed =
|
|
322
|
-
const token = Buffer.from(
|
|
323
|
-
|
|
349
|
+
export function encodeStreamPayloadHeader(payload: StreamOpenPayload): string {
|
|
350
|
+
const parsed = streamOpenPayloadSchema.parse(payload);
|
|
351
|
+
const token = Buffer.from(stringifyStreamPayload(parsed)).toString(
|
|
352
|
+
"base64url",
|
|
353
|
+
);
|
|
354
|
+
return `${METRIK_STREAM_SCHEME} ${token}`;
|
|
324
355
|
}
|
|
325
356
|
|
|
326
|
-
export function
|
|
327
|
-
const parsed =
|
|
357
|
+
export function parseStreamChallengeJson(value: unknown): StreamChallenge {
|
|
358
|
+
const parsed = streamChallengeSchema.safeParse(reviveBigInts(value));
|
|
328
359
|
if (!parsed.success) {
|
|
329
|
-
throw new
|
|
360
|
+
throw new StreamPayloadError(
|
|
330
361
|
parsed.error.issues.map((issue) => issue.message).join("; "),
|
|
331
362
|
);
|
|
332
363
|
}
|
|
333
364
|
return parsed.data;
|
|
334
365
|
}
|
|
335
366
|
|
|
336
|
-
export function
|
|
367
|
+
export function parseStreamPayloadHeader(
|
|
368
|
+
payloadHeader: string,
|
|
369
|
+
): StreamOpenPayload {
|
|
337
370
|
const [scheme, token] = payloadHeader.split(" ", 2);
|
|
338
|
-
if (
|
|
339
|
-
|
|
371
|
+
if (
|
|
372
|
+
scheme !== METRIK_STREAM_SCHEME ||
|
|
373
|
+
token === undefined ||
|
|
374
|
+
token.trim() === ""
|
|
375
|
+
) {
|
|
376
|
+
throw new StreamPayloadError(
|
|
377
|
+
"invalid Metrik verified-stream payload header",
|
|
378
|
+
);
|
|
340
379
|
}
|
|
341
380
|
|
|
342
381
|
let decoded: unknown;
|
|
343
382
|
try {
|
|
344
383
|
decoded = JSON.parse(Buffer.from(token, "base64url").toString("utf8"));
|
|
345
384
|
} catch (error) {
|
|
346
|
-
throw new
|
|
347
|
-
`invalid
|
|
385
|
+
throw new StreamPayloadError(
|
|
386
|
+
`invalid Metrik verified-stream payload encoding: ${
|
|
348
387
|
error instanceof Error ? error.message : String(error)
|
|
349
388
|
}`,
|
|
350
389
|
);
|
|
351
390
|
}
|
|
352
391
|
|
|
353
|
-
const parsed =
|
|
392
|
+
const parsed = streamOpenPayloadSchema.safeParse(reviveBigInts(decoded));
|
|
354
393
|
if (!parsed.success) {
|
|
355
|
-
throw new
|
|
394
|
+
throw new StreamPayloadError(
|
|
356
395
|
parsed.error.issues.map((issue) => issue.message).join("; "),
|
|
357
396
|
);
|
|
358
397
|
}
|
|
@@ -381,7 +420,7 @@ function assertSettlementTarget(
|
|
|
381
420
|
}
|
|
382
421
|
}
|
|
383
422
|
|
|
384
|
-
function
|
|
423
|
+
function stringifyStreamPayload(payload: StreamOpenPayload): string {
|
|
385
424
|
return JSON.stringify(payload, (_key, value) =>
|
|
386
425
|
typeof value === "bigint" ? `${value.toString()}n` : value,
|
|
387
426
|
);
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { lookup as dnsLookup } from "node:dns/promises";
|
|
2
|
+
import { isIP } from "node:net";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Outbound-request guard for x402 surfaces where the URL comes from a model
|
|
6
|
+
* (MCP `x402_pay`, `refund`, `refund_status`): without it, those tools are an
|
|
7
|
+
* SSRF probe of whatever network the server runs on.
|
|
8
|
+
*
|
|
9
|
+
* Every request is refused unless:
|
|
10
|
+
* - the URL is `https:` (or `http:` only when private networks are explicitly
|
|
11
|
+
* allowed, i.e. local testing);
|
|
12
|
+
* - its host is on the allowlist, when one is configured
|
|
13
|
+
* (`METRIK_AGENT_X402_ALLOWED_HOSTS`; `*.example.com` matches subdomains);
|
|
14
|
+
* - its host — an IP literal, or EVERY address the name resolves to — is not
|
|
15
|
+
* loopback, private, link-local, unique-local, CGNAT, multicast, reserved or
|
|
16
|
+
* unspecified.
|
|
17
|
+
*
|
|
18
|
+
* Redirects are never followed (`redirect: "manual"`; a 3xx is a refusal), so
|
|
19
|
+
* a public host cannot bounce the request — or a payment signature — onto an
|
|
20
|
+
* internal one.
|
|
21
|
+
*
|
|
22
|
+
* Limitation, stated: the address is checked at lookup time and the platform
|
|
23
|
+
* `fetch` resolves the name again when it connects, so a DNS-rebinding host
|
|
24
|
+
* with a near-zero TTL can still race the check. Use the allowlist where that
|
|
25
|
+
* matters.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
export type LookupFn = (
|
|
29
|
+
hostname: string,
|
|
30
|
+
) => Promise<readonly { readonly address: string; readonly family: number }[]>;
|
|
31
|
+
|
|
32
|
+
export interface GuardedFetchOptions {
|
|
33
|
+
/** Exact hostnames, or `*.domain` for subdomains. Unset = any public host. */
|
|
34
|
+
readonly allowedHosts?: readonly string[];
|
|
35
|
+
/** Tests / local development only: permit loopback and private ranges. */
|
|
36
|
+
readonly allowPrivateNetworks?: boolean;
|
|
37
|
+
/** The fetch to wrap. Default `globalThis.fetch`. */
|
|
38
|
+
readonly fetch?: typeof fetch;
|
|
39
|
+
/** DNS resolution. Default `dns.lookup(host, { all: true })`. */
|
|
40
|
+
readonly lookup?: LookupFn;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** A request the guard refused; nothing was sent. */
|
|
44
|
+
export class OutboundRequestRefusedError extends Error {
|
|
45
|
+
constructor(reason: string) {
|
|
46
|
+
super(`outbound request refused: ${reason}`);
|
|
47
|
+
this.name = "OutboundRequestRefusedError";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const defaultLookup: LookupFn = async (hostname) =>
|
|
52
|
+
await dnsLookup(hostname, { all: true, verbatim: true });
|
|
53
|
+
|
|
54
|
+
function ipv4ToInt(address: string): number {
|
|
55
|
+
return address.split(".").reduce((acc, part) => acc * 256 + Number(part), 0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const BLOCKED_V4: readonly (readonly [string, number])[] = [
|
|
59
|
+
["0.0.0.0", 8],
|
|
60
|
+
["10.0.0.0", 8],
|
|
61
|
+
["100.64.0.0", 10],
|
|
62
|
+
["127.0.0.0", 8],
|
|
63
|
+
["169.254.0.0", 16],
|
|
64
|
+
["172.16.0.0", 12],
|
|
65
|
+
["192.0.0.0", 24],
|
|
66
|
+
["192.0.2.0", 24],
|
|
67
|
+
["192.168.0.0", 16],
|
|
68
|
+
["198.18.0.0", 15],
|
|
69
|
+
["198.51.100.0", 24],
|
|
70
|
+
["203.0.113.0", 24],
|
|
71
|
+
["224.0.0.0", 4],
|
|
72
|
+
["240.0.0.0", 4],
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
function blockedV4(address: string): boolean {
|
|
76
|
+
const value = ipv4ToInt(address);
|
|
77
|
+
return BLOCKED_V4.some(([base, bits]) => {
|
|
78
|
+
const mask = bits === 0 ? 0 : (~0 << (32 - bits)) >>> 0;
|
|
79
|
+
return (value & mask) >>> 0 === (ipv4ToInt(base) & mask) >>> 0;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function blockedV6(raw: string): boolean {
|
|
84
|
+
const address = raw.toLowerCase().replace(/^\[|\]$/g, "");
|
|
85
|
+
if (address === "::" || address === "::1") return true;
|
|
86
|
+
// IPv4-mapped / -compatible: judge the embedded IPv4 address.
|
|
87
|
+
const mapped = /^(?:::ffff:|::)(\d+\.\d+\.\d+\.\d+)$/.exec(address);
|
|
88
|
+
if (mapped?.[1] !== undefined) return blockedV4(mapped[1]);
|
|
89
|
+
const hexMapped = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(address);
|
|
90
|
+
if (hexMapped?.[1] !== undefined && hexMapped[2] !== undefined) {
|
|
91
|
+
const hi = parseInt(hexMapped[1], 16);
|
|
92
|
+
const lo = parseInt(hexMapped[2], 16);
|
|
93
|
+
return blockedV4(`${hi >> 8}.${hi & 255}.${lo >> 8}.${lo & 255}`);
|
|
94
|
+
}
|
|
95
|
+
const first = parseInt(address.split(":")[0] || "0", 16);
|
|
96
|
+
return (
|
|
97
|
+
(first & 0xfe00) === 0xfc00 || // fc00::/7 unique local
|
|
98
|
+
(first & 0xffc0) === 0xfe80 || // fe80::/10 link-local
|
|
99
|
+
(first & 0xffc0) === 0xfec0 || // fec0::/10 site-local (deprecated)
|
|
100
|
+
(first & 0xff00) === 0xff00 || // ff00::/8 multicast
|
|
101
|
+
address.startsWith("64:ff9b:") || // NAT64 (embeds IPv4)
|
|
102
|
+
address.startsWith("2001:db8:") // documentation
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Whether an IP literal is in a range an outbound x402 request must not reach. */
|
|
107
|
+
export function isBlockedAddress(address: string): boolean {
|
|
108
|
+
const bare = address.replace(/^\[|\]$/g, "");
|
|
109
|
+
const family = isIP(bare);
|
|
110
|
+
if (family === 4) return blockedV4(bare);
|
|
111
|
+
if (family === 6) return blockedV6(bare);
|
|
112
|
+
return true; // not an IP: never "safe" by default
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function hostAllowed(hostname: string, allowed: readonly string[]): boolean {
|
|
116
|
+
const host = hostname.toLowerCase();
|
|
117
|
+
return allowed.some((entry) => {
|
|
118
|
+
const rule = entry.trim().toLowerCase();
|
|
119
|
+
if (rule.startsWith("*.")) return host.endsWith(rule.slice(1));
|
|
120
|
+
return host === rule;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Validate one URL against the guard; throws {@link OutboundRequestRefusedError}. */
|
|
125
|
+
export async function assertOutboundUrlAllowed(
|
|
126
|
+
raw: string | URL,
|
|
127
|
+
options: GuardedFetchOptions = {},
|
|
128
|
+
): Promise<URL> {
|
|
129
|
+
let url: URL;
|
|
130
|
+
try {
|
|
131
|
+
url = new URL(String(raw));
|
|
132
|
+
} catch {
|
|
133
|
+
throw new OutboundRequestRefusedError(`"${String(raw)}" is not a URL`);
|
|
134
|
+
}
|
|
135
|
+
const allowPrivate = options.allowPrivateNetworks === true;
|
|
136
|
+
if (
|
|
137
|
+
url.protocol !== "https:" &&
|
|
138
|
+
!(url.protocol === "http:" && allowPrivate)
|
|
139
|
+
) {
|
|
140
|
+
throw new OutboundRequestRefusedError(
|
|
141
|
+
`${url.protocol} is not allowed (https only)`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
if (url.username !== "" || url.password !== "") {
|
|
145
|
+
throw new OutboundRequestRefusedError("credentials in the URL");
|
|
146
|
+
}
|
|
147
|
+
const hostname = url.hostname.replace(/^\[|\]$/g, "");
|
|
148
|
+
if (
|
|
149
|
+
options.allowedHosts !== undefined &&
|
|
150
|
+
options.allowedHosts.length > 0 &&
|
|
151
|
+
!hostAllowed(hostname, options.allowedHosts)
|
|
152
|
+
) {
|
|
153
|
+
throw new OutboundRequestRefusedError(
|
|
154
|
+
`${hostname} is not in METRIK_AGENT_X402_ALLOWED_HOSTS`,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
if (allowPrivate) return url;
|
|
158
|
+
if (isIP(hostname) !== 0) {
|
|
159
|
+
if (isBlockedAddress(hostname)) {
|
|
160
|
+
throw new OutboundRequestRefusedError(
|
|
161
|
+
`${hostname} is a loopback, private, link-local or reserved address`,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return url;
|
|
165
|
+
}
|
|
166
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost")) {
|
|
167
|
+
throw new OutboundRequestRefusedError(`${hostname} is loopback`);
|
|
168
|
+
}
|
|
169
|
+
let addresses: readonly { readonly address: string }[];
|
|
170
|
+
try {
|
|
171
|
+
addresses = await (options.lookup ?? defaultLookup)(hostname);
|
|
172
|
+
} catch {
|
|
173
|
+
throw new OutboundRequestRefusedError(`${hostname} did not resolve`);
|
|
174
|
+
}
|
|
175
|
+
if (addresses.length === 0) {
|
|
176
|
+
throw new OutboundRequestRefusedError(`${hostname} did not resolve`);
|
|
177
|
+
}
|
|
178
|
+
const blocked = addresses.find((entry) => isBlockedAddress(entry.address));
|
|
179
|
+
if (blocked !== undefined) {
|
|
180
|
+
throw new OutboundRequestRefusedError(
|
|
181
|
+
`${hostname} resolves to ${blocked.address}, a loopback, private, link-local or reserved address`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return url;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* A `fetch` that applies {@link assertOutboundUrlAllowed} to every request and
|
|
189
|
+
* never follows a redirect.
|
|
190
|
+
*/
|
|
191
|
+
export function createGuardedFetch(
|
|
192
|
+
options: GuardedFetchOptions = {},
|
|
193
|
+
): typeof fetch {
|
|
194
|
+
const base = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
195
|
+
const guarded = async (
|
|
196
|
+
input: string | URL | Request,
|
|
197
|
+
init?: RequestInit,
|
|
198
|
+
): Promise<Response> => {
|
|
199
|
+
const target = input instanceof Request ? input.url : input;
|
|
200
|
+
await assertOutboundUrlAllowed(target, options);
|
|
201
|
+
const response = await base(input, { ...init, redirect: "manual" });
|
|
202
|
+
if (
|
|
203
|
+
response.type === "opaqueredirect" ||
|
|
204
|
+
(response.status >= 300 && response.status < 400)
|
|
205
|
+
) {
|
|
206
|
+
throw new OutboundRequestRefusedError(
|
|
207
|
+
`${new URL(String(target)).host} answered with a redirect (${response.status}), which is never followed`,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
return response;
|
|
211
|
+
};
|
|
212
|
+
return guarded as typeof fetch;
|
|
213
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@absol-labs/agent/x402-buyer` — the BUYER side of Metrik x402: pay an x402
|
|
3
|
+
* v2 endpoint through `@absol-labs/sdk/x402`'s `payWithX402` with every SDK
|
|
4
|
+
* protection intact, gated by a spend mandate (`checkMandate()`) before
|
|
5
|
+
* anything is signed. Kept out of the root barrel so consumers that never use
|
|
6
|
+
* x402 do not load `@x402/*`. See docs/x402.md.
|
|
7
|
+
*/
|
|
8
|
+
export * from "./pay.js";
|
|
9
|
+
export * from "./guarded-fetch.js";
|