<>ts-stack
Get StartedArchitecturePackagesSpecsGuides
⌘K
Reference
Home
Get StartedOverviewInstallChoose your stackKey concepts
ArchitectureOverviewStack layersBEEF (BRC-62)BRC-100 Wallet InterfaceIdentity & AuthConformance pipeline
PackagesOverviewSDKWalletNetworkOverlaysMessagingMiddlewareHelpers
InfrastructureOverviewmessage-box-serveroverlay-serveruhrp-server-basicuhrp-server-cloud-bucketwabwallet-infrachaintracks-serverwebrtpay-relay
SpecsOverviewBRC-100 Wallet InterfaceOverlay HTTPMessage-box HTTPAuthsocket (WebSocket)BRC-31 Auth HandshakeBRC-29 Peer PaymentBRC-121 / HTTP 402ARC BroadcastMerkle ServiceStorage AdapterGASP SyncUHRPAir-Gap Optical (BRC-141)
ConformanceOverviewVector catalogTS runnerContributing vectors
GuidesOverviewIdentity, DIDs and credentialsIdentity migrationBuild a wallet-aware appRun an overlay nodePeer-to-peer messagingHTTP 402 payments
ReferenceOverviewBRC indexRepository health
AboutVersioningContributingDoc agentDocumentation sources
Loading…
NextIdentity, DIDs and credentials
Edit this page on GitHub
© 2026 BSV Blockchain. ts-stack is open-source.
GitHubContributingVersioning

Explicit paid lookup clients and protected workflow state

A paid lookup has two owners. The selected seller retains its quoted obligation, payment evidence and disclosure decision. The buyer retains the original request, selected capability, payment construction and delivered material. An HTTP response connects those owners; it does not replace either one's durable records.

OutputPaidLookupTransport in @bsv/sdk performs one immutable quote, pay or recover operation. It authenticates against the original selected seller using the original buyer's wallet. Its constructor takes an integrity-protected retained capability, the corresponding recovery trust settings, and the exact Acquire request. The pay operation also requires the original challenge and exact signed BRC-105 payment. A recover operation can include the retained challenge; omitting it supports recovery after the initial quote reply was lost.

The constructor binds the request to the selected service and chain. Responses must preserve the original buyer, seller, listing, request, rules and challenge. The transport checks challenge amount and derivation-prefix headers, the selected release policy and minimum recovery commitment. Recovery uses the original acquisition identity and endpoint even after the original manifest expires. Manifest expiry does not authorize a new payment or another seller.

Every network operation is finite, authenticated, bounded and cancellable. The client disables AuthFetch's automatic payment path and attaches a payment header only for an explicit pay instance. It never constructs a wallet action, retries with a new payment, polls for completion, fans payment out to catalogue hosts, or stores results. A failed call can have an unknown remote outcome. Recover that same operation before deciding what is known; a timeout is not proof of absence. Existing AuthFetch callers and their defaults are unchanged.

An unpaid quote may return either a challenge or an already-retained status. A paid or recovery call returns a status packet. Delivered data is a seller report until the application independently verifies the listing's transaction and Script, the exact payment output, release evidence and application material. Keep received, validated and usable outcomes distinct. Retain unusable delivered data for diagnosis and recovery instead of silently requesting or buying a replacement.

The selected profile's request and response bounds remain within the four-MiB wire limit. A BRC-105 payment contains at most 64 KiB of Atomic BEEF; JSON/base64 framing can require a substantially larger HTTP header. The acquisition path permits at most 128 KiB of aggregate outbound headers, and private-acquisition Overlay Express hosts use the corresponding bounded listener allowance. Reverse proxies must preserve those limits. Responses have a separate 16-KiB header limit. Malformed Atomic BEEF is an invalid candidate; an uncertain wallet or chain operation remains unavailable and must be reconciled.

Encrypted local control state

The portable @bsv/output-knowledge/operations/protected entry adds ProtectedOperationStateStore, WalletProtectedOperationPayload, protectedOperationBinding and PROTECTED_OPERATION_INITIAL. These compose above existing native SQLite or browser IndexedDB operation stores. Their schemas, default capacities and ordinary public workflow behavior remain unchanged.

WalletProtectedOperationPayload uses the selected BRC-100 wallet's authenticated self-encryption. It binds each ciphertext to the namespace, complete installed configuration and exact revision through a fresh salted key identifier. It pins the selected wallet identity and methods around awaited custody operations. The public configuration must contain only public identifiers; private requests and results belong in encrypted values. An installation does not create or export a new root key, and losing access to the original custody cannot authorize a replacement installation.

Create the underlying store with the exact protectedOperationBinding and the public empty sentinel. Explicit initialize commits the first encrypted value at revision one. Later open requires existing encrypted state and never initializes an absent or empty store. Reserve the full plaintext frame and ciphertext expansion before an operation can incur a financial effect. Values are bounded by the installed maximumValueBytes; the wallet codec supports at most two MiB of plaintext, including framing. A complete four-MiB delivery needs a separately bounded protected result owner. A small encrypted control cell is not such an owner, and increasing a wire limit would not solve that storage requirement.

Owned plaintext work buffers are cleared after processing, including when a returned buffer exceeds capacity or an installed capability changes during decryption. This does not erase copies retained inside the installed wallet.

Each CAS owns the supplied value before awaiting encryption. Multiple writers use the original backing store's atomic revision check. A lost acknowledgement can be recognized only when the immediately following revision decrypts to that exact value; random encryption salts do not defeat this comparison. A later revision is a conflict, not evidence that an uncertain earlier write rolled back. These stores detect changed record bindings and custody. They do not detect restoration of an entire earlier valid database. Backups, browser eviction, disk exhaustion, restoration and paid-result deletion need explicit application policy.

New signing and original recovery

The native recoverable action controller accepts an optional fourth finalize argument, checkNewSigning. This synchronous callback returns void while the original operation still has current authority to construct a new final transaction, or throws. It is checked after awaited authorization and allocation, around managed signing, after complete input Script verification, and immediately before requesting retention. The shared managed signer preserves the original unlock-template receivers, key batching and telemetry behavior.

The callback must read the current clock and current application authority at each invocation. Capturing an earlier boolean or timestamp defeats that purpose. For a quote deadline, reject when the current time is greater than or equal to payableUntil; the deadline is exclusive. An async callback or a non-void return is rejected. Ordinary callers that omit the callback retain their existing behavior.

A callback cannot cancel an effect already underway or prove the commit time of an awaited storage operation. Retention can commit after the last synchronous check, and its response can be lost. Such uncertainty always belongs to the original operation. recover reads and processes the exact retained final without signing again. finalize also returns the same retained final without consulting the new-signing callback. If recovery finds only a prepared allocation, it may reconstruct the unsigned transaction but does not sign it. A separate explicit advance needs current authority before it can continue new signing. No path in this local capability broadcasts a transaction.

Validation and composition status

The accompanying tests exercise selected-host authenticated HTTP, lost quote and paid responses, one actual native seller-wallet credit, original recovery, malformed and maximum-size payment envelopes, encrypted SQLite/IndexedDB state, concurrent CAS, native process termination, and delayed signing authority. The packed browser test uses a separate Chrome profile and native IndexedDB to check ciphertext at rest, browser restart, cross-tab CAS and wrong-wallet refusal. Those tests complement the required complete mutation and exact-head hosted gates; they do not substitute for them.

These are reusable building blocks. The durable buyer orchestration, complete four-MiB protected delivered-result owner, domain/LCH material adapters and their end-to-end demonstrations remain under implementation. Applications must not interpret a finite transport, encrypted control cell or local noSend transaction as completion of that whole purchase workflow. See server acquisition and recovery and local action recovery for the existing owners.