@unconfirmed/sui-effect 0.1.0 → 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/AGENTS.md +47 -14
- package/CHANGELOG.md +86 -0
- package/LLMS.md +2889 -1726
- package/README.md +517 -11
- package/dist/domain/bcs.d.ts +44 -0
- package/dist/domain/bcs.d.ts.map +1 -1
- package/dist/domain/bcs.js +64 -0
- package/dist/domain/bcs.js.map +1 -1
- package/dist/domain/errors.d.ts +164 -26
- package/dist/domain/errors.d.ts.map +1 -1
- package/dist/domain/errors.js +193 -15
- package/dist/domain/errors.js.map +1 -1
- package/dist/domain/executed.d.ts +123 -18
- package/dist/domain/executed.d.ts.map +1 -1
- package/dist/domain/executed.js +196 -5
- package/dist/domain/executed.js.map +1 -1
- package/dist/domain/journal-entry.d.ts +6 -2
- package/dist/domain/journal-entry.d.ts.map +1 -1
- package/dist/domain/schemas.d.ts +234 -67
- package/dist/domain/schemas.d.ts.map +1 -1
- package/dist/domain/schemas.js +82 -4
- package/dist/domain/schemas.js.map +1 -1
- package/dist/domain/sui-schema.d.ts +3 -2
- package/dist/domain/sui-schema.d.ts.map +1 -1
- package/dist/domain/sui-schema.js +3 -2
- package/dist/domain/sui-schema.js.map +1 -1
- package/dist/extension.d.ts +1 -1
- package/dist/extension.d.ts.map +1 -1
- package/dist/extension.js +1 -1
- package/dist/extension.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/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 +69 -2
- 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/Sui.d.ts +42 -1
- package/dist/services/Sui.d.ts.map +1 -1
- package/dist/services/Sui.js +18 -4
- package/dist/services/Sui.js.map +1 -1
- package/dist/services/SuiCore.d.ts +12 -0
- package/dist/services/SuiCore.d.ts.map +1 -1
- package/dist/services/SuiCore.js +124 -0
- package/dist/services/SuiCore.js.map +1 -1
- package/dist/services/SuiCoreFake.d.ts +59 -4
- package/dist/services/SuiCoreFake.d.ts.map +1 -1
- package/dist/services/SuiCoreFake.js +199 -23
- package/dist/services/SuiCoreFake.js.map +1 -1
- package/dist/services/SuiExtension.d.ts +127 -14
- package/dist/services/SuiExtension.d.ts.map +1 -1
- package/dist/services/SuiExtension.js +125 -28
- package/dist/services/SuiExtension.js.map +1 -1
- package/dist/services/SuiGraphQL.d.ts +13 -0
- package/dist/services/SuiGraphQL.d.ts.map +1 -1
- package/dist/services/SuiGraphQL.js +13 -0
- package/dist/services/SuiGraphQL.js.map +1 -1
- package/dist/services/Tx.d.ts +630 -12
- package/dist/services/Tx.d.ts.map +1 -1
- package/dist/services/Tx.js +187 -8
- package/dist/services/Tx.js.map +1 -1
- package/dist/testing.d.ts +22 -3
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +39 -3
- 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 +871 -33
- package/examples/extension-template/src/Escrow.ts +1 -1
- package/examples/extension-template/test/escrow.test.ts +91 -2
- package/package.json +3 -2
package/AGENTS.md
CHANGED
|
@@ -26,7 +26,15 @@ the work plan. Where this file and the spec disagree, fix this file.
|
|
|
26
26
|
edges: the Promise facade of `SuiExtension.fromService`, and `Script.run`,
|
|
27
27
|
which is a process entrypoint and whose whole job is to fork the root fiber,
|
|
28
28
|
await its `Exit` and exit.
|
|
29
|
-
- No `any`. No `unknown` in an error channel. No `console.log` in `src/`.
|
|
29
|
+
- No `any`. No `unknown` in an error channel. No `console.log` in `src/`. The
|
|
30
|
+
one `console.warn` is `SuiCore.mapSdkError`'s duplicate-SDK warning, which
|
|
31
|
+
fires at most once per process and is documented where it lives. **Nothing in
|
|
32
|
+
`src/` writes to stderr otherwise** — `test/release-0-1-2.test.ts` captures it
|
|
33
|
+
around a full `Tx.run` on the fake and asserts it is empty.
|
|
34
|
+
- **A branded id from a shorthand spelling** comes from `SuiAddress.normalize`
|
|
35
|
+
/ `ObjectId.normalize` (decode, then brand); `.make` validates without
|
|
36
|
+
decoding and is for the padded form only. Neither is for a value that came
|
|
37
|
+
from outside: that goes through `Schema.decodeUnknownEffect`.
|
|
30
38
|
- **One Move type rule.** `typeMatches(expected, actual)` (`src/domain/bcs.ts`)
|
|
31
39
|
is the only comparison: a bare expected tag matches every instantiation of the
|
|
32
40
|
generic, a parameterized one is compared in full after normalization. The
|
|
@@ -67,7 +75,7 @@ the work plan. Where this file and the spec disagree, fix this file.
|
|
|
67
75
|
| Tier | What it is | When to use it |
|
|
68
76
|
|---|---|---|
|
|
69
77
|
| `SuiCore` | A 1:1 Effect wrap of `ClientWithCoreApi`. One member per `SuiClientTypes.TransportMethods` key plus `getObject`, `getDynamicObjectField`, `waitForTransaction`, `signAndExecuteTransaction` and `use`. `Include` generics preserved. | Reaching a field or method `Sui` does not expose, and inside extension implementations. |
|
|
70
|
-
| `Sui` | The opinionated tier over `SuiCore`: fixed include sets, decoded BCS content, `Option` where absence is normal, chunked and integrity-checked batch reads (`getObjects` per-item `Result`, `
|
|
78
|
+
| `Sui` | The opinionated tier over `SuiCore`: fixed include sets, decoded BCS content, `Option` where absence is normal, chunked and integrity-checked batch reads (`getObjects` per-item `Result`, `getObjectsStrict` first-error-wins — `getObjectsOrFail` is the deprecated alias), `Stream` pagination, one sender lock. | Almost all application and extension code. |
|
|
71
79
|
|
|
72
80
|
Reads go through `Sui`; writes go through `Tx`. An extension never calls
|
|
73
81
|
`SuiCore.executeTransaction` directly. `Sui` exposes the `SuiCore` it was built
|
|
@@ -79,11 +87,11 @@ and nothing else.
|
|
|
79
87
|
| Name | What it is |
|
|
80
88
|
|---|---|
|
|
81
89
|
| `Signer` | A credential as a **value**, never a service: `{ address, scheme, signTransaction, signPersonalMessage }`. One process may hold two. Secret material never reaches the value. |
|
|
82
|
-
| `Tx.build/sign/cosign/sponsored/submit/reconcile/run/reconcileAll` | The lifecycle as functions, each with a closed error union, all `R = Sui`. |
|
|
90
|
+
| `Tx.build/sign/cosign/sponsored/submit/submitVia/reconcile/recorded/run/reconcileAll` | The lifecycle as functions, each with a closed error union, all `R = Sui`. `submitVia` is `submit` for a submission somebody else makes; `recorded(digest)` reads one journal entry, which is what `reconcileAll` — unresolved entries only — cannot answer. `Tx.run` takes `onSigned`, the hook between the last signature and the first send. |
|
|
83
91
|
| `SubmitConfig` | A `Context.Reference` holding expiration policy, the optional `validFor` wall-clock bound, the gas-budget ceiling, `preflight`, the sender lock, the resubmit schedule, attempts, timeout and expiry margin, plus `expiryEvidence`, `reconcileRecheck`, `awaitVisibility`, `visibilityTimeout` and `nonce`. |
|
|
84
92
|
| `Journal` | A `Context.Reference` with an in-memory default. `@unconfirmed/sui-effect/journal` swaps in a durable one over `KeyValueStore`; `Tx.reconcileAll()` is the explicit startup call. |
|
|
85
93
|
| `Script` | `{ sui, core, signer, network }` plus `Script.run` and `Script.exitCode`. `ScriptReadOnly` is the signer-less variant, a separate key on purpose. |
|
|
86
|
-
| `SuiExtension.fromService` | The Promise face of an Effect service, and the only place in `src/` allowed to run Effects. Options: `sui` (chain pinning), `warm` (build the runtime synchronously in `register`). The face carries `$ready()` and `$dispose()`; a synchronous member called before the runtime exists fails with `ExtensionNotReady`, while `Effect` and `Stream` members work cold. Every registration on one client shares one base `Sui`/`SuiCore` — one chain-id read and one sender-lock map — reference counted, so `$dispose()` releases it only when the last registration does
|
|
94
|
+
| `SuiExtension.fromService` | The Promise face of an Effect service, and the only place in `src/` allowed to run Effects. Options: `sui` (chain pinning), `warm` (build the runtime synchronously in `register`, which throws **any** layer failure out of `$extend`). The face carries `$ready()` and `$dispose()`; a synchronous member called before the runtime exists fails with `ExtensionNotReady`, while `Effect` and `Stream` members work cold — a cold call is a real `Promise` subclass that is also an `AsyncIterable`, with its rejection pre-handled. `PromiseFace` recurses by **type**, so an interface-typed namespace is mapped; the leaves are functions, arrays, `Uint8Array`, `Date`, `Promise`, BCS codecs and anything marked `SuiExtension.Leaf<T>` / `SuiExtension.leaf(value)`. Every registration on one client shares one base `Sui`/`SuiCore` — one chain-id read and one sender-lock map — reference counted, so `$dispose()` releases it only when the last registration does; a `warm` registration re-warms on the next use after `$dispose()`. |
|
|
87
95
|
| `SuiGraphQL` | A bare tag over the SDK's `SuiGraphQLClient` (`layer`, `layerConfig`, `layerUnavailable`). @unconfirmed/sui-effect wraps no GraphQL API; the tag exists so extensions share one client. |
|
|
88
96
|
|
|
89
97
|
## Extensions
|
|
@@ -99,7 +107,12 @@ copyable package every block of that guide is quoted from, and
|
|
|
99
107
|
`Tx.submit` journals `Signed` before the first execute, re-sends the identical
|
|
100
108
|
bytes (never a rebuild) on a retryable `TransportError` or a timeout, and
|
|
101
109
|
reconciles when the retries run out. A `TransportError` never escapes once bytes
|
|
102
|
-
may have been sent: it becomes `SubmissionUnknown`, which carries them.
|
|
110
|
+
may have been sent: it becomes `SubmissionUnknown`, which carries them. **The
|
|
111
|
+
one exception is a gRPC `INVALID_ARGUMENT`** (`REFUSED_OUTRIGHT` in `Tx.ts`):
|
|
112
|
+
the node refused the request, nothing executed, and reconciling would ask
|
|
113
|
+
whether a never-sent transaction is on chain — a question a lagging or scripted
|
|
114
|
+
node can answer yes. That error escapes as itself, which is why `SubmitError`
|
|
115
|
+
includes `TransportError`.
|
|
103
116
|
`JournalError` escapes only from the `Signed` write, before anything is sent;
|
|
104
117
|
after the network has answered, a failed journal write is logged and the answer
|
|
105
118
|
stands.
|
|
@@ -151,7 +164,7 @@ Every failure is one flat tag; there is no error inheritance.
|
|
|
151
164
|
| `ObjectNotFound` / `ObjectDeleted` / `ObjectUnavailable` | The three `ObjectError.reason` values. |
|
|
152
165
|
| `TransactionNotFound` | No transaction with that digest is known. |
|
|
153
166
|
| `NetworkMismatch` | The node is on another chain than the layer was built for. |
|
|
154
|
-
| `DecodeError` | BCS content or a schema boundary did not decode. |
|
|
167
|
+
| `DecodeError` | BCS content or a schema boundary did not decode. `kind` is `"type"` (tag mismatch, nothing parsed), `"bytes"` (BCS parse or trailing bytes) or `"shape"` (a domain schema). Every producer sets it; consumers branch on it, never on `issue`. |
|
|
155
168
|
| `SimulationFailed` | Simulation reported an execution failure. No gas charged. |
|
|
156
169
|
| `ExecutionFailed` | Applied on chain and failed. Gas charged. |
|
|
157
170
|
| `SubmissionUnknown` | Bytes may have been sent; the outcome is unknown. Carries the signed bytes, unless it came from reconciling a bare digest. |
|
|
@@ -164,21 +177,33 @@ Every failure is one flat tag; there is no error inheritance.
|
|
|
164
177
|
`"not_applied"` for every other tag in the taxonomy, and `"unknown"` for
|
|
165
178
|
anything that is neither one of those tags nor declares an `outcome`.
|
|
166
179
|
`Script.exitCode` exits 1 for that last case rather than 3. An extension error
|
|
167
|
-
may declare its own `outcome`, and should. `SuiError.
|
|
168
|
-
`
|
|
180
|
+
may declare its own `outcome`, and should. `SuiError.outcome` also takes `{ phase: "pre-submit" }`, which changes only the
|
|
181
|
+
unclassified answer (`"not_applied"` instead of `"unknown"`, true by
|
|
182
|
+
construction before a send). `SuiError.isRetryable`, `SuiError.isTaxonomy`,
|
|
183
|
+
`SuiError.describe` (one actionable line, and total over foreign errors) and
|
|
184
|
+
`SuiError.toJson` round it out. **Every error class without a `message` schema
|
|
185
|
+
field carries `override get message()` returning `describe(this)`**, so
|
|
186
|
+
`.message` is never empty; it is a getter, so it stays out of the encoding — and `toJson` adds `outcome` from the instance
|
|
187
|
+
when the error declares one, which is almost always a class field rather than a
|
|
188
|
+
schema field.
|
|
169
189
|
|
|
170
190
|
## Testing
|
|
171
191
|
|
|
172
192
|
`@unconfirmed/sui-effect/testing` ships `SuiCoreFake.layer(script)`, `layerTest(script)`
|
|
173
|
-
(the real `Sui` over the fake `SuiCore`), `layerExtensionTest(layer, script)`
|
|
174
|
-
(an extension's own layer over that
|
|
193
|
+
(the real `Sui` over the fake `SuiCore`), `layerExtensionTest(layer, script, { extra })`
|
|
194
|
+
(an extension's own layer over that, with `SuiGraphQL.layerUnavailable` provided
|
|
195
|
+
by default and `extra` for any other dependency the layer requires) and `SuiTest` (`putObject`, `bumpVersion`,
|
|
175
196
|
`recordTransaction`, `deleteObject`, `setClock`, `setEpoch`, `scriptExecute`,
|
|
176
197
|
`scriptSimulate`, `scriptGetTransaction`, `calls`), which is the whole harness
|
|
177
198
|
an extension's tests need. Call recording is reached through `SuiTest.calls`,
|
|
178
199
|
not off the fake handle. The fake serves in-memory objects with
|
|
179
200
|
BCS content, the Clock object `0x6`, and scripted outcomes
|
|
180
|
-
(`FakeOutcome.succeed`, `failWith
|
|
181
|
-
|
|
201
|
+
(`FakeOutcome.succeed`, `failWith` — which takes the SDK's wire `ExecutionError`
|
|
202
|
+
**or** sui-effect's decoded `ExecutionReason`, encoding the second and throwing
|
|
203
|
+
on anything else — `transportError`, `notFound`, `timeoutThen`)
|
|
204
|
+
for simulate, execute, `getObject` (read-failure injection), `getTransaction` —
|
|
205
|
+
which is also what drives every
|
|
206
|
+
`waitForTransaction` outcome — `coinMetadata`, and the resolver's budget simulation
|
|
182
207
|
(`buildSimulate`, which is how a test makes `Tx.build` fail with
|
|
183
208
|
`SimulationFailed`). It records every call so a test can
|
|
184
209
|
assert the include set that was sent. It also implements
|
|
@@ -204,6 +229,14 @@ rather than failing a `Simulation` decode.
|
|
|
204
229
|
The fake enforces the invariants the lifecycle depends on: a known digest
|
|
205
230
|
executes idempotently, gas selection excludes object inputs, the coin set
|
|
206
231
|
evolves (deleted, mutated with `FakeChange.balance`, gas-bumped, created), a
|
|
207
|
-
submission
|
|
232
|
+
submission whose signatures do not cover the addresses the bytes name — by count
|
|
233
|
+
**and** by the addresses recovered from the signatures — is refused the way a
|
|
234
|
+
validator refuses it (an `RpcError` carrying `INVALID_ARGUMENT`, so `Tx.submit`
|
|
235
|
+
fails fast instead of reconciling into a scripted success), and a
|
|
208
236
|
version history is served through `tryGetPastObject`, which is what
|
|
209
|
-
`SuiCore.getObjectAtVersion` reads.
|
|
237
|
+
`SuiCore.getObjectAtVersion` reads. The resolver's budget simulate is recorded
|
|
238
|
+
as a `simulateTransaction` call (`resolver: true`) and answered by
|
|
239
|
+
`FakeScript.buildSimulate` when there is one and by the ordered `simulate`
|
|
240
|
+
script otherwise, so "building always simulates" is observable on the harness.
|
|
241
|
+
`getBalance` and `listBalances` are keyed by owner and coin type; a `FakeBalance`
|
|
242
|
+
with no `owner` answers for everyone.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@unconfirmed/sui-effect`. The format is one line per
|
|
4
|
+
change, newest release first.
|
|
5
|
+
|
|
6
|
+
## 0.1.2
|
|
7
|
+
|
|
8
|
+
Two defects from the first three downstream conversions, and the surface they
|
|
9
|
+
exposed. Nothing was removed. Two shapes changed: `Tx.reconcileAll` now returns
|
|
10
|
+
a tagged union, and `Tx.submit`'s error union gained `TransportError` for the
|
|
11
|
+
one case where a node refuses a submission outright.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`Tx.submit` no longer reconciles a submission the node refused.** A gRPC `INVALID_ARGUMENT` — malformed bytes, or a sponsored transaction carrying only the sender's signature — is the node answering that it did not execute anything, so it escapes as the `TransportError` it is. Reconciling it asked "is this digest on chain?" about a transaction that was never sent, and a lagging node (or a scripted `getTransaction`) could answer yes: an app's sponsored, under-signed submission was reported as a **successful `Executed`**. `SubmitError` therefore includes `TransportError`; every other transport failure still becomes `SubmissionUnknown`.
|
|
16
|
+
- **`SuiCoreFake` refuses an under-signed or wrongly-signed submission the way a validator does**, with an `RpcError` carrying `INVALID_ARGUMENT` rather than a plain `Error` that `mapSdkError` classified as a *retryable* transport failure. It checks the signature count and, when the signatures parse, the addresses they were made by. A sponsored submit against the fake needs `Tx.cosign` (or `Tx.run`'s `sponsor`) first, exactly as it does against a node.
|
|
17
|
+
- **The fake's resolver simulate is recorded**, so `SuiTest.calls("simulateTransaction")` sees the simulate that `Tx.build` promises, and it is answered by `FakeScript.buildSimulate` when there is one and by the ordered `simulate` script otherwise — `simulate: [FakeOutcome.failWith(...)]` now surfaces through `Tx.build` and `Tx.run` as `SimulationFailed` instead of vanishing.
|
|
18
|
+
- **Nothing in `src/` writes to stderr** (the one documented `console.warn` aside). A test captures stderr around a full `Tx.run` on the fake, with `bigint`s in the script, and asserts it is empty: the reported `console.error("DEBUG …", JSON.stringify(outcomes))` lines are in no published 0.1.1 artefact, but a `JSON.stringify` over a scripted `bigint` throws, and the throw surfaced later as an unrelated `FakeUnimplemented`.
|
|
19
|
+
- **Every error class has a real `.message`.** `Schema.TaggedError` leaves it empty, so anything surfacing `error.message` showed nothing; the classes without a `message` schema field now carry `override get message()` returning `SuiError.describe(this)`. It is a getter, so `SuiError.toJson`'s encoding is unchanged.
|
|
20
|
+
- **`SuiError.describe` accepts a foreign error** instead of returning `undefined` from an exhaustive `switch` while its signature promised a `string`. An extension's error, or any `{ _tag }`, gets its tag and message.
|
|
21
|
+
- **`SuiCoreFake.getBalance` is keyed by owner**, not by coin type alone. A `FakeBalance` may carry an `owner`; one without answers for every owner, which is what a pre-0.1.2 script meant.
|
|
22
|
+
- **`FakeOutcome.failWith` accepts sui-effect's decoded `ExecutionReason`** as well as the SDK's wire `ExecutionError`, encoding the first into the second. A fixture in the wrong shape used to decode-fail several calls later, on a different method, after the outcome cursor had already moved; it now throws where the fixture is written, naming both shapes.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **`DecodeError.kind`**: `"type"` (the Move type was not the expected one — nothing was parsed, and the one a consumer may answer with a 404), `"bytes"` (the BCS parse failed or left trailing bytes — never safe to swallow), `"shape"` (a domain schema refused a parsed or JSON value). Every producer sets it, `SuiError.describe` prints it, and it defaults to `"shape"`, so an extension constructing a `DecodeError` without one still compiles. Branch on `kind`, never on `issue`.
|
|
27
|
+
- **`Tx.reconcileAll` returns a `Schema.TaggedUnion`**: `{ _tag: "Executed", executed }`, `{ _tag: "ExecutionFailed", error }`, `{ _tag: "NotApplied", error }`, `{ _tag: "SubmissionUnknown", error }`. The old bare union — an `Executed` with no discriminator beside three errors that had one — is exported as the deprecated type `ReconciledOutcome`.
|
|
28
|
+
- **`Tx.recorded(digest)`**: the journal entry for one digest, as an `Option`. `reconcileAll` returns **only** the entries that were unresolved, and this is how to ask about one that already settled.
|
|
29
|
+
- **`Tx.submitVia(signed, send)`**: the submission lifecycle when a relay or a sponsorship service does the sending. Journals `Signed` before calling `send`, calls it exactly once, decodes whatever it answers (an SDK `TransactionResult`, a reduced envelope, a bare digest, or nothing — in which case it asks the chain), reconciles an ambiguous failure with the full evidence rules, and journals the terminal answer. A `send` error whose instance declares `outcome: "not_applied"` fails straight through without a reconcile.
|
|
30
|
+
- **`Tx.run`'s `onSigned` hook**: called with the signed bytes after the last signature and before the first `executeTransaction`, inside the sender lock, for the record the journal does not hold. Its failure is a `JournalError` and fails the run with nothing sent.
|
|
31
|
+
- **`Executed.fromPartial(envelope)`**: an `Executed` from a reduced relay or sponsor envelope. `changedObjects` entries need only `objectId` and `idOperation`; what the envelope did not say stays `Unknown` rather than being guessed, and the accessors read `Unknown` as "not said" so `created()` and `deleted()` still classify. JSON spellings are accepted (`bcs` as base64 or a byte array, every `u64` as a number or a `bigint`). It cannot invent the `objectTypes` join, so the type-filtered accessors match nothing without it, and `gasUsedTotal` is `0n` for an envelope that reported no gas.
|
|
32
|
+
- **`Executed.fromTransactionResult(result)`** is public: the strict constructor, for an SDK `TransactionResult` read with the full include set.
|
|
33
|
+
- **`Event.json`**: kept when the source carried one, which in practice means a relay envelope whose events have no BCS. Never populated from a gRPC execute.
|
|
34
|
+
- **`SuiError.outcome(error, { phase: "pre-submit" })`** answers `"not_applied"` rather than `"unknown"` for an unclassified error, which is true by construction before anything is sent. The default is `"post-submit"`, the 0.1.1 behaviour. **`SuiError.isTaxonomy(error)`** answers whether an error is one of the tags this package owns.
|
|
35
|
+
- **`Sui.getObjectsStrict`**: `getObjectsOrFail` under a name that reads correctly in isolation. The old name stays as a deprecated alias of the same function.
|
|
36
|
+
- **`Signer.fromConfig` accepts a 32-byte hex seed** (64 hex characters, `0x` optional, read as Ed25519) as well as a Bech32 `suiprivkey`, so a raw seed from a secret manager no longer needs `fromHex` in application code.
|
|
37
|
+
- **`Signer.fromSdkSigner` validates its argument** and throws a `TypeError` naming the missing member. A double without `getKeyScheme` produced `scheme: undefined` and nothing complained until a validator did. Its JSDoc now states that `toSuiAddress()` and `getKeyScheme()` are read at construction, and that clear-signing inputs are the SDK signer's own concern.
|
|
38
|
+
- **`SuiLayerOptions.retry`**: a `Schedule` for the one `getChainIdentifier` a `Sui` layer makes. A `ManagedRuntime` memoizes its layer build, failure included, so one unlucky read at boot otherwise poisons a browser tab or a Worker isolate for its whole life.
|
|
39
|
+
- **`FakeScript.getObject`** (and `SuiTest.scriptGetObject`): scripted outcomes for a **read**, so a test can inject a transport failure, a miss or a timeout into `getObject`. An absent or exhausted script serves the object map as before.
|
|
40
|
+
- **`Script.report(exit, { stderr?, journal? })`**: the diagnostic lines and the unresolved-entry printing `Script.run` does at the end, returning the exit code, for a CLI that owns its own argv parser and process and cannot hand the entrypoint over.
|
|
41
|
+
- **`Script.run` prints each unresolved journal entry encoded through the `JournalEntry` schema** — the same JSON a durable journal stores, bytes base64 — beside the two human lines it already printed.
|
|
42
|
+
|
|
43
|
+
### Documentation
|
|
44
|
+
|
|
45
|
+
- The extension guide gains three sections: **"Application consumers"** (a module-level `ManagedRuntime` over `Sui.layerNoDepsWith({ chainId })` and `SuiCore.layerFromClient`, HMR disposal, the memoized-failed-build trap, the in-memory journal in a browser, mapping `outcome` onto UI states with the pre-submit caveat, signing with an external cosigner, and a `layerTest`-backed double for an app's own `runSui`), **"Workers and Durable Objects"** (no `process`, `ConfigProvider.fromEnvRecord(env)`, one runtime per isolate, the sender lock not crossing isolates and address-balance gas, DO alarms versus `Schedule` sleeps, and the whole `KeyValueStore.makeStringOnly` adapter over DO storage), and **"Relay and sponsor envelopes"** (`Executed.fromPartial`, what it cannot invent, and `Tx.submitVia`).
|
|
46
|
+
- A **"Sponsored by an external service"** recipe in the signers section: build with `Tx.sponsored`, sign, hand over the base64 bytes and the serialized signature, and reconcile by the digest — which a co-signature does not change.
|
|
47
|
+
- The testing section gains: `getTransaction` is what a submit test's reconcile reads (script `notFound` unless the test means "this landed"), a sponsored submit needs `Tx.cosign` and should assert the signature count on `SuiTest.calls("executeTransaction")`, which script slot answers the build's simulate, that `layerTest` asserts the built-in chain id for `mainnet` and `testnet`, how to inject a read failure, and why an isolated-consumer fixture in the package `tsconfig`'s `include` typechecks your code against the tarball it last installed.
|
|
48
|
+
- Error guidance: tag strings are namespaced by whoever defined them and must be copied from the installed package; `DecodeError.kind` replaces branching on `issue`; a wrapper error must copy the `outcome` and digest of what it wrapped, because `Script.exitCode` honours `outcome` first.
|
|
49
|
+
- Migration-table rows for a hand-rolled idempotent submitter, `sui.core.getTransaction` for a transaction that may have failed, a predecessor `ready()` genesis check mapping to `Sui.layerNoDepsWith({ chainId })`, and a removed standalone read export; plus the `.find(... type?.includes(...))`-then-throw grep pattern that `Executed.expectCreated` replaces, and the rule that a consumer-edit table is regenerated from the published `exports` map rather than from facade call sites.
|
|
50
|
+
- README: the `INVALID_ARGUMENT` rule, `onSigned`, `submitVia`, the `Reconciled` shape and `Tx.recorded`, `DecodeError.kind`, the error `.message` getter, `outcome`'s phase, relay envelopes and `Executed.events`' exact type, `bigint` at the JSON boundary, the `SubmitConfig` override idiom with `maxGasBudget`'s 50 SUI default and when `lockSender: false` is correct, and a section on applications, Workers and Durable Objects.
|
|
51
|
+
|
|
52
|
+
## 0.1.1
|
|
53
|
+
|
|
54
|
+
Seventeen fixes from the first downstream conversion. Nothing in the public API
|
|
55
|
+
was removed or renamed: an extension built against 0.1.0 compiles unchanged, and
|
|
56
|
+
the type-level workarounds it had to carry are now unnecessary.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- `PromiseFace<S>` recurses into **interface-typed** members, not only those assignable to `Record<string, unknown>`, so an interface-typed namespace (`readonly protocol: ProtocolService`) is mapped in the type the way the runtime has always mapped it — before this the face type said `Effect` where the value was a `Promise`.
|
|
61
|
+
- `SuiError.toJson` includes `outcome` when the error instance declares one, including the usual case where it is a class field rather than a schema field, so a log line carries the same axis `SuiError.outcome` and `Script.exitCode` read.
|
|
62
|
+
- The placeholder a **cold** member call returns is a real `Promise` subclass implementing `Symbol.asyncIterator`, so `instanceof Promise` holds and `expect(...).rejects` recognises it; its rejection is pre-handled, so a cold call nobody awaits no longer aborts the process with an unhandled `ExtensionNotReady`.
|
|
63
|
+
- A `warm` registration re-runs its warm build on the next use after `$dispose()` instead of degrading to a cold registration whose every synchronous member throws `ExtensionNotReady`.
|
|
64
|
+
- `mapSdkError` duck-types the SDK's error classes when `instanceof` fails — `reason` plus `objectId` for `ObjectNotFound` / `ObjectDeleted` / `ObjectUnavailable`, `reason` plus `digest` for `TransactionNotFound`, the name plus `executionError` for `SimulationFailed` — so two copies of `@mysten/sui` in one process no longer turn every one of those tags into `TransportError { status: "notFound" }`, and the first such failure logs one warning naming the real problem.
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
|
|
68
|
+
- `SuiExtension.Leaf<T>` and `SuiExtension.leaf(value)`: the marker an extension puts on a class-instance member the Promise face must pass through whole rather than recurse into. `Uint8Array`, `Date`, `Promise`, arrays and BCS codecs (`parse` plus `serialize`) are recognised without it.
|
|
69
|
+
- `SuiAddress.normalize(input)` and `ObjectId.normalize(input)`: decode-and-brand from any spelling the SDK accepts, which is what `"0x1"` needs and what `.make` (validate without decoding) refuses.
|
|
70
|
+
- `SuiSchema.decodeWith(bcsType, expectedType, map)`: a BCS layout plus a throwing mapper into a domain value, as one codec, so an extension stops hand-rolling `Effect.try` around `Schema.decodeUnknownEffect` and losing the `DecodeError`.
|
|
71
|
+
- `layerExtensionTest(layer, script, { extra })`: extra dependency layers for an extension whose layer requires more than the client could provide, with `SuiGraphQL.layerUnavailable` merged in by default.
|
|
72
|
+
- `FakeScript.coinMetadata`, so `getCoinMetadata` is testable on the harness; an unscripted coin type answers `{ coinMetadata: null }` the way a node does.
|
|
73
|
+
- `CHANGELOG.md`, shipped in the package's `files`.
|
|
74
|
+
|
|
75
|
+
### Documentation
|
|
76
|
+
|
|
77
|
+
- The extension guide gains: the sanctioned idiom for a standalone function that needs a sibling extension's service, a worked generic-Move-type example on the fake, the `bun install --force` step after re-packing a vendored tarball with an unchanged filename, that `waitForTransaction` outcomes are driven by `FakeScript.getTransaction`, that a `warm` registration throws **any** layer failure synchronously out of `$extend`, and what a cold placeholder is now that it is a real `Promise`.
|
|
78
|
+
- `SuiGraphQL`'s JSDoc states that `yield* SuiGraphQL` yields the `SuiGraphQLClient` itself and that the service type is `SuiGraphQL["Service"]`.
|
|
79
|
+
|
|
80
|
+
## 0.1.0
|
|
81
|
+
|
|
82
|
+
Initial release: two client tiers (`SuiCore`, `Sui`), a closed error taxonomy,
|
|
83
|
+
the transaction lifecycle as functions with typed outcomes (`Tx`), the journal,
|
|
84
|
+
the `Script` preset, the BCS bridge and branded schemas, `SuiExtension.fromService`
|
|
85
|
+
for the Promise face of an Effect service, `SuiGraphQL` as a bare tag, and the
|
|
86
|
+
in-memory fake with its test layers.
|