@forestrie/mcp-register 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +126 -2
- package/bin/mcp-register.mjs +2 -0
- package/dist/core/base64.d.ts +7 -0
- package/dist/core/base64.d.ts.map +1 -0
- package/dist/core/base64.js +20 -0
- package/dist/core/base64.js.map +1 -0
- package/dist/core/delegation.d.ts +56 -0
- package/dist/core/delegation.d.ts.map +1 -0
- package/dist/core/delegation.js +130 -0
- package/dist/core/delegation.js.map +1 -0
- package/dist/core/grant.d.ts +41 -0
- package/dist/core/grant.d.ts.map +1 -0
- package/dist/core/grant.js +78 -0
- package/dist/core/grant.js.map +1 -0
- package/dist/core/hex.d.ts +4 -0
- package/dist/core/hex.d.ts.map +1 -0
- package/dist/core/hex.js +18 -0
- package/dist/core/hex.js.map +1 -0
- package/dist/core/index.d.ts +28 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +21 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/issue.d.ts +38 -0
- package/dist/core/issue.d.ts.map +1 -0
- package/dist/core/issue.js +135 -0
- package/dist/core/issue.js.map +1 -0
- package/dist/core/limits.d.ts +9 -0
- package/dist/core/limits.d.ts.map +1 -0
- package/dist/core/limits.js +9 -0
- package/dist/core/limits.js.map +1 -0
- package/dist/core/scrapi.d.ts +66 -0
- package/dist/core/scrapi.d.ts.map +1 -0
- package/dist/core/scrapi.js +174 -0
- package/dist/core/scrapi.js.map +1 -0
- package/dist/core/signer.d.ts +24 -0
- package/dist/core/signer.d.ts.map +1 -0
- package/dist/core/signer.js +2 -0
- package/dist/core/signer.js.map +1 -0
- package/dist/core/statement.d.ts +26 -0
- package/dist/core/statement.d.ts.map +1 -0
- package/dist/core/statement.js +70 -0
- package/dist/core/statement.js.map +1 -0
- package/dist/core/version.d.ts +23 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +23 -0
- package/dist/core/version.js.map +1 -0
- package/dist/core/x402.d.ts +99 -0
- package/dist/core/x402.d.ts.map +1 -0
- package/dist/core/x402.js +202 -0
- package/dist/core/x402.js.map +1 -0
- package/dist/net/delegate.d.ts +56 -0
- package/dist/net/delegate.d.ts.map +1 -0
- package/dist/net/delegate.js +182 -0
- package/dist/net/delegate.js.map +1 -0
- package/dist/net/http.d.ts +17 -0
- package/dist/net/http.d.ts.map +1 -0
- package/dist/net/http.js +52 -0
- package/dist/net/http.js.map +1 -0
- package/dist/net/index.d.ts +14 -0
- package/dist/net/index.d.ts.map +1 -0
- package/dist/net/index.js +13 -0
- package/dist/net/index.js.map +1 -0
- package/dist/net/write.d.ts +55 -0
- package/dist/net/write.d.ts.map +1 -0
- package/dist/net/write.js +46 -0
- package/dist/net/write.js.map +1 -0
- package/dist/node/cli.d.ts +8 -0
- package/dist/node/cli.d.ts.map +1 -0
- package/dist/node/cli.js +143 -0
- package/dist/node/cli.js.map +1 -0
- package/dist/node/grant-store.d.ts +49 -0
- package/dist/node/grant-store.d.ts.map +1 -0
- package/dist/node/grant-store.js +95 -0
- package/dist/node/grant-store.js.map +1 -0
- package/dist/node/grant-tools.d.ts +29 -0
- package/dist/node/grant-tools.d.ts.map +1 -0
- package/dist/node/grant-tools.js +498 -0
- package/dist/node/grant-tools.js.map +1 -0
- package/dist/node/ledger.d.ts +26 -0
- package/dist/node/ledger.d.ts.map +1 -0
- package/dist/node/ledger.js +78 -0
- package/dist/node/ledger.js.map +1 -0
- package/dist/node/payer.d.ts +48 -0
- package/dist/node/payer.d.ts.map +1 -0
- package/dist/node/payer.js +170 -0
- package/dist/node/payer.js.map +1 -0
- package/dist/node/resolve-input.d.ts +19 -0
- package/dist/node/resolve-input.d.ts.map +1 -0
- package/dist/node/resolve-input.js +76 -0
- package/dist/node/resolve-input.js.map +1 -0
- package/dist/node/server.d.ts +47 -0
- package/dist/node/server.d.ts.map +1 -0
- package/dist/node/server.js +212 -0
- package/dist/node/server.js.map +1 -0
- package/dist/node/signer-file.d.ts +34 -0
- package/dist/node/signer-file.d.ts.map +1 -0
- package/dist/node/signer-file.js +183 -0
- package/dist/node/signer-file.js.map +1 -0
- package/dist/node/store.d.ts +40 -0
- package/dist/node/store.d.ts.map +1 -0
- package/dist/node/store.js +117 -0
- package/dist/node/store.js.map +1 -0
- package/dist/node/text.d.ts +29 -0
- package/dist/node/text.d.ts.map +1 -0
- package/dist/node/text.js +124 -0
- package/dist/node/text.js.map +1 -0
- package/dist/node/tools.d.ts +118 -0
- package/dist/node/tools.d.ts.map +1 -0
- package/dist/node/tools.js +548 -0
- package/dist/node/tools.js.map +1 -0
- package/package.json +108 -3
- package/src/core/base64.ts +18 -0
- package/src/core/delegation.ts +239 -0
- package/src/core/grant.ts +127 -0
- package/src/core/hex.ts +18 -0
- package/src/core/index.ts +84 -0
- package/src/core/issue.ts +209 -0
- package/src/core/limits.ts +8 -0
- package/src/core/scrapi.ts +236 -0
- package/src/core/signer.ts +23 -0
- package/src/core/statement.ts +133 -0
- package/src/core/version.ts +25 -0
- package/src/core/x402.ts +314 -0
- package/src/net/delegate.ts +274 -0
- package/src/net/http.ts +71 -0
- package/src/net/index.ts +26 -0
- package/src/net/write.ts +124 -0
- package/src/node/cli.ts +170 -0
- package/src/node/grant-store.ts +154 -0
- package/src/node/grant-tools.ts +707 -0
- package/src/node/ledger.ts +98 -0
- package/src/node/payer.ts +241 -0
- package/src/node/resolve-input.ts +96 -0
- package/src/node/server.ts +332 -0
- package/src/node/signer-file.ts +251 -0
- package/src/node/store.ts +175 -0
- package/src/node/text.ts +153 -0
- package/src/node/tools.ts +810 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version strings, as literals.
|
|
3
|
+
*
|
|
4
|
+
* Not read from `package.json`: `src/core` is browser-safe, so it has no
|
|
5
|
+
* `node:fs`, and a JSON import would bake a resolveJsonModule edge into the
|
|
6
|
+
* `"."` bundle for a handful of strings. The MCP smoke test asserts
|
|
7
|
+
* `PACKAGE_VERSION === package.json#version`, so a forgotten bump is a red
|
|
8
|
+
* test rather than a silent lie in `initialize`'s serverInfo.
|
|
9
|
+
*
|
|
10
|
+
* Only the versions this package reports (`--help`, `initialize`) live here.
|
|
11
|
+
* Bump each one in the same commit as the dependency it names.
|
|
12
|
+
*/
|
|
13
|
+
/** Keep in sync with package.json#version. Asserted by test/node/mcp-smoke. */
|
|
14
|
+
export const PACKAGE_VERSION = "0.1.0";
|
|
15
|
+
/** Keep in sync with package.json#dependencies["@forestrie/mcp-verify"] — the
|
|
16
|
+
* verifier this package composes with. Asserted by
|
|
17
|
+
* test/core/version.test.ts. */
|
|
18
|
+
export const VERIFIER_VERSION = "0.5.0";
|
|
19
|
+
/** Keep in sync with package.json#dependencies["@forestrie/mcp-resolve"] —
|
|
20
|
+
* the resolver this package composes with. Asserted by
|
|
21
|
+
* test/core/version.test.ts. */
|
|
22
|
+
export const RESOLVE_VERSION = "0.3.0";
|
|
23
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AAEvC;;iCAEiC;AACjC,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC;;iCAEiC;AACjC,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 over already-decoded JSON: read canopy's payment requirements, pick
|
|
3
|
+
* the one option this server may pay, and refuse anything outside its caps.
|
|
4
|
+
*
|
|
5
|
+
* canopy's register-grant gate (canopy `scrapi/register-grant-payment.ts`)
|
|
6
|
+
* answers a payment-gated child grant with 402 and an `X-PAYMENT-REQUIRED`
|
|
7
|
+
* header: base64 of x402 v2 `PaymentRequirements`
|
|
8
|
+
* (`{x402Version: 2, accepts: [{scheme: "exact", network, amount, asset,
|
|
9
|
+
* payTo, maxTimeoutSeconds, extra}], resource: {url, …}}`), priced as a
|
|
10
|
+
* unit price × the child grant's `maxHeight`. The retry carries
|
|
11
|
+
* `X-PAYMENT`: base64 of the x402 v2 `PaymentPayload` (an EIP-3009
|
|
12
|
+
* authorisation for the exact amount).
|
|
13
|
+
*
|
|
14
|
+
* The caps are the server's configuration, never a tool argument: a model
|
|
15
|
+
* (or whatever prompt-injected it) cannot raise them. Every amount is in the
|
|
16
|
+
* asset's atomic units.
|
|
17
|
+
*/
|
|
18
|
+
export declare class PaymentError extends Error {
|
|
19
|
+
readonly code: "invalid_payment_requirements" | "invalid_payment" | CapRefusalCode;
|
|
20
|
+
constructor(code: "invalid_payment_requirements" | "invalid_payment" | CapRefusalCode, message: string);
|
|
21
|
+
}
|
|
22
|
+
export type CapRefusalCode = "cap_network" | "cap_asset" | "cap_testnet_only" | "cap_payee" | "cap_resource" | "cap_per_call" | "cap_per_day";
|
|
23
|
+
export interface PaymentOption {
|
|
24
|
+
scheme: "exact";
|
|
25
|
+
network: string;
|
|
26
|
+
amount: string;
|
|
27
|
+
asset: string;
|
|
28
|
+
payTo: string;
|
|
29
|
+
maxTimeoutSeconds?: number;
|
|
30
|
+
extra?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
export interface PaymentRequired {
|
|
33
|
+
x402Version: 2;
|
|
34
|
+
accepts: PaymentOption[];
|
|
35
|
+
resource?: {
|
|
36
|
+
url: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
mimeType?: string;
|
|
39
|
+
};
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
/** Hard limits from the server's configuration. */
|
|
43
|
+
export interface PaymentCaps {
|
|
44
|
+
/** The one CAIP-2 network this server pays on, e.g. `eip155:84532`. */
|
|
45
|
+
network: string;
|
|
46
|
+
/** The one asset contract it pays in, lowercase `0x…`. */
|
|
47
|
+
asset: string;
|
|
48
|
+
maxPerCallAtomic: bigint;
|
|
49
|
+
maxPerDayAtomic: bigint;
|
|
50
|
+
/** When set, the only payee it pays. */
|
|
51
|
+
payTo?: string;
|
|
52
|
+
/** Pay on a network outside {@link TESTNETS}. Off by default. */
|
|
53
|
+
allowMainnet: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** EVM testnets x402 facilitators settle on. Anything else is mainnet money. */
|
|
56
|
+
export declare const TESTNETS: ReadonlySet<string>;
|
|
57
|
+
/** Base Sepolia, and Circle's USDC on it: the network and asset canopy prices in. */
|
|
58
|
+
export declare const DEFAULT_PAY_NETWORK = "eip155:84532";
|
|
59
|
+
export declare const DEFAULT_PAY_ASSET = "0x036cbd53842c5426634e7929541ec2318f3dcf7e";
|
|
60
|
+
/** Validate decoded `X-PAYMENT-REQUIRED` JSON. Throws `PaymentError`. */
|
|
61
|
+
export declare function readPaymentRequired(json: unknown): PaymentRequired;
|
|
62
|
+
export interface CapContext {
|
|
63
|
+
/** The URL the payment is for: the register-grant URL this server POSTed. */
|
|
64
|
+
resourceUrl: string;
|
|
65
|
+
/** Atomic units already committed today (UTC), on this network and asset. */
|
|
66
|
+
spentTodayAtomic: bigint;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The one option this server may pay, or a `PaymentError` naming the cap
|
|
70
|
+
* that refuses it. Checked in the order a reader would ask: where, in what,
|
|
71
|
+
* to whom, for what, how much now, how much today.
|
|
72
|
+
*/
|
|
73
|
+
export declare function selectWithinCaps(required: PaymentRequired, caps: PaymentCaps, ctx: CapContext): PaymentOption;
|
|
74
|
+
/** What an `X-PAYMENT` authorises, for reporting. Never includes the signature. */
|
|
75
|
+
export interface PaymentSummary {
|
|
76
|
+
network: string;
|
|
77
|
+
asset?: string;
|
|
78
|
+
from: string;
|
|
79
|
+
to: string;
|
|
80
|
+
value: string;
|
|
81
|
+
nonce: string;
|
|
82
|
+
validBefore: string;
|
|
83
|
+
}
|
|
84
|
+
/** Read decoded `X-PAYMENT` JSON (x402 v2 exact EVM). Throws `PaymentError`. */
|
|
85
|
+
export declare function readPaymentPayload(json: unknown): PaymentSummary;
|
|
86
|
+
/**
|
|
87
|
+
* The EIP-3009 nonce for paying for one grant: SHA-256 over a domain tag,
|
|
88
|
+
* the grant's content (its grant v0 CBOR, so a re-signed copy of the same
|
|
89
|
+
* grant gets the same nonce) and the payer's 20-byte address.
|
|
90
|
+
*
|
|
91
|
+
* EIP-3009 lets a token contract execute at most one authorisation per
|
|
92
|
+
* (payer, nonce), and canopy's claim and its settlement de-duplication are
|
|
93
|
+
* keyed by the nonce too. So every authorisation this payer ever signs for
|
|
94
|
+
* this grant shares one nonce, and at most one of them can settle: two
|
|
95
|
+
* overlapping calls, a retry after a lost answer, or a second process
|
|
96
|
+
* sharing the same payer cannot pay for the grant twice.
|
|
97
|
+
*/
|
|
98
|
+
export declare function grantPaymentNonce(grantContent: Uint8Array, payerAddress: Uint8Array): Promise<string>;
|
|
99
|
+
//# sourceMappingURL=x402.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.d.ts","sourceRoot":"","sources":["../../src/core/x402.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,qBAAa,YAAa,SAAQ,KAAK;IAEnC,QAAQ,CAAC,IAAI,EACX,8BAA8B,GAAG,iBAAiB,GAAG,cAAc;gBAD5D,IAAI,EACX,8BAA8B,GAAG,iBAAiB,GAAG,cAAc,EACrE,OAAO,EAAE,MAAM;CAIlB;AAED,MAAM,MAAM,cAAc,GACtB,aAAa,GACb,WAAW,GACX,kBAAkB,GAClB,WAAW,GACX,cAAc,GACd,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,CAAC,CAAC;IACf,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,gFAAgF;AAChF,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,MAAM,CAOvC,CAAC;AAEH,qFAAqF;AACrF,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAClD,eAAO,MAAM,iBAAiB,+CAA+C,CAAC;AAS9E,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,CA8DlE;AAED,MAAM,WAAW,UAAU;IACzB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,UAAU,GACd,aAAa,CAgDf;AAWD,mFAAmF;AACnF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAgChE;AAMD;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,UAAU,EACxB,YAAY,EAAE,UAAU,GACvB,OAAO,CAAC,MAAM,CAAC,CAmBjB"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 over already-decoded JSON: read canopy's payment requirements, pick
|
|
3
|
+
* the one option this server may pay, and refuse anything outside its caps.
|
|
4
|
+
*
|
|
5
|
+
* canopy's register-grant gate (canopy `scrapi/register-grant-payment.ts`)
|
|
6
|
+
* answers a payment-gated child grant with 402 and an `X-PAYMENT-REQUIRED`
|
|
7
|
+
* header: base64 of x402 v2 `PaymentRequirements`
|
|
8
|
+
* (`{x402Version: 2, accepts: [{scheme: "exact", network, amount, asset,
|
|
9
|
+
* payTo, maxTimeoutSeconds, extra}], resource: {url, …}}`), priced as a
|
|
10
|
+
* unit price × the child grant's `maxHeight`. The retry carries
|
|
11
|
+
* `X-PAYMENT`: base64 of the x402 v2 `PaymentPayload` (an EIP-3009
|
|
12
|
+
* authorisation for the exact amount).
|
|
13
|
+
*
|
|
14
|
+
* The caps are the server's configuration, never a tool argument: a model
|
|
15
|
+
* (or whatever prompt-injected it) cannot raise them. Every amount is in the
|
|
16
|
+
* asset's atomic units.
|
|
17
|
+
*/
|
|
18
|
+
export class PaymentError extends Error {
|
|
19
|
+
code;
|
|
20
|
+
constructor(code, message) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.code = code;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** EVM testnets x402 facilitators settle on. Anything else is mainnet money. */
|
|
26
|
+
export const TESTNETS = new Set([
|
|
27
|
+
"eip155:84532", // Base Sepolia
|
|
28
|
+
"eip155:11155111", // Ethereum Sepolia
|
|
29
|
+
"eip155:421614", // Arbitrum Sepolia
|
|
30
|
+
"eip155:11155420", // OP Sepolia
|
|
31
|
+
"eip155:80002", // Polygon Amoy
|
|
32
|
+
"eip155:43113", // Avalanche Fuji
|
|
33
|
+
]);
|
|
34
|
+
/** Base Sepolia, and Circle's USDC on it: the network and asset canopy prices in. */
|
|
35
|
+
export const DEFAULT_PAY_NETWORK = "eip155:84532";
|
|
36
|
+
export const DEFAULT_PAY_ASSET = "0x036cbd53842c5426634e7929541ec2318f3dcf7e";
|
|
37
|
+
const ATOMIC = /^[0-9]{1,78}$/;
|
|
38
|
+
const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
39
|
+
function isObject(v) {
|
|
40
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
41
|
+
}
|
|
42
|
+
/** Validate decoded `X-PAYMENT-REQUIRED` JSON. Throws `PaymentError`. */
|
|
43
|
+
export function readPaymentRequired(json) {
|
|
44
|
+
const bad = (why) => new PaymentError("invalid_payment_requirements", `canopy's X-PAYMENT-REQUIRED is not x402 v2 payment requirements: ${why}`);
|
|
45
|
+
if (!isObject(json))
|
|
46
|
+
throw bad("not a JSON object");
|
|
47
|
+
if (json["x402Version"] !== 2)
|
|
48
|
+
throw bad("x402Version is not 2");
|
|
49
|
+
const accepts = json["accepts"];
|
|
50
|
+
if (!Array.isArray(accepts) || accepts.length === 0)
|
|
51
|
+
throw bad("accepts is empty");
|
|
52
|
+
const options = [];
|
|
53
|
+
for (const a of accepts) {
|
|
54
|
+
if (!isObject(a))
|
|
55
|
+
throw bad("an accepts entry is not an object");
|
|
56
|
+
const { scheme, network, amount, asset, payTo } = a;
|
|
57
|
+
if (typeof scheme !== "string" ||
|
|
58
|
+
typeof network !== "string" ||
|
|
59
|
+
typeof amount !== "string" ||
|
|
60
|
+
typeof asset !== "string" ||
|
|
61
|
+
typeof payTo !== "string")
|
|
62
|
+
throw bad("an accepts entry lacks scheme, network, amount, asset or payTo");
|
|
63
|
+
if (!ATOMIC.test(amount))
|
|
64
|
+
throw bad(`amount ${amount} is not an atomic-unit integer`);
|
|
65
|
+
if (!ADDRESS.test(asset) || !ADDRESS.test(payTo))
|
|
66
|
+
throw bad("asset and payTo must be 0x-prefixed 20-byte addresses");
|
|
67
|
+
if (scheme !== "exact")
|
|
68
|
+
continue; // the only scheme canopy offers
|
|
69
|
+
options.push({
|
|
70
|
+
scheme,
|
|
71
|
+
network,
|
|
72
|
+
amount,
|
|
73
|
+
asset,
|
|
74
|
+
payTo,
|
|
75
|
+
...(typeof a["maxTimeoutSeconds"] === "number"
|
|
76
|
+
? { maxTimeoutSeconds: a["maxTimeoutSeconds"] }
|
|
77
|
+
: {}),
|
|
78
|
+
...(isObject(a["extra"]) ? { extra: a["extra"] } : {}),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (options.length === 0)
|
|
82
|
+
throw bad('no accepts entry has scheme "exact"');
|
|
83
|
+
const resource = json["resource"];
|
|
84
|
+
return {
|
|
85
|
+
x402Version: 2,
|
|
86
|
+
accepts: options,
|
|
87
|
+
...(isObject(resource) && typeof resource["url"] === "string"
|
|
88
|
+
? {
|
|
89
|
+
resource: {
|
|
90
|
+
url: resource["url"],
|
|
91
|
+
...(typeof resource["description"] === "string"
|
|
92
|
+
? { description: resource["description"] }
|
|
93
|
+
: {}),
|
|
94
|
+
...(typeof resource["mimeType"] === "string"
|
|
95
|
+
? { mimeType: resource["mimeType"] }
|
|
96
|
+
: {}),
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
: {}),
|
|
100
|
+
...(typeof json["error"] === "string" ? { error: json["error"] } : {}),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The one option this server may pay, or a `PaymentError` naming the cap
|
|
105
|
+
* that refuses it. Checked in the order a reader would ask: where, in what,
|
|
106
|
+
* to whom, for what, how much now, how much today.
|
|
107
|
+
*/
|
|
108
|
+
export function selectWithinCaps(required, caps, ctx) {
|
|
109
|
+
const offered = (f) => [...new Set(required.accepts.map(f))].join(", ");
|
|
110
|
+
if (!TESTNETS.has(caps.network) && !caps.allowMainnet)
|
|
111
|
+
throw new PaymentError("cap_testnet_only", `the configured network ${caps.network} is not a testnet, and paying on a mainnet is off (set MCP_REGISTER_PAY_ALLOW_MAINNET=1 to allow it)`);
|
|
112
|
+
const onNetwork = required.accepts.filter((o) => o.network === caps.network);
|
|
113
|
+
if (onNetwork.length === 0)
|
|
114
|
+
throw new PaymentError("cap_network", `canopy asks for payment on ${offered((o) => o.network)}; this server pays only on ${caps.network}`);
|
|
115
|
+
const option = onNetwork.find((o) => o.asset.toLowerCase() === caps.asset);
|
|
116
|
+
if (option === undefined)
|
|
117
|
+
throw new PaymentError("cap_asset", `canopy asks for payment in ${offered((o) => o.asset)}; this server pays only in ${caps.asset}`);
|
|
118
|
+
if (caps.payTo !== undefined &&
|
|
119
|
+
option.payTo.toLowerCase() !== caps.payTo.toLowerCase())
|
|
120
|
+
throw new PaymentError("cap_payee", `canopy asks for payment to ${option.payTo}; this server pays only ${caps.payTo}`);
|
|
121
|
+
if (required.resource !== undefined &&
|
|
122
|
+
stripQuery(required.resource.url) !== stripQuery(ctx.resourceUrl))
|
|
123
|
+
throw new PaymentError("cap_resource", `the payment requirements are for ${required.resource.url}, not the request this server made (${ctx.resourceUrl})`);
|
|
124
|
+
const amount = BigInt(option.amount);
|
|
125
|
+
if (amount > caps.maxPerCallAtomic)
|
|
126
|
+
throw new PaymentError("cap_per_call", `canopy asks ${option.amount} atomic units; this server's per-call cap is ${caps.maxPerCallAtomic}. Issue a grant with a smaller maxHeight, or pay in relay mode from a wallet you control`);
|
|
127
|
+
if (ctx.spentTodayAtomic + amount > caps.maxPerDayAtomic)
|
|
128
|
+
throw new PaymentError("cap_per_day", `paying ${option.amount} would bring today's (UTC) spend to ${ctx.spentTodayAtomic + amount} atomic units; this server's daily cap is ${caps.maxPerDayAtomic}`);
|
|
129
|
+
return option;
|
|
130
|
+
}
|
|
131
|
+
function stripQuery(url) {
|
|
132
|
+
try {
|
|
133
|
+
const u = new URL(url);
|
|
134
|
+
return `${u.origin}${u.pathname}`;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return url;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** Read decoded `X-PAYMENT` JSON (x402 v2 exact EVM). Throws `PaymentError`. */
|
|
141
|
+
export function readPaymentPayload(json) {
|
|
142
|
+
const bad = (why) => new PaymentError("invalid_payment", `the payment is not an x402 v2 exact EVM payment payload: ${why}`);
|
|
143
|
+
if (!isObject(json))
|
|
144
|
+
throw bad("not a JSON object");
|
|
145
|
+
if (json["x402Version"] !== 2 && json["x402Version"] !== 1)
|
|
146
|
+
throw bad("x402Version is not 1 or 2");
|
|
147
|
+
const accepted = isObject(json["accepted"]) ? json["accepted"] : json;
|
|
148
|
+
const payload = json["payload"];
|
|
149
|
+
if (!isObject(payload))
|
|
150
|
+
throw bad("payload is missing");
|
|
151
|
+
const auth = payload["authorization"];
|
|
152
|
+
if (!isObject(auth))
|
|
153
|
+
throw bad("payload.authorization is missing");
|
|
154
|
+
const field = (k) => {
|
|
155
|
+
const v = auth[k];
|
|
156
|
+
if (typeof v !== "string")
|
|
157
|
+
throw bad(`authorization.${k} is missing`);
|
|
158
|
+
return v;
|
|
159
|
+
};
|
|
160
|
+
const network = accepted["network"];
|
|
161
|
+
if (typeof network !== "string")
|
|
162
|
+
throw bad("network is missing");
|
|
163
|
+
return {
|
|
164
|
+
network,
|
|
165
|
+
...(typeof accepted["asset"] === "string"
|
|
166
|
+
? { asset: accepted["asset"] }
|
|
167
|
+
: {}),
|
|
168
|
+
from: field("from"),
|
|
169
|
+
to: field("to"),
|
|
170
|
+
value: field("value"),
|
|
171
|
+
nonce: field("nonce"),
|
|
172
|
+
validBefore: field("validBefore"),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const NONCE_TAG = new TextEncoder().encode("forestrie/mcp-register x402 grant payment nonce v1");
|
|
176
|
+
/**
|
|
177
|
+
* The EIP-3009 nonce for paying for one grant: SHA-256 over a domain tag,
|
|
178
|
+
* the grant's content (its grant v0 CBOR, so a re-signed copy of the same
|
|
179
|
+
* grant gets the same nonce) and the payer's 20-byte address.
|
|
180
|
+
*
|
|
181
|
+
* EIP-3009 lets a token contract execute at most one authorisation per
|
|
182
|
+
* (payer, nonce), and canopy's claim and its settlement de-duplication are
|
|
183
|
+
* keyed by the nonce too. So every authorisation this payer ever signs for
|
|
184
|
+
* this grant shares one nonce, and at most one of them can settle: two
|
|
185
|
+
* overlapping calls, a retry after a lost answer, or a second process
|
|
186
|
+
* sharing the same payer cannot pay for the grant twice.
|
|
187
|
+
*/
|
|
188
|
+
export async function grantPaymentNonce(grantContent, payerAddress) {
|
|
189
|
+
if (payerAddress.length !== 20)
|
|
190
|
+
throw new PaymentError("invalid_payment", `the payer address must be 20 bytes (got ${payerAddress.length})`);
|
|
191
|
+
const content = new Uint8Array(await crypto.subtle.digest("SHA-256", grantContent));
|
|
192
|
+
const material = new Uint8Array(NONCE_TAG.length + 1 + 32 + 20);
|
|
193
|
+
material.set(NONCE_TAG, 0);
|
|
194
|
+
material.set(content, NONCE_TAG.length + 1);
|
|
195
|
+
material.set(payerAddress, NONCE_TAG.length + 33);
|
|
196
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", material));
|
|
197
|
+
let hex = "0x";
|
|
198
|
+
for (const b of digest)
|
|
199
|
+
hex += b.toString(16).padStart(2, "0");
|
|
200
|
+
return hex;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=x402.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.js","sourceRoot":"","sources":["../../src/core/x402.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegate sealing for the caller's data log, falling back to `prepare`.
|
|
3
|
+
*
|
|
4
|
+
* 1. GET pending-delegation. A standing entry means the coordinator knows
|
|
5
|
+
* the log's public root and has a vouched sealer key for it.
|
|
6
|
+
* 2. No standing entry: the coordinator never learned the root. canopy
|
|
7
|
+
* forwards it at register-grant, best effort; `POST
|
|
8
|
+
* /api/forest/{child}/prepare` under the same creation grant does it
|
|
9
|
+
* explicitly. Then poll pending-delegation again, a bounded number of
|
|
10
|
+
* times.
|
|
11
|
+
* 3. Verify the registrar voucher against the pinned sealer key, build the
|
|
12
|
+
* certificate and on-chain proof with the log key, and submit them.
|
|
13
|
+
*
|
|
14
|
+
* Each failure names its stage, so the caller can tell "prepare refused the
|
|
15
|
+
* grant" from "the coordinator rejected the certificate".
|
|
16
|
+
*/
|
|
17
|
+
import type { FetchOptions } from "@forestrie/mcp-resolve/net";
|
|
18
|
+
import { type GrantView } from "../core/grant.js";
|
|
19
|
+
import { type Problem } from "../core/scrapi.js";
|
|
20
|
+
import type { Es256Signer } from "../core/signer.js";
|
|
21
|
+
export type DelegateStage = "pending_delegation" | "prepare" | "voucher" | "certificate";
|
|
22
|
+
export interface DelegateSealingInput {
|
|
23
|
+
baseUrl: string;
|
|
24
|
+
coordinatorUrl: string;
|
|
25
|
+
/** The registrar's voucher key, 64 bytes x‖y, pinned out of band. */
|
|
26
|
+
knownSealerKeyXY: Uint8Array;
|
|
27
|
+
grantB64: string;
|
|
28
|
+
grant: GrantView;
|
|
29
|
+
mmrEnd?: number;
|
|
30
|
+
ttlSeconds?: number;
|
|
31
|
+
/** Polls of pending-delegation after a successful prepare. Default 5. */
|
|
32
|
+
pollsAfterPrepare?: number;
|
|
33
|
+
/** Wait between those polls, ms. Default 2000. */
|
|
34
|
+
pollIntervalMs?: number;
|
|
35
|
+
sleep?: (ms: number) => Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export type DelegateSealingOutcome = {
|
|
38
|
+
kind: "delegated";
|
|
39
|
+
logId: string;
|
|
40
|
+
sealerId: string;
|
|
41
|
+
epoch: number;
|
|
42
|
+
mmrEnd: number;
|
|
43
|
+
issuedAt: number;
|
|
44
|
+
expiresAt: number;
|
|
45
|
+
/** True when this call had to run prepare first. */
|
|
46
|
+
prepared: boolean;
|
|
47
|
+
certificateKey?: string;
|
|
48
|
+
} | {
|
|
49
|
+
kind: "problem";
|
|
50
|
+
stage: DelegateStage;
|
|
51
|
+
message: string;
|
|
52
|
+
problem?: Problem;
|
|
53
|
+
prepared: boolean;
|
|
54
|
+
};
|
|
55
|
+
export declare function delegateSealing(input: DelegateSealingInput, signer: Es256Signer, opts?: FetchOptions): Promise<DelegateSealingOutcome>;
|
|
56
|
+
//# sourceMappingURL=delegate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegate.d.ts","sourceRoot":"","sources":["../../src/net/delegate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAS/D,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAOrD,MAAM,MAAM,aAAa,GACvB,oBAAoB,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAE/D,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,gBAAgB,EAAE,UAAU,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,sBAAsB,GAC9B;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAKN,wBAAsB,eAAe,CACnC,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,WAAW,EACnB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,sBAAsB,CAAC,CAqKjC"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { buildCertificateSubmission, checkVoucher, DelegationError, findStandingEntry, } from "../core/delegation.js";
|
|
2
|
+
import { prepareGrantProblems } from "../core/grant.js";
|
|
3
|
+
import { readProblem } from "../core/scrapi.js";
|
|
4
|
+
import { getPendingDelegation, postDelegationCertificate, prepareChildLog, } from "./write.js";
|
|
5
|
+
const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
6
|
+
export async function delegateSealing(input, signer, opts) {
|
|
7
|
+
const logId = input.grant.logId;
|
|
8
|
+
let prepared = false;
|
|
9
|
+
const readStanding = async () => {
|
|
10
|
+
const res = await getPendingDelegation({ coordinatorUrl: input.coordinatorUrl, logId }, opts);
|
|
11
|
+
if (res.status !== 200)
|
|
12
|
+
return {
|
|
13
|
+
ok: false,
|
|
14
|
+
outcome: {
|
|
15
|
+
kind: "problem",
|
|
16
|
+
stage: "pending_delegation",
|
|
17
|
+
message: `pending-delegation answered HTTP ${res.status}`,
|
|
18
|
+
problem: readJsonProblem(res.status, res.body),
|
|
19
|
+
prepared,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
let body;
|
|
23
|
+
try {
|
|
24
|
+
body = JSON.parse(new TextDecoder().decode(res.body));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
outcome: {
|
|
30
|
+
kind: "problem",
|
|
31
|
+
stage: "pending_delegation",
|
|
32
|
+
message: "pending-delegation did not return JSON",
|
|
33
|
+
prepared,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
return { ok: true, standing: findStandingEntry(body) };
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
outcome: {
|
|
44
|
+
kind: "problem",
|
|
45
|
+
stage: err instanceof DelegationError && err.code === "voucher_rejected"
|
|
46
|
+
? "voucher"
|
|
47
|
+
: "pending_delegation",
|
|
48
|
+
message: err.message,
|
|
49
|
+
prepared,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
let read = await readStanding();
|
|
55
|
+
if (!read.ok)
|
|
56
|
+
return read.outcome;
|
|
57
|
+
if (read.standing === undefined) {
|
|
58
|
+
const refusals = prepareGrantProblems(input.grant);
|
|
59
|
+
if (refusals.length > 0)
|
|
60
|
+
return {
|
|
61
|
+
kind: "problem",
|
|
62
|
+
stage: "prepare",
|
|
63
|
+
message: `the coordinator has no standing sealer key for log ${logId} (its public root was never forwarded), and prepare cannot fix that with this grant: ${refusals.join("; ")}`,
|
|
64
|
+
prepared,
|
|
65
|
+
};
|
|
66
|
+
const res = await prepareChildLog({ baseUrl: input.baseUrl, logId, grantB64: input.grantB64 }, opts);
|
|
67
|
+
if (res.status < 200 || res.status >= 300)
|
|
68
|
+
return {
|
|
69
|
+
kind: "problem",
|
|
70
|
+
stage: "prepare",
|
|
71
|
+
message: `prepare answered HTTP ${res.status}`,
|
|
72
|
+
problem: readProblem(res),
|
|
73
|
+
prepared,
|
|
74
|
+
};
|
|
75
|
+
prepared = true;
|
|
76
|
+
const sleep = input.sleep ?? defaultSleep;
|
|
77
|
+
const polls = input.pollsAfterPrepare ?? 5;
|
|
78
|
+
for (let i = 0; i < polls; i++) {
|
|
79
|
+
await sleep(input.pollIntervalMs ?? 2000);
|
|
80
|
+
read = await readStanding();
|
|
81
|
+
if (!read.ok)
|
|
82
|
+
return read.outcome;
|
|
83
|
+
if (read.standing !== undefined)
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
if (read.standing === undefined)
|
|
87
|
+
return {
|
|
88
|
+
kind: "problem",
|
|
89
|
+
stage: "pending_delegation",
|
|
90
|
+
message: `prepare succeeded, but after ${polls} polls the coordinator still offers no standing sealer key for log ${logId}; try delegate_sealing again shortly`,
|
|
91
|
+
prepared,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const standing = read.standing;
|
|
95
|
+
try {
|
|
96
|
+
await checkVoucher(standing, input.knownSealerKeyXY);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
return {
|
|
100
|
+
kind: "problem",
|
|
101
|
+
stage: "voucher",
|
|
102
|
+
message: err.message,
|
|
103
|
+
prepared,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
let submission;
|
|
107
|
+
try {
|
|
108
|
+
submission = await buildCertificateSubmission({
|
|
109
|
+
logId,
|
|
110
|
+
standing,
|
|
111
|
+
...(input.mmrEnd !== undefined ? { mmrEnd: input.mmrEnd } : {}),
|
|
112
|
+
...(input.ttlSeconds !== undefined
|
|
113
|
+
? { ttlSeconds: input.ttlSeconds }
|
|
114
|
+
: {}),
|
|
115
|
+
}, signer);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
// A malformed standing key, a bad ttl or a signer failure: report it
|
|
119
|
+
// at its stage rather than as a raw throw.
|
|
120
|
+
return {
|
|
121
|
+
kind: "problem",
|
|
122
|
+
stage: "certificate",
|
|
123
|
+
message: `could not build the delegation certificate: ${err instanceof Error ? err.message : String(err)}`,
|
|
124
|
+
prepared,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const res = await postDelegationCertificate({ coordinatorUrl: input.coordinatorUrl, submission }, opts);
|
|
128
|
+
if (res.status < 200 || res.status >= 300)
|
|
129
|
+
return {
|
|
130
|
+
kind: "problem",
|
|
131
|
+
stage: "certificate",
|
|
132
|
+
message: `the coordinator rejected the delegation certificate: HTTP ${res.status}`,
|
|
133
|
+
problem: readJsonProblem(res.status, res.body),
|
|
134
|
+
prepared,
|
|
135
|
+
};
|
|
136
|
+
let certificateKey;
|
|
137
|
+
try {
|
|
138
|
+
const body = JSON.parse(new TextDecoder().decode(res.body));
|
|
139
|
+
if (typeof body.certificateKey === "string")
|
|
140
|
+
certificateKey = body.certificateKey;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// A 2xx without a JSON body still means accepted.
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
kind: "delegated",
|
|
147
|
+
logId,
|
|
148
|
+
sealerId: standing.sealerId,
|
|
149
|
+
epoch: standing.epoch,
|
|
150
|
+
mmrEnd: submission.mmrEnd,
|
|
151
|
+
issuedAt: submission.issuedAt,
|
|
152
|
+
expiresAt: submission.expiresAt,
|
|
153
|
+
prepared,
|
|
154
|
+
...(certificateKey !== undefined ? { certificateKey } : {}),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function readJsonProblem(status, body) {
|
|
158
|
+
const text = new TextDecoder().decode(body);
|
|
159
|
+
try {
|
|
160
|
+
const parsed = JSON.parse(text);
|
|
161
|
+
const title = typeof parsed.title === "string"
|
|
162
|
+
? parsed.title
|
|
163
|
+
: typeof parsed.error === "string"
|
|
164
|
+
? parsed.error
|
|
165
|
+
: `HTTP ${status}`;
|
|
166
|
+
const detail = typeof parsed.detail === "string"
|
|
167
|
+
? parsed.detail
|
|
168
|
+
: typeof parsed.message === "string"
|
|
169
|
+
? parsed.message
|
|
170
|
+
: undefined;
|
|
171
|
+
return { status, title, ...(detail !== undefined ? { detail } : {}) };
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
const printable = text.replace(/[^\x20-\x7e]+/g, " ").trim();
|
|
175
|
+
return {
|
|
176
|
+
status,
|
|
177
|
+
title: `HTTP ${status}`,
|
|
178
|
+
...(printable ? { detail: printable.slice(0, 500) } : {}),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=delegate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegate.js","sourceRoot":"","sources":["../../src/net/delegate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one request helper the write path uses. Same contract as
|
|
3
|
+
* `@forestrie/mcp-resolve/net`'s readers, whose `NetError` and
|
|
4
|
+
* `RawResponse` it reuses: `redirect: "manual"` (a 303 is the answer, not
|
|
5
|
+
* something to follow), every non-2xx returned rather than thrown, and
|
|
6
|
+
* `NetError` only when no response was obtained.
|
|
7
|
+
*/
|
|
8
|
+
import { type FetchOptions, type RawResponse } from "@forestrie/mcp-resolve/net";
|
|
9
|
+
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
10
|
+
export interface RequestInit {
|
|
11
|
+
method: "GET" | "POST";
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
body?: Uint8Array | string;
|
|
14
|
+
}
|
|
15
|
+
export declare function rawRequest(url: string, init: RequestInit, opts?: FetchOptions): Promise<RawResponse>;
|
|
16
|
+
export declare function trimBase(url: string): string;
|
|
17
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/net/http.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CAC5B;AAED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,WAAW,CAAC,CAyCtB;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C"}
|