{"_id":"@bsv/wallet-relay","_rev":"12-835abbeee03456544982c034d48bceaf","name":"@bsv/wallet-relay","dist-tags":{"latest":"0.5.1"},"versions":{"0.1.0":{"name":"@bsv/wallet-relay","version":"0.1.0","_id":"@bsv/wallet-relay@0.1.0","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"1c40e19d5c539893b76be47d07dbd8750e3efd2e","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.1.0.tgz","fileCount":47,"integrity":"sha512-EvX0FoAkgqjLLERMzH+Mmed1ph0KsMb6Fbbz1gBrnJp3sEMBM4o7HioNIEgoK7VHWSVj1F4qR3qeUV+dd3vevw==","signatures":[{"sig":"MEUCIFGoNf0T7Y8UiB8wzujWACqrEHjccFhFjoMfxp7mSIHuAiEA5QG8KdykJDNgIM8302ASXly+1fwGMogVU2g9zvtSdVY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":603472},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js","require":"./dist/react.cjs"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js","require":"./dist/client.cjs"}},"gitHead":"604a3d9c0f4168b4fac0240fbb3beed4e8062a3a","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"jest --config jest.config.cjs","build":"tsup","lint:fix":"eslint src tests --fix","typecheck":"tsc --noEmit"},"_npmUser":{"name":"dkellen","email":"darrkellen@gmail.com"},"_npmVersion":"11.10.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"_nodeVersion":"22.20.0","_hasShrinkwrap":false,"devDependencies":{"ws":"^8.0.0","jest":"^30.3.0","tsup":"^8.5.1","react":"^19.2.4","eslint":"^9.39.4","qrcode":"^1.5.0","express":"^4.18.0","ts-jest":"^29.4.9","@bsv/sdk":"^2.0.13","@types/ws":"^8.18.1","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^22.19.17","@types/react":"^19.2.14","@types/qrcode":"^1.5.6","@types/express":"^5.0.6","eslint-plugin-n":"^17.24.0","eslint-plugin-react":"^7.37.5","eslint-plugin-import":"^2.32.0","eslint-plugin-promise":"^7.2.1","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.3.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^8.58.2","eslint-plugin-react-hooks":"^5.2.0","@typescript-eslint/eslint-plugin":"^8.58.2"},"peerDependencies":{"ws":">=8.0.0","react":">=17.0.0","qrcode":">=1.5.0","express":">=4.0.0","@bsv/sdk":">=2.0.0"},"peerDependenciesMeta":{"ws":{"optional":true},"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.1.0_1776448589459_0.2721344021876866","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bsv/wallet-relay","version":"0.1.1","_id":"@bsv/wallet-relay@0.1.1","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"377328b477818391eb61dd6d69b64fb6c7244d0c","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.1.1.tgz","fileCount":47,"integrity":"sha512-S9pxf8YQUc4lApmZxXkoitt6XaYZgjUI+559OjGR5Ij2/uS57hjepTkdbw0EMFWaXaZ38fCBEX34He5sgHDIIw==","signatures":[{"sig":"MEYCIQCt7oljVZ66U/xSuAvprydnGlPX384bY5QmoiWsdkWmJAIhAMsuLYNHtx/gH1tXISL4TYlrIZi7TEd6+iL/wSusm/qn","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":650790},"main":"./dist/index.cjs","type":"module","_from":"file:bsv-wallet-relay-0.1.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js","require":"./dist/react.cjs"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js","require":"./dist/client.cjs"}},"scripts":{"dev":"tsup --watch","test":"jest --config jest.config.cjs","build":"tsup","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/tmp/50192fab7bd8217df5f120ce6c1e8ea7/bsv-wallet-relay-0.1.1.tgz","_integrity":"sha512-S9pxf8YQUc4lApmZxXkoitt6XaYZgjUI+559OjGR5Ij2/uS57hjepTkdbw0EMFWaXaZ38fCBEX34He5sgHDIIw==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.12.1","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"devDependencies":{"ws":"^8.0.0","jest":"^30.3.0","tsup":"^8.0.0","react":"^19.2.4","qrcode":"^1.5.0","express":"^4.18.0","ts-jest":"^29.4.6","@bsv/sdk":"^2.1.0","@types/ws":"^8.5.0","react-dom":"^19.2.0","typescript":"^5.4.0","@types/jest":"^30.0.0","@types/node":"^22.0.0","@types/react":"^19.2.14","@types/qrcode":"^1.5.0","@types/express":"^5.0.0","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.3.0","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"ws":">=8.0.0","react":">=17.0.0","qrcode":">=1.5.0","express":">=4.0.0","@bsv/sdk":"^2.1.0"},"peerDependenciesMeta":{"ws":{"optional":true},"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.1.1_1778776276386_0.14617158100637395","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bsv/wallet-relay","version":"0.2.0","_id":"@bsv/wallet-relay@0.2.0","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"fa07d67fca2b01314b146d99818ede2b3b04817b","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.2.0.tgz","fileCount":75,"integrity":"sha512-fTHwuF44NMJsbaiz8Vr/HjWu5ihwUb6k+J6BG2pUYg+OB9AgaSIOFaCB70DpOgE6YY8M0Nh1aTqDnTEm5rGRkg==","signatures":[{"sig":"MEYCIQClnE7LWW4fXBktkol193Ud40eVQVYhWE3+yIEpMuK7egIhAO5S8FLM8gFZPD2R+xO8CrgF55DWrVEtVmqL6dRM/bC/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":628493},"main":"./dist/index.cjs","type":"module","_from":"file:bsv-wallet-relay-0.2.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js","require":"./dist/react.cjs"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js","require":"./dist/client.cjs"}},"scripts":{"dev":"tsup --watch","test":"jest --config jest.config.cjs","build":"tsup && tsc -p tsconfig.build.json --emitDeclarationOnly","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/tmp/ad2854c56430d81740ed5eefddc0d7c6/bsv-wallet-relay-0.2.0.tgz","_integrity":"sha512-fTHwuF44NMJsbaiz8Vr/HjWu5ihwUb6k+J6BG2pUYg+OB9AgaSIOFaCB70DpOgE6YY8M0Nh1aTqDnTEm5rGRkg==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.13.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"_nodeVersion":"24.16.0","_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.0","jest":"^30.4.2","tsup":"^8.0.0","react":"^19.2.7","qrcode":"^1.5.0","express":"^5.2.1","ts-jest":"^29.4.11","@bsv/sdk":"^2.1.3","@types/ws":"^8.5.0","react-dom":"^19.2.7","typescript":"^6.0.3","@types/jest":"^30.0.0","@types/node":"^25.9.3","@types/react":"^19.2.17","@types/qrcode":"^1.5.0","@types/express":"^5.0.0","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"ws":">=8.0.0","react":">=17.0.0","qrcode":">=1.5.0","express":">=4.0.0","@bsv/sdk":"^2"},"peerDependenciesMeta":{"ws":{"optional":true},"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.2.0_1781910929406_0.5193440622266825","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@bsv/wallet-relay","version":"0.2.1","_id":"@bsv/wallet-relay@0.2.1","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"1dff31598dae01778901d3770ca0da225a71358f","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.2.1.tgz","fileCount":75,"integrity":"sha512-Z7ct1JlEpC3JW9iuSzlVjbBGVtmDaVuyo1Pg/IEbaJG7J5Br1aLbK6RqfT9wOoJT4EZC1xY0wkz0yqpccAeFyw==","signatures":[{"sig":"MEQCIFvemg8rURp+ugS3iVHNhcecB03Mcz2oMa4HsUo3rlijAiA5pbAHva+CqHsqzWTC+DLhQ4a8CO2FhPyUveLdaUSBsw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":640439},"main":"./dist/index.cjs","type":"module","_from":"file:bsv-wallet-relay-0.2.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js","require":"./dist/react.cjs"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js","require":"./dist/client.cjs"}},"scripts":{"dev":"tsup --watch","test":"jest --config jest.config.cjs","build":"tsup && tsc -p tsconfig.build.json --emitDeclarationOnly","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/tmp/f2db30704450c3efc46a518c41313dd4/bsv-wallet-relay-0.2.1.tgz","_integrity":"sha512-Z7ct1JlEpC3JW9iuSzlVjbBGVtmDaVuyo1Pg/IEbaJG7J5Br1aLbK6RqfT9wOoJT4EZC1xY0wkz0yqpccAeFyw==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.16.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"_nodeVersion":"24.18.0","_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.0","jest":"^30.4.2","tsup":"^8.0.0","react":"^19.2.7","qrcode":"^1.5.0","express":"^5.2.1","ts-jest":"^29.4.11","@bsv/sdk":"^2.1.3","@types/ws":"^8.5.0","react-dom":"^19.2.7","typescript":"^6.0.3","@types/jest":"^30.0.0","@types/node":"^26.0.0","@types/react":"^19.2.17","@types/qrcode":"^1.5.0","@types/express":"^5.0.0","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"ws":">=8.0.0","react":">=17.0.0","qrcode":">=1.5.0","express":">=4.0.0","@bsv/sdk":"^2.1.6"},"peerDependenciesMeta":{"ws":{"optional":true},"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.2.1_1784244853116_0.9852268796562724","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@bsv/wallet-relay","version":"0.2.2","_id":"@bsv/wallet-relay@0.2.2","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"5eed425a4af1659ae225e9280c83136954062cde","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.2.2.tgz","fileCount":75,"integrity":"sha512-yYj0IRSD0zoWxCr7ogYFM0OWid//LnFx88bD+dfQyrYcEbH9O1niOsdtSGrf0XIxn6JV9YEZZ/IEO3hH6F7frA==","signatures":[{"sig":"MEYCIQCHN0ZzSJu7WphMPEY5iy6HYWkAxDu1h8wSLXk6dC72zQIhANSJiFKGTC4PKKeu56w6waV7uq9jJ3Hpab8JjDLaLtO2","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.2.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":640440},"main":"./dist/index.cjs","type":"module","_from":"file:bsv-wallet-relay-0.2.2.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js","require":"./dist/react.cjs"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js","require":"./dist/client.cjs"}},"scripts":{"dev":"tsup --watch","test":"jest --config jest.config.cjs","build":"tsup && tsc -p tsconfig.build.json --emitDeclarationOnly","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/tmp/ea80615458b582c95dd1b98bc40b2e6d/bsv-wallet-relay-0.2.2.tgz","_integrity":"sha512-yYj0IRSD0zoWxCr7ogYFM0OWid//LnFx88bD+dfQyrYcEbH9O1niOsdtSGrf0XIxn6JV9YEZZ/IEO3hH6F7frA==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.16.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"_nodeVersion":"24.18.0","_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.1","jest":"^30.4.2","tsup":"^8.5.1","react":"^19.2.8","qrcode":"^1.5.4","express":"^5.2.1","ts-jest":"^29.4.12","@bsv/sdk":"^2.2.0","@types/ws":"^8.18.1","react-dom":"^19.2.8","typescript":"^6.0.3","@types/jest":"^30.0.0","@types/node":"^26.1.1","@types/react":"^19.2.17","@types/qrcode":"^1.5.6","@types/express":"^5.0.6","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"ws":">=8.0.0","react":">=17.0.0","qrcode":">=1.5.0","express":">=4.0.0","@bsv/sdk":"^2.1.6"},"peerDependenciesMeta":{"ws":{"optional":true},"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.2.2_1784948709330_0.28219551217539385","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"name":"@bsv/wallet-relay","version":"0.3.3","keywords":["bsv","wallet","relay","mobile","pairing"],"author":{"name":"BSV Blockchain Association"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bsv/wallet-relay@0.3.3","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"d2538c3e15f91f136473864f775e48f42d18f3dc","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.3.3.tgz","fileCount":116,"integrity":"sha512-N04LQY4QGb4a2DXLJzasm7xsAPkGS64lhePUF+nWukYqSbp7CD0VnZ2czbqAv79wyVRDGZVm6UO+hDS5oibjlA==","signatures":[{"sig":"MEYCIQCpGhgs03OCKem9C3UKoWHNSqbM3PXz/f+rIeb/6STqlAIhALP1IKE0FAPkWKkFDKAXvYI3xORunZf2Tjn4fiF+y9kj","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.3.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":746687},"main":"./dist/index.cjs","type":"module","_from":"file:/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.3.3.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=22"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./client":{"import":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"require":{"types":"./dist/client.d.cts","default":"./dist/client.cjs"}},"./package.json":"./package.json"},"scripts":{"dev":"node build.mjs --watch","lint":"oxlint build.mjs bin src tests --deny-warnings","test":"jest --config jest.config.cjs --watchman=false","build":"node build.mjs && tsc -p tsconfig.build.json --emitDeclarationOnly && node scripts/copy-cjs-types.mjs","typecheck":"tsc --noEmit","pack:check":"pnpm build && node ../../../scripts/check-package-artifact.mjs . --allow-source-prefixes template --consumer-dependencies react --exports QRSessionManager,WalletRelayService,WalletRequestHandler,WebSocketRelay,compileOriginMatcher --entry-exports \"./client=WalletPairingSession|WalletRelayClient|WalletRelayError;./react=QRDisplay|QRPairingCode|RequestLog|WalletConnectionModal|useQRPairing|useWalletRelayClient\" --bin wallet-relay --bin-args --help","format:check":"pnpm --workspace-root exec prettier --check \"packages/wallet/ts-wallet-relay/**/*.{cjs,js,json,md,mjs,ts,tsx}\"","test:browser":"pnpm build && node ../../../scripts/check-browser-package.mjs .","test:coverage":"jest --config jest.config.cjs --coverage --watchman=false","test:property":"jest --config jest.config.cjs --selectProjects node --runInBand --watchman=false --runTestsByPath tests/pairingUri.property.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.3.3.tgz","_integrity":"sha512-N04LQY4QGb4a2DXLJzasm7xsAPkGS64lhePUF+nWukYqSbp7CD0VnZ2czbqAv79wyVRDGZVm6UO+hDS5oibjlA==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.16.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ws":"^8.21.1","@types/express":"^5.0.6"},"publishConfig":{"access":"public"},"typesVersions":{"*":{"*":["dist/index.d.ts"],"react":["dist/react.d.ts"],"client":["dist/client.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","react":"^19.2.8","oxlint":"^1.76.0","qrcode":"^1.5.4","esbuild":"^0.28.1","express":"^5.2.1","ts-jest":"^29.4.12","@bsv/sdk":"^2.2.15","@types/ws":"^8.18.1","react-dom":"^19.2.8","fast-check":"^4.9.0","typescript":"npm:@typescript/typescript6@6.0.2","@types/jest":"^30.0.0","@types/node":"^26.1.2","@types/react":"^19.2.17","@types/qrcode":"^1.5.6","@typescript/native":"npm:typescript@7.0.2","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^7.0.0"},"peerDependencies":{"react":">=17.0.0","qrcode":">=1.5.0","express":">=4.0.0","@bsv/sdk":"^2.1.6"},"peerDependenciesMeta":{"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.3.3_1785457154180_0.9822743145553909","host":"s3://npm-registry-packages-npm-production"}},"0.3.4":{"name":"@bsv/wallet-relay","version":"0.3.4","keywords":["bsv","wallet","relay","mobile","pairing"],"author":{"name":"BSV Blockchain Association"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bsv/wallet-relay@0.3.4","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"4d41338e368c649539803f1470226990109a5963","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.3.4.tgz","fileCount":116,"integrity":"sha512-wBOzy7ixyr1GlBW09wD1Z3MNuw4bDgQF0Xity5dZW/NtI2xyk77ntSCZhKzST/4XrObI1ETw3QfoeJU8KBJljQ==","signatures":[{"sig":"MEUCICK7VWn56KMfBPcVceOpvenxAe1ZFWF6l50UhyhlqKE8AiEAkfu44ggUBkJ2Ed3tmuiPBQ4toL+Hckv2UyPpfjn2VlA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.3.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":747017},"main":"./dist/index.cjs","type":"module","_from":"file:/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.3.4.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=22"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./client":{"import":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"require":{"types":"./dist/client.d.cts","default":"./dist/client.cjs"}},"./package.json":"./package.json"},"scripts":{"dev":"node build.mjs --watch","lint":"oxlint build.mjs bin src tests --deny-warnings","test":"jest --config jest.config.cjs --watchman=false","build":"node build.mjs && tsc -p tsconfig.build.json --emitDeclarationOnly && node scripts/copy-cjs-types.mjs","typecheck":"tsc --noEmit","pack:check":"pnpm build && node ../../../scripts/check-package-artifact.mjs . --allow-source-prefixes template --consumer-dependencies react --exports QRSessionManager,WalletRelayService,WalletRequestHandler,WebSocketRelay,compileOriginMatcher --entry-exports \"./client=WalletPairingSession|WalletRelayClient|WalletRelayError;./react=QRDisplay|QRPairingCode|RequestLog|WalletConnectionModal|useQRPairing|useWalletRelayClient\" --bin wallet-relay --bin-args --help && node ../../../scripts/check-auth-express-consumers.mjs @bsv/wallet-relay","format:check":"pnpm --workspace-root exec prettier --check \"packages/wallet/ts-wallet-relay/**/*.{cjs,js,json,md,mjs,ts,tsx}\"","test:browser":"pnpm build && node ../../../scripts/check-browser-package.mjs .","test:coverage":"jest --config jest.config.cjs --coverage --watchman=false","test:property":"jest --config jest.config.cjs --selectProjects node --runInBand --watchman=false --runTestsByPath tests/pairingUri.property.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.3.4.tgz","_integrity":"sha512-wBOzy7ixyr1GlBW09wD1Z3MNuw4bDgQF0Xity5dZW/NtI2xyk77ntSCZhKzST/4XrObI1ETw3QfoeJU8KBJljQ==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.16.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ws":"^8.21.1"},"publishConfig":{"access":"public"},"typesVersions":{"*":{"*":["dist/index.d.ts"],"react":["dist/react.d.ts"],"client":["dist/client.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","react":"^19.2.8","oxlint":"^1.76.0","qrcode":"^1.5.4","esbuild":"^0.28.1","express":"^5.2.1","ts-jest":"^29.4.12","@bsv/sdk":"^2.2.17","@types/ws":"^8.18.1","react-dom":"^19.2.8","fast-check":"^4.9.0","typescript":"npm:@typescript/typescript6@6.0.2","@types/jest":"^30.0.0","@types/node":"^26.1.2","@types/react":"^19.2.17","@types/qrcode":"^1.5.6","@types/express":"^5.0.6","@typescript/native":"npm:typescript@7.0.2","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^7.0.0"},"peerDependencies":{"react":">=17.0.0","qrcode":">=1.5.0","express":">=4.18.0 <6","@bsv/sdk":"^2.1.6","@types/express":">=4.17.0 <6"},"peerDependenciesMeta":{"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false},"@types/express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.3.4_1785542796628_0.8627997304145831","host":"s3://npm-registry-packages-npm-production"}},"0.3.5":{"name":"@bsv/wallet-relay","version":"0.3.5","keywords":["bsv","wallet","relay","mobile","pairing"],"author":{"name":"BSV Blockchain Association"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bsv/wallet-relay@0.3.5","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"65c6e40cc69da8c67e271fbd76c9a277bba60329","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.3.5.tgz","fileCount":116,"integrity":"sha512-XwivzXFH4/v006t4derkJTkwg8PgPYXeG8bfl6WctA1JaXUUNVDurfUIlaXCW4alsgzynYdYbuw9vAJC/3Eugw==","signatures":[{"sig":"MEUCIBIO0e0Qt/7hkUbhFWGEKbbOY3UgxRkfSfwFTZncFM3zAiEAygx4lrjvc6cf01mBQFpFg5LH8X28bUDyfrJjEXi/opA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.3.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":754012},"main":"./dist/index.cjs","type":"module","_from":"file:/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.3.5.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=22"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./client":{"import":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"require":{"types":"./dist/client.d.cts","default":"./dist/client.cjs"}},"./package.json":"./package.json"},"scripts":{"dev":"node build.mjs --watch","lint":"oxlint build.mjs bin src tests --deny-warnings","test":"jest --config jest.config.cjs --watchman=false","build":"node build.mjs && tsc -p tsconfig.build.json --emitDeclarationOnly && node scripts/copy-cjs-types.mjs","typecheck":"tsc --noEmit","pack:check":"pnpm build && node ../../../scripts/check-package-artifact.mjs . --allow-source-prefixes template --consumer-dependencies react --exports QRSessionManager,WalletRelayService,WalletRequestHandler,WebSocketRelay,compileOriginMatcher --entry-exports \"./client=WalletPairingSession|WalletRelayClient|WalletRelayError;./react=QRDisplay|QRPairingCode|RequestLog|WalletConnectionModal|useQRPairing|useWalletRelayClient\" --bin wallet-relay --bin-args --help && node ../../../scripts/check-auth-express-consumers.mjs @bsv/wallet-relay","format:check":"pnpm --workspace-root exec prettier --check \"packages/wallet/ts-wallet-relay/**/*.{cjs,js,json,md,mjs,ts,tsx}\"","test:browser":"pnpm build && node ../../../scripts/check-browser-package.mjs .","test:coverage":"jest --config jest.config.cjs --coverage --watchman=false","test:property":"jest --config jest.config.cjs --selectProjects node --runInBand --watchman=false --runTestsByPath tests/pairingUri.property.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.3.5.tgz","_integrity":"sha512-XwivzXFH4/v006t4derkJTkwg8PgPYXeG8bfl6WctA1JaXUUNVDurfUIlaXCW4alsgzynYdYbuw9vAJC/3Eugw==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.16.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ws":"^8.21.1"},"publishConfig":{"access":"public"},"typesVersions":{"*":{"*":["dist/index.d.ts"],"react":["dist/react.d.ts"],"client":["dist/client.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","react":"^19.2.8","oxlint":"^1.76.0","qrcode":"^1.5.4","esbuild":"^0.28.1","express":"^5.2.1","ts-jest":"^29.4.12","@bsv/sdk":"^2.4.1","@types/ws":"^8.18.1","react-dom":"^19.2.8","fast-check":"^4.9.0","typescript":"npm:@typescript/typescript6@6.0.2","@types/jest":"^30.0.0","@types/node":"^26.1.2","@types/react":"^19.2.17","@types/qrcode":"^1.5.6","@types/express":"^5.0.6","@typescript/native":"npm:typescript@7.0.2","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^7.0.0"},"peerDependencies":{"react":">=17.0.0","qrcode":">=1.5.0","express":">=4.18.0 <6","@bsv/sdk":"^2.4.1","@types/express":">=4.17.0 <6"},"peerDependenciesMeta":{"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false},"@types/express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.3.5_1786767296967_0.930135942042839","host":"s3://npm-registry-packages-npm-production"}},"0.3.6":{"name":"@bsv/wallet-relay","version":"0.3.6","keywords":["bsv","wallet","relay","mobile","pairing"],"author":{"name":"BSV Association"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bsv/wallet-relay@0.3.6","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"9844ad9d41d89a1fb521b131df3bcf764b34fcbb","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.3.6.tgz","fileCount":116,"integrity":"sha512-YYJtT6zmdvwvBGCQ1MQUl0hO11uJFcSv0URpym+hiTDRo4hRmhIUp5YI+cFb2vqANcSQ74nopFBJGYoKS2WXew==","signatures":[{"sig":"MEUCIF3Dhp6BKjtcMWmwZbFAck67Xs2b/z2jVKTveEbylC5FAiEAvoEGy6qJknpaRhIC1eKsrytkExDg3JHEmteLuCoKsic=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.3.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":754001},"main":"./dist/index.cjs","type":"module","_from":"file:/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.3.6.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=22"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./client":{"import":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"require":{"types":"./dist/client.d.cts","default":"./dist/client.cjs"}},"./package.json":"./package.json"},"scripts":{"dev":"node build.mjs --watch","lint":"oxlint build.mjs bin src tests --deny-warnings","test":"jest --config jest.config.cjs --watchman=false","build":"node build.mjs && tsc -p tsconfig.build.json --emitDeclarationOnly && node scripts/copy-cjs-types.mjs","typecheck":"tsc --noEmit","pack:check":"pnpm build && node ../../../scripts/check-package-artifact.mjs . --allow-source-prefixes template --consumer-dependencies react --exports QRSessionManager,WalletRelayService,WalletRequestHandler,WebSocketRelay,compileOriginMatcher --entry-exports \"./client=WalletPairingSession|WalletRelayClient|WalletRelayError;./react=QRDisplay|QRPairingCode|RequestLog|WalletConnectionModal|useQRPairing|useWalletRelayClient\" --bin wallet-relay --bin-args --help && node ../../../scripts/check-auth-express-consumers.mjs @bsv/wallet-relay","format:check":"pnpm --workspace-root exec prettier --check \"packages/wallet/ts-wallet-relay/**/*.{cjs,js,json,md,mjs,ts,tsx}\"","test:browser":"pnpm build && node ../../../scripts/check-browser-package.mjs .","test:coverage":"jest --config jest.config.cjs --coverage --watchman=false","test:property":"jest --config jest.config.cjs --selectProjects node --runInBand --watchman=false --runTestsByPath tests/pairingUri.property.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.3.6.tgz","_integrity":"sha512-YYJtT6zmdvwvBGCQ1MQUl0hO11uJFcSv0URpym+hiTDRo4hRmhIUp5YI+cFb2vqANcSQ74nopFBJGYoKS2WXew==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.16.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ws":"^8.21.1"},"publishConfig":{"access":"public"},"typesVersions":{"*":{"*":["dist/index.d.ts"],"react":["dist/react.d.ts"],"client":["dist/client.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","react":"^19.2.8","oxlint":"^1.76.0","qrcode":"^1.5.4","esbuild":"^0.28.1","express":"^5.2.1","ts-jest":"^29.4.12","@bsv/sdk":"^2.4.2","@types/ws":"^8.18.1","react-dom":"^19.2.8","fast-check":"^4.9.0","typescript":"npm:@typescript/typescript6@6.0.2","@types/jest":"^30.0.0","@types/node":"^26.1.2","@types/react":"^19.2.17","@types/qrcode":"^1.5.6","@types/express":"^5.0.6","@typescript/native":"npm:typescript@7.0.2","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^7.0.0"},"peerDependencies":{"react":">=17.0.0","qrcode":">=1.5.0","express":">=4.18.0 <6","@bsv/sdk":"^2.4.1","@types/express":">=4.17.0 <6"},"peerDependenciesMeta":{"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false},"@types/express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.3.6_1787866233673_0.6057971343679769","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@bsv/wallet-relay","version":"0.4.0","keywords":["bsv","wallet","relay","mobile","pairing"],"author":{"name":"BSV Association"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bsv/wallet-relay@0.4.0","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"90f405a6e781b7dc95e1b30db5432b92d8704f53","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.4.0.tgz","fileCount":116,"integrity":"sha512-BWz6A6ugmsy6CpfCZGCTDQBvo2YZW/8wagaxggWCkoJlHjShb7ctUnMzqjAFi/YugLmukL/WOjtlvUFBsyIbbQ==","signatures":[{"sig":"MEQCIAOKQJnkbSt2G9UbQWKDarE7c+C8R3EMcORPb/dEKFLZAiB9UOFhAiD5w7pkGUmttFlCkSbCcTJe4AO5e7kXRYJ7bw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":779036},"main":"./dist/index.cjs","type":"module","_from":"file:/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.4.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=22"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./client":{"import":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"require":{"types":"./dist/client.d.cts","default":"./dist/client.cjs"}},"./package.json":"./package.json"},"scripts":{"dev":"node build.mjs --watch","lint":"oxlint build.mjs bin src tests --deny-warnings","test":"jest --config jest.config.cjs --watchman=false","build":"node build.mjs && tsc -p tsconfig.build.json --emitDeclarationOnly && node scripts/copy-cjs-types.mjs","typecheck":"tsc --noEmit","pack:check":"pnpm build && node ../../../scripts/check-package-artifact.mjs . --allow-source-prefixes template --consumer-dependencies react --exports QRSessionManager,WalletRelayService,WalletRequestHandler,WebSocketRelay,compileOriginMatcher --entry-exports \"./client=WalletPairingSession|WalletRelayClient|WalletRelayError;./react=QRDisplay|QRPairingCode|RequestLog|WalletConnectionModal|useQRPairing|useWalletRelayClient\" --bin wallet-relay --bin-args --help && node ../../../scripts/check-auth-express-consumers.mjs @bsv/wallet-relay","format:check":"pnpm --workspace-root exec prettier --check \"packages/wallet/ts-wallet-relay/**/*.{cjs,js,json,md,mjs,ts,tsx}\"","test:browser":"pnpm build && node ../../../scripts/check-browser-package.mjs .","test:coverage":"jest --config jest.config.cjs --coverage --watchman=false","test:property":"jest --config jest.config.cjs --selectProjects node --runInBand --watchman=false --runTestsByPath tests/pairingUri.property.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.4.0.tgz","_integrity":"sha512-BWz6A6ugmsy6CpfCZGCTDQBvo2YZW/8wagaxggWCkoJlHjShb7ctUnMzqjAFi/YugLmukL/WOjtlvUFBsyIbbQ==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.16.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ws":"^8.21.1"},"publishConfig":{"access":"public"},"typesVersions":{"*":{"*":["dist/index.d.ts"],"react":["dist/react.d.ts"],"client":["dist/client.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","react":"^19.2.8","oxlint":"^1.76.0","qrcode":"^1.5.4","esbuild":"^0.28.1","express":"^5.2.1","ts-jest":"^29.4.12","@bsv/sdk":"^2.5.0","@types/ws":"^8.18.1","react-dom":"^19.2.8","fast-check":"^4.9.0","typescript":"npm:@typescript/typescript6@6.0.2","@types/jest":"^30.0.0","@types/node":"^26.1.2","@types/react":"^19.2.17","@types/qrcode":"^1.5.6","@types/express":"^5.0.6","@typescript/native":"npm:typescript@7.0.2","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^7.0.0"},"peerDependencies":{"react":">=17.0.0","qrcode":">=1.5.0","express":">=4.18.0 <6","@bsv/sdk":"^2.4.1","@types/express":">=4.17.0 <6"},"peerDependenciesMeta":{"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false},"@types/express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.4.0_1789065767266_0.10150750069238534","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@bsv/wallet-relay","version":"0.5.0","keywords":["bsv","wallet","relay","mobile","pairing"],"author":{"name":"BSV Association"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bsv/wallet-relay@0.5.0","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"bin":{"wallet-relay":"bin/init.mjs"},"dist":{"shasum":"8c2396a45a99b1de6b047484704a94522584be63","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.5.0.tgz","fileCount":116,"integrity":"sha512-l8oXt/XO/ZGypwDL+KMYE5d7GAuNqupqhCfu7ZF60OY6FpTjBgdBR9Wspvw1dF20XGPo4pq4GvntfxOBhlkQ6A==","signatures":[{"sig":"MEUCIErRaE1mvNipFSMkR1sg1aGi+RN2XfMzErRdzS627CF+AiEAq0/FU5ys9hFuOX6DAz2UYbIEa/Z4t/OkrbMeBJgyiBY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":807166},"main":"./dist/index.cjs","type":"module","_from":"file:/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.5.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=22"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./client":{"import":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"require":{"types":"./dist/client.d.cts","default":"./dist/client.cjs"}},"./package.json":"./package.json"},"scripts":{"dev":"node build.mjs --watch","lint":"oxlint build.mjs bin src tests --deny-warnings","test":"jest --config jest.config.cjs --watchman=false","build":"node build.mjs && tsc -p tsconfig.build.json --emitDeclarationOnly && node scripts/copy-cjs-types.mjs","typecheck":"tsc --noEmit","pack:check":"pnpm build && node ../../../scripts/check-package-artifact.mjs . --allow-source-prefixes template --consumer-dependencies react --exports QRSessionManager,WalletRelayService,WalletRequestHandler,WebSocketRelay,compileOriginMatcher --entry-exports \"./client=WalletPairingSession|WalletRelayClient|WalletRelayError;./react=QRDisplay|QRPairingCode|RequestLog|WalletConnectionModal|useQRPairing|useWalletRelayClient\" --bin wallet-relay --bin-args --help && node ../../../scripts/check-auth-express-consumers.mjs @bsv/wallet-relay","format:check":"pnpm --workspace-root exec prettier --check \"packages/wallet/ts-wallet-relay/**/*.{cjs,js,json,md,mjs,ts,tsx}\"","test:browser":"pnpm build && node ../../../scripts/check-browser-package.mjs .","test:coverage":"jest --config jest.config.cjs --coverage --watchman=false","test:property":"jest --config jest.config.cjs --selectProjects node --runInBand --watchman=false --runTestsByPath tests/pairingUri.property.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"_resolved":"/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.5.0.tgz","_integrity":"sha512-l8oXt/XO/ZGypwDL+KMYE5d7GAuNqupqhCfu7ZF60OY6FpTjBgdBR9Wspvw1dF20XGPo4pq4GvntfxOBhlkQ6A==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.16.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ws":"^8.21.1"},"publishConfig":{"access":"public"},"typesVersions":{"*":{"*":["dist/index.d.ts"],"react":["dist/react.d.ts"],"client":["dist/client.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","react":"^19.2.8","oxlint":"^1.76.0","qrcode":"^1.5.4","esbuild":"^0.28.1","express":"^5.2.1","ts-jest":"^29.4.12","@bsv/sdk":"^2.7.0","@types/ws":"^8.18.1","react-dom":"^19.2.8","fast-check":"^4.9.0","typescript":"npm:@typescript/typescript6@6.0.2","@types/jest":"^30.0.0","@types/node":"^26.1.2","@types/react":"^19.2.17","@types/qrcode":"^1.5.6","@types/express":"^5.0.6","@typescript/native":"npm:typescript@7.0.2","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^7.0.0"},"peerDependencies":{"react":">=17.0.0","qrcode":">=1.5.0","express":">=4.18.0 <6","@bsv/sdk":"^2.4.1","@types/express":">=4.17.0 <6"},"peerDependenciesMeta":{"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false},"@types/express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/wallet-relay_0.5.0_1789508187094_0.6098361950969651","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"_id":"@bsv/wallet-relay@0.5.1","bin":{"wallet-relay":"bin/init.mjs"},"bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"dist":{"shasum":"0c1f6ea1c3431ad1b766282dc13c907fc7236e9a","tarball":"https://registry.npmjs.org/@bsv/wallet-relay/-/wallet-relay-0.5.1.tgz","fileCount":128,"integrity":"sha512-nxeWMwh8w4E4CAtL+2szMTF0fkMeCNI7T62Nvc/h0ax6AfpnjqO4rp1paXHMXdXG77YDoRpNjmy77tshZKIglA==","signatures":[{"sig":"MEYCIQDbICpkTiDBrWrSbNnJMwkiG1mGHwdPpggMupBxrdbIrAIhAJw6YjDA1wR5hc3c78lstgDMxolnWnJ9JL/FNl1RXolo","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHNXiOQsnCe0LtcMO5XAqOnzeR0FSs+px4Lp5qYkumzgAiBTkxC/CIG7DDvmbsMhtQsQvs9tQF5ZuUSjQiQrG1R7Ow=="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bsv%2fwallet-relay@0.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1104748},"main":"./dist/index.cjs","name":"@bsv/wallet-relay","type":"module","_from":"file:/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.5.1.tgz","types":"./dist/index.d.ts","author":{"name":"BSV Association"},"module":"./dist/index.js","engines":{"node":">=22"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./client":{"import":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"require":{"types":"./dist/client.d.cts","default":"./dist/client.cjs"}},"./package.json":"./package.json"},"license":"SEE LICENSE IN LICENSE.txt","scripts":{"dev":"node build.mjs --watch","lint":"oxlint build.mjs bin src tests --deny-warnings","test":"jest --config jest.config.cjs --watchman=false","build":"node build.mjs && tsc -p tsconfig.build.json --emitDeclarationOnly && node scripts/copy-cjs-types.mjs","typecheck":"tsc --noEmit","pack:check":"pnpm build && node ../../../scripts/check-package-artifact.mjs . --allow-source-prefixes template --consumer-dependencies react --exports QRSessionManager,WalletRelayService,WalletRequestHandler,WebSocketRelay,compileOriginMatcher --entry-exports \"./client=WalletPairingSession|WalletRelayClient|WalletRelayError;./react=QRDisplay|QRPairingCode|RequestLog|WalletConnectionModal|useQRPairing|useWalletRelayClient\" --bin wallet-relay --bin-args --help && node ../../../scripts/check-auth-express-consumers.mjs @bsv/wallet-relay","format:check":"pnpm --workspace-root exec prettier --check \"packages/wallet/ts-wallet-relay/**/*.{cjs,js,json,md,mjs,ts,tsx}\"","test:browser":"pnpm build && node ../../../scripts/check-browser-package.mjs .","test:coverage":"jest --config jest.config.cjs --coverage --watchman=false && node --test --experimental-test-coverage --test-coverage-include=bin/init.mjs --test-coverage-include=build.mjs --test-reporter=lcov --test-reporter-destination=coverage/scripts.lcov.info tests/scripts.node.test.mjs && node scripts/merge-coverage.mjs","test:property":"jest --config jest.config.cjs --selectProjects node --runInBand --watchman=false --runTestsByPath tests/pairingUri.property.test.ts"},"version":"0.5.1","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a7500074-419b-44bf-af8b-1c8e7c4b0b0e"}},"homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","keywords":["bsv","wallet","relay","mobile","pairing"],"_resolved":"/home/runner/work/ts-stack/ts-stack/release-artifacts/packages/bsv-wallet-relay-0.5.1.tgz","_integrity":"sha512-nxeWMwh8w4E4CAtL+2szMTF0fkMeCNI7T62Nvc/h0ax6AfpnjqO4rp1paXHMXdXG77YDoRpNjmy77tshZKIglA==","repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"_npmVersion":"11.16.0","description":"BSV mobile wallet relay — relay server and pairing client","directories":{},"maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ws":"^8.21.1","@noble/curves":"2.2.0","@noble/hashes":"2.2.0"},"publishConfig":{"access":"public"},"typesVersions":{"*":{"*":["dist/index.d.ts"],"react":["dist/react.d.ts"],"client":["dist/client.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","react":"^19.2.8","oxlint":"^1.76.0","qrcode":"^1.5.4","esbuild":"^0.28.1","express":"^5.2.1","ts-jest":"^29.4.12","@bsv/sdk":"^2.8.0","@types/ws":"^8.18.1","react-dom":"^19.2.8","babel-jest":"30.4.1","fast-check":"^4.9.0","typescript":"npm:@typescript/typescript6@6.0.2","@types/jest":"^30.0.0","@types/node":"^26.1.2","@types/react":"^19.2.17","@types/qrcode":"^1.5.6","@types/express":"^5.0.6","@typescript/native":"npm:typescript@7.0.2","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.4.1","@testing-library/jest-dom":"^7.0.0","@babel/plugin-transform-modules-commonjs":"7.29.7"},"peerDependencies":{"react":">=17.0.0","qrcode":">=1.5.0","express":">=4.18.0 <6","@bsv/sdk":"^2.4.1","@types/express":">=4.17.0 <6"},"peerDependenciesMeta":{"react":{"optional":true},"qrcode":{"optional":true},"express":{"optional":true},"@bsv/sdk":{"optional":false},"@types/express":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/wallet-relay_0.5.1_1790140551856_0.32101236492662477"}}},"time":{"created":"2026-04-17T17:56:29.365Z","modified":"2026-09-23T05:15:52.344Z","0.1.0":"2026-04-17T17:56:29.619Z","0.1.1":"2026-05-14T16:31:16.595Z","0.2.0":"2026-06-19T23:15:29.615Z","0.2.1":"2026-07-16T23:34:13.305Z","0.2.2":"2026-07-25T03:05:09.458Z","0.3.3":"2026-07-31T00:19:14.456Z","0.3.4":"2026-08-01T00:06:36.825Z","0.3.5":"2026-08-15T04:14:57.199Z","0.3.6":"2026-08-27T21:30:33.855Z","0.4.0":"2026-09-10T18:42:47.434Z","0.5.0":"2026-09-15T21:36:27.244Z","0.5.1":"2026-09-23T05:15:51.946Z"},"bugs":{"url":"https://github.com/bsv-blockchain/ts-stack/issues"},"author":{"name":"BSV Association"},"license":"SEE LICENSE IN LICENSE.txt","homepage":"https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay#readme","keywords":["bsv","wallet","relay","mobile","pairing"],"repository":{"url":"git+https://github.com/bsv-blockchain/ts-stack.git","type":"git","directory":"packages/wallet/ts-wallet-relay"},"description":"BSV mobile wallet relay — relay server and pairing client","maintainers":[{"name":"johngalt5","email":"dylan@murraydt.com"},{"name":"loftsteinn","email":"oli@oskarsson.nl"},{"name":"dkellen","email":"darrkellen@gmail.com"},{"name":"braydude","email":"brayden167@gmail.com"},{"name":"tyeverett","email":"p2ppsr@tyweb.us"}],"readme":"# @bsv/wallet-relay\n\nBSV mobile wallet QR pairing — relay server, session management, and desktop frontend utilities.\n\nLets any web app offer \"connect via mobile wallet\" as a signing or authentication option. The desktop shows a QR code; the user scans it with their BSV wallet app; from that point all wallet operations are handled by the mobile over an encrypted WebSocket relay. Wallet keys never leave the mobile device. The relay never sees plaintext.\n\n> **Early release — use at your own discretion.** This library is functional and used in production internally, but the API may change without notice. No stability guarantees are made until a v1.0 release is tagged.\n\n---\n\n## Who needs what\n\n| You are                                                       | What you need                                                                                                                                   |\n| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |\n| **Web app developer** adding mobile wallet support to a site  | Backend: one `WalletRelayService` call. Frontend: `useWalletRelayClient` + `WalletConnectionModal` + `QRDisplay` from `@bsv/wallet-relay/react` |\n| **Mobile wallet developer** adding QR pairing to a wallet app | `WalletPairingSession` from `@bsv/wallet-relay/client`                                                                                          |\n\n**Most integrators are in the first group.** If you're building a website that lets users connect their mobile BSV wallet, you do not touch the mobile side at all. The `WalletPairingSession` API exists for wallet app developers (like BSV Browser) who are implementing the mobile end of the protocol.\n\n---\n\n## Quickstart — web app\n\n### 1. Install\n\n```bash\nnpm install @bsv/wallet-relay @bsv/sdk\nnpm install express cors ws qrcode   # backend peer deps — not needed for frontend-only projects\n```\n\nThe optional Express runtime and its declarations are supplied by the backend\napplication, so relay routes share one Express 4 or 5 type graph with the host.\n\n`@bsv/sdk` is used throughout — backend wallet crypto, frontend local wallet detection, and mobile pairing. Install it in every layer of your project.\n\nWallet RPC byte fields are normalized and validated in both directions. The\nrelay preserves historical `number[]`, current `Uint8Array`, and numeric-key\nJSON wallet representations for direct and deferred-signing actions without\nchanging non-byte RPC fields.\n\n> **TypeScript:** your `tsconfig.json` needs `\"moduleResolution\": \"bundler\"` (or `\"node16\"` / `\"nodenext\"`) to resolve the `@bsv/wallet-relay/react` and `@bsv/wallet-relay/client` subpath exports.\n\n### 2. Generate a stable backend key\n\nThe backend needs a fixed private key. The mobile derives its ECDH shared secret from the backend's identity key, which is embedded in the QR code — so **the same key must be used across server restarts**. Generate it once and store it in `.env`:\n\n```bash\nnode --input-type=commonjs -e \"const {PrivateKey}=require('@bsv/sdk'); console.log(PrivateKey.fromRandom().toHex())\"\n```\n\n`.env`:\n\n```\nWALLET_PRIVATE_KEY=<hex output from above — keep secret, never commit>\nRELAY_URL=ws://localhost:3000\nORIGIN=http://localhost:5173\n```\n\n- `RELAY_URL` — WebSocket address the mobile connects to. In production use a publicly reachable URL (e.g. `wss://yourapp.com`).\n- `ORIGIN` — Default URL embedded in the QR when no per-session origin is supplied. Used as the fallback by `createSession()` when its `Origin` header is missing.\n\n> **Production note:** in a typical deployment, both `RELAY_URL` and `ORIGIN` share the same domain (`wss://yourapp.com` + `https://yourapp.com`). No extra configuration is needed. The relay can freely be on a separate domain or a third-party service — the mobile fetches the relay address from the origin server over HTTPS, making the origin's TLS certificate the trust anchor rather than hostname matching.\n\n> **Desktop API transport:** an absolute `WalletRelayClient.apiUrl` must use\n> HTTPS in production because its requests carry the desktop session token and\n> wallet RPC payloads. Root-relative same-origin paths and HTTP loopback hosts\n> remain available; credential-bearing URLs, query strings, and fragments are\n> rejected. Relay discovery does not follow redirects, has a 10-second deadline,\n> and rejects responses larger than 256 KiB or containing invalid UTF-8.\n\n> **Multi-app deployments:** one relay can serve N webapps. Pass an `allowedOrigins` allowlist (`string[]`, `RegExp`, or predicate) to `WalletRelayService` and the built-in `GET /api/session` route forwards each browser's `Origin` header into `createSession({ origin })` — every QR points back at the calling webapp instead of the relay's own URL. See [API.md](./API.md#walletrelayservice) for the full option.\n\n> **Public-service default:** when neither `allowedOrigins` nor a constructor `origin` is supplied, the relay accepts browser origins from previously unknown domains. `ORIGIN` remains the fallback URL placed in a QR; setting it as an environment variable does not silently create a WebSocket allowlist. The scaffold mirrors this with public reflected CORS by default and an optional comma-separated `ALLOWED_ORIGINS` whitelist. Origin checks and CORS are deployment controls, not authentication: desktop tokens, topic validation, QR signatures, and encrypted pairing remain enforced in either mode.\n\n> **Local dev with split frontend/backend:** a physical mobile device must use an HTTPS origin with a valid certificate (for example, a trusted development tunnel) to reach `GET /api/session/:id`. Plain HTTP pairing origins are accepted only on `localhost`, `127.0.0.1`, or `[::1]`; an `http://<lan-ip>` QR is rejected. `ORIGIN` stays as the Vite URL for browser CORS. This variable is not needed in production.\n\n### 3. App setup\n\n<details open>\n<summary><strong>Scaffold (recommended)</strong></summary>\n\n```bash\nnpx @bsv/wallet-relay init\n```\n\nGenerates a working Express backend and React+Vite frontend wired together. Existing files are never overwritten.\n\n```\nbackend/\n  server.ts          — Express + WalletRelayService, reads env vars\n  .env.example       — copy to .env and fill in WALLET_PRIVATE_KEY\nfrontend/\n  hooks/\n    useWalletSession.ts    — re-exports useWalletRelayClient from @bsv/wallet-relay/react\n  components/\n    WalletConnectionModal.tsx  — styled wrapper around @bsv/wallet-relay/react WalletConnectionModal\n    QRDisplay.tsx              — styled wrapper around @bsv/wallet-relay/react QRDisplay\n    WalletActions.tsx          — buttons for each wallet method (app-specific, customise here)\n    RequestLog.tsx             — styled wrapper around @bsv/wallet-relay/react RequestLog\n  views/\n    DesktopView.tsx    — composes all of the above\n  types/\n    wallet.ts          — WalletMethod (app-specific); re-exports shared types from @bsv/wallet-relay/client\n```\n\nOptions: `--nextjs` for a Next.js project, `--backend` / `--frontend` for one side only, `--backend-dir` / `--frontend-dir` to control output directories.\n\nThe scaffolded files contain explicit `CUSTOMIZE` markers for application-owned\nwallet methods, UI copy, and the `installUrl` in `WalletConnectionModal`\n(defaulting to `https://desktop.bsvb.tech`, the BSV wallet with desktop and\nmobile support). These are consumer integration points, not unfinished relay\nlibrary behavior.\n\n**After scaffolding:**\n\n```bash\ncp backend/.env.example backend/.env\n# Fill in WALLET_PRIVATE_KEY in backend/.env, then:\nnpm run dev --prefix backend\nnpm run dev --prefix frontend\n```\n\n</details>\n\n<details>\n<summary><strong>Manual setup</strong></summary>\n\n#### Backend\n\n```ts\nimport express from 'express'\nimport { createServer } from 'http'\nimport cors from 'cors'\nimport { ProtoWallet, PrivateKey } from '@bsv/sdk'\nimport { WalletRelayService } from '@bsv/wallet-relay'\n\nconst allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',').map(value => value.trim())\n\nconst app = express()\napp.use(\n  cors({\n    // Public by default; set ALLOWED_ORIGINS to opt into an exact whitelist.\n    origin: allowedOrigins?.length ? allowedOrigins : true,\n    allowedHeaders: ['Content-Type', 'Authorization', 'X-Desktop-Token']\n  })\n)\napp.use(express.json())\n\nconst server = createServer(app)\nconst wallet = new ProtoWallet(PrivateKey.fromHex(process.env.WALLET_PRIVATE_KEY!))\n\nnew WalletRelayService({\n  app,\n  server,\n  wallet,\n  allowedOrigins: allowedOrigins?.length ? allowedOrigins : undefined\n})\n\nserver.listen(3000)\n```\n\nThat's the entire backend. `WalletRelayService` registers four REST routes and the `/ws` WebSocket endpoint automatically:\n\n| Method   | Path               | Description                                                                         |\n| -------- | ------------------ | ----------------------------------------------------------------------------------- |\n| `GET`    | `/api/session`     | Create session, return `{ sessionId, status, qrDataUrl, pairingUri, desktopToken }` |\n| `GET`    | `/api/session/:id` | Poll session status                                                                 |\n| `POST`   | `/api/request/:id` | Send a wallet RPC call to the paired mobile                                         |\n| `DELETE` | `/api/session/:id` | Terminate session — closes the mobile's WebSocket so the mobile app is notified     |\n\n`relayUrl` and `origin` are optional — they default to `process.env.RELAY_URL` / `process.env.ORIGIN`, then `ws://localhost:3000` / `http://localhost:5173`. For multi-app deployments, optionally pass `allowedOrigins` (a `string[]`, `RegExp`, or predicate). With neither `allowedOrigins` nor an explicit constructor `origin`, origin validation is public-by-default. Supplying an explicit constructor `origin` retains the legacy exact-origin restriction:\n\n```ts\nnew WalletRelayService({\n  app,\n  server,\n  wallet,\n  allowedOrigins: ['https://app-a.example.com', 'https://app-b.example.com']\n  // or: /\\.example\\.com$/\n  // or: (origin) => origin.endsWith('.example.com')\n})\n```\n\nThe built-in `GET /api/session` route forwards the request's `Origin` header into `createSession({ origin })`, so the QR points back at the calling webapp rather than the relay's own URL. Origins not in `allowedOrigins` get a `403`.\n\nSession creation and status responses are emitted with `Cache-Control: no-store` because the creation response contains a wallet-equivalent bearer token. Preserve that policy at reverse proxies and CDNs. The scaffold also caps JSON request bodies at 64 KiB; apply an equivalent bound when supplying your own parser or framework routes.\n\nThe service limits new sessions to 120 per minute and 1,000 live sessions by default. Tune `maxSessionCreationsPerMinute` / `maxSessions` for measured demand and add a source-aware rate limit at the public edge; the in-process global limit is a final resource boundary, not a substitute for distributed abuse controls.\n\n> **`desktopToken`** is returned by `GET /api/session` and must be sent as an `X-Desktop-Token` header on every `POST /api/request/:id` call. It grants the ability to ask the connected wallet to perform operations, so treat it as a wallet-equivalent bearer secret: do not log it, place it in URLs, copy it into the QR, or share it with the mobile. `WalletRelayClient` stores it in `sessionStorage` by default solely to support same-tab refresh; use `persistSession: false` for higher-assurance pages and clear it with `disconnect()`. `useWalletRelayClient` / `WalletRelayClient` handle the header automatically. If you call `relay.sendRequest()` directly from your own route handlers, forward the header yourself — see [Next.js setup](#nextjs-setup) below.\n\nFor a direct desktop-role browser WebSocket, authenticate without putting the token in the routinely logged URL: `new WebSocket(url, ['bsv-wallet-relay', 'bsv-wallet-relay-token.' + desktopToken])`. The server selects and echoes only `bsv-wallet-relay`. The legacy `?token=` form remains accepted for wire compatibility but should not be used by new clients.\n\n`WalletRelayClient` retains at most 100 request-log entries by default; set `maxLogEntries: 0` to disable retention or choose a bounded value up to 10,000. Wallet results may contain certificates, decrypted plaintext, linkage proofs, and other sensitive values, so render or export the debug log only in an appropriately trusted UI.\n\n> **CORS and CSP:** if your frontend and backend run on different origins, include `X-Desktop-Token` in CORS `allowedHeaders`; otherwise the browser's preflight blocks `POST /api/request/:id`. Public CORS should reflect the requesting origin without enabling cookie credentials. To opt into a whitelist, apply the same exact origins to CORS and `allowedOrigins`. CSP is owned by the embedding app, not injected by the relay; its `connect-src` must include the configured HTTP(S) origin and WS(S) relay. Do not use CORS or CSP as a substitute for relay authentication.\n\n#### Sharing the server with other WebSocket services\n\nThe relay mounts at `/ws` and is **non-greedy**: it claims only its own path and ignores every other upgrade request, so a messaging service — or any other WebSocket endpoint — can share the same HTTP server without being rejected.\n\nChange the path with `path`, or take over upgrade routing entirely with `noServer`:\n\n```ts\nimport { WebSocketServer } from 'ws'\n\n// Mount the relay at a different path\nnew WalletRelayService({ app, server, wallet, path: '/wallet-ws' })\n\n// Or run your own upgrade dispatcher across several WS services\nconst relay = new WalletRelayService({ app, server, wallet, noServer: true })\nconst msgWss = new WebSocketServer({ noServer: true })\n\nserver.on('upgrade', (req, socket, head) => {\n  const { pathname } = new URL(req.url ?? '', 'http://localhost')\n  if (pathname === '/ws') relay.handleUpgrade(req, socket, head)\n  else if (pathname === '/messaging')\n    msgWss.handleUpgrade(req, socket, head, ws => msgWss.emit('connection', ws, req))\n  else socket.destroy()\n})\n```\n\nIn `noServer` mode the relay attaches no `upgrade` listener of its own — you dispatch to `relay.handleUpgrade()`. In default mode, unmatched upgrade paths are left untouched for other listeners; if nothing ever claims a path, that socket stays open until the client times out (add an `else socket.destroy()` in your own dispatcher to reject it eagerly).\n\n#### Frontend\n\n`@bsv/wallet-relay/react` exports everything needed for wallet detection and QR pairing:\n\n```tsx\nimport { useState, useCallback } from 'react'\nimport type { WalletClient } from '@bsv/sdk'\nimport { useWalletRelayClient, WalletConnectionModal, QRDisplay } from '@bsv/wallet-relay/react'\n\nexport function App() {\n  const [mode, setMode] = useState<'detecting' | 'local' | 'mobile'>('detecting')\n\n  // autoCreate: false — only start a backend session when the user picks the mobile path\n  const { session, error, createSession, cancelSession, sendRequest } = useWalletRelayClient({\n    autoCreate: false\n  })\n\n  const handleLocalWallet = useCallback((wallet: WalletClient) => {\n    setMode('local')\n    // CUSTOMIZE: store the wallet in your application state.\n  }, [])\n\n  // Stop polling when the user navigates away from the QR screen\n  useEffect(() => {\n    if (mode !== 'mobile') return\n    return () => {\n      cancelSession()\n    }\n  }, [mode])\n\n  return (\n    <>\n      {mode === 'detecting' && (\n        <WalletConnectionModal\n          onLocalWallet={handleLocalWallet}\n          onMobileQR={() => {\n            setMode('mobile')\n            void createSession()\n          }}\n        />\n      )}\n\n      {mode === 'mobile' && (\n        <>\n          {error && <p>{error}</p>}\n          <QRDisplay session={session} onRefresh={createSession} />\n        </>\n      )}\n\n      {mode === 'local' && <>{/* CUSTOMIZE: render the local-wallet application. */}</>}\n    </>\n  )\n}\n```\n\n`WalletConnectionModal` silently checks for a local BSV wallet first:\n\n- **Local wallet found** → calls `onLocalWallet` immediately, renders nothing\n- **Not found** → renders an install link and a \"Connect via Mobile QR\" button\n\n`QRDisplay` shows the QR image, a status badge (`pending` / `connected` / `disconnected` / `expired`), and a refresh button when the session expires. Both components are unstyled — pass `className`, `style`, and per-element props to style them. See [API.md](./API.md) for the full prop reference.\n\n</details>\n\n### Next.js setup\n\nThe relay WebSocket is decoupled from your origin server — the mobile fetches the relay URL from your origin over HTTPS after scanning the QR. This means the WebSocket relay can run anywhere: a separate persistent service, or a third-party provider (Ably, Pusher, Soketi).\n\n| Deployment                    | Supported | Notes                                                                                                      |\n| ----------------------------- | --------- | ---------------------------------------------------------------------------------------------------------- |\n| Self-hosted / VPS / container | ✓         | Run `WalletRelayService` with built-in WebSocket relay                                                     |\n| Vercel / Netlify / serverless | ✓         | REST routes in serverless functions; point `RELAY_URL` at a separate relay service or third-party provider |\n\n**Relay service** — deploy a minimal Express + `WalletRelayService` on Railway, Render, or Fly.io. This handles the WebSocket connections and session state. Set `RELAY_URL` in your Next.js environment to its `wss://` address.\n\n**Next.js API routes** call `relay` methods directly — no custom server required. You must forward `X-Desktop-Token` on the request route.\n\n```ts\n// app/api/session/route.ts\nimport { relay } from '@/lib/relay' // your WalletRelayService singleton\n\nexport async function GET() {\n  const info = await relay.createSession()\n  return Response.json(info)\n}\n```\n\n```ts\n// app/api/session/[id]/route.ts\nimport { relay } from '@/lib/relay'\n\nexport async function GET(_req: Request, { params }: { params: { id: string } }) {\n  const info = relay.getSession(params.id)\n  if (!info) return Response.json({ error: 'Session not found' }, { status: 404 })\n  return Response.json(info)\n}\n\nexport async function DELETE(req: Request, { params }: { params: { id: string } }) {\n  const token = req.headers.get('x-desktop-token') ?? undefined\n  if (!token) return Response.json({ error: 'Missing desktop token' }, { status: 401 })\n  try {\n    relay.deleteSession(params.id, token)\n    return new Response(null, { status: 204 })\n  } catch (err) {\n    const msg = err instanceof Error ? err.message : 'Failed'\n    const status = msg === 'Invalid desktop token' ? 401 : msg === 'Session not found' ? 404 : 500\n    return Response.json({ error: msg }, { status })\n  }\n}\n```\n\n```ts\n// app/api/request/[id]/route.ts\nimport { relay } from '@/lib/relay'\n\nexport async function POST(req: Request, { params }: { params: { id: string } }) {\n  const { method, params: rpcParams } = (await req.json()) as { method: string; params: unknown }\n  const token = req.headers.get('x-desktop-token') ?? undefined\n  try {\n    const result = await relay.sendRequest(params.id, method, rpcParams, token)\n    return Response.json(result)\n  } catch (err) {\n    const msg = err instanceof Error ? err.message : 'Request failed'\n    const status = msg === 'Invalid desktop token' ? 401 : msg.startsWith('Session is') ? 400 : 504\n    return Response.json({ error: msg }, { status })\n  }\n}\n```\n\nThe frontend is identical to the Vite/Express setup — `useWalletRelayClient` works the same regardless of backend framework.\n\n### 4. Use the wallet proxy — no call site changes needed\n\n`useWalletRelayClient` returns a `wallet` object alongside `session`. Once `session?.status === 'connected'`, `wallet` is a fully `WalletInterface`-compatible proxy that forwards every call to the paired mobile over the relay. When the session is not connected, `wallet` is `null`.\n\n**This means you do not need separate code paths for mobile vs local wallet.** The proxy has the same method signatures as `WalletClient` — swap the `wallet` reference in your existing wallet context and every call site in your app continues to work unchanged:\n\n```tsx\n// Before (local WalletClient):\nconst { publicKey } = await wallet.getPublicKey({ identityKey: true })\nconst { certificates } = await wallet.listCertificates({ certifiers: [...], types: [...] })\nconst { txid } = await wallet.createAction({ description: 'Pay invoice', outputs: [...] })\n\n// After (mobile relay proxy — identical call sites, zero changes):\nconst { publicKey } = await wallet.getPublicKey({ identityKey: true })\nconst { certificates } = await wallet.listCertificates({ certifiers: [...], types: [...] })\nconst { txid } = await wallet.createAction({ description: 'Pay invoice', outputs: [...] })\n```\n\nHow it works: each method on the proxy captures its name at construction time, calls `sendRequest(method, params)` internally, unwraps `res.result`, and throws on `res.error` — so callers see a normal return value or a thrown `Error`, exactly as they would from a local `WalletClient`.\n\n```tsx\n// Typical integration — inject into your existing wallet context on connect:\nconst { session, wallet } = useWalletRelayClient({ autoCreate: false })\n\nuseEffect(() => {\n  if (session?.status === 'connected' && wallet) {\n    setWalletContext(wallet) // drop-in — all existing wallet calls now route to mobile\n  }\n}, [session?.status, wallet])\n```\n\nIf you want refreshes to keep the user paired without auto-creating a session for users who never clicked \"Sign in with phone\", add `autoResume: true`:\n\n```tsx\nconst { session, wallet, createSession } = useWalletRelayClient({\n  autoCreate: false,\n  autoResume: true // resume on mount only — never auto-create\n})\n```\n\nThe proxy is created once and cached for the lifetime of the session. Available methods: `getPublicKey`, `listOutputs`, `createAction`, `signAction`, `createSignature`, `listActions`, `internalizeAction`, `acquireCertificate`, `relinquishCertificate`, `listCertificates`, `revealCounterpartyKeyLinkage`.\n\n> **Lower-level option:** `sendRequest(method, params)` is still available if you need the raw `{ result, error, requestId, timestamp }` response envelope — useful for request logging or custom error handling.\n\n---\n\n## For mobile wallet developers\n\nIf you are building a BSV wallet app and want to support QR pairing with desktop web apps, use `WalletPairingSession` from `@bsv/wallet-relay/client`:\n\n```ts\nimport { WalletClient } from '@bsv/sdk'\nimport {\n  WalletPairingSession,\n  parsePairingUri,\n  verifyPairingSignature\n} from '@bsv/wallet-relay/client'\n\nconst result = parsePairingUri(scannedUri)\nif (result.error) {\n  showError(result.error)\n  return\n}\n\n// Verify the QR signature before trusting any of the fields\nif (!(await verifyPairingSignature(result.params))) {\n  showError('QR code signature is invalid — do not connect')\n  return\n}\n\n// Show result.params.origin to the user — this is the domain they are about to connect to\nawait showApprovalUI(result.params.origin)\n\nconst wallet = new WalletClient('auto')\nconst session = new WalletPairingSession(wallet, result.params, {\n  // Defaults to the full BSV Browser method set — override only if needed:\n  // implementedMethods: new Set(['getPublicKey', 'createAction']),\n  // autoApproveMethods: new Set(['getPublicKey']),\n  onApprovalRequired: async (method, params) => await showApprovalModal(method, params),\n  walletMeta: { name: 'My Wallet', version: '1.0' }\n})\n\nsession\n  // WalletClient implements WalletInterface but isn't string-indexed — cast required\n  .onRequest(async (method, params) =>\n    (wallet as Record<string, (p: unknown) => Promise<unknown>>)[method](params)\n  )\n  .on('connected', () => setStatus('connected'))\n  .on('disconnected', () => setStatus('disconnected'))\n  .on('error', msg => setError(msg))\n\n// Fetch the relay URL from the origin server over HTTPS — must be called before connect()\nawait session.resolveRelay()\nawait session.connect()\n```\n\nThe relay URL is no longer embedded in the QR code. Instead `resolveRelay()` verifies the required QR signature, then calls `GET {origin}/api/session/{topic}` over HTTPS and reads the `relay` field from the response. The origin's TLS certificate is the trust anchor — the relay itself can be hosted anywhere. Plain HTTP origins, cleartext non-loopback WebSockets, redirects, unsigned QR codes, malformed session responses, and unbounded responses are rejected; loopback HTTP/WS remains available for same-device development.\n\nThe short-lived QR is also a bearer pairing invitation. Its signature authenticates the backend to the phone; it does not identify which phone is expected. Anyone who can copy or scan an unexpired QR can pair their own wallet first, after which the relay pins that mobile identity key. Scanning normally requires physical proximity to the displayed code, but a copied image, screen share, support transcript, log, or exposed raw pairing URI removes that proximity barrier. Keep those values confidential and require explicit per-operation approval on the phone. The current security model intentionally relies on possession of the short-lived invitation plus the phone's later approvals; deployments that need a pre-identified phone must add that assurance at the application level.\n\nThe QR signature covers `topic`, backend identity key, origin, and expiry, but\nnot the `protocolID` field or deep-link scheme. Those unsigned values are\nrouting inputs, not authenticated authority. With the built-in service,\ntampering with either causes key-derivation or application-routing failure\nrather than granting wallet authority, but it can prevent pairing. Applications\nmust not make authorization decisions from either unsigned value.\n\nMethods outside `autoApproveMethods` fail closed when `onApprovalRequired` is\nomitted. Configure an approval UI for signing, spending, decryption, HMAC, and\nother privileged operations; the default auto-approved set contains only\n`getPublicKey`.\n\nTo resume after a network drop, call `resolveRelay()` again before `reconnect()` (it is a lightweight HTTP call):\n\n```ts\nconst lastSeq = await SecureStore.getItemAsync(`lastseq_${topic}`)\nawait session.resolveRelay()\nawait session.reconnect(Number(lastSeq ?? 0))\n```\n\n`DEFAULT_IMPLEMENTED_METHODS` and `DEFAULT_AUTO_APPROVE_METHODS` are exported from `@bsv/wallet-relay/client` if you want to reference or extend the defaults.\n\n---\n\n## React components\n\n`@bsv/wallet-relay/react` exports six items:\n\n| Export                  | Description                                                                                                                                                               |\n| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `useWalletRelayClient`  | Session creation, status polling, `wallet` proxy (drop-in `WalletInterface`), `cancelSession` for cleanup on navigation, and `sendRequest` — the main hook for QR pairing |\n| `WalletConnectionModal` | Detects local wallet; shows install link + mobile QR button if none found                                                                                                 |\n| `QRDisplay`             | QR image with status badge and session refresh                                                                                                                            |\n| `QRPairingCode`         | Tappable QR that opens the `wallet://pair?…` deeplink directly                                                                                                            |\n| `RequestLog`            | Live request/response log (useful for debugging and demo UIs)                                                                                                             |\n| `useQRPairing`          | Cross-platform deeplink hook — use directly in React Native                                                                                                               |\n\nAll visual components are unstyled. Pass `className`, `style`, and per-element props to style them. See [API.md](./API.md) for full prop documentation.\n\n**React Native** — use `useQRPairing` directly instead of `QRPairingCode`:\n\n```tsx\nimport { Linking } from 'react-native'\nimport { useQRPairing } from '@bsv/wallet-relay/react'\n\nconst { open } = useQRPairing(pairingUri, { openUrl: Linking.openURL })\n\nreturn (\n  <TouchableOpacity onPress={open}>\n    <Image source={{ uri: qrDataUrl }} style={styles.qr} />\n  </TouchableOpacity>\n)\n```\n\n---\n\n## Advanced usage — building blocks\n\nAll internal classes are exported for custom composition: custom session stores, non-Express frameworks, alternative transports.\n\n```ts\nimport {\n  WebSocketRelay,\n  QRSessionManager,\n  WalletRequestHandler,\n  buildPairingUri,\n  encryptEnvelope,\n  decryptEnvelope\n} from '@bsv/wallet-relay'\n\nconst sessions = new QRSessionManager()\nconst relay = new WebSocketRelay(server)\nconst handler = new WalletRequestHandler()\n\nrelay.onValidateTopic(topic => sessions.getSession(topic) !== null)\nrelay.onIncoming((topic, envelope, role) => {\n  /* custom logic */\n})\nsessions.onSessionExpired(id => relay.removeTopic(id))\n```\n\n`WebSocketRelay` accepts the same `path` and `noServer` options as the facade (see [Sharing the server with other WebSocket services](#sharing-the-server-with-other-websocket-services)); in `noServer` mode, dispatch upgrades to `relay.handleUpgrade(req, socket, head)`.\n\nThe high-level facades (`WalletRelayService`, `WalletPairingSession`) follow semver strictly. The building blocks are stable but may have more targeted breaking changes between minor versions.\n\n---\n\n## Encryption model\n\nAll messages use BSV wallet-native ECDH via `@bsv/sdk`. No custom crypto.\n\n- Each side calls `wallet.encrypt({ protocolID, keyID: sessionId, counterparty })` where `counterparty` is the other party's identity public key\n- The relay routes ciphertext blobs — it never decrypts anything\n- The pairing bootstrap sends `mobileIdentityKey` unencrypted in the outer envelope once (on `pairing_approved`) so the backend can verify the inner payload. All subsequent messages use only the stored key.\n- RPC IDs, sequences, topics, and response shapes are checked exactly. Known BRC-100 wallet results are validated before either side trusts them; false verification, internalization, relinquishment, or authentication verdicts are rejected rather than returned as successful results.\n- Wire messages are limited to 64 KiB, the default in-memory session/topic cap is 1000, and a second mobile cannot replace the active mobile for a session.\n- Every fresh or reconnecting mobile socket must prove possession of its identity key within 15 seconds; merely knowing a session topic cannot reserve the mobile slot.\n\n`WalletLike` throughout is `Pick<WalletInterface, 'getPublicKey' | 'encrypt' | 'decrypt' | 'createSignature'>` — satisfied by both `ProtoWallet` and `WalletClient` from `@bsv/sdk`.\n\n---\n\n## Entry points\n\n| Import                     | Environment            | Contains                                                                                                    |\n| -------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- |\n| `@bsv/wallet-relay`        | Node.js only           | `WalletRelayService`, `WebSocketRelay`, `QRSessionManager`, `WalletRequestHandler`, shared utilities        |\n| `@bsv/wallet-relay/client` | Browser + React Native | `WalletRelayClient`, `WalletPairingSession`, `WalletMethodName`, shared utilities, no Node.js deps          |\n| `@bsv/wallet-relay/react`  | React ≥17              | `useWalletRelayClient`, `WalletConnectionModal`, `QRDisplay`, `QRPairingCode`, `RequestLog`, `useQRPairing` |\n\n---\n\n## Development and Distribution\n\nRun development from the `ts-stack` repository root with Node.js 24.11 or newer\nand pnpm 10:\n\n```bash\npnpm install\npnpm --filter @bsv/wallet-relay format:check\npnpm --filter @bsv/wallet-relay lint\npnpm --filter @bsv/wallet-relay typecheck\npnpm --filter @bsv/wallet-relay test:coverage\npnpm --filter @bsv/wallet-relay pack:check\npnpm --filter @bsv/wallet-relay test:browser\n```\n\nThe coverage gate ratchets all four Jest metrics. `pack:check` installs the\nexact tarball into ESM and CommonJS consumers, validates root/client/React\nentrypoints and conditional declarations, and executes the installed CLI help\npath without writing files. The browser check bundles only `./client` with Vite\nand esbuild, rejects server dependencies, validates source maps, and enforces\nraw, gzip, and Brotli budgets. Publishing and version changes are performed\nonly by the repository release workflow.\n\n---\n\n## API reference\n\nSee [API.md](./API.md) for full parameter and method documentation.\n\n## License\n\nOpen BSV License Version 6. See [LICENSE.txt](./LICENSE.txt).\n\n## Heartbeat tolerance and close diagnostics\n\nVersion 0.5 pings every 30 seconds and tolerates two consecutive missed pongs.\nAny inbound message resets the missed-pong counter. Set `maxMissedHeartbeats: 1`\non `WalletRelayService` or `WebSocketRelay` to retain the previous one-miss behavior.\n`heartbeatIntervalMs` accepts integers from 1 to 2147483647 milliseconds.\nNo relay envelope or wallet RPC encoding changes are required.\n\nUse `onSocketClosed` on the service (or `onSocketClose` on the relay) to record\nclose code, cause, connection duration, and missed pongs. The diagnostic callback\nruns before disconnect bookkeeping; thrown errors and rejected promises are\ncontained, and asynchronous logging is not awaited. Keep callbacks short and\nhandle exporter failures inside your logging integration.\n","readmeFilename":"README.md"}