@unconfirmed/sui-effect 0.1.1 → 0.1.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/AGENTS.md +34 -11
- package/CHANGELOG.md +77 -0
- package/LLMS.md +630 -704
- package/README.md +175 -9
- package/dist/domain/bcs.d.ts.map +1 -1
- package/dist/domain/bcs.js +25 -9
- package/dist/domain/bcs.js.map +1 -1
- package/dist/domain/errors.d.ts +178 -40
- package/dist/domain/errors.d.ts.map +1 -1
- package/dist/domain/errors.js +271 -37
- package/dist/domain/errors.js.map +1 -1
- package/dist/domain/executed.d.ts +71 -2
- package/dist/domain/executed.d.ts.map +1 -1
- package/dist/domain/executed.js +210 -9
- package/dist/domain/executed.js.map +1 -1
- package/dist/domain/journal-entry.d.ts +37 -37
- package/dist/domain/journal-entry.js +1 -1
- package/dist/domain/schemas.d.ts +172 -65
- package/dist/domain/schemas.d.ts.map +1 -1
- package/dist/domain/schemas.js +131 -32
- package/dist/domain/schemas.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/script.d.ts +1 -1
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +1 -1
- package/dist/script.js.map +1 -1
- package/dist/services/Script.d.ts +42 -0
- package/dist/services/Script.d.ts.map +1 -1
- package/dist/services/Script.js +112 -77
- package/dist/services/Script.js.map +1 -1
- package/dist/services/Signer.d.ts +32 -7
- package/dist/services/Signer.d.ts.map +1 -1
- package/dist/services/Signer.js +69 -10
- package/dist/services/Signer.js.map +1 -1
- package/dist/services/SubmitConfig.d.ts +3 -22
- package/dist/services/SubmitConfig.d.ts.map +1 -1
- package/dist/services/SubmitConfig.js +54 -9
- package/dist/services/SubmitConfig.js.map +1 -1
- package/dist/services/Sui.d.ts +42 -1
- package/dist/services/Sui.d.ts.map +1 -1
- package/dist/services/Sui.js +46 -17
- package/dist/services/Sui.js.map +1 -1
- package/dist/services/SuiCore.d.ts.map +1 -1
- package/dist/services/SuiCore.js +47 -33
- package/dist/services/SuiCore.js.map +1 -1
- package/dist/services/SuiCoreFake.d.ts +47 -4
- package/dist/services/SuiCoreFake.d.ts.map +1 -1
- package/dist/services/SuiCoreFake.js +193 -22
- package/dist/services/SuiCoreFake.js.map +1 -1
- package/dist/services/Tx.d.ts +236 -402
- package/dist/services/Tx.d.ts.map +1 -1
- package/dist/services/Tx.js +205 -10
- package/dist/services/Tx.js.map +1 -1
- package/dist/testing.d.ts +1 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +9 -0
- package/dist/testing.js.map +1 -1
- package/dist/tx.d.ts +1 -1
- package/dist/tx.d.ts.map +1 -1
- package/dist/tx.js +1 -1
- package/dist/tx.js.map +1 -1
- package/docs/extensions.md +608 -19
- package/examples/extension-template/src/Escrow.ts +1 -1
- package/examples/extension-template/src/errors.ts +29 -0
- package/examples/extension-template/src/schema.ts +8 -17
- package/examples/extension-template/test/escrow.test.ts +44 -0
- package/package.json +1 -1
|
@@ -213,7 +213,7 @@ const make = (
|
|
|
213
213
|
Effect.flatMap((raw) =>
|
|
214
214
|
decodeAddress(raw).pipe(
|
|
215
215
|
Effect.mapError((issue) =>
|
|
216
|
-
new DecodeError({ expectedType: "SuiAddress", issue: issue.message })
|
|
216
|
+
new DecodeError({ expectedType: "SuiAddress", kind: "shape", issue: issue.message })
|
|
217
217
|
)
|
|
218
218
|
)
|
|
219
219
|
),
|
|
@@ -10,6 +10,14 @@
|
|
|
10
10
|
*
|
|
11
11
|
* The tags are prefixed with the package name because `EscrowNotFound` is a
|
|
12
12
|
* name two packages could plausibly both want.
|
|
13
|
+
*
|
|
14
|
+
* And every one of them has a real `.message`. `Schema.TaggedError` leaves it
|
|
15
|
+
* empty, so an error that supplies neither an `override get message()` nor a
|
|
16
|
+
* `message` schema field surfaces an empty string everywhere a consumer
|
|
17
|
+
* catches it, and `SuiError.toJson` emits no `message` key at all. The getter
|
|
18
|
+
* is the usual answer — it stays out of the encoding, so it costs nothing at
|
|
19
|
+
* the constructor — and a `message` schema field is for the case where the
|
|
20
|
+
* sentence comes from somewhere else, as `EscrowSettlementUnknown`'s does.
|
|
13
21
|
*/
|
|
14
22
|
import { Schema } from "effect"
|
|
15
23
|
import { Digest, type Outcome, ObjectId } from "@unconfirmed/sui-effect"
|
|
@@ -25,6 +33,18 @@ export class EscrowNotFound extends Schema.TaggedError<EscrowNotFound>()(
|
|
|
25
33
|
{ escrowId: ObjectId }
|
|
26
34
|
) {
|
|
27
35
|
readonly outcome: Outcome = "not_applied"
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* `Schema.TaggedError` leaves `.message` empty, so anything surfacing
|
|
39
|
+
* `error.message` — a log line, a `catch` in a consumer's UI,
|
|
40
|
+
* `SuiError.toJson` — shows nothing unless the class supplies one. This is
|
|
41
|
+
* the idiom sui-effect's own errors use, and the reason every error here has
|
|
42
|
+
* one: define a getter over the fields, never a `message` schema field you
|
|
43
|
+
* then have to pass to every constructor.
|
|
44
|
+
*/
|
|
45
|
+
override get message(): string {
|
|
46
|
+
return `no escrow ${this.escrowId}`
|
|
47
|
+
}
|
|
28
48
|
}
|
|
29
49
|
|
|
30
50
|
/**
|
|
@@ -34,6 +54,10 @@ export class EscrowNotFound extends Schema.TaggedError<EscrowNotFound>()(
|
|
|
34
54
|
* This is the case the `outcome` field exists for: the transaction applied, the
|
|
35
55
|
* operation as a whole did not finish, and the only safe next step is to
|
|
36
56
|
* reconcile rather than to retry. A script that fails with this exits 3.
|
|
57
|
+
*
|
|
58
|
+
* Its `message` is a **schema field** rather than a getter, because the
|
|
59
|
+
* sentence comes from the settlement service rather than from these fields.
|
|
60
|
+
* Either way `.message` is a real string and `SuiError.toJson` carries it.
|
|
37
61
|
*/
|
|
38
62
|
export class EscrowSettlementUnknown extends Schema.TaggedError<EscrowSettlementUnknown>()(
|
|
39
63
|
"escrow/EscrowSettlementUnknown",
|
|
@@ -58,4 +82,9 @@ export class EscrowUnsupportedNetwork extends Schema.TaggedError<EscrowUnsupport
|
|
|
58
82
|
{ network: Schema.String }
|
|
59
83
|
) {
|
|
60
84
|
readonly outcome: Outcome = "not_applied"
|
|
85
|
+
|
|
86
|
+
/** See {@link EscrowNotFound.message}: a getter, not a schema field. */
|
|
87
|
+
override get message(): string {
|
|
88
|
+
return `this release bundles no escrow deployment for ${this.network}`
|
|
89
|
+
}
|
|
61
90
|
}
|
|
@@ -72,22 +72,12 @@ const SettlementBcs = bcs.struct("Settlement", {
|
|
|
72
72
|
* needs a real `BcsType` so it can re-serialize what it parsed and reject
|
|
73
73
|
* trailing bytes, and a domain type is not a BCS layout.
|
|
74
74
|
*/
|
|
75
|
-
export class Settlement extends Schema.Class<Settlement>("Settlement")({
|
|
75
|
+
export class Settlement extends Schema.Class<Settlement>("escrow/Settlement")({
|
|
76
76
|
escrowId: ObjectId,
|
|
77
77
|
settledAt: Schema.DateTimeUtc,
|
|
78
78
|
claimedBy: SuiAddress
|
|
79
79
|
}) {}
|
|
80
80
|
|
|
81
|
-
/**
|
|
82
|
-
* The halfway shape the transformation produces: the domain field names, before
|
|
83
|
-
* `Settlement`'s own schema brands the ids.
|
|
84
|
-
*/
|
|
85
|
-
interface SettlementParts {
|
|
86
|
-
readonly escrowId: string
|
|
87
|
-
readonly settledAt: DateTime.Utc
|
|
88
|
-
readonly claimedBy: string
|
|
89
|
-
}
|
|
90
|
-
|
|
91
81
|
/**
|
|
92
82
|
* The composed codec: BCS bytes to `Settlement`, and back.
|
|
93
83
|
*
|
|
@@ -101,10 +91,11 @@ interface SettlementParts {
|
|
|
101
91
|
*
|
|
102
92
|
* Two details worth copying:
|
|
103
93
|
*
|
|
104
|
-
* - **`decode` produces the target's
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
94
|
+
* - **`decode` produces the target's `Encoded` side, not an instance.**
|
|
95
|
+
* `typeof Settlement.Encoded` is exactly that shape, so nothing has to be
|
|
96
|
+
* written out by hand and nothing can drift. `decodeTo` sits between the
|
|
97
|
+
* source type and the target schema, which is what lets the target's own
|
|
98
|
+
* checks — the `ObjectId` and `SuiAddress` brands here — run afterwards.
|
|
108
99
|
* - **`encode` is the inverse mapper and is not optional.** A codec that cannot
|
|
109
100
|
* encode is one `Schema.encodeUnknownEffect` fails on, and the compiler asks
|
|
110
101
|
* for it here rather than at the call site.
|
|
@@ -124,7 +115,7 @@ export const SettlementContent = (typeOrigin: string) =>
|
|
|
124
115
|
).pipe(
|
|
125
116
|
Schema.decodeTo(
|
|
126
117
|
Settlement,
|
|
127
|
-
SchemaTransformation.transformOrFail<
|
|
118
|
+
SchemaTransformation.transformOrFail<typeof Settlement.Encoded, typeof SettlementBcs.$inferType>({
|
|
128
119
|
decode: (fields, options) =>
|
|
129
120
|
// `transformOrFail`, not `transform`, because one of these mappings can
|
|
130
121
|
// fail: a `u64` of milliseconds is not necessarily a time. A `transform`
|
|
@@ -141,7 +132,7 @@ export const SettlementContent = (typeOrigin: string) =>
|
|
|
141
132
|
options
|
|
142
133
|
)
|
|
143
134
|
),
|
|
144
|
-
(settledAt):
|
|
135
|
+
(settledAt): typeof Settlement.Encoded => ({
|
|
145
136
|
escrowId: fields.escrow_id,
|
|
146
137
|
settledAt,
|
|
147
138
|
claimedBy: fields.claimed_by
|
|
@@ -268,6 +268,15 @@ describe("Settlement: a domain class over the BCS bridge", () => {
|
|
|
268
268
|
claimed_by: bcs.Address
|
|
269
269
|
})
|
|
270
270
|
|
|
271
|
+
// The identifier is the class's stable runtime marker and its JSON-Schema
|
|
272
|
+
// `$ref` key, so it follows the guide's `"<package>/<Name>"` rule: two
|
|
273
|
+
// extensions with a `Settlement` class must not collide in one document.
|
|
274
|
+
test("the class identifier is scoped to the package", () => {
|
|
275
|
+
expect(JSON.stringify(Schema.toJsonSchemaDocument(Settlement))).toContain(
|
|
276
|
+
"escrow/Settlement"
|
|
277
|
+
)
|
|
278
|
+
})
|
|
279
|
+
|
|
271
280
|
test("snake_case Move fields decode into the camelCase domain class", async () => {
|
|
272
281
|
const bytes = SettlementBcs.serialize({
|
|
273
282
|
escrow_id: ESCROW_ID,
|
|
@@ -645,4 +654,39 @@ describe("the errors", () => {
|
|
|
645
654
|
expect(json["outcome"]).toBe("unknown")
|
|
646
655
|
expect(json["outcome"]).toBe(SuiError.outcome(error))
|
|
647
656
|
})
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* `Schema.TaggedError` leaves `.message` empty, so an error that defines
|
|
660
|
+
* neither a getter nor a `message` schema field logs as an empty string and
|
|
661
|
+
* `SuiError.toJson` emits no `message` key at all. Every error here defines
|
|
662
|
+
* one, and the guide promises a reader that they will.
|
|
663
|
+
*/
|
|
664
|
+
test("every error has a real message, and toJson carries it", () => {
|
|
665
|
+
const errors = [
|
|
666
|
+
new EscrowNotFound({ escrowId: ESCROW_ID }),
|
|
667
|
+
new EscrowSettlementUnknown({
|
|
668
|
+
escrowId: ESCROW_ID,
|
|
669
|
+
digest: "1".repeat(32) as never,
|
|
670
|
+
message: "the operator never confirmed"
|
|
671
|
+
}),
|
|
672
|
+
new EscrowUnsupportedNetwork({ network: "devnet" })
|
|
673
|
+
]
|
|
674
|
+
for (const error of errors) {
|
|
675
|
+
expect([error._tag, error.message.length > 0]).toEqual([error._tag, true])
|
|
676
|
+
expect([error._tag, SuiError.toJson(error)["message"]]).toEqual([
|
|
677
|
+
error._tag,
|
|
678
|
+
error.message
|
|
679
|
+
])
|
|
680
|
+
}
|
|
681
|
+
// The getter reads the error's own fields, so the sentence names the thing
|
|
682
|
+
// that failed rather than repeating the tag.
|
|
683
|
+
expect(new EscrowNotFound({ escrowId: ESCROW_ID }).message).toBe(`no escrow ${ESCROW_ID}`)
|
|
684
|
+
expect(new EscrowUnsupportedNetwork({ network: "devnet" }).message).toBe(
|
|
685
|
+
"this release bundles no escrow deployment for devnet"
|
|
686
|
+
)
|
|
687
|
+
// And a getter stays out of the encoding, so it is not a constructor
|
|
688
|
+
// argument: only `EscrowSettlementUnknown` takes a `message`.
|
|
689
|
+
expect(Object.keys(SuiError.toJson(new EscrowUnsupportedNetwork({ network: "devnet" }))))
|
|
690
|
+
.toEqual(["_tag", "network", "outcome", "message"])
|
|
691
|
+
})
|
|
648
692
|
})
|
package/package.json
CHANGED