@cardano-slips/flow 0.1.0 → 0.3.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/README.md +53 -9
- package/dist/address.d.ts +12 -0
- package/dist/address.d.ts.map +1 -1
- package/dist/address.js +43 -0
- package/dist/address.js.map +1 -1
- package/dist/balance-error.d.ts +48 -0
- package/dist/balance-error.d.ts.map +1 -0
- package/dist/balance-error.js +45 -0
- package/dist/balance-error.js.map +1 -0
- package/dist/balance.d.ts +54 -0
- package/dist/balance.d.ts.map +1 -0
- package/dist/balance.js +175 -0
- package/dist/balance.js.map +1 -0
- package/dist/card.css +492 -0
- package/dist/card.d.ts +41 -0
- package/dist/card.d.ts.map +1 -0
- package/dist/card.js +69 -0
- package/dist/card.js.map +1 -0
- package/dist/cip30.d.ts +10 -0
- package/dist/cip30.d.ts.map +1 -1
- package/dist/cip30.js +16 -0
- package/dist/cip30.js.map +1 -1
- package/dist/complete-error.d.ts +57 -0
- package/dist/complete-error.d.ts.map +1 -0
- package/dist/complete-error.js +52 -0
- package/dist/complete-error.js.map +1 -0
- package/dist/complete.d.ts +77 -0
- package/dist/complete.d.ts.map +1 -0
- package/dist/complete.js +182 -0
- package/dist/complete.js.map +1 -0
- package/dist/derived.d.ts +8 -0
- package/dist/derived.d.ts.map +1 -0
- package/dist/derived.js +2 -0
- package/dist/derived.js.map +1 -0
- package/dist/effects-panel.d.ts +37 -0
- package/dist/effects-panel.d.ts.map +1 -0
- package/dist/effects-panel.js +64 -0
- package/dist/effects-panel.js.map +1 -0
- package/dist/effects.css +629 -0
- package/dist/exchange.d.ts +54 -0
- package/dist/exchange.d.ts.map +1 -0
- package/dist/exchange.js +136 -0
- package/dist/exchange.js.map +1 -0
- package/dist/explain.d.ts +39 -0
- package/dist/explain.d.ts.map +1 -0
- package/dist/explain.js +172 -0
- package/dist/explain.js.map +1 -0
- package/dist/index.d.ts +34 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -2
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts +74 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +402 -0
- package/dist/ledger.js.map +1 -0
- package/dist/outcome-panel.d.ts +63 -0
- package/dist/outcome-panel.d.ts.map +1 -0
- package/dist/outcome-panel.js +40 -0
- package/dist/outcome-panel.js.map +1 -0
- package/dist/parameter-form.d.ts +26 -0
- package/dist/parameter-form.d.ts.map +1 -0
- package/dist/parameter-form.js +42 -0
- package/dist/parameter-form.js.map +1 -0
- package/dist/resolve.d.ts +11 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +21 -0
- package/dist/resolve.js.map +1 -0
- package/dist/sign-error.d.ts +62 -0
- package/dist/sign-error.d.ts.map +1 -0
- package/dist/sign-error.js +42 -0
- package/dist/sign-error.js.map +1 -0
- package/dist/sign.d.ts +38 -0
- package/dist/sign.d.ts.map +1 -0
- package/dist/sign.js +79 -0
- package/dist/sign.js.map +1 -0
- package/dist/slip-card.d.ts +55 -0
- package/dist/slip-card.d.ts.map +1 -0
- package/dist/slip-card.js +89 -0
- package/dist/slip-card.js.map +1 -0
- package/dist/tokens.css +97 -123
- package/dist/utxo.d.ts +16 -0
- package/dist/utxo.d.ts.map +1 -0
- package/dist/utxo.js +51 -0
- package/dist/utxo.js.map +1 -0
- package/dist/witness.d.ts +23 -0
- package/dist/witness.d.ts.map +1 -0
- package/dist/witness.js +101 -0
- package/dist/witness.js.map +1 -0
- package/package.json +13 -6
- package/src/address.ts +53 -0
- package/src/balance-error.ts +77 -0
- package/src/balance.ts +285 -0
- package/src/card.css +492 -0
- package/src/card.ts +86 -0
- package/src/cip30.ts +19 -0
- package/src/complete-error.ts +95 -0
- package/src/complete.ts +307 -0
- package/src/derived.ts +8 -0
- package/src/effects-panel.tsx +386 -0
- package/src/effects.css +629 -0
- package/src/exchange.ts +212 -0
- package/src/explain.ts +211 -0
- package/src/index.ts +64 -3
- package/src/ledger.ts +503 -0
- package/src/outcome-panel.tsx +263 -0
- package/src/parameter-form.tsx +138 -0
- package/src/resolve.ts +40 -0
- package/src/sign-error.ts +89 -0
- package/src/sign.ts +118 -0
- package/src/slip-card.tsx +244 -0
- package/src/tokens.css +97 -123
- package/src/utxo.ts +70 -0
- package/src/witness.ts +132 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { valueOf } from "./card.js";
|
|
4
|
+
/**
|
|
5
|
+
* The bounds line. The spec requires it beside the field rather than only on
|
|
6
|
+
* failure, so a person can tell what will be accepted before they type.
|
|
7
|
+
*/
|
|
8
|
+
export const boundsOf = (parameter) => {
|
|
9
|
+
if (parameter.type === "select") {
|
|
10
|
+
const labels = parameter.options.map((option) => option.label);
|
|
11
|
+
if (labels.length > 3)
|
|
12
|
+
return `${labels.length} options`;
|
|
13
|
+
if (labels.length === 1)
|
|
14
|
+
return labels[0];
|
|
15
|
+
return `${labels.slice(0, -1).join(", ")} or ${labels.at(-1)}`;
|
|
16
|
+
}
|
|
17
|
+
// On `text` the bounds count characters; on `number` they bound the value.
|
|
18
|
+
const unit = parameter.type === "text" ? " characters" : "";
|
|
19
|
+
if (parameter.min !== undefined && parameter.max !== undefined) {
|
|
20
|
+
return `Between ${parameter.min} and ${parameter.max}${unit}`;
|
|
21
|
+
}
|
|
22
|
+
// The same words `checkValues` uses, so the bounds and the sentence a broken
|
|
23
|
+
// value produces read as one voice rather than two.
|
|
24
|
+
if (parameter.min !== undefined)
|
|
25
|
+
return `At least ${parameter.min}${unit}`;
|
|
26
|
+
if (parameter.max !== undefined)
|
|
27
|
+
return `At most ${parameter.max}${unit}`;
|
|
28
|
+
return undefined;
|
|
29
|
+
};
|
|
30
|
+
const errorOf = (errors, name) => errors !== undefined && Object.hasOwn(errors, name) ? errors[name] : undefined;
|
|
31
|
+
const Field = ({ parameter, value, error, id, onChange }) => {
|
|
32
|
+
const helpId = `${id}-help`;
|
|
33
|
+
const invalid = error === undefined ? undefined : "";
|
|
34
|
+
const change = (next) => onChange(parameter.name, next);
|
|
35
|
+
return (_jsxs("div", { className: "slip-field", "data-invalid": invalid, children: [_jsx("label", { className: "slip-field__label", htmlFor: id, children: parameter.label }), _jsx("div", { className: "slip-field__control", children: parameter.type === "select" ? (_jsxs("select", { id: id, className: "slip-field__input", value: value, "aria-describedby": helpId, "aria-invalid": error === undefined ? undefined : true, onChange: (event) => change(event.target.value), children: [parameter.required === true && value !== "" ? undefined : _jsx("option", { value: "" }), parameter.options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value)))] })) : (_jsx("input", { id: id, className: parameter.type === "number" ? "slip-field__input slip-field__input--numeral" : "slip-field__input", type: "text",
|
|
36
|
+
// Never `type="number"`: it hands back an empty string for anything
|
|
37
|
+
// the browser dislikes, which hides the very value `checkValues` is
|
|
38
|
+
// there to judge — and the person never learns what was wrong.
|
|
39
|
+
inputMode: parameter.type === "number" ? "decimal" : undefined, value: value, "aria-describedby": helpId, "aria-invalid": error === undefined ? undefined : true, onChange: (event) => change(event.target.value) })) }), _jsxs("div", { className: "slip-field__help", id: helpId, children: [_jsx("span", { className: "slip-field__bounds", children: error?.message ?? boundsOf(parameter) }), error?.code === undefined ? (_jsx("span", { className: "slip-field__note", children: parameter.required === true ? "Required" : "Optional" })) : (_jsx("span", { className: "slip-field__code", children: error.code }))] })] }));
|
|
40
|
+
};
|
|
41
|
+
export const ParameterForm = ({ parameters, values, errors, onChange, idPrefix = "slip" }) => (_jsx("div", { className: "slip-fields", children: parameters.map((parameter) => (_jsx(Field, { parameter: parameter, value: valueOf(values, parameter.name), error: errorOf(errors, parameter.name), id: `${idPrefix}-${parameter.name}`, onChange: onChange }, parameter.name))) }));
|
|
42
|
+
//# sourceMappingURL=parameter-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parameter-form.js","sourceRoot":"","sources":["../src/parameter-form.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wallet's own unspent outputs, in the form the verifier's derivation takes
|
|
3
|
+
* them. The engine is handed the value of every input the body spends because
|
|
4
|
+
* it never looks one up (invariant 1) — this is where the client, which does
|
|
5
|
+
* know, says so.
|
|
6
|
+
*/
|
|
7
|
+
import type { ResolvedInput } from "@cardano-slips/verifier";
|
|
8
|
+
import type { UTxO } from "@evolution-sdk/evolution";
|
|
9
|
+
export declare const asResolvedInput: (utxo: UTxO.UTxO) => ResolvedInput;
|
|
10
|
+
export declare const asResolvedInputs: (utxos: ReadonlyArray<UTxO.UTxO>) => ReadonlyArray<ResolvedInput>;
|
|
11
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAc,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAUxE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAA;AAgBpD,eAAO,MAAM,eAAe,GAAI,MAAM,IAAI,CAAC,IAAI,KAAG,aAIhD,CAAA;AAEF,eAAO,MAAM,gBAAgB,GAAI,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,KAAG,aAAa,CAAC,aAAa,CAClE,CAAA"}
|
package/dist/resolve.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Address, AssetName, Assets, MultiAsset as Multi, PolicyId, Schema, TransactionHash } from "@evolution-sdk/evolution";
|
|
2
|
+
const addressBytes = Schema.encodeSync(Address.FromBytes);
|
|
3
|
+
const multiAssetOf = (assets) => {
|
|
4
|
+
const held = Assets.getMultiAsset(assets);
|
|
5
|
+
if (held === undefined)
|
|
6
|
+
return [];
|
|
7
|
+
return Multi.getPolicyIds(held).map((policyId) => ({
|
|
8
|
+
policyId: PolicyId.toBytes(policyId),
|
|
9
|
+
assets: Multi.getAssetsByPolicy(held, policyId).map(([name, quantity]) => ({
|
|
10
|
+
name: AssetName.toBytes(name),
|
|
11
|
+
quantity
|
|
12
|
+
}))
|
|
13
|
+
}));
|
|
14
|
+
};
|
|
15
|
+
export const asResolvedInput = (utxo) => ({
|
|
16
|
+
input: { transactionId: TransactionHash.toBytes(utxo.transactionId), index: utxo.index },
|
|
17
|
+
address: addressBytes(utxo.address),
|
|
18
|
+
value: { coin: Assets.lovelaceOf(utxo.assets), assets: multiAssetOf(utxo.assets) }
|
|
19
|
+
});
|
|
20
|
+
export const asResolvedInputs = (utxos) => utxos.map(asResolvedInput);
|
|
21
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,OAAO,EACP,SAAS,EACT,MAAM,EACN,UAAU,IAAI,KAAK,EACnB,QAAQ,EACR,MAAM,EACN,eAAe,EAChB,MAAM,0BAA0B,CAAA;AAGjC,MAAM,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;AAEzD,MAAM,YAAY,GAAG,CAAC,MAAqB,EAAc,EAAE;IACzD,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;IACzC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,CAAA;IACjC,OAAO,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACjD,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC;QACpC,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;YACzE,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;YAC7B,QAAQ;SACT,CAAC,CAAC;KACJ,CAAC,CAAC,CAAA;AACL,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAe,EAAiB,EAAE,CAAC,CAAC;IAClE,KAAK,EAAE,EAAE,aAAa,EAAE,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;IACxF,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC;IACnC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;CACnF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAA+B,EAAgC,EAAE,CAChG,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why a transaction was not signed, or not submitted. One error, a closed set
|
|
3
|
+
* of refusals, because the client renders a state per refusal and a state
|
|
4
|
+
* nothing can produce is a screen nobody sees.
|
|
5
|
+
*/
|
|
6
|
+
import { type ClientErrorCode } from "@cardano-slips/core";
|
|
7
|
+
import { type Cip30ApiError } from "./cip30.js";
|
|
8
|
+
export type SignRefusal =
|
|
9
|
+
/** The bytes we hold are not a transaction these bytes can be read as. */
|
|
10
|
+
"UnreadableTransaction"
|
|
11
|
+
/** This is not the body the effects were derived from, so nothing may be signed into it. */
|
|
12
|
+
| "WrongBody"
|
|
13
|
+
/** The person said no in the wallet. Not a fault. */
|
|
14
|
+
| "Declined"
|
|
15
|
+
/** The wallet tried to sign and could not, or rejected for a reason of its own. */
|
|
16
|
+
| "SignFailed"
|
|
17
|
+
/** What came back is not a witness set — a whole transaction included. */
|
|
18
|
+
| "UnreadableWitnesses"
|
|
19
|
+
/** The set carries script or datum material the body was never judged with. */
|
|
20
|
+
| "UnexpectedWitnessMaterial"
|
|
21
|
+
/** The set carries no signature, so assembling it would leave the transaction unsigned. */
|
|
22
|
+
| "NoWitnesses"
|
|
23
|
+
/** Submission failed because an input was spent between building and signing. */
|
|
24
|
+
| "InputsSpent"
|
|
25
|
+
/** The validity interval passed before the transaction reached the chain. */
|
|
26
|
+
| "IntervalPassed"
|
|
27
|
+
/** Submission failed for any other reason. */
|
|
28
|
+
| "SubmitFailed"
|
|
29
|
+
/** The wallet submitted, and named a transaction other than the one we assembled. */
|
|
30
|
+
| "WrongTransactionId";
|
|
31
|
+
/**
|
|
32
|
+
* Exhaustive by type: adding a refusal above without listing it here fails to
|
|
33
|
+
* compile, and `test/sign.test.ts` fails if any of them stops being reachable.
|
|
34
|
+
*/
|
|
35
|
+
export declare const signRefusals: Readonly<Record<SignRefusal, true>>;
|
|
36
|
+
/**
|
|
37
|
+
* Only the passed interval has a spec code, because only it is a failure of the
|
|
38
|
+
* exchange the spec describes — the intent outlived its own `validUntil`. The
|
|
39
|
+
* rest are states of a wallet or of the chain, and a protocol code on one of
|
|
40
|
+
* those would say the endpoint answered when nothing was ever asked of it
|
|
41
|
+
* (`wallet-error.ts` draws the same line).
|
|
42
|
+
*/
|
|
43
|
+
export declare const slipErrorCodeFor: (refusal: SignRefusal) => ClientErrorCode | undefined;
|
|
44
|
+
declare const SigningError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
45
|
+
readonly _tag: "SigningError";
|
|
46
|
+
} & Readonly<A>;
|
|
47
|
+
/** `cip30` is the wallet's own `{ code, info }`, kept so a decline stays distinguishable from a crash. */
|
|
48
|
+
export declare class SigningError extends SigningError_base<{
|
|
49
|
+
readonly refusal: SignRefusal;
|
|
50
|
+
readonly detail: string;
|
|
51
|
+
readonly cip30?: Cip30ApiError;
|
|
52
|
+
readonly cause?: unknown;
|
|
53
|
+
}> {
|
|
54
|
+
get message(): string;
|
|
55
|
+
get code(): ClientErrorCode | undefined;
|
|
56
|
+
}
|
|
57
|
+
export declare const refuse: (refusal: SignRefusal, detail: string, extra?: {
|
|
58
|
+
readonly cip30?: Cip30ApiError;
|
|
59
|
+
readonly cause?: unknown;
|
|
60
|
+
}) => SigningError;
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=sign-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-error.d.ts","sourceRoot":"","sources":["../src/sign-error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAG1D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,MAAM,MAAM,WAAW;AACrB,0EAA0E;AACxE,uBAAuB;AACzB,4FAA4F;GAC1F,WAAW;AACb,qDAAqD;GACnD,UAAU;AACZ,mFAAmF;GACjF,YAAY;AACd,0EAA0E;GACxE,qBAAqB;AACvB,+EAA+E;GAC7E,2BAA2B;AAC7B,2FAA2F;GACzF,aAAa;AACf,iFAAiF;GAC/E,aAAa;AACf,6EAA6E;GAC3E,gBAAgB;AAClB,8CAA8C;GAC5C,cAAc;AAChB,qFAAqF;GACnF,oBAAoB,CAAA;AAExB;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAY5D,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,WAAW,KAAG,eAAe,GAAG,SACb,CAAA;;;;AAE7D,0GAA0G;AAC1G,qBAAa,YAAa,SAAQ,kBAAiC;IACjE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAA;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAE7B;IAED,IAAI,IAAI,IAAI,eAAe,GAAG,SAAS,CAEtC;CACF;AAED,eAAO,MAAM,MAAM,GACjB,SAAS,WAAW,EACpB,QAAQ,MAAM,EACd,QAAO;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,KACvE,YAMC,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Data } from "effect";
|
|
2
|
+
/**
|
|
3
|
+
* Exhaustive by type: adding a refusal above without listing it here fails to
|
|
4
|
+
* compile, and `test/sign.test.ts` fails if any of them stops being reachable.
|
|
5
|
+
*/
|
|
6
|
+
export const signRefusals = {
|
|
7
|
+
UnreadableTransaction: true,
|
|
8
|
+
WrongBody: true,
|
|
9
|
+
Declined: true,
|
|
10
|
+
SignFailed: true,
|
|
11
|
+
UnreadableWitnesses: true,
|
|
12
|
+
UnexpectedWitnessMaterial: true,
|
|
13
|
+
NoWitnesses: true,
|
|
14
|
+
InputsSpent: true,
|
|
15
|
+
IntervalPassed: true,
|
|
16
|
+
SubmitFailed: true,
|
|
17
|
+
WrongTransactionId: true
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Only the passed interval has a spec code, because only it is a failure of the
|
|
21
|
+
* exchange the spec describes — the intent outlived its own `validUntil`. The
|
|
22
|
+
* rest are states of a wallet or of the chain, and a protocol code on one of
|
|
23
|
+
* those would say the endpoint answered when nothing was ever asked of it
|
|
24
|
+
* (`wallet-error.ts` draws the same line).
|
|
25
|
+
*/
|
|
26
|
+
export const slipErrorCodeFor = (refusal) => refusal === "IntervalPassed" ? "INTENT_EXPIRED" : undefined;
|
|
27
|
+
/** `cip30` is the wallet's own `{ code, info }`, kept so a decline stays distinguishable from a crash. */
|
|
28
|
+
export class SigningError extends Data.TaggedError("SigningError") {
|
|
29
|
+
get message() {
|
|
30
|
+
return this.detail;
|
|
31
|
+
}
|
|
32
|
+
get code() {
|
|
33
|
+
return slipErrorCodeFor(this.refusal);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export const refuse = (refusal, detail, extra = {}) => new SigningError({
|
|
37
|
+
refusal,
|
|
38
|
+
detail,
|
|
39
|
+
...(extra.cip30 === undefined ? {} : { cip30: extra.cip30 }),
|
|
40
|
+
...(extra.cause === undefined ? {} : { cause: extra.cause })
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=sign-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-error.js","sourceRoot":"","sources":["../src/sign-error.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AA4B7B;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAwC;IAC/D,qBAAqB,EAAE,IAAI;IAC3B,SAAS,EAAE,IAAI;IACf,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE,IAAI;IAChB,mBAAmB,EAAE,IAAI;IACzB,yBAAyB,EAAE,IAAI;IAC/B,WAAW,EAAE,IAAI;IACjB,WAAW,EAAE,IAAI;IACjB,cAAc,EAAE,IAAI;IACpB,YAAY,EAAE,IAAI;IAClB,kBAAkB,EAAE,IAAI;CACzB,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAoB,EAA+B,EAAE,CACpF,OAAO,KAAK,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAA;AAE7D,0GAA0G;AAC1G,MAAM,OAAO,YAAa,SAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAK/D;IACA,IAAa,OAAO;QAClB,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACvC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,OAAoB,EACpB,MAAc,EACd,QAAsE,EAAE,EAC1D,EAAE,CAChB,IAAI,YAAY,CAAC;IACf,OAAO;IACP,MAAM;IACN,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAC5D,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;CAC7D,CAAC,CAAA"}
|
package/dist/sign.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `signTx` → witness assembly → `submitTx`. CIP-30 returns a **witness set**,
|
|
3
|
+
* never a signed transaction (invariant 4), so the body a person was shown and
|
|
4
|
+
* the body that reaches the chain are joined here or nowhere.
|
|
5
|
+
*/
|
|
6
|
+
import { Effect } from "effect";
|
|
7
|
+
import { type CborHex, type Cip30Api } from "./cip30.js";
|
|
8
|
+
import { type SigningError } from "./sign-error.js";
|
|
9
|
+
export type SignRequest = {
|
|
10
|
+
readonly api: Cip30Api;
|
|
11
|
+
/** The complete unsigned transaction. */
|
|
12
|
+
readonly transaction: CborHex;
|
|
13
|
+
/**
|
|
14
|
+
* The id of the body the effects were derived from, from `transactionIdOf`.
|
|
15
|
+
* Required, not derived here: a signature is bound to the body a person was
|
|
16
|
+
* shown, and a function that recomputed the id from the bytes in front of it
|
|
17
|
+
* would bind it to whatever it was handed.
|
|
18
|
+
*/
|
|
19
|
+
readonly transactionId: string;
|
|
20
|
+
};
|
|
21
|
+
export type SignedTransaction = {
|
|
22
|
+
/** The body with the witnesses in it: what `submitTx` takes. */
|
|
23
|
+
readonly cbor: CborHex;
|
|
24
|
+
/** Unchanged by signing, because witnesses live outside the body. */
|
|
25
|
+
readonly transactionId: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Signs, or says why not. Nothing is asked of the wallet until the transaction
|
|
29
|
+
* is known to be the one the effects were derived from.
|
|
30
|
+
*/
|
|
31
|
+
export declare const signTransaction: ({ api, transaction, transactionId }: SignRequest) => Effect.Effect<SignedTransaction, SigningError>;
|
|
32
|
+
/**
|
|
33
|
+
* Submits, and holds the wallet to the transaction it was given: an id other
|
|
34
|
+
* than the one we assembled is a receipt for something else, and showing it
|
|
35
|
+
* would tell a person their transaction is on the chain when another one is.
|
|
36
|
+
*/
|
|
37
|
+
export declare const submitTransaction: (api: Cip30Api, signed: SignedTransaction) => Effect.Effect<string, SigningError>;
|
|
38
|
+
//# sourceMappingURL=sign.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAwC,MAAM,YAAY,CAAA;AAC9F,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAG3D,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAA;IACtB,yCAAyC;IACzC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B,CAAA;AASD;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,qCAI7B,WAAW,KAAG,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,YAAY,CAwB1D,CAAA;AAsBJ;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,KAAK,QAAQ,EAAE,QAAQ,iBAAiB,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAoB3G,CAAA"}
|
package/dist/sign.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `signTx` → witness assembly → `submitTx`. CIP-30 returns a **witness set**,
|
|
3
|
+
* never a signed transaction (invariant 4), so the body a person was shown and
|
|
4
|
+
* the body that reaches the chain are joined here or nowhere.
|
|
5
|
+
*/
|
|
6
|
+
import { Effect } from "effect";
|
|
7
|
+
import { readApiError, REFUSED, USER_DECLINED } from "./cip30.js";
|
|
8
|
+
import { refuse } from "./sign-error.js";
|
|
9
|
+
import { assembleWitnesses, requireSameBody } from "./witness.js";
|
|
10
|
+
/** What the wallet said, kept whole so a message names its own cause. */
|
|
11
|
+
const said = (cause) => {
|
|
12
|
+
const error = readApiError(cause);
|
|
13
|
+
if (error === undefined)
|
|
14
|
+
return String(cause);
|
|
15
|
+
return error.info === "" ? `code ${error.code}` : error.info;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Signs, or says why not. Nothing is asked of the wallet until the transaction
|
|
19
|
+
* is known to be the one the effects were derived from.
|
|
20
|
+
*/
|
|
21
|
+
export const signTransaction = ({ api, transaction, transactionId }) => Effect.gen(function* () {
|
|
22
|
+
yield* requireSameBody(transaction, transactionId);
|
|
23
|
+
const witnesses = yield* Effect.tryPromise({
|
|
24
|
+
// `partialSign: true`: the wallet signs what it holds keys for and leaves
|
|
25
|
+
// the rest, rather than refusing a transaction a co-signer completes.
|
|
26
|
+
try: () => api.signTx(transaction, true),
|
|
27
|
+
catch: (cause) => {
|
|
28
|
+
const error = readApiError(cause);
|
|
29
|
+
// `-3` is `APIError`'s refusal, which wallets send from `signTx` in
|
|
30
|
+
// practice even though CIP-30 numbers a decline `2` here.
|
|
31
|
+
if (error?.code === USER_DECLINED || error?.code === REFUSED) {
|
|
32
|
+
return refuse("Declined", "The signature was declined in the wallet.", { cip30: error, cause });
|
|
33
|
+
}
|
|
34
|
+
return refuse("SignFailed", `The wallet could not sign this transaction: ${said(cause)}`, {
|
|
35
|
+
...(error === undefined ? {} : { cip30: error }),
|
|
36
|
+
cause
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const cbor = yield* assembleWitnesses(transaction, witnesses, transactionId);
|
|
41
|
+
return { cbor, transactionId };
|
|
42
|
+
});
|
|
43
|
+
/** The ledger's own name for an input that is no longer there — what the rebuild path watches for. */
|
|
44
|
+
const spentInputs = /BadInputsUTxO/i;
|
|
45
|
+
/** The ledger's name for a transaction that arrived outside its validity interval. */
|
|
46
|
+
const outsideInterval = /OutsideValidityInterval/i;
|
|
47
|
+
const submissionFailure = (cause) => {
|
|
48
|
+
const error = readApiError(cause);
|
|
49
|
+
const detail = said(cause);
|
|
50
|
+
const extra = { ...(error === undefined ? {} : { cip30: error }), cause };
|
|
51
|
+
if (spentInputs.test(detail)) {
|
|
52
|
+
return refuse("InputsSpent", "The wallet's funds moved before this transaction reached the chain.", extra);
|
|
53
|
+
}
|
|
54
|
+
if (outsideInterval.test(detail)) {
|
|
55
|
+
return refuse("IntervalPassed", "This transaction expired before it reached the chain.", extra);
|
|
56
|
+
}
|
|
57
|
+
return refuse("SubmitFailed", `This transaction was not accepted: ${detail}`, extra);
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Submits, and holds the wallet to the transaction it was given: an id other
|
|
61
|
+
* than the one we assembled is a receipt for something else, and showing it
|
|
62
|
+
* would tell a person their transaction is on the chain when another one is.
|
|
63
|
+
*/
|
|
64
|
+
export const submitTransaction = (api, signed) => Effect.gen(function* () {
|
|
65
|
+
const returned = yield* Effect.tryPromise({
|
|
66
|
+
try: () => api.submitTx(signed.cbor),
|
|
67
|
+
catch: submissionFailure
|
|
68
|
+
});
|
|
69
|
+
// Typed to answer with the id and under no obligation to: reading a method
|
|
70
|
+
// off whatever it did answer would reach a person as a stack trace.
|
|
71
|
+
if (typeof returned !== "string") {
|
|
72
|
+
return yield* Effect.fail(refuse("WrongTransactionId", "The wallet did not name the transaction it submitted."));
|
|
73
|
+
}
|
|
74
|
+
if (returned.toLowerCase() !== signed.transactionId.toLowerCase()) {
|
|
75
|
+
return yield* Effect.fail(refuse("WrongTransactionId", "The wallet submitted a different transaction from the one it was given."));
|
|
76
|
+
}
|
|
77
|
+
return signed.transactionId;
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=sign.js.map
|
package/dist/sign.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign.js","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rendered face of a Slip link — `2 · Action card` on the design sheet.
|
|
3
|
+
* It renders what the endpoint declared and collects what the endpoint asked
|
|
4
|
+
* for; it makes no claim about the transaction, which is the effects panel's
|
|
5
|
+
* job and is checked against the bytes rather than against this card.
|
|
6
|
+
*
|
|
7
|
+
* The Slip is assumed to have been decoded and passed `checkTemplates`: a
|
|
8
|
+
* response with a placeholder naming no parameter is one a client never renders.
|
|
9
|
+
*/
|
|
10
|
+
import { type LinkedAction, type ParameterValues, type Slip } from "@cardano-slips/core";
|
|
11
|
+
import { type FieldError } from "./parameter-form.js";
|
|
12
|
+
/** What the person chose, ready to `POST`. */
|
|
13
|
+
export type SlipSubmission = {
|
|
14
|
+
readonly action: LinkedAction;
|
|
15
|
+
/** Only what this action asked for. A caller is handed no answer it did not request. */
|
|
16
|
+
readonly values: ParameterValues;
|
|
17
|
+
/** Absolute, with every placeholder percent-encoded, so no typed value can move the request. */
|
|
18
|
+
readonly href: string;
|
|
19
|
+
};
|
|
20
|
+
export type SlipCardProps = {
|
|
21
|
+
readonly slip: Slip;
|
|
22
|
+
/**
|
|
23
|
+
* Where the metadata came from. Every `href` resolves against it and its host
|
|
24
|
+
* is the publisher the card names, so the card cannot be rendered without it.
|
|
25
|
+
*/
|
|
26
|
+
readonly discoveryUrl: string;
|
|
27
|
+
readonly onSubmit?: (submission: SlipSubmission) => void;
|
|
28
|
+
/**
|
|
29
|
+
* What the endpoint refused, by parameter name. The only failure that lands
|
|
30
|
+
* on a field instead of replacing the card, because there is something to fix.
|
|
31
|
+
* It is the caller's to clear, since only the caller knows which answer the
|
|
32
|
+
* endpoint was refusing.
|
|
33
|
+
*/
|
|
34
|
+
readonly rejected?: Readonly<Record<string, FieldError>>;
|
|
35
|
+
/** True while a request is in flight: every button stops taking presses. */
|
|
36
|
+
readonly busy?: boolean;
|
|
37
|
+
/** Prefixes generated ids, so two cards on one page do not collide. */
|
|
38
|
+
readonly idPrefix?: string;
|
|
39
|
+
};
|
|
40
|
+
export declare const SlipCard: ({ slip, discoveryUrl, onSubmit, rejected, busy, idPrefix }: SlipCardProps) => React.JSX.Element;
|
|
41
|
+
/** The same box and the same rhythm while the metadata is in flight, so nothing shifts when it lands. */
|
|
42
|
+
export declare const SlipCardSkeleton: () => React.JSX.Element;
|
|
43
|
+
export type SlipCardErrorProps = {
|
|
44
|
+
/** The endpoint that did not answer, in full: the person is being asked to judge it. */
|
|
45
|
+
readonly url: string;
|
|
46
|
+
readonly message: string;
|
|
47
|
+
readonly onRetry?: () => void;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* The endpoint did not answer, or answered with something that is not a Slip.
|
|
51
|
+
* This replaces the card rather than landing on a field, because there is
|
|
52
|
+
* nothing here for the person to fix.
|
|
53
|
+
*/
|
|
54
|
+
export declare const SlipCardError: ({ url, message, onRetry }: SlipCardErrorProps) => React.JSX.Element;
|
|
55
|
+
//# sourceMappingURL=slip-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slip-card.d.ts","sourceRoot":"","sources":["../src/slip-card.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,OAAO,EAAyB,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,KAAK,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAK/G,OAAO,EAAE,KAAK,UAAU,EAAiB,MAAM,qBAAqB,CAAA;AAEpE,8CAA8C;AAC9C,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;IAC7B,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAA;IAChC,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,IAAI,CAAA;IACxD;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAA;IACxD,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAQD,eAAO,MAAM,QAAQ,GAAI,4DAOtB,aAAa,KAAG,KAAK,CAAC,GAAG,CAAC,OAiI5B,CAAA;AAED,yGAAyG;AACzG,eAAO,MAAM,gBAAgB,QAAO,KAAK,CAAC,GAAG,CAAC,OAgB7C,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wFAAwF;IACxF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAC9B,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,2BAA2B,kBAAkB,KAAG,KAAK,CAAC,GAAG,CAAC,OAoBvF,CAAA"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* The rendered face of a Slip link — `2 · Action card` on the design sheet.
|
|
5
|
+
* It renders what the endpoint declared and collects what the endpoint asked
|
|
6
|
+
* for; it makes no claim about the transaction, which is the effects panel's
|
|
7
|
+
* job and is checked against the bytes rather than against this card.
|
|
8
|
+
*
|
|
9
|
+
* The Slip is assumed to have been decoded and passed `checkTemplates`: a
|
|
10
|
+
* response with a placeholder naming no parameter is one a client never renders.
|
|
11
|
+
*/
|
|
12
|
+
import { checkValues, fillHref } from "@cardano-slips/core";
|
|
13
|
+
import { Either } from "effect";
|
|
14
|
+
import { useState } from "react";
|
|
15
|
+
import { actionLabel, actionsOf, blockedLabel, closureOf, monogramOf, originOf, valuesFor } from "./card.js";
|
|
16
|
+
import { ParameterForm } from "./parameter-form.js";
|
|
17
|
+
/** The line that is the whole point of the card, and the reason it is worth pressing. */
|
|
18
|
+
const promise = "You'll see the exact effects, checked against this card, before you sign.";
|
|
19
|
+
/** Nothing to choose between means the one action is already the open one. */
|
|
20
|
+
const opened = (count) => (count === 1 ? 0 : undefined);
|
|
21
|
+
export const SlipCard = ({ slip, discoveryUrl, onSubmit, rejected, busy = false, idPrefix = "slip" }) => {
|
|
22
|
+
const actions = actionsOf(slip, discoveryUrl);
|
|
23
|
+
const [values, setValues] = useState({});
|
|
24
|
+
// Errors stay quiet until a send is attempted: a card that opens red is
|
|
25
|
+
// scolding someone for not having typed yet.
|
|
26
|
+
const [attempted, setAttempted] = useState(false);
|
|
27
|
+
const [open, setOpen] = useState(opened(actions.length));
|
|
28
|
+
const [failedIcon, setFailedIcon] = useState(undefined);
|
|
29
|
+
// Resetting during render is React's own answer to a prop moving out from
|
|
30
|
+
// under the state derived from it. A second Slip must not open pre-filled
|
|
31
|
+
// with the first one's answers, and remembering to pass a `key` is not a
|
|
32
|
+
// thing to leave to whoever embeds this.
|
|
33
|
+
const [shown, setShown] = useState(discoveryUrl);
|
|
34
|
+
if (shown !== discoveryUrl) {
|
|
35
|
+
setShown(discoveryUrl);
|
|
36
|
+
setValues({});
|
|
37
|
+
setAttempted(false);
|
|
38
|
+
setOpen(opened(actions.length));
|
|
39
|
+
setFailedIcon(undefined);
|
|
40
|
+
}
|
|
41
|
+
const closed = slip.disabled === true;
|
|
42
|
+
const parameters = (open === undefined ? undefined : actions[open]?.parameters) ?? [];
|
|
43
|
+
const issues = checkValues(parameters, values);
|
|
44
|
+
const blocked = attempted && issues.length > 0;
|
|
45
|
+
// `??=` would be wrong here: a parameter may be called `constructor`, and a
|
|
46
|
+
// plain object already answers to that with something that is not nullish.
|
|
47
|
+
const errors = {};
|
|
48
|
+
const note = (name, error) => {
|
|
49
|
+
if (!Object.hasOwn(errors, name))
|
|
50
|
+
errors[name] = error;
|
|
51
|
+
};
|
|
52
|
+
if (attempted)
|
|
53
|
+
for (const issue of issues)
|
|
54
|
+
note(issue.name, { message: issue.message });
|
|
55
|
+
for (const [name, error] of Object.entries(rejected ?? {}))
|
|
56
|
+
note(name, error);
|
|
57
|
+
const press = (index) => {
|
|
58
|
+
const action = actions[index];
|
|
59
|
+
// The spec: an action without parameters is submitted as soon as it is
|
|
60
|
+
// chosen. One that has them opens its form instead of sending blind.
|
|
61
|
+
if (action.parameters !== undefined && index !== open) {
|
|
62
|
+
setOpen(index);
|
|
63
|
+
setAttempted(false);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const target = fillHref(action, values, discoveryUrl);
|
|
67
|
+
if (Either.isLeft(target)) {
|
|
68
|
+
setAttempted(true);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
onSubmit?.({ action, values: valuesFor(action, values), href: target.right });
|
|
72
|
+
};
|
|
73
|
+
const monogram = monogramOf(discoveryUrl);
|
|
74
|
+
const origin = originOf(discoveryUrl);
|
|
75
|
+
return (_jsxs("div", { className: "slip-root slip-card", "data-closed": closed ? "" : undefined, "data-busy": busy ? "" : undefined, children: [_jsxs("div", { className: "slip-card__head", children: [_jsx("div", { className: "slip-card__icon", children: failedIcon !== slip.icon ? (_jsx("img", { className: "slip-card__image", src: slip.icon, alt: "", onError: () => setFailedIcon(slip.icon) })) : monogram === undefined ? (_jsx("span", { className: "slip-card__pattern" })) : (_jsx("span", { className: "slip-card__monogram", children: monogram })) }), _jsxs("div", { className: "slip-card__identity", children: [_jsx("h2", { className: "slip-card__title", children: slip.title }), origin === undefined ? undefined : _jsx("span", { className: "slip-card__origin", children: origin })] })] }), _jsx("p", { className: "slip-card__description", children: slip.description }), parameters.length === 0 ? undefined : (_jsx(ParameterForm, { parameters: parameters, values: values, errors: errors, idPrefix: idPrefix, onChange: (name, value) => setValues((held) => ({ ...held, [name]: value })) })), _jsx("div", { className: "slip-card__actions", children: actions.map((action, index) => {
|
|
76
|
+
const closure = closureOf(slip, action);
|
|
77
|
+
const stopped = index === (open ?? 0) && blocked;
|
|
78
|
+
return (_jsx("button", { type: "button", className: "slip-card__action", "data-primary": index === (open ?? 0) ? "" : undefined, disabled: busy || closure !== undefined || stopped, onClick: () => press(index), children: stopped ? blockedLabel(issues) : actionLabel(slip, action, values) }, index));
|
|
79
|
+
}) }), closed ? (_jsx("p", { className: "slip-card__reason", children: slip.reason?.message })) : (actions.map((action, index) => action.disabled === true && action.reason !== undefined ? (_jsx("p", { className: "slip-card__reason", children: action.reason.message }, index)) : undefined)), closed ? undefined : _jsx("p", { className: "slip-card__note", children: promise })] }));
|
|
80
|
+
};
|
|
81
|
+
/** The same box and the same rhythm while the metadata is in flight, so nothing shifts when it lands. */
|
|
82
|
+
export const SlipCardSkeleton = () => (_jsxs("div", { className: "slip-root slip-card slip-card--loading", role: "status", "aria-busy": "true", children: [_jsx("span", { className: "slip-hidden", children: "Loading this Slip" }), _jsxs("div", { className: "slip-card__head", children: [_jsx("span", { className: "slip-skeleton slip-skeleton--icon" }), _jsxs("div", { className: "slip-card__identity", children: [_jsx("span", { className: "slip-skeleton slip-skeleton--title" }), _jsx("span", { className: "slip-skeleton slip-skeleton--origin" })] })] }), _jsxs("div", { className: "slip-skeleton__lines", children: [_jsx("span", { className: "slip-skeleton slip-skeleton--line" }), _jsx("span", { className: "slip-skeleton slip-skeleton--line slip-skeleton--short" })] }), _jsx("span", { className: "slip-skeleton slip-skeleton--action" })] }));
|
|
83
|
+
/**
|
|
84
|
+
* The endpoint did not answer, or answered with something that is not a Slip.
|
|
85
|
+
* This replaces the card rather than landing on a field, because there is
|
|
86
|
+
* nothing here for the person to fix.
|
|
87
|
+
*/
|
|
88
|
+
export const SlipCardError = ({ url, message, onRetry }) => (_jsxs("div", { className: "slip-root slip-card slip-card--failed", role: "alert", children: [_jsxs("div", { className: "slip-card__head", children: [_jsx("span", { className: "slip-card__alarm", "aria-hidden": "true", children: "!" }), _jsxs("div", { className: "slip-card__identity", children: [_jsx("h2", { className: "slip-card__title", children: "This Slip didn't load" }), _jsx("span", { className: "slip-card__origin", children: url })] })] }), _jsx("p", { className: "slip-card__description", children: message }), onRetry === undefined ? undefined : (_jsx("div", { className: "slip-card__actions", children: _jsx("button", { type: "button", className: "slip-card__action", onClick: onRetry, children: "Try again" }) }))] }));
|
|
89
|
+
//# sourceMappingURL=slip-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slip-card.js","sourceRoot":"","sources":["../src/slip-card.tsx"],"names":[],"mappings":"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"}
|