@supercuts-walrus/backend 0.1.0 → 0.1.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/dist/buyer-setup.js +2 -2
- package/dist/cli.js +6 -3
- package/dist/demo.js +70 -8
- package/dist/funding.d.ts +38 -0
- package/dist/funding.js +78 -0
- package/dist/live-runtime.d.ts +3 -0
- package/dist/live-runtime.js +80 -6
- package/dist/mandate.js +9 -8
- package/dist/mcp-bootstrap.js +24 -2
- package/dist/mcp.js +39 -19
- package/dist/onboarding-doctor.js +13 -2
- package/dist/phase3.js +35 -5
- package/dist/remote-buyer.d.ts +18 -0
- package/dist/remote-buyer.js +59 -5
- package/dist/role-lock.d.ts +8 -0
- package/dist/role-lock.js +54 -0
- package/dist/seller-package.d.ts +9 -0
- package/dist/seller-package.js +50 -0
- package/dist/seller-service.js +9 -3
- package/dist/x402-resource-service.d.ts +2 -0
- package/dist/x402-resource-service.js +36 -17
- package/package.json +1 -1
|
@@ -67,8 +67,10 @@ export class X402ResourceService {
|
|
|
67
67
|
challenge(artifact) {
|
|
68
68
|
// The live Sui exact facilitator requires the x402 nonce to be exactly
|
|
69
69
|
// 32 random bytes (hex encoded), not merely an application nonce.
|
|
70
|
-
const requirements = this.requirements(artifact), nonce = this.#ledger.challenge(artifact.requestId,
|
|
71
|
-
|
|
70
|
+
const requirements = this.requirements(artifact), baseHash = requirementsHash(requirements), nonce = this.#ledger.challenge(artifact.requestId, baseHash, () => randomBytes(32).toString("hex"));
|
|
71
|
+
const stored = this.#ledger.getChallenge(artifact.requestId, baseHash) ?? fail("X402_CHALLENGE_MISSING", "resource challenge was not persisted");
|
|
72
|
+
const expiresAt = stored.createdAt + requirements.maxTimeoutSeconds * 1_000;
|
|
73
|
+
requirements.extra = { ...requirements.extra, nonce, expiresAt };
|
|
72
74
|
// The nonce changes the signed requirement set and is persisted per request.
|
|
73
75
|
const finalHash = requirementsHash(requirements);
|
|
74
76
|
return { x402Version: 2, resource: { url: this.resourceUrl(artifact.requestId), description: "Supercuts seller capability artifact", mimeType: "application/json" }, accepts: [{ ...requirements, extra: { ...requirements.extra, requirementsHash: finalHash } }] };
|
|
@@ -96,10 +98,10 @@ export class X402ResourceService {
|
|
|
96
98
|
const offered = payload.accepted;
|
|
97
99
|
if (!offered || requirementsHash(offered) !== requirementsHash(requirements))
|
|
98
100
|
fail("X402_REQUIREMENTS_MISMATCH", "payment payload changed the challenged requirements");
|
|
99
|
-
const extra = requirements.extra, nonce = String(extra.nonce ?? ""), declaredHash = String(extra.requirementsHash ?? "");
|
|
100
|
-
const unsignedRequirements = { ...requirements, extra: { requestId: extra.requestId, operationId: extra.operationId, nonce } };
|
|
101
|
-
if (declaredHash !== requirementsHash(unsignedRequirements))
|
|
102
|
-
fail("X402_REQUIREMENTS_MISMATCH", "challenge requirements hash is invalid");
|
|
101
|
+
const extra = requirements.extra, nonce = String(extra.nonce ?? ""), declaredHash = String(extra.requirementsHash ?? ""), expiresAt = Number(extra.expiresAt);
|
|
102
|
+
const unsignedRequirements = { ...requirements, extra: { requestId: extra.requestId, operationId: extra.operationId, nonce, expiresAt } };
|
|
103
|
+
if (!Number.isSafeInteger(expiresAt) || expiresAt !== stored.createdAt + requirements.maxTimeoutSeconds * 1_000 || declaredHash !== requirementsHash(unsignedRequirements))
|
|
104
|
+
fail("X402_REQUIREMENTS_MISMATCH", "challenge requirements hash or expiry is invalid");
|
|
103
105
|
verifyBinding(binding, artifact.requestId, nonce, unsignedRequirements, binding.transactionDigest);
|
|
104
106
|
const { payerSignature: _signature, ...unsignedBinding } = binding;
|
|
105
107
|
if (!(await isValidPersonalMessageSignature(paymentBindingBytes(unsignedBinding), binding.payerSignature, { address: binding.payer })))
|
|
@@ -133,20 +135,37 @@ export class X402ResourceService {
|
|
|
133
135
|
createServer() { return createServer((request, response) => void this.handle(request, response)); }
|
|
134
136
|
async facilitator(path, body) {
|
|
135
137
|
const endpoint = new URL(path, `${this.#facilitator.toString().replace(/\/$/, "")}/`);
|
|
136
|
-
const
|
|
137
|
-
let
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
const delays = this.config.facilitatorRetryDelaysMs ?? [0, 2_000, 5_000, 10_000];
|
|
139
|
+
let lastCause;
|
|
140
|
+
for (const delay of delays) {
|
|
141
|
+
if (delay > 0)
|
|
142
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
143
|
+
let response;
|
|
144
|
+
try {
|
|
145
|
+
response = await this.http(endpoint, { method: "POST", headers: { "content-type": "application/json", "x-supercuts-facilitator-key": this.config.facilitatorKey }, body: JSON.stringify(body), signal: AbortSignal.timeout(60_000) });
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
lastCause = error;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const raw = Buffer.from(await response.arrayBuffer());
|
|
152
|
+
let value;
|
|
153
|
+
try {
|
|
154
|
+
value = JSON.parse(raw.toString("utf8"));
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
lastCause = error;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (response.ok && value && typeof value === "object" && !Array.isArray(value))
|
|
161
|
+
return value;
|
|
145
162
|
const message = value && typeof value === "object" && !Array.isArray(value) && typeof value.message === "string"
|
|
146
163
|
? `: ${value.message}` : "";
|
|
147
|
-
|
|
164
|
+
if (response.status < 500)
|
|
165
|
+
fail("X402_FACILITATOR_INVALID", `facilitator ${path} failed with ${response.status}${message}`);
|
|
166
|
+
lastCause = new Error(`facilitator ${path} returned ${response.status}${message}`);
|
|
148
167
|
}
|
|
149
|
-
return
|
|
168
|
+
return fail("X402_FACILITATOR_UNAVAILABLE", `facilitator ${path} remained unavailable after bounded retries`, lastCause);
|
|
150
169
|
}
|
|
151
170
|
send(response, status, body, headers = {}) { response.writeHead(status, { "content-length": String(body.length), ...headers }); response.end(body); }
|
|
152
171
|
}
|