@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.
Files changed (74) hide show
  1. package/AGENTS.md +34 -11
  2. package/CHANGELOG.md +77 -0
  3. package/LLMS.md +630 -704
  4. package/README.md +175 -9
  5. package/dist/domain/bcs.d.ts.map +1 -1
  6. package/dist/domain/bcs.js +25 -9
  7. package/dist/domain/bcs.js.map +1 -1
  8. package/dist/domain/errors.d.ts +178 -40
  9. package/dist/domain/errors.d.ts.map +1 -1
  10. package/dist/domain/errors.js +271 -37
  11. package/dist/domain/errors.js.map +1 -1
  12. package/dist/domain/executed.d.ts +71 -2
  13. package/dist/domain/executed.d.ts.map +1 -1
  14. package/dist/domain/executed.js +210 -9
  15. package/dist/domain/executed.js.map +1 -1
  16. package/dist/domain/journal-entry.d.ts +37 -37
  17. package/dist/domain/journal-entry.js +1 -1
  18. package/dist/domain/schemas.d.ts +172 -65
  19. package/dist/domain/schemas.d.ts.map +1 -1
  20. package/dist/domain/schemas.js +131 -32
  21. package/dist/domain/schemas.js.map +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/internal.d.ts +1 -1
  27. package/dist/internal.d.ts.map +1 -1
  28. package/dist/internal.js +1 -1
  29. package/dist/internal.js.map +1 -1
  30. package/dist/script.d.ts +1 -1
  31. package/dist/script.d.ts.map +1 -1
  32. package/dist/script.js +1 -1
  33. package/dist/script.js.map +1 -1
  34. package/dist/services/Script.d.ts +42 -0
  35. package/dist/services/Script.d.ts.map +1 -1
  36. package/dist/services/Script.js +112 -77
  37. package/dist/services/Script.js.map +1 -1
  38. package/dist/services/Signer.d.ts +32 -7
  39. package/dist/services/Signer.d.ts.map +1 -1
  40. package/dist/services/Signer.js +69 -10
  41. package/dist/services/Signer.js.map +1 -1
  42. package/dist/services/SubmitConfig.d.ts +3 -22
  43. package/dist/services/SubmitConfig.d.ts.map +1 -1
  44. package/dist/services/SubmitConfig.js +54 -9
  45. package/dist/services/SubmitConfig.js.map +1 -1
  46. package/dist/services/Sui.d.ts +42 -1
  47. package/dist/services/Sui.d.ts.map +1 -1
  48. package/dist/services/Sui.js +46 -17
  49. package/dist/services/Sui.js.map +1 -1
  50. package/dist/services/SuiCore.d.ts.map +1 -1
  51. package/dist/services/SuiCore.js +47 -33
  52. package/dist/services/SuiCore.js.map +1 -1
  53. package/dist/services/SuiCoreFake.d.ts +47 -4
  54. package/dist/services/SuiCoreFake.d.ts.map +1 -1
  55. package/dist/services/SuiCoreFake.js +193 -22
  56. package/dist/services/SuiCoreFake.js.map +1 -1
  57. package/dist/services/Tx.d.ts +236 -402
  58. package/dist/services/Tx.d.ts.map +1 -1
  59. package/dist/services/Tx.js +205 -10
  60. package/dist/services/Tx.js.map +1 -1
  61. package/dist/testing.d.ts +1 -0
  62. package/dist/testing.d.ts.map +1 -1
  63. package/dist/testing.js +9 -0
  64. package/dist/testing.js.map +1 -1
  65. package/dist/tx.d.ts +1 -1
  66. package/dist/tx.d.ts.map +1 -1
  67. package/dist/tx.js +1 -1
  68. package/dist/tx.js.map +1 -1
  69. package/docs/extensions.md +608 -19
  70. package/examples/extension-template/src/Escrow.ts +1 -1
  71. package/examples/extension-template/src/errors.ts +29 -0
  72. package/examples/extension-template/src/schema.ts +8 -17
  73. package/examples/extension-template/test/escrow.test.ts +44 -0
  74. 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 field shape, not an instance.** `decodeTo`
105
- * sits between the source type and the target schema, which is what lets the
106
- * target's own checks the `ObjectId` and `SuiAddress` brands here — run
107
- * afterwards.
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<SettlementParts, typeof SettlementBcs.$inferType>({
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): SettlementParts => ({
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unconfirmed/sui-effect",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "An opinionated Effect v4 layer over @mysten/sui: two client tiers, closed error unions, and a typed transaction lifecycle.",
5
5
  "license": "MIT",
6
6
  "type": "module",