warpmetal 0.7.2 → 0.7.3
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
CHANGED
|
@@ -58,7 +58,7 @@ integration.
|
|
|
58
58
|
|
|
59
59
|
The repository also contains a skills-only WarpMetal plugin for the public
|
|
60
60
|
Plugins Directory shared by Codex and ChatGPT. The plugin remains a separate
|
|
61
|
-
artifact from the npm CLI and requires `warpmetal` CLI version 0.7.
|
|
61
|
+
artifact from the npm CLI and requires `warpmetal` CLI version 0.7.3 or newer.
|
|
62
62
|
|
|
63
63
|
To test the repository marketplace after the plugin lands on `main`:
|
|
64
64
|
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ with ad hoc HTTP commands.
|
|
|
11
11
|
|
|
12
12
|
## Start safely
|
|
13
13
|
|
|
14
|
-
1. Run `warpmetal --version` and require version `0.7.
|
|
14
|
+
1. Run `warpmetal --version` and require version `0.7.3` or newer for this
|
|
15
15
|
plugin. If it is missing or older, explain the compatibility requirement,
|
|
16
16
|
ask before installing or upgrading software, and use only the official npm
|
|
17
17
|
package from `https://www.npmjs.com/package/warpmetal`.
|
|
@@ -61,6 +61,10 @@ arrays. The default envelope and suggested artifact paths live under the
|
|
|
61
61
|
private WarpMetal state directory. An explicit output path must not already
|
|
62
62
|
contain different content. `challengeHandle` is intentionally absent from the
|
|
63
63
|
wallet envelope: it is neither a buyer payment identifier nor signing input.
|
|
64
|
+
If a previously issued unsigned sponsorship reservation expired, WarpMetal may
|
|
65
|
+
retire that attempt and return a new `paymentAttemptId`. The CLI replaces the
|
|
66
|
+
saved challenge and stale wallet-attempt metadata; use only the newly returned
|
|
67
|
+
workflow.
|
|
64
68
|
|
|
65
69
|
The current integration targets `@x402api/agent-wallet-cli@0.2.4`. A compatible
|
|
66
70
|
live term is marked `agentWalletSupported: true` and must use the sponsored
|
|
@@ -171,6 +171,12 @@ current `termEndsAt` generation are different.
|
|
|
171
171
|
|
|
172
172
|
## Retries and recovery
|
|
173
173
|
|
|
174
|
+
- Expired unsigned gas sponsorship: run the WarpMetal challenge flow again.
|
|
175
|
+
WarpMetal retires the expired merchant attempt and requests fresh instructions
|
|
176
|
+
under a new payment-attempt ID and idempotency key. The CLI replaces stale
|
|
177
|
+
wallet-attempt metadata when it saves the new challenge. Inspect the new
|
|
178
|
+
terms and authorize only the new workflow; never reuse an expired envelope or
|
|
179
|
+
artifact.
|
|
174
180
|
- `payment_pending` or `payment_finalizing`: keep the same checkout bytes and
|
|
175
181
|
artifact. `--wait` performs bounded retries with that exact authorization.
|
|
176
182
|
- Timeout or process restart after authorization: use the saved x402api attempt
|
|
@@ -188,6 +194,6 @@ current `termEndsAt` generation are different.
|
|
|
188
194
|
a fresh challenge; never retry the artifact or fall back to buyer-funded gas.
|
|
189
195
|
- `manual_review`: payment or fulfillment may be final. Stop all payment and
|
|
190
196
|
mutation retries.
|
|
191
|
-
- Expired or corrupt artifact, changed request digest, unexpected recipient,
|
|
197
|
+
- Expired or corrupt signed artifact, changed request digest, unexpected recipient,
|
|
192
198
|
unsupported network, asset, profile, sponsorship error, or request-binding
|
|
193
199
|
mismatch: stop instead of falling back or asking the buyer to fund ETH/SOL.
|
|
@@ -105,6 +105,11 @@ Confirm the plan, hostname, OS, and public key before preparing it.
|
|
|
105
105
|
## Retry and terminal-state rules
|
|
106
106
|
|
|
107
107
|
- Reuse the same idempotency key only for the exact same logical request.
|
|
108
|
+
- If an unsigned gas-sponsorship reservation expires, run `warpmetal checkout
|
|
109
|
+
challenge` again. WarpMetal retires the old merchant attempt, requests fresh
|
|
110
|
+
instructions with a new payment-attempt ID and idempotency key, and the CLI
|
|
111
|
+
replaces its saved challenge metadata. Re-evaluate the new terms before
|
|
112
|
+
authorization; never sign or submit the expired challenge.
|
|
108
113
|
- For `payment_pending`, retry the exact checkout body and the exact same
|
|
109
114
|
payment artifact. Do not create a replacement payment.
|
|
110
115
|
- A signed HTTP 402 rejects that signature. Use the new live challenge for one
|
package/src/state.js
CHANGED
|
@@ -6,6 +6,26 @@ import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
|
6
6
|
import { CliError } from "./errors.js";
|
|
7
7
|
|
|
8
8
|
const STATE_VERSION = 3;
|
|
9
|
+
const WALLET_PAYMENT_STATE_FIELDS = [
|
|
10
|
+
"walletPaymentAttemptId",
|
|
11
|
+
"walletBuyerPaymentIdentifier",
|
|
12
|
+
"walletName",
|
|
13
|
+
"walletPayerAddress",
|
|
14
|
+
"paymentArtifactExpiresAt",
|
|
15
|
+
"paymentArtifactSavedAt",
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function replaceChallenge(record, challenge) {
|
|
19
|
+
const changed =
|
|
20
|
+
(record.paymentAttemptId &&
|
|
21
|
+
record.paymentAttemptId !== challenge.paymentAttemptId) ||
|
|
22
|
+
(record.paymentChallengeDigest &&
|
|
23
|
+
record.paymentChallengeDigest !== challenge.paymentChallengeDigest);
|
|
24
|
+
if (changed) {
|
|
25
|
+
for (const name of WALLET_PAYMENT_STATE_FIELDS) delete record[name];
|
|
26
|
+
}
|
|
27
|
+
Object.assign(record, challenge);
|
|
28
|
+
}
|
|
9
29
|
|
|
10
30
|
function emptyState() {
|
|
11
31
|
return {
|
|
@@ -235,9 +255,8 @@ export class StateStore {
|
|
|
235
255
|
async saveRenewalChallenge(serverId, challenge) {
|
|
236
256
|
await this.update((state) => {
|
|
237
257
|
const renewal = state.renewals[serverId] || { serverId };
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
});
|
|
258
|
+
replaceChallenge(renewal, challenge);
|
|
259
|
+
renewal.challengeSavedAt = new Date().toISOString();
|
|
241
260
|
state.renewals[serverId] = renewal;
|
|
242
261
|
});
|
|
243
262
|
}
|
|
@@ -292,13 +311,15 @@ export class StateStore {
|
|
|
292
311
|
throw new CliError(`No local order state exists for ${taskId}.`, {
|
|
293
312
|
exitCode: 2,
|
|
294
313
|
});
|
|
295
|
-
order
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
314
|
+
replaceChallenge(order, {
|
|
315
|
+
paymentRequired,
|
|
316
|
+
paymentAttemptId,
|
|
317
|
+
challengeHandle,
|
|
318
|
+
paymentRequestDigest,
|
|
319
|
+
paymentChallengeDigest,
|
|
320
|
+
paymentRequestEnvelopePath: paymentWorkflow?.requestEnvelopePath,
|
|
321
|
+
paymentArtifactPath: paymentWorkflow?.paymentArtifactPath,
|
|
322
|
+
});
|
|
302
323
|
order.paymentChallengeSavedAt = new Date().toISOString();
|
|
303
324
|
});
|
|
304
325
|
}
|