@unconfirmed/sui-effect 0.1.0 → 0.1.1

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 (53) hide show
  1. package/AGENTS.md +16 -6
  2. package/CHANGELOG.md +40 -0
  3. package/LLMS.md +1609 -1098
  4. package/README.md +347 -3
  5. package/dist/domain/bcs.d.ts +44 -0
  6. package/dist/domain/bcs.d.ts.map +1 -1
  7. package/dist/domain/bcs.js +57 -0
  8. package/dist/domain/bcs.js.map +1 -1
  9. package/dist/domain/errors.d.ts +63 -21
  10. package/dist/domain/errors.d.ts.map +1 -1
  11. package/dist/domain/errors.js +35 -7
  12. package/dist/domain/errors.js.map +1 -1
  13. package/dist/domain/executed.d.ts +54 -18
  14. package/dist/domain/executed.d.ts.map +1 -1
  15. package/dist/domain/journal-entry.d.ts +6 -2
  16. package/dist/domain/journal-entry.d.ts.map +1 -1
  17. package/dist/domain/schemas.d.ts +207 -66
  18. package/dist/domain/schemas.d.ts.map +1 -1
  19. package/dist/domain/schemas.js +62 -2
  20. package/dist/domain/schemas.js.map +1 -1
  21. package/dist/domain/sui-schema.d.ts +3 -2
  22. package/dist/domain/sui-schema.d.ts.map +1 -1
  23. package/dist/domain/sui-schema.js +3 -2
  24. package/dist/domain/sui-schema.js.map +1 -1
  25. package/dist/extension.d.ts +1 -1
  26. package/dist/extension.d.ts.map +1 -1
  27. package/dist/extension.js +1 -1
  28. package/dist/extension.js.map +1 -1
  29. package/dist/services/SuiCore.d.ts +12 -0
  30. package/dist/services/SuiCore.d.ts.map +1 -1
  31. package/dist/services/SuiCore.js +124 -0
  32. package/dist/services/SuiCore.js.map +1 -1
  33. package/dist/services/SuiCoreFake.d.ts +12 -0
  34. package/dist/services/SuiCoreFake.d.ts.map +1 -1
  35. package/dist/services/SuiCoreFake.js +6 -1
  36. package/dist/services/SuiCoreFake.js.map +1 -1
  37. package/dist/services/SuiExtension.d.ts +127 -14
  38. package/dist/services/SuiExtension.d.ts.map +1 -1
  39. package/dist/services/SuiExtension.js +125 -28
  40. package/dist/services/SuiExtension.js.map +1 -1
  41. package/dist/services/SuiGraphQL.d.ts +13 -0
  42. package/dist/services/SuiGraphQL.d.ts.map +1 -1
  43. package/dist/services/SuiGraphQL.js +13 -0
  44. package/dist/services/SuiGraphQL.js.map +1 -1
  45. package/dist/services/Tx.d.ts +3 -1
  46. package/dist/services/Tx.d.ts.map +1 -1
  47. package/dist/testing.d.ts +21 -3
  48. package/dist/testing.d.ts.map +1 -1
  49. package/dist/testing.js +30 -3
  50. package/dist/testing.js.map +1 -1
  51. package/docs/extensions.md +338 -25
  52. package/examples/extension-template/test/escrow.test.ts +91 -2
  53. package/package.json +3 -2
package/AGENTS.md CHANGED
@@ -26,7 +26,13 @@ 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.
32
+ - **A branded id from a shorthand spelling** comes from `SuiAddress.normalize`
33
+ / `ObjectId.normalize` (decode, then brand); `.make` validates without
34
+ decoding and is for the padded form only. Neither is for a value that came
35
+ from outside: that goes through `Schema.decodeUnknownEffect`.
30
36
  - **One Move type rule.** `typeMatches(expected, actual)` (`src/domain/bcs.ts`)
31
37
  is the only comparison: a bare expected tag matches every instantiation of the
32
38
  generic, a parameterized one is compared in full after normalization. The
@@ -83,7 +89,7 @@ and nothing else.
83
89
  | `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
90
  | `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
91
  | `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. |
92
+ | `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
93
  | `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
94
 
89
95
  ## Extensions
@@ -165,20 +171,24 @@ Every failure is one flat tag; there is no error inheritance.
165
171
  anything that is neither one of those tags nor declares an `outcome`.
166
172
  `Script.exitCode` exits 1 for that last case rather than 3. An extension error
167
173
  may declare its own `outcome`, and should. `SuiError.isRetryable`, `SuiError.describe` (one actionable line) and
168
- `SuiError.toJson` round it out.
174
+ `SuiError.toJson` round it out — and `toJson` adds `outcome` from the instance
175
+ when the error declares one, which is almost always a class field rather than a
176
+ schema field.
169
177
 
170
178
  ## Testing
171
179
 
172
180
  `@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) and `SuiTest` (`putObject`, `bumpVersion`,
181
+ (the real `Sui` over the fake `SuiCore`), `layerExtensionTest(layer, script, { extra })`
182
+ (an extension's own layer over that, with `SuiGraphQL.layerUnavailable` provided
183
+ by default and `extra` for any other dependency the layer requires) and `SuiTest` (`putObject`, `bumpVersion`,
175
184
  `recordTransaction`, `deleteObject`, `setClock`, `setEpoch`, `scriptExecute`,
176
185
  `scriptSimulate`, `scriptGetTransaction`, `calls`), which is the whole harness
177
186
  an extension's tests need. Call recording is reached through `SuiTest.calls`,
178
187
  not off the fake handle. The fake serves in-memory objects with
179
188
  BCS content, the Clock object `0x6`, and scripted outcomes
180
189
  (`FakeOutcome.succeed`, `failWith`, `transportError`, `notFound`, `timeoutThen`)
181
- for simulate, execute, `getTransaction` and the resolver's budget simulation
190
+ for simulate, execute, `getTransaction` which is also what drives every
191
+ `waitForTransaction` outcome — `coinMetadata`, and the resolver's budget simulation
182
192
  (`buildSimulate`, which is how a test makes `Tx.build` fail with
183
193
  `SimulationFailed`). It records every call so a test can
184
194
  assert the include set that was sent. It also implements
package/CHANGELOG.md ADDED
@@ -0,0 +1,40 @@
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.1
7
+
8
+ Seventeen fixes from the first downstream conversion. Nothing in the public API
9
+ was removed or renamed: an extension built against 0.1.0 compiles unchanged, and
10
+ the type-level workarounds it had to carry are now unnecessary.
11
+
12
+ ### Fixed
13
+
14
+ - `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`.
15
+ - `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.
16
+ - 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`.
17
+ - 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`.
18
+ - `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.
19
+
20
+ ### Added
21
+
22
+ - `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.
23
+ - `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.
24
+ - `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`.
25
+ - `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.
26
+ - `FakeScript.coinMetadata`, so `getCoinMetadata` is testable on the harness; an unscripted coin type answers `{ coinMetadata: null }` the way a node does.
27
+ - `CHANGELOG.md`, shipped in the package's `files`.
28
+
29
+ ### Documentation
30
+
31
+ - 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`.
32
+ - `SuiGraphQL`'s JSDoc states that `yield* SuiGraphQL` yields the `SuiGraphQLClient` itself and that the service type is `SuiGraphQL["Service"]`.
33
+
34
+ ## 0.1.0
35
+
36
+ Initial release: two client tiers (`SuiCore`, `Sui`), a closed error taxonomy,
37
+ the transaction lifecycle as functions with typed outcomes (`Tx`), the journal,
38
+ the `Script` preset, the BCS bridge and branded schemas, `SuiExtension.fromService`
39
+ for the Promise face of an Effect service, `SuiGraphQL` as a bare tag, and the
40
+ in-memory fake with its test layers.