@xochi/client 0.1.1 → 0.1.2
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/CHANGELOG.md +10 -0
- package/README.md +1 -0
- package/dist/cjs/machine/machine.d.ts +2 -0
- package/dist/cjs/machine/machine.js +19 -7
- package/dist/cjs/shared/index.d.ts +1 -0
- package/dist/cjs/shared/index.js +1 -0
- package/dist/cjs/shared/shieldedPreview.d.ts +841 -0
- package/dist/cjs/shared/shieldedPreview.js +128 -0
- package/dist/esm/machine/machine.d.ts +2 -0
- package/dist/esm/machine/machine.js +19 -7
- package/dist/esm/shared/index.d.ts +1 -0
- package/dist/esm/shared/index.js +1 -0
- package/dist/esm/shared/shieldedPreview.d.ts +841 -0
- package/dist/esm/shared/shieldedPreview.js +124 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ All notable changes to `@xochi/client` are documented here. Format follows [Keep
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.2] - 2026-10-27
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Typed wire shapes and a zod decoder for Riddler's shielded terms preview (`POST /xochi/shielded/preview`, Riddler#1296): `ShieldedPreviewResponseSchema`, `ShieldedPreviewSchema`, `ShieldedFeeBreakdownSchema`, `ShieldedNetworkIdentitySchema`, `ShieldedCorridorSchema`, the `ShieldedPreviewRequestWire` / `ShieldedPreviewResponseWire` types and `decodeShieldedPreview(body)`, which also refuses a fee breakdown whose totals do not add up. Shapes only, with no transport method: the preview needs a `quote`-scoped Riddler credential, and the Xochi Worker proxy route that would expose it is a follow-up owned by xochi#635. A test holds the schemas' members to the vendored `wire/openapi.json`.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- A wallet signature prompt can be cancelled immediately, and every prompt now times out after 90 seconds. A dismissed WalletConnect request previously left consumers in `signing` forever with no retry action; `CancelSignRequested` returns the unchanged quote to its confirm surface, timeout returns to retry or quote refresh as its expiry allows, and any late signature is ignored.
|
|
16
|
+
|
|
7
17
|
## [0.1.1] - 2026-10-26
|
|
8
18
|
|
|
9
19
|
### Added
|
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@ Lifecycle rules the machine enforces, beyond the signer checks under [Fund safet
|
|
|
83
83
|
- Confirm is gated on `canSignQuote` and `holdsCurrentQuote`: a held quote is signable (and a deposit address revealable) only while its quoted amount and trade match the form. The trade key is built from the same normalised fields as the quote request (`normalizeTradeFields`), so an edit that leaves the request unchanged keeps the quote.
|
|
84
84
|
- A new amount, a trade/wallet context change, Reset, a resume, or entering `signing` / `awaiting_deposit` / `executing` drops in-flight quote flights. Refresh is ignored past `quoting`, Allocate outside `ALLOCATABLE_STATES` (idle / pending / quoting / quoted), and a quote reply that finds the trade past `quoting` or ended is dropped; a failed allocation never reopens a trade as `quoted`.
|
|
85
85
|
- The sign ceremony survives `signing -> executing` only for the machine's own execute step (`sign.stage === "execute"`); a status-driven move abandons it, and a signature reply outside `signing` is ignored.
|
|
86
|
+
- Every wallet prompt arms the one-shot `signPrompt` timer for `SIGN_PROMPT_TIMEOUT_MS` (90 s). Schedule it like the other timers. A host should expose `CancelSignRequested` while `view(model).phase === "awaiting-wallet"`; cancellation returns to the unchanged quote, clears the live ceremony and ignores a late signature. A timeout does the same, then normal quote expiry may move the receipt to its refresh surface.
|
|
86
87
|
- `StreamStatus` frames for another intent are ignored. Read stream frames with `mapStatusFrame`: it passes in-flight frames only, so every terminal arrives by the poll with its receipt and reason. A `failed` frame a host dispatches itself follows the poll's rule ([Fund safety](#fund-safety)).
|
|
87
88
|
- An execute reported `notAccepted` (below) waits with no status read and resends from the `execute` timer under a new flow id; a status move off `executing`, Reset, or any end of the ceremony drops the pending resend (`clear:execute`). **Hosts must schedule the `execute` timer** like the others and render the `busy` signing slot. A host that drops the timer is slowed, not stranded: the poll timer stays armed through the wait, and the first poll tick (every `STATUS_POLL_MS`, 4 s) or returning tab (`VisibilityChanged`) at or after the resend time does the timer's work, so the resend goes up to 4 s late. The deadline check still decides: a resend that late can fall inside `EXECUTE_RESEND_MARGIN_SECS`, and then the machine stops resending ("not sent yet", [Fund safety](#fund-safety)) instead.
|
|
88
89
|
|
|
@@ -162,6 +162,10 @@ function step(m, msg, fx) {
|
|
|
162
162
|
return m.amount ? startQuote(m, fx, msg.now, quoteOpts(m.amount)) : m;
|
|
163
163
|
case "SignRequested":
|
|
164
164
|
return beginSign(m, fx, msg.now);
|
|
165
|
+
case "CancelSignRequested":
|
|
166
|
+
if (m.intent.status !== "signing" || !m.sign)
|
|
167
|
+
return m;
|
|
168
|
+
return transition(abandonSign(m, fx), fx, "quoted", { error: "Signature cancelled" });
|
|
165
169
|
case "PullSignRequested":
|
|
166
170
|
return beginPullSign(m, fx, msg.now);
|
|
167
171
|
case "ResetRequested":
|
|
@@ -723,8 +727,9 @@ function onTimer(m, fx, timer, now) {
|
|
|
723
727
|
return resendBackstop(m, fx, now);
|
|
724
728
|
return m.poll && !m.poll.stopped ? pollTick(m, fx, true) : m;
|
|
725
729
|
case "signPrompt":
|
|
726
|
-
// A
|
|
727
|
-
|
|
730
|
+
// A wallet prompt that never resolved. The flow still owns the prompt;
|
|
731
|
+
// `signFlowFailed` makes any reply arriving after this timer inert.
|
|
732
|
+
return m.sign
|
|
728
733
|
? signFlowFailed(m, fx, {
|
|
729
734
|
rejected: false,
|
|
730
735
|
value: "wallet_prompt_timeout",
|
|
@@ -832,6 +837,10 @@ function beginSign(m, fx, now) {
|
|
|
832
837
|
chainId: next.ctx.wallet.chainId,
|
|
833
838
|
},
|
|
834
839
|
});
|
|
840
|
+
// A wallet request can be dismissed without rejecting (mobile deep links in
|
|
841
|
+
// particular). Bound every prompt, including signature 1, so the ceremony
|
|
842
|
+
// always returns to an actionable surface.
|
|
843
|
+
setTimer(fx, "signPrompt", exports.SIGN_PROMPT_TIMEOUT_MS, false);
|
|
835
844
|
return { ...next, sign: { id, origin: "sign", stage: "intent", intentSignature: null } };
|
|
836
845
|
}
|
|
837
846
|
function beginPullSign(m, fx, now) {
|
|
@@ -932,8 +941,7 @@ function onSigned(m, fx, flowId, purpose, result, now) {
|
|
|
932
941
|
// open; its signature then belongs to no ceremony.
|
|
933
942
|
if (m.intent.status !== "signing")
|
|
934
943
|
return abandonSign(m, fx);
|
|
935
|
-
|
|
936
|
-
clearTimer(fx, "signPrompt");
|
|
944
|
+
clearTimer(fx, "signPrompt");
|
|
937
945
|
if (!result.ok)
|
|
938
946
|
return signFlowFailed(m, fx, result.error);
|
|
939
947
|
if (purpose === "pull") {
|
|
@@ -1216,7 +1224,7 @@ function endSignFlow(m, flow) {
|
|
|
1216
1224
|
* affordance, no prompt timer. Nothing signed so far can execute after this.
|
|
1217
1225
|
*/
|
|
1218
1226
|
function abandonSign(m, fx) {
|
|
1219
|
-
if (m.sign
|
|
1227
|
+
if (m.sign)
|
|
1220
1228
|
clearTimer(fx, "signPrompt");
|
|
1221
1229
|
if (awaitingResend(m))
|
|
1222
1230
|
clearTimer(fx, "execute");
|
|
@@ -1232,12 +1240,16 @@ function signFlowFailed(m, fx, report) {
|
|
|
1232
1240
|
const flow = m.sign;
|
|
1233
1241
|
if (!flow)
|
|
1234
1242
|
return m;
|
|
1235
|
-
|
|
1236
|
-
clearTimer(fx, "signPrompt");
|
|
1243
|
+
clearTimer(fx, "signPrompt");
|
|
1237
1244
|
const next = endSignFlow(m, flow);
|
|
1238
1245
|
if (flow.origin === "sign") {
|
|
1239
1246
|
if (report.rejected)
|
|
1240
1247
|
return transition(next, fx, "quoted", { error: "Signature rejected" });
|
|
1248
|
+
if (report.value === "wallet_prompt_timeout") {
|
|
1249
|
+
return transition(next, fx, "quoted", {
|
|
1250
|
+
error: "Couldn't reach the wallet. Press Confirm to try again.",
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1241
1253
|
log(fx, "error", `${LOG} Sign error:`, report.detail);
|
|
1242
1254
|
return transition(next, fx, "failed", { error: report.value ?? "Signing failed" });
|
|
1243
1255
|
}
|
package/dist/cjs/shared/index.js
CHANGED