Skip to content

feat(browser): export manifests and recover pointer payments - #230

Open
mickvandijke wants to merge 9 commits into
mainfrom
feat/browser-pointer-recovery-manifest-export-20261015
Open

mickvandijke wants to merge 9 commits into
mainfrom
feat/browser-pointer-recovery-manifest-export-20261015

Conversation

@mickvandijke

@mickvandijke mickvandijke commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Browser applications can read manifests but cannot export them through the shared WASM API. Pointer writes also lose recoverable state if a page disappears between payment submission and its receipt. This change exports canonical manifest creation and file links. It adds an awaited checkpoint of the signed pointer state and verified plan before payment, forwards each transaction the wallet broadcasts to the page, and rebuilds the paid proof from the original plan and an observed transaction without submitting another one.

The companion SDK PR #7 consumes these exports for typed pointer recovery, manifest export and streaming saves. Merge this PR first; the SDK must then rebuild WASM from ant-client main before release. Since b44ebfb its manifest entries and inputs carry the new sha256.

Rebased onto main (e47ea7a) on 2026-10-19 for #229, which adds sha256 to manifest entries; each rebased commit compiles on its own. Hashes below are the rebased commits; evidence at earlier commits names their pre-rebase hashes.

Second review follow-up (b97d4aa, breaking):

  • Pointer options: createPointer/updatePointer/transferPointer take options?: { onPrepared, onSubmission, onPaid } (Option<JsValue>), so the TypeScript parameter is optional again. A bare onPaid function is no longer accepted. Unknown options are still refused before anything is paid.
  • onSubmission: the core forwards each transaction the wallet reports broadcasting, and the wallet waits on it. A page lost between broadcast and receipt can recover without every wallet keeping the hash itself.
  • Recovery: recoverPointerPayment takes { transactionHash } as well as keyed { transactionHashes }, exactly as the write does. A reported submission or a single-hash receipt therefore recovers; a keyed receipt must still name the checkpoint's quote.
  • Failure semantics: onPrepared is bounded by the 30-second callback timeout it now shares with onPaid. Nothing is paid unless the wallet is invoked, and every failure before that, including the re-checked settlement refusal, ends "payment was not submitted". storePaidPointer says a proof expired when its quotes are past the storers' age limit.
  • Checkpoint size: the checkpoint is still a versioned JSON string, but the record is base64 and the plan base64 MessagePack. Against the mock close group it is 87,297 characters instead of 156,250.
  • Manifests: ManifestInput::create returns a typed ManifestInputError. The entry count is checked before any entry is parsed. createManifest checks top-level and torrent keys itself, because serde_wasm_bindgen reads only declared struct fields, so deny_unknown_fields never refused unknown keys from JavaScript. Validation and sorting run once. known_size sums as u64, so it no longer overflows past 4 GiB on wasm32.

Third review follow-up (5839239):

  • onSubmission cannot block a paid write: it is bounded by the callback timeout and never rejects to the wallet. The write waits for every reported broadcast to be kept, whether or not the wallet waited, as the upload adapter does.
  • Typed write failures: a PointerWriteError splits at the wallet call. Every earlier failure, including invalid input, an existing pointer and a refused settlement, ends "payment was not submitted". write_pointer no longer needs a too_many_arguments exemption.
  • Expired proofs: storePaidPointer notes a proof past the storers' real 24-hour limit, by the device's clock, alongside the storer's own error, rather than replacing it.
  • One embedding policy: is_embeddable serves native and browser writers. Browser input refuses an intermediate shrink level, so it accepts only a small root map or the published map of at most three chunks.
  • Manifest internals: createManifest reads accepted keys from each input struct's serde derive, and the view takes addresses from the already-shrunk link form. ADR-0007 is added to the ADR index.

Real-devnet test (cb38005): a real-Chromium test that loses a pointer payment's page after the payment confirms, recovers the paid state from the onPrepared checkpoint and the onSubmission hash, and builds a manifest for the native CLI. CI's real-browser job runs it.

SHA-256 on created entries (404fa34): createManifest entries take an optional hex sha256, recorded as the creator's claim just as a native writer records it. It must be 32 bytes of hex; the browser computes none itself. The manifest view already shows it since #229.

Fourth review follow-up (93f3bd2, f96c2fb): unknown keys are checked on any JavaScript object. The check tested instanceof Object, which an object from Object.create(null) or from another frame fails, so such an object's keys went unchecked. A misspelt onPrepared in one was ignored, and the write paid with no checkpoint kept. The browser-tests README and ADR-0007's account of what a checkpoint holds are also corrected.

The first review follow-up (36b0162) addressed 15 earlier findings: the encoder refuses an embedded DataMap with no chunks, browser input follows native embedding and size-hint policy, torrent hashes use the shared parser, the settlement refusal is re-checked before the wallet, and the "retry pays again" warning was restored.

Linear issue

Closes V2-1478
Closes V2-1354

Browser follow-ups to the manifest work in #219 and pointer transfer work in #210, using their existing Linear references.

Risk tier

  • T0 — docs / tooling / CI / pure UX-output. Repo CI only.
  • T1 — client-only, no network-facing behavior change. CI + prod compat smoke.
  • T2 — node/client logic with behavioral surface, no protocol/format/economics change. Dev testnet + ADR.
  • T3 — protocol / storage format / payments / routing. T2 evidence + adversarial testing.

Proposed for human confirmation: browser checkpoint and recovery behavior changes; existing quote verification, payment amounts, signed records and storage rules remain in the shared core.

Compatibility

  • Wire: none. Existing file, pointer, quote and payment protocols are unchanged.
  • Storage: manifest v1 bytes are unchanged (the committed encoding fixture still matches). The encoder now refuses an empty embedded DataMap, which every decoder already rejected. Adds a versioned (v1), application-persisted pointer checkpoint containing the signed record and verified plan, never the owner seed. v1 has not shipped, so its encoding changed in place.
  • API: breaking. Pointer writes no longer accept a bare onPaid function as their last argument; pass { onPaid }. ManifestInput::create returns Result<CreatedManifest, ManifestInputError> instead of Result<_, String>. Additive: public Rust manifest-input types, WASM createManifest (with an optional per-entry sha256), createFileLink and recoverPointerPayment exports, the onPrepared and onSubmission options, and ManifestEntry::effective_name_with. A supplied onPrepared must settle successfully within 30 seconds before payment. Once paid, an onPaid failure still cannot prevent storage. Recovery takes the application's original checkpoint and a receipt or reported submission; it does not authorize fresh payment. BrowserManifestView and its entries also derive Deserialize, with kind as a String.

Semver impact

  • breaking
  • feature
  • fix

Proposed for human review: the bare-function onPaid form and the String error of ManifestInput::create are removed.

Test evidence

At f96c2fb:

  • cargo test -p ant-core --lib: 854 passed, including tests for the entry-count order, serde-derived input field names, published-map embedding, link-form addresses, u64 known_size overflow, proof expiry and the sha256 input.
  • Generated-WASM suite (ant-core/wasm-tests, browser-wasm,test-utils release build): 237 passed. Tests cover:
    • createManifest/createFileLink with JavaScript input: unknown top-level, torrent and entry keys, including on objects without a prototype or from another realm, tag casing, Uint8Array DataMaps, number and BigInt sizes, a recorded and a malformed sha256.
    • onSubmission: ordering, recovery from a reported submission, a hanging or failing callback not stopping a paid write, and a wallet that does not wait on it.
    • Recovery from a single transaction hash.
    • Failures before the wallet ending "payment was not submitted".
    • An onPrepared that never settles, the bare-function form being refused, and unknown options on objects without a prototype or from another realm.
  • cargo fmt --all -- --check, workspace clippy (--all-targets --all-features) and wasm32 clippy for both browser-wasm and browser-wasm,test-utils, with -D warnings: passed.
  • A host build with only browser-wasm (neither native nor wasm32) still fails clippy on dead code in client_engine/read_budget.rs and data/client/mod.rs. Both predate this PR, and it adds nothing to that list.
  • CI is running at f96c2fb. At 404fa34, these jobs passed: Real Chromium and local nodes, Browser WASM, unit tests, builds, clippy, format, documentation, Merkle E2E (macOS) and the PR checks. E2E Tests (macOS) failed in test_estimate_all_stored_partial_sample_is_incomplete, because the native 10-node test network's close-group lookup found 6 of the 7 peers it needed. That is upload code this PR does not touch; the Ubuntu E2E jobs had not finished. Security Audit fails on three zip 2.4.2 advisories (RUSTSEC-2026-0367, -0368, -0369, published 2026-10-09 and -10) in main's lockfile; this PR changes no Cargo files. (chore(deps): move rustls to 0.23.46 for four RustSec advisories #232 fixed the rustls advisories it failed on at the pre-rebase 973ae93.)

Real devnet at 404fa34 (the later commits change only the unknown-key check, tests and docs): Chromium 151.0.7922.34 (Playwright 1.62.1), seven isolated nodes at the pinned 26129a2611cac08f9f53a557f91fb8806b40a1cc, and local Anvil 1.7.1. It used the production WASM (browser-wasm only) built from 404fa34, sha256 27719b21bc2136bf59e18365a31a5e5364735ce95f098f508380459ca0fc8223. The same suite also passed at the pre-rebase 4d27758.

  • All three real-browser tests passed in 35.6 seconds, none skipped: a paid upload resumed after an interruption without paying again and downloaded by address; pointer create, update, read, resolve and transfer, with five real payments at finality final; and the new recovery test.
  • In the recovery test, exactly one payment was submitted. The lost page's error does not claim "payment was not submitted". The pointer was absent before recovery. recoverPointerPayment rebuilt the paid state from the checkpoint and the reported transaction hash, storePaidPointer stored it, and a fresh client read it back at counter 0 with the expected target. A second create was refused with "already exists … payment was not submitted".
  • ant --json manifest show built from 404fa34 decoded the browser-created .ant file (sha256 27f1d667bec142416240b2894732591b36f0c1c4895d3adc9207f88ab79468e4) and its link identically: name, torrent v1 info hash, entry path, public address and size.

SDK PR #7 adopted 404fa34 in b44ebfb, with WASM rebuilt from it: SDK build, TypeScript, 250 tests in 23 files (including the real devnet checkpoint, re-encoded for the new checkpoint layout, recovered and resumed through the core), all five example builds, npm pack --dry-run and ADR governance passed; its verify:wasm fails only because 404fa34 is not on main. It passes receipts to recoverPointerPayment unkeyed, and its manifest entries and inputs carry sha256. It keeps its own submission journal: its payment function is the wallet the core calls, so the core's onSubmission would only hand its broadcasts back, and the journal also holds what recovery observes. 93f3bd2 and f96c2fb need no SDK change. Its real-browser devnet run has not been repeated against this WASM.

Before the review follow-ups, at 8316468b7f5f813457f195bccb16a452426d5f35 (exact revisions, commands, limitations and artifacts):

  • Real Chromium 151 and seven isolated nodes at 26129a2611cac08f9f53a557f91fb8806b40a1cc, with local Anvil: paid pointer create/update/transfer, all-seven finality, paid replay, and recovery after deliberately losing confirmation with exactly one payment submission. Browser-created public/private manifests decode in the unchanged native CLI. This run predates the options object, onSubmission and the current checkpoint encoding. The run at 404fa34 repeats the recovery and native decoding at the current head, but not the private manifest.
  • Both repositories' ADR governance passed. The SDK audit records the devnet's 1.5-second operation pacing, browser limits and persistence contract. No mainnet, cross-browser or sustained-burst claim.

New dependency

None. Cargo manifests and lockfile are unchanged.

ADR

Proposed ADR-0007: browser manifest creation and pointer payment recovery, updated for onSubmission, single-hash recovery, callback timeouts, typed write failures, the shared embedding policy, the removed bare-function form and the sha256 input, and listed in the ADR index. No Accepted ADR was edited; acceptance requires human engineering review.

Mitigation / rollback

Revert the new exports and regenerate consuming WASM artifacts if needed; retain all pointer checkpoints, submitted-transaction evidence and paid proofs until reconciled. Never treat rollback or a missing receipt as authorization to pay again. Existing stored files and pointer states remain readable by compatible clients.

🤖 Generated with Claude Code

@dirvine dirvine left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — manifest export + pointer payment recovery (T2)

Reviewed at head 8316468 (base 225a6768; 4 files, +350/−5) via the standing review panel (GLM 5.3, Qwen 3.8 27B, DS4 Flash): a correctness round completed 3/3 with substantive reviews, plus a dedicated adversarial round that completed 1/3 (Qwen only; GLM and DS4 seats returned incomplete terminations after three attempts, so that round is provisional — noted at the end). Outcome: no severe findings; approve with caveats. Severe bar applied: silent data loss, stuck node, registry corruption, backwards-compat break, silent failure misclassification.

Verified against source on the exact head:

  • No double payment. recoverPointerPayment (ant-core/src/browser/wasm_transport/pointer.rs:583+) is offline: it re-derives the paid proof from the checkpoint's plan plus an observed receipt via the existing wallet_quotes → paid_transactions → plan.proof helpers, then hands {record, proof} back for the unchanged pointer_put_paid path. It never quotes, signs, or submits a transaction; the checkpoint contains no owner seed.
  • Receipt trust is not new surface. The adversarial seat flagged that a forged receipt could mint a proof for unpaid state. Adjudicated: the proof only carries the tx-hash claim — storers verify it on-chain before accepting the record (ant-protocol payment::single_node::verify_paid_quote: on-chain amount ≥ quote price, correct rewards address). A fabricated tx hash fails at store time, and this is the same wallet/receipt trust boundary the upload adapter already uses. Not severe; no change needed here.
  • Checkpoint validation. Version 1 only, deny_unknown_fields, 4 MiB cap, Pointer::from_bytes signature check, and plan/record consistency (plan.address == record.state_id(), plan.data_size == record.len()).
  • ABI/back-compat. createPointer/updatePointer/transferPointer gain an optional trailing onPrepared callback; omitted → None for existing JS callers. New exports are additive. No Cargo.toml/Cargo.lock changes.
  • Manifest. Embedded DataMaps are capped at MAX_MANIFEST_BYTES and must use canonical MessagePack (re-encoded and byte-compared); public entries require a valid file link. Minor note: name/paths have no per-field size bound — application-supplied, non-severe.
  • Hygiene. cargo fmt --all --check clean on head; no whitespace errors; no dependency changes.

Caveats (non-blocking):

  1. Security Audit fails — inherited, not introduced by this PR. Four rustls 0.23.45 advisories (RUSTSEC-2026-0346…0349, published 2026-10-14; fix: rustls ≥ 0.23.46). This PR changes no Cargo files, and main's last CI run (2026-09-28) predates the advisories — main would fail the same audit today. Suggest a separate lockfile bump on main.
  2. E2E Tests (macos-latest) pending at review time. Everything else green on this exact head (Real Chromium + local nodes, unit tests on both OSes, Merkle E2E, Browser WASM, clippy, fmt, docs).

Panel participation, for the record: correctness round — GLM 5.3, Qwen 3.8, DS4 all returned substantive approve-with-caveats reviews, no severe findings (3/3). Adversarial round — Qwen only (1/3, provisional); the GLM and DS4 seats did not terminate within limits after retries. Qwen's single candidate severe finding is the receipt-forgery item adjudicated above.

Verdict: no blocking findings. Merge after the macOS E2E check completes; treat the rustls bump as a main-branch follow-up, not a gate for this PR.

mickvandijke added a commit to WithAutonomi/ant-browser-sdk that referenced this pull request Oct 19, 2026
Rebuild the bundled WASM from WithAutonomi/ant-client#230 at bab6beb with
the same rustc 1.99.0, notices and std copyright.

- The core's pointer checkpoint now holds its record in base64url and its
  plan in base64url MessagePack. Re-encode the devnet fixture's core
  checkpoint into that layout from the same signed record and plan; the
  receipt and expected paid state are as captured. Rewrite the tamper test
  for the new layout, and check that the untouched checkpoint recovers, so
  each refusal is caused by its edit.
- recoverPointerPayment now takes a single transactionHash for the plan's
  quotes, as the write does, so pass receipts through instead of keying
  them in the SDK. Cover both forms against the real devnet checkpoint.
- Document that storers refuse a paid proof once its quotes are a day old.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mickvandijke and others added 7 commits October 19, 2026 15:20
Manifests:
- The shared encoder refuses an embedded DataMap without chunks, which
  the decoder already refused, so no writer can produce an unreadable
  .ant file or link.
- Browser input follows native writer policy: a root DataMap is embedded
  only up to MAX_EMBEDDED_ROOT_MAP_BYTES, and a size hint must match a
  root map's exact size.
- Torrent hashes use the shared parser; the duplicate entry-count check
  is gone.
- canonicalize() computes effective names once, and the browser view
  derives each address once. Path-less embedded entries self-encrypt
  their DataMap far fewer times.
- CreatedManifest and the manifest views derive Deserialize.

Pointers:
- create/update/transfer take a trailing { onPrepared, onPaid } options
  object instead of a seventh positional callback. A bare function is
  still taken as onPaid, and unknown options are refused before paying.
- The settlement-refusal check runs again just before the wallet is
  invoked, after onPrepared may have waited.
- recoverPointerPayment requires the receipt's transactionHashes to name
  the checkpoint's quote, no longer needs totalAmount, and reports a
  newer checkpoint as an unsupported version.
- A checkpoint recovery could not read is refused before payment, and
  the plan is no longer cloned to serialize it.
- Documented that onSubmission records nothing for pointer writes, so
  the wallet must keep the broadcast hash; restored the pay-twice
  warning.
- WASM tests cover checkpoint ordering, callback failure, option
  validation, the refusal re-check and recovery.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pointers:
- Pointer writes take `options?: { onPrepared, onSubmission, onPaid }`
  (`Option<JsValue>`), so the TypeScript parameter is optional again.
- New `onSubmission` option: the core forwards every transaction the
  wallet reports broadcasting, and the wallet waits on it. A page lost
  between broadcast and receipt can therefore recover without each
  wallet keeping the hash itself.
- recoverPointerPayment accepts `{ transactionHash }` as well as keyed
  `{ transactionHashes }`, exactly as the write does, so a reported
  submission or a single-hash receipt recovers. A keyed receipt must
  still name the checkpoint's quote.
- onPrepared is bounded by the 30 s callback timeout (shared with
  onPaid). Every failure before the wallet is invoked, including the
  re-checked settlement refusal, ends "payment was not submitted";
  nothing is paid unless the wallet is called.
- The checkpoint stays a versioned JSON string, but the record is
  base64 and the plan base64 MessagePack rather than JSON number arrays:
  87,297 instead of 156,250 characters against the mock close group.
- storePaidPointer says a proof expired when a refused proof's quotes
  are past the storers' age limit, rather than a generic store error.
- A failure building onPaid's argument can no longer abort a paid write.

Manifests:
- ManifestInput::create returns a typed thiserror ManifestInputError
  instead of String.
- The entry count is checked again before any entry is parsed.
- createManifest checks top-level and torrent keys itself:
  serde_wasm_bindgen reads only declared struct fields, so
  deny_unknown_fields never refused unknown keys from JavaScript.
- Validation and sorting run once: the bytes and link form are encoded
  through Manifest::encode_canonical.
- ManifestEntry::known_size sums chunk sizes as u64, so it no longer
  overflows past 4 GiB on wasm32. The browser view names entries
  through ManifestEntry::effective_name_with instead of a copy of the
  rule.
- Documented that an embedded root DataMap must be one an upload shrank,
  since the link carries its shrunk form.

WASM tests cover createManifest/createFileLink input from JavaScript,
onSubmission ordering and recovery from it, single-hash recovery, and
the onPrepared timeout. ADR-0007 is updated to match.

BREAKING CHANGE: createPointer, updatePointer and transferPointer no
longer accept a bare function as their last argument; pass
`{ onPaid }` instead. ManifestInput::create now returns
`Result<CreatedManifest, ManifestInputError>` instead of
`Result<CreatedManifest, String>`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pointers:
- onSubmission is bounded by the callback timeout and never rejects to
  the wallet: the transaction is already broadcast, so a page that
  cannot keep it must not hold up or fail the payment, as for onPaid.
- The write waits for every reported broadcast to be kept before it
  goes on or fails, whether or not the wallet waited, as the upload
  adapter does.
- Write failures are a typed PointerWriteError split at the wallet call:
  every failure before it, including invalid input, an existing pointer
  and a refused settlement, ends "payment was not submitted"; later
  failures are reported as they are.
- write_pointer takes the write with its target, dropping the
  too_many_arguments exemption.
- storePaidPointer notes a proof past the storers' real 24 h quote age
  (no safety margin), by this device's clock, alongside the storer's
  own error, instead of replacing it with a pay-again instruction.
  batch::paid_proof_has_expired is public and ungated, so no build
  config leaves its proof import unused.
- Restored the warning that a write with neither onPrepared nor
  onSubmission keeps nothing to recover from.

Manifests:
- One embedding policy, data::manifest::is_embeddable, serves native and
  browser writers: a small root map, or a published map of at most
  MAX_PUBLISHED_MAP_CHUNKS. Browser input refuses an intermediate shrink
  level.
- createManifest reads accepted keys from each input struct's serde
  derive (struct_fields) instead of hand-kept lists.
- The created view takes addresses from the link form, whose maps are
  already shrunk, instead of shrinking each embedded map again.

ADR-0007 is updated and listed in the ADR index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A real-Chromium test against the pinned devnet nodes and Anvil. It
pays once for a pointer, loses the page after the payment confirms and
before the state is stored, and rebuilds the paid state with
recoverPointerPayment from the onPrepared checkpoint and the
transaction onSubmission kept. It then stores that state with
storePaidPointer and reads it back, with no second payment. A write
refused before the wallet is checked to say "payment was not
submitted". The test also builds a manifest with createManifest and
writes the .ant file and link to its output directory for the native
CLI. The two pointer tests now share one local-chain wallet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main now records the creator's SHA-256 on manifest entries (#229,
V2-1564), and decodeManifest already shows it. createManifest entries
take an optional hex `sha256` as well, so a page that hashes a file can
record it just as a native writer does. It is the creator's claim and
must be 32 bytes of hex; the browser computes none itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mickvandijke
mickvandijke force-pushed the feat/browser-pointer-recovery-manifest-export-20261015 branch from 4d27758 to 404fa34 Compare October 19, 2026 13:30
mickvandijke added a commit to WithAutonomi/ant-browser-sdk that referenced this pull request Oct 19, 2026
Rebuild the bundled WASM from WithAutonomi/ant-client#230 at 4d27758 with
the same rustc 1.99.0, notices and std copyright. The JS API is
unchanged; only doc comments and export order differ.

- storePaidPointer no longer replaces a storer's refusal of a day-old
  proof with "paid proof expired": it reports the storer's error, noting
  when this device's clock puts a quote past the age storers accept.
  Document that instead.
- The core's onSubmission bounds and pointer write errors need nothing
  here: the SDK's pay function does not call the core's onSubmission, and
  nothing matches "payment was not submitted". createManifest now refuses
  an intermediate shrunk DataMap, which no upload returns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mickvandijke and others added 2 commits October 19, 2026 16:20
reject_unknown_keys took its object with dyn_ref, which tests
`instanceof Object`. An object without Object.prototype, such as one
from Object.create(null), or an object from another frame fails that
test, so its keys went unchecked. For pointer write options that meant a
misspelt `onPrepared` was ignored and the write paid with no checkpoint
kept; createManifest likewise accepted unknown top-level and torrent
keys. Any value JavaScript reports as an object is now checked. Tests
cover both kinds of object for createManifest and the pointer options.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t contents

The pointer recovery paragraph in the browser-tests README had split
the paid upload paragraph from its last sentence. ADR-0007 now says
what a checkpoint holds, a signed record and a quoted payment plan, and
that the transaction evidence is in the kept submissions and receipts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mickvandijke added a commit to WithAutonomi/ant-browser-sdk that referenced this pull request Oct 19, 2026
Rebuild the bundled WASM from WithAutonomi/ant-client#230 at 404fa34,
now rebased onto main, with the same rustc 1.99.0 and std copyright.
The rebase brings ant-protocol 5.0.0 from crates.io instead of the
pinned 4.0.0 revision, saorsa-core 0.29.1 and saorsa-transport 0.38.1;
the notices follow. The JS bindings change only in export order.

Manifest entries may now record the creator's SHA-256 of the plaintext
(ant-client #229, ADR-0006), and createManifest accepts one as hex.
- ManifestEntry carries it as optional hex `sha256`; the SDK dropped the
  field the core returns, so CLI manifests lost it when read here.
- ManifestEntryInput takes an optional `sha256`, which Rust validates.
- The SDK surfaces the hash and does not check it: the CLI checks it on
  extraction, which the browser has none of, and downloads are verified
  by content address. ADR-0007 and the README say so.
- Tests decode ant-client's golden fixture with a sha256, carry one
  through createManifest, decode and link, and refuse malformed ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants