@ninsei-labs/sdk 0.53.0 → 0.55.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/CHANGELOG.md CHANGED
@@ -1,4 +1,44 @@
1
- ## Unreleased
1
+ ## 0.55.0 — 2026-10-30
2
+
3
+ - `order.escrowNativeWei` reads the quote's own native amount (`payNative`) for a token-funded order and returns
4
+ its wei value. A quote without that figure is refused by name (`native-amount-unread`) instead of rescaling the
5
+ payment-token amount.
6
+ - Relay public features now carry the `capabilities` list from relay wire revision 13, so a maker's signed
7
+ `node_features` has the type the relay verifies. A node without `firm/1` carries no HPKE key and no windows.
8
+ - `@ninsei-labs/sdk/relay` exposes the relay digests, the node features verifier, the firm terms digest and the
9
+ HPKE view envelope for a node that embeds the SDK.
10
+ - `swaps.start` keeps the exact atomic XMR amount from the signed order in the record's `escrow.expectedAtomic`.
11
+ The arrival check and a recovery file rebuilt from the chain compare that integer instead of the rounded
12
+ display number. A malformed or non-positive value is refused before the record is saved.
13
+
14
+ ## 0.54.0 — 2026-10-29
15
+
16
+ - `findSwaps` no longer walks the allocator's 100,000 v1 indices in one synchronous call. One call scans at most
17
+ `RECOVERY_SCAN_DEFAULT` (1000) indices, yields to the event loop between chunks, and returns `nextIndex` with
18
+ `complete: false` and `incompleteReason: "max-index"` when it stopped. A caller continues from `nextIndex`; a search
19
+ that matched every order in the logs is complete without scanning the rest. `maxIndex` is the number of indices for
20
+ this call.
21
+ - `findSwaps` accepts an AbortSignal-like `signal` and an `onProgress` callback. An aborted scan returns
22
+ `incompleteReason: "aborted"` with the same `nextIndex`; progress is reported after every chunk and after the final
23
+ index. The SDK creates no worker: a caller can run the same call in one.
24
+ - The relay firm client has its signed-features check and request builder: a `NodeFeatures` digest with the
25
+ `FirmWindow` array, signature recovery, request binding, a normalised client half, and one HPKE envelope per
26
+ request. Ask carries one view scalar; bid carries two. Wire revision 13 removed the `capabilities` array: the
27
+ features now always carry a nonzero HPKE key and at least one firm window.
28
+ - The relay firm client's HTTP hop is `requestFirmQuote`: it posts the exact payload once, keeps a relay refusal
29
+ code (`compliance`, `no_liquidity`, `size`, `paused`, `unavailable`, `bad_request`, `price_changed`), maps a
30
+ transport failure to `server-unavailable`, and verifies the outer frame and the inner `OrderQuote` before
31
+ returning. It also checks the relay/forwarded/answer relay-id equality.
32
+ - `quotes.firmRelay` is the recovery-key adapter: it derives the client half and both view points from one
33
+ key, fills the provider's role for ask or bid, verifies the node half's DLEQ proof and commitment, sends one
34
+ relay request, and checks the registry provider and factory against the answer before returning the signed
35
+ `orderQuote`, the one-time joint XMR address, a `counterparty` object ready for `swaps.start`, and the maker
36
+ view half. `FirmOffer` now matches the direct `firm` call (`providerId`, `order`, optional `viewHalfClaimer`).
37
+ - `swaps.sellWatch` is the client-side sell wait: it reads the escrow itself and returns `ready`,
38
+ `claimed` or `refunded` (or `sell-timeout`), with no backend watcher and no signature.
39
+ - `swaps.startSell` records a sell from a verified relay offer: the one-time address, escrow, our half and the
40
+ order expectations survive a reload; the same offer resumes the same record. `swaps.sellClaim` claims from
41
+ that record, from the claimer's own wallet.
2
42
 
3
43
  ## 0.53.0 — 2026-10-28
4
44
 
@@ -0,0 +1,46 @@
1
+ # Dependency license policy
2
+
3
+ The SDK is published as a public package under MIT. Its production dependency tree must stay compatible with
4
+ that promise: a dependency with a copyleft, source-available, unknown or missing licence is a decision for a
5
+ person, not something that enters a release by accident.
6
+
7
+ ## Allowed licences
8
+
9
+ A production dependency may use one of these licences:
10
+
11
+ - MIT
12
+ - MIT-0
13
+ - ISC
14
+ - Apache-2.0
15
+ - BSD-2-Clause
16
+ - BSD-3-Clause
17
+ - Unlicense
18
+ - 0BSD
19
+ - CC0-1.0
20
+ - BlueOak-1.0.0
21
+
22
+ An SPDX expression is read as written: `MIT OR Apache-2.0` is allowed when one branch is allowed, and
23
+ `MIT AND ISC` is allowed when every branch is allowed. A `WITH` exception keeps the base licence's decision.
24
+ `SEE LICENSE IN ...`, `UNLICENSED`, `UNKNOWN`, and every licence outside the list are refused.
25
+
26
+ ## How the check runs
27
+
28
+ `pnpm licenses list --prod --json` reads the installed production tree, including transitive packages. The
29
+ check is implemented in `tools/check-licenses.mjs`; CI runs it in the **License Compliance** workflow on every
30
+ pull request and every push to `main`.
31
+
32
+ ```sh
33
+ pnpm run check:licenses
34
+ ```
35
+
36
+ The command prints the packages grouped by licence. If any package is outside the allowlist, it prints each
37
+ package and its licence, then exits non-zero.
38
+
39
+ ## Notices travel with the package
40
+
41
+ `pnpm run notices` regenerates `THIRD_PARTY_NOTICES.md` from the production tree, including the licence text and
42
+ the `NOTICE` files each package ships. The file is published with the package and the same CI workflow checks that
43
+ it is current. A dependency change that edits the lockfile but not the notices fails the check; run `pnpm run
44
+ notices` and review the result with the dependency change.
45
+
46
+ Development dependencies are not part of the published package and are not covered by these checks.
package/README.md CHANGED
@@ -17,7 +17,8 @@ machine). The wallet arrives as an EIP-1193 provider, storage as an adapter, and
17
17
  | `recovery.open` — parsing the recovery file | works |
18
18
  | `sim` — sandbox scenarios and time | works (applying to a swap — stage 2) |
19
19
  | `quotes.watch` | works: live indicative quotes, its own client; a snapshot carries the display fields (sides, networks, `why`, signature, age, maturity), and the size can be NAMED (`size`) |
20
- | `quotes.firm` | answers `not-implemented` (stage 2: signing with a key and the order protocol) |
20
+ | `quotes.firm` | works: a signed, binding quote with a TTL; a refusal is a named code |
21
+ | `quotes.firmRelay` | works: a firm quote through a relay, built from one recovery key; the node half is DLEQ-checked |
21
22
  | `swaps.list` / `swaps.get` | read state from storage (and after a page reload) |
22
23
  | `swaps.start` | holds the order: guards → recovery file and the person's confirmation → order → locking funds → **recording with us and watching the Monero address**; returns the named state `step: "xmr-incoming"` |
23
24
  | `swaps.watch` | waits for XMR to arrive at the joint address with the same request as the page (`GET /swaps/{id}`): arrived — returns the fact (amount, confirmations, txid); did not wait — a refusal with the code `xmr-timeout`; already on the address but barred by `unlock_time` — a refusal with the code `xmr-locked` (the boundary is in `params.until`), and NO ready mark; the maker DECLINED the order — returns `SwapDeclinedWatch` (`declined: true`, `terminal: "declined"`, the node's own `code`), with every action off; with expectations and a wallet, places the ready mark after the arrival |
@@ -173,7 +174,7 @@ signature, the age (`ageMs`) and the maturity level (`finality`) — display fie
173
174
  The price does not depend on volume: the volume is needed by the provider to say whether it takes such a size. So
174
175
  the size is computed from the person's amount and is snapped to the node's grid **down**, and a size outside the
175
176
  range is not aligned: it is the provider's refusal, and it arrives as a code. Indicative quotes commit to nothing;
176
- `quotes.firm` commits (stage 2).
177
+ `quotes.firm` and `quotes.firmRelay` commit, and the relay path carries the maker's signed terms and its view half.
177
178
 
178
179
  ## Found orders and the paying token
179
180
 
@@ -182,8 +183,12 @@ public `salt` in its own `OrderCreated`: the binding is `ninsei-taker-v2|<chain>
182
183
  words on another device or at another factory produce a different half and no number is reserved. The result says
183
184
  `derivation: "salt-v2"` and leaves `index` null. Existing v1 orders stay on `ninsei-taker-v1|<chain>|<index>` and are
184
185
  still found by the index path; a v2 result needs no range scan. For a v1 fallback, discovery does **not** stop after a
185
- run of empty numbers: the allocator's whole range is searched by default, a smaller caller-supplied `maxIndex` returns
186
- `complete: false` with `searchedUpTo`, and `gap` is ignored. Each found order reports:
186
+ run of empty numbers. One call scans at most `RECOVERY_SCAN_DEFAULT` (1000) indices; that keeps a shared factory from
187
+ freezing the page. The result names where it stopped: `complete: false`, `searchedUpTo`, `incompleteReason: "max-index"`
188
+ and `nextIndex`. A caller that needs more passes `nextIndex` back as `fromIndex`; the scan yields between chunks so the
189
+ page stays responsive. `maxIndex` is the number of indices for this call, and `gap` is ignored. `onProgress` receives
190
+ `{ scanned, index }` after each chunk and after the final index; `signal` stops between chunks and returns
191
+ `incompleteReason: "aborted"` with the same resumable shape.
187
192
 
188
193
  - `amount` — the escrow's **native** amount in wei;
189
194
  - `settlementToken: "native"` — what the escrow receives;
@@ -311,7 +316,10 @@ trigger where those exist; on another VM they simply do not appear, rather than
311
316
  5. **Workers and WASM are separate files** from `assetsBase`, so the interface's bundler (Astro/Vite) does not
312
317
  touch them: `atomic/order-worker.js`, the Monero bundles.
313
318
  6. **Strict CSP.** The package is designed for a policy without `eval` and inline.
314
- 7. **Zero dependencies.**
319
+ 7. **Few dependencies, all permissive.** Every production dependency is checked in CI against an allowlist: MIT, MIT-0,
320
+ ISC, Apache-2.0, BSD-2-Clause, BSD-3-Clause, Unlicense, 0BSD, CC0-1.0 and BlueOak-1.0.0. Copyleft,
321
+ source-available, unknown or missing licences fail `pnpm run check:licenses`; the licence texts travel in
322
+ [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md), and the policy is in [LICENSE-POLICY.md](LICENSE-POLICY.md).
315
323
 
316
324
  ## Releases and prereleases
317
325