{"_id":"@b1narydt/channel-express-middleware","_rev":"11-9dca88adba4128f402e5415e97415c94","name":"@b1narydt/channel-express-middleware","dist-tags":{"latest":"0.1.9"},"versions":{"0.1.0":{"name":"@b1narydt/channel-express-middleware","version":"0.1.0","license":"SEE LICENSE IN LICENSE.txt","_id":"@b1narydt/channel-express-middleware@0.1.0","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"}],"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"dist":{"shasum":"d42f564ad7d9359fc405d7336ff9bdf9725bd191","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.0.tgz","fileCount":277,"integrity":"sha512-LBV7LAk3K8K+RIwZ8etJ7lycYeEjEbP6g3CJEIRlmfmmnV1Ux0oputkcSwA5LJxTe5Efmvn2lzF9gGb0xew9wg==","signatures":[{"sig":"MEUCIEwwOOn2ULSpsZCkHNd7zfm8p8RM0NCmawkpnfxmrTW9AiEApiKUoZqeGE+i65Ugvn3sVKNWNa+vClMPEGtsdmChBfA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1943331},"main":"dist/cjs/mod.js","type":"module","types":"dist/types/mod.d.ts","module":"dist/esm/mod.js","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"}},"gitHead":"fe22c0aa1676f259c15ad8974139f16b0705ba7c","scripts":{"dev":"tsc -b -w","lint":"ts-standard --fix src/**/*.ts","test":"npm run build && jest","build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","prepublish":"npm run build","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'"},"_npmUser":{"name":"ilahoti","email":"ishaan@b1nary.tech"},"repository":{"url":"git+https://github.com/b1narydt/channel-express-middleware.git","type":"git"},"_npmVersion":"11.6.2","description":"BSV payment channel Express middleware for off-chain micropayments","directories":{},"_nodeVersion":"25.2.1","dependencies":{"express":"^5.1.0","@bsv/sdk":"^2.0.0","@bsv/message-box-client":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","knex":"^3.1.0","react":"^19.2.4","ts-jest":"^29.1.1","react-dom":"^19.2.4","typescript":"^5.2.2","@types/jest":"^29.5.5","ts-standard":"^12.0.2","@types/react":"^19.2.14","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","@types/react-dom":"^19.2.3","@types/better-sqlite3":"^7.6.13","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.2.0","tsconfig-to-dual-package":"^1.2.0","@bsv/auth-express-middleware":"^2.0.2"},"peerDependencies":{"knex":"^3.1.0","react":"^18.0.0 || ^19.0.0","better-sqlite3":"^12.0.0","@bsv/wallet-toolbox":">=0.1.0","@bsv/auth-express-middleware":"^2.x"},"peerDependenciesMeta":{"knex":{"optional":true},"react":{"optional":true},"better-sqlite3":{"optional":true},"@bsv/wallet-toolbox":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/channel-express-middleware_0.1.0_1772929190647_0.5341616517921808","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@b1narydt/channel-express-middleware","version":"0.1.1","license":"SEE LICENSE IN LICENSE.txt","_id":"@b1narydt/channel-express-middleware@0.1.1","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"}],"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"dist":{"shasum":"15d2b586165f9e7f10aa7ee7d4d5d0711546f5aa","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.1.tgz","fileCount":277,"integrity":"sha512-crUcXpaPbn/ELzQlJS+pBEY38ntdAapMDTXICKf0nd0HeX149RpBgwmbKDSs1DwsXEbs73FjH8IkkdOYAt8zVg==","signatures":[{"sig":"MEQCIDwE+mogJZdSzpstm5F9L1NYyNFkUZEG3WueVamo2BCBAiBR3WWVbsRNXSrmIeOO4+SxtAadJ8Jb4zJg9RJWML1r7w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1945975},"main":"dist/cjs/mod.js","type":"module","types":"dist/types/mod.d.ts","module":"dist/esm/mod.js","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"}},"gitHead":"fe22c0aa1676f259c15ad8974139f16b0705ba7c","scripts":{"dev":"tsc -b -w","lint":"ts-standard --fix src/**/*.ts","test":"npm run build && jest","build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","prepublish":"npm run build","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'"},"_npmUser":{"name":"ilahoti","email":"ishaan@b1nary.tech"},"repository":{"url":"git+https://github.com/b1narydt/channel-express-middleware.git","type":"git"},"_npmVersion":"11.6.2","description":"BSV payment channel Express middleware for off-chain micropayments","directories":{},"_nodeVersion":"25.2.1","dependencies":{"express":"^5.1.0","@bsv/sdk":"^2.0.0","@bsv/message-box-client":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","knex":"^3.1.0","react":"^19.2.4","ts-jest":"^29.1.1","react-dom":"^19.2.4","typescript":"^5.2.2","@types/jest":"^29.5.5","ts-standard":"^12.0.2","@types/react":"^19.2.14","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","@types/react-dom":"^19.2.3","@types/better-sqlite3":"^7.6.13","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.2.0","tsconfig-to-dual-package":"^1.2.0","@bsv/auth-express-middleware":"^2.0.2"},"peerDependencies":{"knex":"^3.1.0","react":"^18.0.0 || ^19.0.0","better-sqlite3":"^12.0.0","@bsv/wallet-toolbox":">=0.1.0","@bsv/auth-express-middleware":"^2.x"},"peerDependenciesMeta":{"knex":{"optional":true},"react":{"optional":true},"better-sqlite3":{"optional":true},"@bsv/wallet-toolbox":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/channel-express-middleware_0.1.1_1772939511289_0.4494534552554861","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@b1narydt/channel-express-middleware","version":"0.1.2","license":"SEE LICENSE IN LICENSE.txt","_id":"@b1narydt/channel-express-middleware@0.1.2","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"},{"name":"mburcham","email":"mitch@b1nary.tech"}],"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"dist":{"shasum":"a4236234b467494d2896cf2f317e579c11014b9e","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.2.tgz","fileCount":493,"integrity":"sha512-CFzJxMsD7oB1vdl0kAfaFuSLyAOe9fUMg79mE7sp6ZYv1CWV1QLORHS0uesxJmdqIPzftPm0bz2ByQElaw8nWQ==","signatures":[{"sig":"MEUCIQCpzVdvo2q6K85VCrH/M1xrv0s51XuPwtjlGNkWscrSRgIgcHgrk3Kx90s22fvN5Ef5RTIYxkuPkbvP7cnPy1Hvns8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4915707},"main":"dist/cjs/mod.js","type":"module","types":"dist/types/mod.d.ts","module":"dist/esm/mod.js","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"}},"gitHead":"8b7ba3f1a83f0a92df1fc15fad91c97ed4ea8b6c","scripts":{"dev":"tsc -b -w","lint":"ts-standard --fix src/**/*.ts","test":"npm run build && jest","build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","prepare":"npm run build","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'"},"_npmUser":{"name":"mburcham","email":"mitch@b1nary.tech"},"repository":{"url":"git+https://github.com/b1narydt/channel-express-middleware.git","type":"git"},"_npmVersion":"10.9.2","description":"BSV payment channel Express middleware for off-chain micropayments","directories":{},"_nodeVersion":"22.17.0","dependencies":{"express":"^5.1.0","@bsv/sdk":"^2.0.0","@bsv/message-box-client":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","knex":"^3.1.0","react":"^19.2.4","ts-jest":"^29.1.1","react-dom":"^19.2.4","typescript":"^5.2.2","@types/jest":"^29.5.5","ts-standard":"^12.0.2","@types/react":"^19.2.14","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","@types/react-dom":"^19.2.3","@types/better-sqlite3":"^7.6.13","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.2.0","tsconfig-to-dual-package":"^1.2.0","@bsv/auth-express-middleware":"^2.0.2"},"peerDependencies":{"knex":"^3.1.0","react":"^18.0.0 || ^19.0.0","better-sqlite3":"^12.0.0","@bsv/wallet-toolbox":">=0.1.0","@bsv/auth-express-middleware":"^2.x"},"peerDependenciesMeta":{"knex":{"optional":true},"react":{"optional":true},"better-sqlite3":{"optional":true},"@bsv/wallet-toolbox":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/channel-express-middleware_0.1.2_1773099192916_0.7892620186613928","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@b1narydt/channel-express-middleware","version":"0.1.3","license":"SEE LICENSE IN LICENSE.txt","_id":"@b1narydt/channel-express-middleware@0.1.3","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"},{"name":"mburcham","email":"mitch@b1nary.tech"}],"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"dist":{"shasum":"9cde9729f76ef3c8623be5f0a7eee6c8cb2c3359","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.3.tgz","fileCount":403,"integrity":"sha512-F3bZHogFyAtdJtVcKrmLqKhm36HZ+M7nvcTXR94AEzDdhHqx8WTzVHKVF64Kjw+swi8Xh5/SWpdsMI/0kSTVuQ==","signatures":[{"sig":"MEYCIQCp3zV7g5CokivbP3woxCpMKjlpBHfKcDLY4JshP6jpPgIhAIG9LaKqc3koKttf7M8qd3WwzvTEW1cz/Z8ZO4b8yl2P","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1787169},"main":"dist/cjs/mod.js","type":"module","types":"dist/types/mod.d.ts","module":"dist/esm/mod.js","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"}},"gitHead":"8b7ba3f1a83f0a92df1fc15fad91c97ed4ea8b6c","scripts":{"dev":"tsc -b -w","lint":"ts-standard --fix src/**/*.ts","test":"npm run build && jest","build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","prepare":"npm run build","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'"},"_npmUser":{"name":"mburcham","email":"mitch@b1nary.tech"},"repository":{"url":"git+https://github.com/b1narydt/channel-express-middleware.git","type":"git"},"_npmVersion":"10.9.2","description":"BSV payment channel Express middleware for off-chain micropayments","directories":{},"_nodeVersion":"22.17.0","dependencies":{"express":"^5.1.0","@bsv/sdk":"^2.0.0","@bsv/message-box-client":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","knex":"^3.1.0","react":"^19.2.4","ts-jest":"^29.1.1","react-dom":"^19.2.4","typescript":"^5.2.2","@types/jest":"^29.5.5","ts-standard":"^12.0.2","@types/react":"^19.2.14","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","@types/react-dom":"^19.2.3","@types/better-sqlite3":"^7.6.13","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.2.0","tsconfig-to-dual-package":"^1.2.0","@bsv/auth-express-middleware":"^2.0.2"},"peerDependencies":{"knex":"^3.1.0","react":"^18.0.0 || ^19.0.0","better-sqlite3":"^12.0.0","@bsv/wallet-toolbox":">=0.1.0","@bsv/auth-express-middleware":"^2.x"},"peerDependenciesMeta":{"knex":{"optional":true},"react":{"optional":true},"better-sqlite3":{"optional":true},"@bsv/wallet-toolbox":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/channel-express-middleware_0.1.3_1773100798931_0.06598348380347119","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@b1narydt/channel-express-middleware","version":"0.1.4","license":"SEE LICENSE IN LICENSE.txt","_id":"@b1narydt/channel-express-middleware@0.1.4","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"},{"name":"mburcham","email":"mitch@b1nary.tech"}],"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"dist":{"shasum":"be0d0100951ce85aa84edb2cbe6a533fbb0472eb","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.4.tgz","fileCount":403,"integrity":"sha512-jz432WU04ON0ZEVgJuAwTlUGyTqZfA//Nq+5BEsv47Xiu4IXU0ZQnnj4c+EafNaH+wuudLs+oanfuAQRkluWqw==","signatures":[{"sig":"MEUCIGukPMK7MNr6UzZqiBxZUVdywf/dbZ6HV2aoTfODuxZcAiEAuw8RKGkX3zp3mxXyD+sdC8Jj9z4vAnnWVEiLNKbeg4Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1788828},"main":"dist/cjs/mod.js","type":"module","types":"dist/types/mod.d.ts","module":"dist/esm/mod.js","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"}},"gitHead":"8b7ba3f1a83f0a92df1fc15fad91c97ed4ea8b6c","scripts":{"dev":"tsc -b -w","lint":"ts-standard --fix src/**/*.ts","test":"npm run build && jest","build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","prepare":"npm run build","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'"},"_npmUser":{"name":"mburcham","email":"mitch@b1nary.tech"},"repository":{"url":"git+https://github.com/b1narydt/channel-express-middleware.git","type":"git"},"_npmVersion":"10.9.2","description":"BSV payment channel Express middleware for off-chain micropayments","directories":{},"_nodeVersion":"22.17.0","dependencies":{"express":"^5.1.0","@bsv/sdk":"^2.0.0","@bsv/message-box-client":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","knex":"^3.1.0","react":"^19.2.4","ts-jest":"^29.1.1","react-dom":"^19.2.4","typescript":"^5.2.2","@types/jest":"^29.5.5","ts-standard":"^12.0.2","@types/react":"^19.2.14","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","@types/react-dom":"^19.2.3","@types/better-sqlite3":"^7.6.13","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.2.0","tsconfig-to-dual-package":"^1.2.0","@bsv/auth-express-middleware":"^2.0.2"},"peerDependencies":{"knex":"^3.1.0","react":"^18.0.0 || ^19.0.0","better-sqlite3":"^12.0.0","@bsv/wallet-toolbox":">=0.1.0","@bsv/auth-express-middleware":"^2.x"},"peerDependenciesMeta":{"knex":{"optional":true},"react":{"optional":true},"better-sqlite3":{"optional":true},"@bsv/wallet-toolbox":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/channel-express-middleware_0.1.4_1773102440172_0.3480975481745878","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@b1narydt/channel-express-middleware","version":"0.1.5","license":"SEE LICENSE IN LICENSE.txt","_id":"@b1narydt/channel-express-middleware@0.1.5","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"},{"name":"mburcham","email":"mitch@b1nary.tech"}],"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"dist":{"shasum":"b1e179fa40483bb9b26acb2016a39854f07ed299","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.5.tgz","fileCount":403,"integrity":"sha512-EF31kJtfwwlvujWvLEbDa/hUQuzD6/5QfLtXWjDi+F0KBCRH9SurgXjajnQl78oKHLBBKihZkZVcKGCzYvZ11w==","signatures":[{"sig":"MEQCIFui9OZTDP4ecoGcV+CedmkmhSd4UHlxeQxlSYjBgzihAiBoN9H0eYjKnAJVSCsgluOGnXU2edkDdrccKmXGZ5rYLg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1804997},"main":"dist/cjs/mod.js","type":"module","types":"dist/types/mod.d.ts","module":"dist/esm/mod.js","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"}},"gitHead":"8b7ba3f1a83f0a92df1fc15fad91c97ed4ea8b6c","scripts":{"dev":"tsc -b -w","lint":"ts-standard --fix src/**/*.ts","test":"npm run build && jest","build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","prepare":"npm run build","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'"},"_npmUser":{"name":"mburcham","email":"mitch@b1nary.tech"},"repository":{"url":"git+https://github.com/b1narydt/channel-express-middleware.git","type":"git"},"_npmVersion":"10.9.2","description":"BSV payment channel Express middleware for off-chain micropayments","directories":{},"_nodeVersion":"22.17.0","dependencies":{"express":"^5.1.0","@bsv/sdk":"^2.0.0","@bsv/message-box-client":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","knex":"^3.1.0","react":"^19.2.4","ts-jest":"^29.1.1","react-dom":"^19.2.4","typescript":"^5.2.2","@types/jest":"^29.5.5","ts-standard":"^12.0.2","@types/react":"^19.2.14","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","@types/react-dom":"^19.2.3","@types/better-sqlite3":"^7.6.13","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.2.0","tsconfig-to-dual-package":"^1.2.0","@bsv/auth-express-middleware":"^2.0.2"},"peerDependencies":{"knex":"^3.1.0","react":"^18.0.0 || ^19.0.0","better-sqlite3":"^12.0.0","@bsv/wallet-toolbox":">=0.1.0","@bsv/auth-express-middleware":"^2.x"},"peerDependenciesMeta":{"knex":{"optional":true},"react":{"optional":true},"better-sqlite3":{"optional":true},"@bsv/wallet-toolbox":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/channel-express-middleware_0.1.5_1773103155639_0.732793149508842","host":"s3://npm-registry-packages-npm-production"}},"0.1.6":{"name":"@b1narydt/channel-express-middleware","version":"0.1.6","license":"SEE LICENSE IN LICENSE.txt","_id":"@b1narydt/channel-express-middleware@0.1.6","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"},{"name":"mburcham","email":"mitch@b1nary.tech"}],"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"dist":{"shasum":"a42483c1bd93a6e01b09fdcb79b5c3ceded2e143","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.6.tgz","fileCount":403,"integrity":"sha512-L2x8L/1foCoN4R419fu6NMJqrkhSC5Mzg80juEPOjzOyrAtmBsL7VIHjqqyXaoYa5iUvHlPEQtCmSxHa+vTyLA==","signatures":[{"sig":"MEUCIQD1C1V4or5mOxa2qlEeJGIU6MiWDazmKrVOESdT3etxewIgNBaczll47X7lj7HZhdejij7rSeDZqnAnwaqNauE25tI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1805852},"main":"dist/cjs/mod.js","type":"module","types":"dist/types/mod.d.ts","module":"dist/esm/mod.js","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"}},"gitHead":"8b7ba3f1a83f0a92df1fc15fad91c97ed4ea8b6c","scripts":{"dev":"tsc -b -w","lint":"ts-standard --fix src/**/*.ts","test":"npm run build && jest","build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","prepare":"npm run build","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'"},"_npmUser":{"name":"mburcham","email":"mitch@b1nary.tech"},"repository":{"url":"git+https://github.com/b1narydt/channel-express-middleware.git","type":"git"},"_npmVersion":"10.9.2","description":"BSV payment channel Express middleware for off-chain micropayments","directories":{},"_nodeVersion":"22.17.0","dependencies":{"express":"^5.1.0","@bsv/sdk":"^2.0.0","@bsv/message-box-client":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","knex":"^3.1.0","react":"^19.2.4","ts-jest":"^29.1.1","react-dom":"^19.2.4","typescript":"^5.2.2","@types/jest":"^29.5.5","ts-standard":"^12.0.2","@types/react":"^19.2.14","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","@types/react-dom":"^19.2.3","@types/better-sqlite3":"^7.6.13","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.2.0","tsconfig-to-dual-package":"^1.2.0","@bsv/auth-express-middleware":"^2.0.2"},"peerDependencies":{"knex":"^3.1.0","react":"^18.0.0 || ^19.0.0","better-sqlite3":"^12.0.0","@bsv/wallet-toolbox":">=0.1.0","@bsv/auth-express-middleware":"^2.x"},"peerDependenciesMeta":{"knex":{"optional":true},"react":{"optional":true},"better-sqlite3":{"optional":true},"@bsv/wallet-toolbox":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/channel-express-middleware_0.1.6_1773108358096_0.1304864804987449","host":"s3://npm-registry-packages-npm-production"}},"0.1.7":{"name":"@b1narydt/channel-express-middleware","version":"0.1.7","license":"SEE LICENSE IN LICENSE.txt","_id":"@b1narydt/channel-express-middleware@0.1.7","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"},{"name":"mburcham","email":"mitch@b1nary.tech"}],"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"dist":{"shasum":"76e6fe20c756661a98e54a8680733aaa84168ee1","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.7.tgz","fileCount":403,"integrity":"sha512-nhBxjQxO1jDi6LecJg1F44ZP5mROxc2DoZoA9yoBDgSTeV831sHfNBuOzYXKz7uA9cUPKpRaWfhW2i2FJgHopQ==","signatures":[{"sig":"MEUCIHM+bGvx/wL2TNzII+ugYNUihJEqA7lToGT54fxqCYdyAiEAyt+4iaAN2KhEBApsMyPSlPUJb4re13040uIgPenvOYM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1805849},"main":"dist/cjs/mod.js","type":"module","types":"dist/types/mod.d.ts","module":"dist/esm/mod.js","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"}},"gitHead":"8b7ba3f1a83f0a92df1fc15fad91c97ed4ea8b6c","scripts":{"dev":"tsc -b -w","lint":"ts-standard --fix src/**/*.ts","test":"npm run build && jest","build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","prepare":"npm run build","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'"},"_npmUser":{"name":"mburcham","email":"mitch@b1nary.tech"},"repository":{"url":"git+https://github.com/b1narydt/channel-express-middleware.git","type":"git"},"_npmVersion":"10.9.2","description":"BSV payment channel Express middleware for off-chain micropayments","directories":{},"_nodeVersion":"22.17.0","dependencies":{"express":"^5.1.0","@bsv/sdk":"^2.0.0","@bsv/message-box-client":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","knex":"^3.1.0","react":"^19.2.4","ts-jest":"^29.1.1","react-dom":"^19.2.4","typescript":"^5.2.2","@types/jest":"^29.5.5","ts-standard":"^12.0.2","@types/react":"^19.2.14","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","@types/react-dom":"^19.2.3","@types/better-sqlite3":"^7.6.13","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.2.0","tsconfig-to-dual-package":"^1.2.0","@bsv/auth-express-middleware":"^2.0.2"},"peerDependencies":{"knex":"^3.1.0","react":"^18.0.0 || ^19.0.0","better-sqlite3":"^12.0.0","@bsv/wallet-toolbox":">=0.1.0","@bsv/auth-express-middleware":"^2.x"},"peerDependenciesMeta":{"knex":{"optional":true},"react":{"optional":true},"better-sqlite3":{"optional":true},"@bsv/wallet-toolbox":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/channel-express-middleware_0.1.7_1773118555867_0.8334692486343322","host":"s3://npm-registry-packages-npm-production"}},"0.1.8":{"name":"@b1narydt/channel-express-middleware","version":"0.1.8","license":"SEE LICENSE IN LICENSE.txt","_id":"@b1narydt/channel-express-middleware@0.1.8","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"},{"name":"mburcham","email":"mitch@b1nary.tech"}],"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"dist":{"shasum":"8de426bd22067d31400dec48225427e8e80a4416","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.8.tgz","fileCount":403,"integrity":"sha512-qM77idavFT9NOmnKP3ea53AOH01gDeSdFT8G9P7h//JbwPyiqwDEjzHOD+YCsWeLo4uzrMSP8FnYwbn0pjvPtA==","signatures":[{"sig":"MEQCID5Qn/qyoiC4w6Xlu4OwroQAOy+f33PtvqUktA9/YcyKAiB4lc9Vkp2CrjLHuCPbBZ1t/FxOy34jvfEUj7ibX6vCOQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1806699},"main":"dist/cjs/mod.js","type":"module","types":"dist/types/mod.d.ts","module":"dist/esm/mod.js","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"}},"gitHead":"8b7ba3f1a83f0a92df1fc15fad91c97ed4ea8b6c","scripts":{"dev":"tsc -b -w","lint":"ts-standard --fix src/**/*.ts","test":"npm run build && jest","build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","prepare":"npm run build","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'"},"_npmUser":{"name":"mburcham","email":"mitch@b1nary.tech"},"repository":{"url":"git+https://github.com/b1narydt/channel-express-middleware.git","type":"git"},"_npmVersion":"10.9.2","description":"BSV payment channel Express middleware for off-chain micropayments","directories":{},"_nodeVersion":"22.17.0","dependencies":{"express":"^5.1.0","@bsv/sdk":"^2.0.0","@bsv/message-box-client":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","knex":"^3.1.0","react":"^19.2.4","ts-jest":"^29.1.1","react-dom":"^19.2.4","typescript":"^5.2.2","@types/jest":"^29.5.5","ts-standard":"^12.0.2","@types/react":"^19.2.14","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","@types/react-dom":"^19.2.3","@types/better-sqlite3":"^7.6.13","@testing-library/react":"^16.3.2","jest-environment-jsdom":"^30.2.0","tsconfig-to-dual-package":"^1.2.0","@bsv/auth-express-middleware":"^2.0.2"},"peerDependencies":{"knex":"^3.1.0","react":"^18.0.0 || ^19.0.0","better-sqlite3":"^12.0.0","@bsv/wallet-toolbox":">=0.1.0","@bsv/auth-express-middleware":"^2.x"},"peerDependenciesMeta":{"knex":{"optional":true},"react":{"optional":true},"better-sqlite3":{"optional":true},"@bsv/wallet-toolbox":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/channel-express-middleware_0.1.8_1773129981771_0.625479362567072","host":"s3://npm-registry-packages-npm-production"}},"0.1.9":{"name":"@b1narydt/channel-express-middleware","version":"0.1.9","description":"BSV payment channel Express middleware for off-chain micropayments","type":"module","main":"dist/cjs/mod.js","module":"dist/esm/mod.js","types":"dist/types/mod.d.ts","exports":{".":{"types":"./dist/types/mod.d.ts","import":"./dist/esm/mod.js","require":"./dist/cjs/mod.js"},"./knex":{"types":"./dist/types/knex.d.ts","import":"./dist/esm/knex.js","require":"./dist/cjs/knex.js"},"./react":{"types":"./dist/types/react.d.ts","import":"./dist/esm/react.js","require":"./dist/cjs/react.js"},"./*.ts":{"types":"./dist/types/src/*.d.ts","import":"./dist/esm/src/*.js","require":"./dist/cjs/src/*.js"}},"scripts":{"build":"tsc -b && tsconfig-to-dual-package tsconfig.cjs.json","dev":"tsc -b -w","prepare":"npm run build","test":"npm run build && jest","test:integration":"npm run build && jest integration --testPathIgnorePatterns='dist/ integration-desktop'","test:desktop":"npm run build && jest integration-desktop --testPathIgnorePatterns='dist/'","lint":"ts-standard --fix src/**/*.ts"},"dependencies":{"@bsv/message-box-client":"^2.0.1","@bsv/sdk":"^2.0.0","express":"^5.1.0"},"peerDependencies":{"@bsv/auth-express-middleware":"^2.x","@bsv/wallet-toolbox":">=0.1.0","better-sqlite3":"^12.0.0","knex":"^3.1.0","react":"^18.0.0 || ^19.0.0"},"peerDependenciesMeta":{"@bsv/wallet-toolbox":{"optional":true},"better-sqlite3":{"optional":true},"knex":{"optional":true},"react":{"optional":true}},"devDependencies":{"@bsv/auth-express-middleware":"^2.0.2","@testing-library/react":"^16.3.2","@types/better-sqlite3":"^7.6.13","@types/jest":"^29.5.5","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","better-sqlite3":"^12.6.2","fake-indexeddb":"^6.2.5","jest":"^29.7.0","jest-environment-jsdom":"^30.2.0","knex":"^3.1.0","react":"^19.2.4","react-dom":"^19.2.4","ts-jest":"^29.1.1","ts-standard":"^12.0.2","tsconfig-to-dual-package":"^1.2.0","typescript":"^5.2.2"},"license":"SEE LICENSE IN LICENSE.txt","repository":{"type":"git","url":"git+https://github.com/b1narydt/channel-express-middleware.git"},"_id":"@b1narydt/channel-express-middleware@0.1.9","gitHead":"8b7ba3f1a83f0a92df1fc15fad91c97ed4ea8b6c","bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"homepage":"https://github.com/b1narydt/channel-express-middleware#readme","_nodeVersion":"22.17.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-P9BgCb3Nu92O+FvroVVpMSD99AaHBMH/JXKLh4WzszmXRYuyISqyaPc7UlwJgQQgQS/fvOca1++v3Zpc4IELog==","shasum":"75c8eb45eafedaa258931ce36408b5a72ba6748b","tarball":"https://registry.npmjs.org/@b1narydt/channel-express-middleware/-/channel-express-middleware-0.1.9.tgz","fileCount":403,"unpackedSize":1807549,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCohsGYxuCbXpp1ALexFSIHF3P5EatM2Jy67hbLRT35PgIhAKYdnpgivImOJXS0BSesYV602qkl5DJV5jVMjVpvoWe/"}]},"_npmUser":{"name":"mburcham","email":"mitch@b1nary.tech"},"directories":{},"maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"},{"name":"mburcham","email":"mitch@b1nary.tech"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/channel-express-middleware_0.1.9_1773131615013_0.12988084358728558"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-08T00:19:50.581Z","modified":"2026-03-10T08:33:35.341Z","0.1.0":"2026-03-08T00:19:50.835Z","0.1.1":"2026-03-08T03:11:51.540Z","0.1.2":"2026-03-09T23:33:13.235Z","0.1.3":"2026-03-09T23:59:59.096Z","0.1.4":"2026-03-10T00:27:20.392Z","0.1.5":"2026-03-10T00:39:15.853Z","0.1.6":"2026-03-10T02:05:58.312Z","0.1.7":"2026-03-10T04:55:56.081Z","0.1.8":"2026-03-10T08:06:21.973Z","0.1.9":"2026-03-10T08:33:35.205Z"},"bugs":{"url":"https://github.com/b1narydt/channel-express-middleware/issues"},"license":"SEE LICENSE IN LICENSE.txt","homepage":"https://github.com/b1narydt/channel-express-middleware#readme","repository":{"type":"git","url":"git+https://github.com/b1narydt/channel-express-middleware.git"},"description":"BSV payment channel Express middleware for off-chain micropayments","maintainers":[{"name":"ilahoti","email":"ishaan@b1nary.tech"},{"name":"mburcham","email":"mitch@b1nary.tech"}],"readme":"# @bsv/payment-channel-middleware\n\nExpress middleware for BSV payment channels. Instead of one on-chain transaction per request, this manages channel lifecycles: **one funding TX, many off-chain commitment updates, one closing TX**.\n\nDesigned to pair with [`@bsv/auth-express-middleware`](https://github.com/bsv-blockchain/auth-express-middleware) for authenticated requests. For individual pay-per-request micropayments (one transaction per API call), see [`@bsv/payment-express-middleware`](https://github.com/bsv-blockchain/payment-express-middleware).\n\n## Table of Contents\n\n- [When to Use This](#when-to-use-this)\n- [Background](#background)\n- [Features](#features)\n- [Installation](#installation)\n- [Prerequisites](#prerequisites)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Channel Providers](#channel-providers)\n- [Channel Store](#channel-store)\n- [React Integration](#react-integration)\n- [Channel Lifecycle](#channel-lifecycle)\n- [Error Handling](#error-handling)\n- [Settlement Recovery](#settlement-recovery)\n- [Security Considerations](#security-considerations)\n- [API Reference](#api-reference)\n- [Examples](#examples)\n- [Resources](#resources)\n- [License](#license)\n\n## When to Use This\n\nUse payment channels when your application needs **high-frequency micropayments** between a consumer and a platform. Channels are ideal when:\n\n- **Streaming content** -- music, video, or data feeds where each chunk costs a fraction of a cent\n- **Metered APIs** -- charge per-request for AI inference, geolocation, weather data, or any API where usage varies\n- **Gaming** -- in-game purchases, pay-per-action, or real-time reward distribution\n- **IoT / machine-to-machine** -- automated micro-billing between devices or services\n\n**Why channels instead of per-request payments?** A per-request payment (via [`@bsv/payment-express-middleware`](https://github.com/bsv-blockchain/payment-express-middleware)) creates one on-chain transaction per API call. That works well for infrequent, higher-value payments. But for hundreds or thousands of small payments in a session, per-request transactions are too slow (each requires wallet interaction and on-chain confirmation) and too expensive (each incurs a mining fee).\n\nPayment channels solve this by locking funds once at the start, exchanging instant off-chain commitments for each payment, and settling once at the end. A session with 1,000 micropayments requires only 2 on-chain transactions instead of 1,000.\n\n## Background\n\nPayment channels allow two parties to exchange many small payments without broadcasting each one to the blockchain.\n\n**How it works:**\n\n1. **Opening:** The consumer creates a funding transaction that locks satoshis into a 2-of-2 multisig output shared between the consumer and the platform. This is the only on-chain transaction until the channel closes.\n\n2. **Updating:** For each content chunk or API call, the consumer creates a new commitment transaction that redistributes the locked funds -- incrementing the platform's share by the chunk price and decrementing the consumer's refund. The consumer signs each commitment and sends it to the platform. These updates happen entirely off-chain; no broadcast is needed.\n\n3. **Closing:** When the consumer is done (or the channel is exhausted), either party can close by co-signing the latest commitment transaction and broadcasting it. The platform receives its accumulated payments and the consumer receives the remaining balance as a refund.\n\n4. **Recovery:** If the platform goes offline before closing, the consumer can send the latest commitment to a designated third-party recovery signer. The recovery signer co-signs and broadcasts the settlement, ensuring the consumer's funds are never locked permanently.\n\nThe result is that a session involving hundreds of micropayments requires only two on-chain transactions (open and close), with all intermediate payments settled instantly off-chain.\n\n## Features\n\n- **Express middleware** -- drop-in handler for payment channel lifecycle (discover, open, update, close)\n- **ChannelClient SDK** -- consumer-side client that manages the full channel protocol\n- **KnexChannelStore** -- production-ready persistence supporting SQLite, PostgreSQL, and MySQL\n- **React hook** -- `usePaymentChannel` for building payment-aware React components\n- **Dynamic pricing** -- per-content pricing and recipient splits via ChannelProvider\n- **M-of-N multisig** -- configurable multisig with 2-of-2, 2-of-3, and custom schemes\n- **BRC-29 key derivation** -- automatic per-channel address derivation for privacy and internalization\n- **Client persistence** -- automatic state persistence (IndexedDB in browser, filesystem in Node.js)\n- **Settlement recovery** -- consumer can recover funds when the platform is offline\n- **BEEF delivery** -- automatic settlement delivery to all recipients in PeerPayClient-compatible format (works with BSV Desktop)\n- **Idle channel cleanup** -- configurable auto-close of abandoned channels\n- **Seamless channel transition** -- close-then-open flow when a channel nears exhaustion\n- **Balance warnings** -- low-balance and critical-balance notifications\n- **Estimation utilities** -- calculate recommended funding and maximum chunks before opening\n- **Optimistic locking** -- concurrent request safety via version-based compare-and-swap\n\n## Installation\n\n```bash\nnpm i @bsv/payment-channel-middleware\n```\n\n### Peer Dependencies\n\n| Package | Required | Purpose |\n|---------|----------|---------|\n| `@bsv/auth-express-middleware` | Yes | Request authentication (BRC-103/104/105) |\n| `@bsv/wallet-toolbox` | Optional | Standalone BRC-100 wallet with UTXO tracking |\n| `knex` | Optional | Database abstraction for KnexChannelStore |\n| `better-sqlite3` | Optional | SQLite driver (default KnexChannelStore backend) |\n| `@bsv/message-box-client` | Optional | Settlement BEEF delivery to recipients |\n| `react` | Optional | React hook integration |\n\nInstall optional dependencies as needed:\n\n```bash\n# For SQLite persistence (recommended for development)\nnpm i knex better-sqlite3\n\n# For PostgreSQL persistence (recommended for production)\nnpm i knex pg\n\n# For settlement delivery to recipients via MessageBox\nnpm i @bsv/message-box-client\n\n# For React integration\nnpm i react\n```\n\n## Prerequisites\n\n- A BRC-100 compatible wallet ([`WalletClient`](https://github.com/bsv-blockchain/ts-sdk) from `@bsv/sdk`)\n- [`@bsv/auth-express-middleware`](https://github.com/bsv-blockchain/auth-express-middleware) for request authentication\n- Express 5.x\n\n## Wallet Setup\n\nThe middleware accepts any `WalletInterface` from `@bsv/sdk`. Two tiers are available depending on your deployment needs:\n\n### Tier 1: ProtoWallet (Lightweight)\n\nFor development, testing, and simple deployments where you don't need UTXO tracking:\n\n```typescript\nimport { ProtoWallet } from '@bsv/sdk'\n\nconst wallet = new ProtoWallet(new PrivateKey(process.env.PLATFORM_KEY_HEX))\n```\n\n- All core functionality works: key derivation, signing, BRC-29 addresses\n- `internalizeAction` calls are non-fatal no-ops (the middleware handles this gracefully)\n- Platform does NOT track earned UTXOs -- settlement outputs are broadcast but not internalized\n- Good for dev/testing and platforms that sweep UTXOs separately\n\n### Tier 2: wallet-toolbox Wallet (Full BRC-100)\n\nFor production where the platform needs to track and spend earned revenue:\n\n```typescript\nimport { Setup } from '@bsv/wallet-toolbox'\n\nconst { wallet } = await Setup.createWalletClientNoEnv({\n  chain: 'main',\n  rootKeyHex: process.env.PLATFORM_ROOT_KEY,\n  storageUrl: 'https://staging-storage.babbage.systems'\n})\n```\n\n- `internalizeAction` succeeds -- settlement outputs are tracked as wallet UTXOs\n- Platform can spend accumulated earnings via standard wallet operations\n- Required when the platform needs programmatic access to revenue\n\n### Where internalizeAction is called\n\n| Call site | Purpose | Full wallet needed? |\n|-----------|---------|-------------------|\n| `handleOpen` (funding TX) | Track multisig output | No (always fails for multisig, expected) |\n| `handleClose` (settlement) | Track platform's recipient outputs | Yes, for revenue tracking |\n| `client.close()` (refund) | Track consumer's refund output | Yes, for consumer wallet |\n| `client.checkPendingSettlements()` | Recover missed settlements | Yes, for consumer wallet |\n\nSee [docs/production-guide.md](docs/production-guide.md) for full wallet-toolbox configuration.\n\n## Quick Start\n\n### Server Setup\n\n```typescript\nimport express from 'express'\nimport { createAuthMiddleware } from '@bsv/auth-express-middleware'\nimport { createChannelMiddleware } from '@bsv/payment-channel-middleware'\nimport { KnexChannelStore } from '@bsv/payment-channel-middleware/knex'\nimport { WalletClient } from '@bsv/sdk'\n\nconst wallet = new WalletClient('auto', 'localhost')\n\nconst app = express()\n\n// Auth middleware must run first\napp.use(createAuthMiddleware({ wallet }))\n\n// Payment channel middleware\nconst channel = createChannelMiddleware({\n  wallet,\n  channelStore: new KnexChannelStore(), // SQLite default: ./data/channels.db\n  chunkPrice: 100,       // satoshis per chunk\n  recipients: [\n    { name: 'Platform', identityKey: '02abc...', percentage: 100 }\n  ]\n})\n\napp.get('/api/content/:id', channel, (req, res) => {\n  // req.payment.satoshisPaid -- amount paid this chunk\n  // req.channel.channelId   -- active channel ID\n  // req.channel.remainingBalance -- sats remaining in channel\n  res.json({ data: getContent(req.params.id) })\n})\n\napp.listen(3000)\n```\n\n### Client Usage\n\n```typescript\nimport { ChannelClient } from '@bsv/payment-channel-middleware'\nimport { WalletClient } from '@bsv/sdk'\n\nconst wallet = new WalletClient('auto', 'localhost')\nconst client = new ChannelClient(wallet, 'https://api.example.com')\n\n// Open a channel (discovers pricing, constructs funding TX)\nconst { channelId, remainingBalance } = await client.open('/api/content/song-1', {\n  fundingAmount: 10000\n})\n\n// Pay for content chunks\nconst { response, receipt } = await client.update('/api/content/song-1')\nconsole.log(response.body) // { data: '...' }\nconsole.log(receipt.remainingBalance) // 9900\n\n// Close when done (settles on-chain, returns refund)\nconst { refundAmount } = await client.close()\n```\n\n## Configuration\n\n### ChannelMiddlewareOptions\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `wallet` | `WalletInterface` | *required* | BSV wallet for key derivation, signing, and internalizing |\n| `channelStore` | `ChannelStore` | `KnexChannelStore()` | Channel state persistence |\n| `channelProvider` | `ChannelProvider` | -- | Dynamic pricing/splits (alternative to `chunkPrice` + `recipients`) |\n| `chunkPrice` | `number` | -- | Static price per chunk in satoshis |\n| `recipients` | `RecipientConfig[]` | -- | Static recipient list with split percentages |\n| `multisig` | `MultisigConfig` | `{ required: 2, total: 2 }` | Multisig configuration |\n| `minFundingAmount` | `number` | `1000` | Minimum funding amount in satoshis |\n| `maxChannelAge` | `number` | `86400000` | Maximum channel age in milliseconds (24h) |\n| `feeModel` | `FeeModel` | `SatoshisPerKilobyte(100)` | Dynamic settlement fee computation from TX size |\n| `settlementFee` | `number` | -- | Explicit settlement fee override (takes precedence over feeModel) |\n| `dustLimit` | `number` | `1` | Minimum output size in satoshis |\n| `balanceWarning` | `BalanceWarningConfig` | `{ low: 15%, critical: 2% }` | Balance warning thresholds |\n| `broadcaster` | `Broadcaster \\| false` | SDK default | Settlement TX broadcaster (`false` to disable) |\n| `chainTracker` | `ChainTracker \\| false` | SDK default | BEEF merkle proof verifier (`false` to disable) |\n| `idleClose` | `IdleCloseConfig` | disabled | Auto-close idle channels |\n| `deliveryService` | `DeliveryService` | -- | BEEF delivery to settlement recipients |\n| `reconcileOnStartup` | `boolean \\| { concurrency }` | `true` | Reconcile pending broadcasts on startup |\n| `recoverySigner` | `string` | -- | Default recovery signer identity key |\n\nEither `channelProvider` or both `chunkPrice` and `recipients` must be provided.\n\n### ChannelClientOptions\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `timeout` | `number` | `30000` | Operation timeout in milliseconds |\n| `retries` | `number` | `3` | Number of retries on failure |\n| `persist` | `boolean \\| ClientPersistence` | `true` | Client-side persistence (auto-detect environment) |\n| `clearOnClose` | `boolean` | `false` | Delete persisted data on channel close |\n| `exhaustionThreshold` | `number` | `80` | Percentage used before firing onTransitionReady |\n| `transitionFundingAmount` | `number` | original amount | Funding for new channel during transition |\n| `recoverySigner` | `string` | -- | Identity key for third-party recovery |\n| `onLowBalance` | `(data) => void` | -- | Callback after every payment with balance info |\n| `onStateChange` | `(state, channelId?) => void` | -- | Lifecycle state change callback |\n| `onTransitionReady` | `(data) => void` | -- | Fires when channel reaches exhaustion threshold |\n| `onRecoveryNeeded` | `(data) => void` | -- | Fires when close fails without recovery signer |\n\n## Channel Providers\n\nChannel providers control per-content pricing and recipient splits.\n\n### Static (default)\n\nWhen you pass `chunkPrice` and `recipients` directly to `createChannelMiddleware`, a `StaticChannelProvider` is used internally. Every content ID gets the same price and splits.\n\n### Dynamic\n\nUse a `FunctionChannelProvider` for per-content pricing:\n\n```typescript\nimport { FunctionChannelProvider, createChannelMiddleware } from '@bsv/payment-channel-middleware'\n\nconst channel = createChannelMiddleware({\n  wallet,\n  channelStore,\n  channelProvider: new FunctionChannelProvider(async (contentId) => {\n    const content = await db.getContent(contentId)\n    return {\n      chunkPrice: content.isPremium ? 200 : 50,\n      recipients: [\n        { name: content.artistName, identityKey: content.artistKey, percentage: 70 },\n        { name: 'Platform', identityKey: PLATFORM_KEY, percentage: 30 }\n      ]\n    }\n  })\n})\n```\n\nOr implement the `ChannelProvider` interface directly:\n\n```typescript\nclass MyChannelProvider implements ChannelProvider {\n  async getChannelConfig(contentId: string): Promise<ChannelConfig> {\n    // your logic\n  }\n}\n```\n\n## Channel Store\n\n### InMemoryChannelStore\n\nSuitable for development and testing. No persistence -- channel state is lost on restart.\n\n```typescript\nimport { InMemoryChannelStore } from '@bsv/payment-channel-middleware'\n\nconst store = new InMemoryChannelStore()\n```\n\n### KnexChannelStore\n\nProduction-ready store supporting any Knex-compatible database. Lazy initialization with embedded migrations (no migration files needed).\n\n```typescript\nimport { KnexChannelStore } from '@bsv/payment-channel-middleware/knex'\n\n// SQLite (zero config -- recommended for development)\nconst store = new KnexChannelStore()\n// Creates ./data/channels.db with WAL mode\n\n// SQLite with custom path\nconst store = new KnexChannelStore({ filename: '/var/data/channels.db' })\n\n// PostgreSQL\nconst store = new KnexChannelStore({\n  config: {\n    client: 'pg',\n    connection: process.env.DATABASE_URL\n  }\n})\n\n// MySQL\nconst store = new KnexChannelStore({\n  config: {\n    client: 'mysql2',\n    connection: process.env.DATABASE_URL\n  }\n})\n\n// Pre-initialized Knex instance\nimport Knex from 'knex'\nconst db = Knex({ client: 'pg', connection: process.env.DATABASE_URL })\nconst store = new KnexChannelStore({ knex: db })\n```\n\nThe `ChannelStore` interface can also be implemented directly for custom backends:\n\n```typescript\ninterface ChannelStore {\n  get(channelId: string): Promise<ChannelState | null>\n  set(channelId: string, state: ChannelState): Promise<void>\n  delete(channelId: string): Promise<void>\n  findActiveByConsumerAndContent(consumerIdentityKey: string, contentId: string): Promise<ChannelState | null>\n  findClosedByConsumer(consumerIdentityKey: string): Promise<ChannelState[]>\n  close(): Promise<void>\n  // Optional methods for advanced features\n  findPendingBroadcasts?(): Promise<ChannelState[]>\n  findExpiredChannels?(cutoffTimestamp: number, limit?: number): Promise<ChannelState[]>\n}\n```\n\n## React Integration\n\n```typescript\nimport { PaymentChannelProvider, usePaymentChannel } from '@bsv/payment-channel-middleware/react'\n\nfunction App() {\n  return (\n    <PaymentChannelProvider wallet={wallet} baseUrl=\"https://api.example.com\">\n      <ContentPlayer />\n    </PaymentChannelProvider>\n  )\n}\n\nfunction ContentPlayer() {\n  const {\n    status,        // 'idle' | 'opening' | 'active' | 'updating' | 'closing' | 'closed' | 'error'\n    balance,       // current balance in satoshis (or null)\n    channelId,     // active channel ID (or null)\n    error,         // ChannelError (or null)\n    percentUsed,   // 0-100\n    lowBalance,    // boolean\n    transitionReady,\n    open,\n    update,\n    close,\n    acceptTransition\n  } = usePaymentChannel()\n\n  const handlePlay = async () => {\n    if (status === 'idle') {\n      await open('/api/stream/song-1', { fundingAmount: 5000 })\n    }\n    const { response } = await update('/api/stream/song-1')\n    playAudio(response.body)\n  }\n\n  return (\n    <div>\n      <p>Status: {status} | Balance: {balance} sats</p>\n      <button onClick={handlePlay}>Play</button>\n      <button onClick={close} disabled={status !== 'active'}>Stop</button>\n    </div>\n  )\n}\n```\n\n## Channel Lifecycle\n\n```\nClient                                Server\n  |                                     |\n  |--- GET /api/content/123 --------->|\n  |<-- 402 { chunkPrice, recipients }--|  No x-bsv-channel header\n  |                                     |\n  |--- x-bsv-channel: { open } ------>|\n  |<-- 200 { channelId, platformKey }--|  Funding TX validated, channel stored\n  |                                     |\n  |--- x-bsv-channel: { update } ---->|  Commitment TX + consumer signature\n  |<-- 200 + content chunk ------------|  req.payment set, next() called\n  |                                     |\n  |--- x-bsv-channel: { update } ---->|  Updated commitment (sequence+1)\n  |<-- 200 + content chunk ------------|\n  |    ...repeat...                     |\n  |                                     |\n  |--- x-bsv-channel: { close } ----->|\n  |<-- 200 { settlementTxid, beef } ---|  Platform co-signs, channel closed\n```\n\n### Discovery (402)\n\nWhen a request arrives without the `x-bsv-channel` header, the middleware returns `402 Payment Required` with pricing information: `chunkPrice`, `recipients`, `multisig` config, and `platformIdentityKey`.\n\n### Open\n\nThe client sends a funding transaction (as Atomic BEEF) that locks funds into a multisig output. The middleware validates the funding output, derives BRC-29 payment addresses for all recipients and the consumer refund, and stores the channel state.\n\n### Update\n\nFor each payment, the client sends an updated commitment transaction with incrementing sequence numbers. The middleware validates the signature, commitment outputs, and balance, then sets `req.payment` and `req.channel` before calling `next()`.\n\n### Close\n\nEither party initiates close. The platform co-signs the latest commitment, broadcasts the settlement transaction, and returns the Atomic BEEF for consumer internalization.\n\n## Error Handling\n\n### Server Error Codes (CHANNEL_ERROR_CODES)\n\n| Code | HTTP | Description |\n|------|------|-------------|\n| `ERR_SERVER_MISCONFIGURED` | 500 | Auth middleware not running before channel middleware |\n| `ERR_CHANNEL_REQUIRED` | 402 | No `x-bsv-channel` header; returns pricing info |\n| `ERR_CHANNEL_NOT_FOUND` | 404 | Channel ID not in store |\n| `ERR_CHANNEL_EXPIRED` | 400 | Channel exceeded `maxChannelAge` |\n| `ERR_CHANNEL_CLOSED` | 400 | Operation on a closed channel |\n| `ERR_CHANNEL_EXHAUSTED` | 400 | Not enough balance for the chunk |\n| `ERR_INSUFFICIENT_BALANCE` | 400 | Not enough funding for the requested chunk |\n| `ERR_INVALID_SIGNATURE` | 400 | Consumer signature fails verification |\n| `ERR_STALE_SEQUENCE` | 400 | Sequence number not strictly increasing |\n| `ERR_INVALID_COMMITMENT` | 400 | Commitment TX outputs don't match expected values |\n| `ERR_FUNDING_TOO_LOW` | 400 | Funding below `minFundingAmount` |\n| `ERR_MALFORMED_HEADER` | 400 | Invalid JSON or missing required fields |\n| `ERR_DUPLICATE_CHUNK` | 400 | Chunk index already committed |\n| `ERR_CLOSE_FAILED` | 500 | Settlement signing failed |\n| `ERR_CHANNEL_INTERNAL` | 500 | Unexpected internal error |\n| `ERR_VERSION_CONFLICT` | 409 | Concurrent update detected |\n| `ERR_INVALID_BEEF` | 400 | Invalid Atomic BEEF in funding TX |\n| `ERR_MULTISIG_INVALID` | 400 | Invalid multisig configuration |\n\n### Client Error Codes (CLIENT_ERROR_CODES)\n\n| Code | Description |\n|------|-------------|\n| `ERR_NOT_OPEN` | No channel open; call `open()` first |\n| `ERR_ALREADY_OPEN` | Channel already open |\n| `ERR_ALREADY_CLOSED` | Channel already closed |\n| `ERR_CHANNEL_EXHAUSTED` | Channel balance insufficient |\n| `ERR_NETWORK` | Network error during operation |\n| `ERR_DISCOVERY_FAILED` | Pricing discovery failed |\n| `ERR_OPEN_FAILED` | Channel open request failed |\n| `ERR_UPDATE_FAILED` | Channel update request failed |\n| `ERR_CLOSE_FAILED` | Channel close request failed |\n| `ERR_PENDING_CLOSE` | Close in progress, retry with `close()` |\n| `ERR_RESTORE_FAILED` | Restored channel missing private key |\n| `ERR_TRANSITION_FAILED` | Channel transition failed |\n| `ERR_TRANSITION_NOT_READY` | Threshold not reached / prepare not called |\n| `ERR_RECOVERY_FAILED` | Recovery attempt failed |\n| `ERR_RECOVERY_IN_PROGRESS` | Recovery already running |\n\nAll server errors follow the format: `{ status: 'error', code: 'ERR_*', description: '...' }`\n\nClient errors are instances of `ChannelError` with `.code` and optional `.statusCode` properties.\n\n## Settlement Recovery\n\n### Platform-Side Recovery\n\nWhen a consumer goes offline before receiving the close response, they can retrieve their settlement data later:\n\n```typescript\nimport { createSettlementRecoveryHandler } from '@bsv/payment-channel-middleware'\n\napp.get('/api/settlements', authMiddleware, createSettlementRecoveryHandler({\n  channelStore: store,\n  platformIdentityKey: platformKey\n}))\n```\n\nThe consumer calls `client.checkPendingSettlements('/api/settlements')` to retrieve and internalize missed settlements.\n\n### Third-Party Recovery\n\nWhen the platform itself is offline, a designated recovery signer can settle channels on behalf of both parties:\n\n```typescript\nimport { createRecoveryListener } from '@bsv/payment-channel-middleware'\n\nconst listener = createRecoveryListener({\n  wallet: signerWallet,\n  pollInterval: 30000,         // check every 30s\n  auditLogPath: './recovery.jsonl'\n})\n\nawait listener.start()\n// listener.stop() for clean shutdown\n```\n\nThe consumer's `ChannelClient` automatically sends recovery requests when `recoverySigner` is configured and the platform is unreachable during close.\n\n## Security Considerations\n\n- **No private keys in client persistence.** The consumer's ephemeral channel private key is never stored. Restored channels can close (using the platform's existing commitment) but cannot create new updates.\n\n- **BRC-29 per-channel derivation.** Each channel uses unique derived payment addresses via BRC-29, so outputs cannot be linked to the consumer's identity key or to each other. Both recipient and consumer refund outputs use BRC-29 addresses, enabling wallet internalization.\n\n- **ANYONECANPAY | SINGLE sighash.** Commitment transactions use `SIGHASH_ANYONECANPAY | SIGHASH_SINGLE | SIGHASH_FORKID` (0xC3), allowing each party to sign their output independently without locking the other's output.\n\n- **Optimistic locking.** Concurrent requests to the same channel are protected by version-based compare-and-swap, preventing double-spend through race conditions.\n\n- **Optional broadcaster.** Pass `broadcaster: false` to disable automatic settlement broadcasting for environments where you manage broadcast externally.\n\n## API Reference\n\nSee [API Reference](./API.md) for complete documentation of all exported functions, classes, interfaces, and types.\n\nFor client-side usage patterns, see the [docs/](./docs/) directory:\n\n- [Client Guide](./docs/client-guide.md) -- complete ChannelClient SDK tutorial\n- [Production Guide](./docs/production-guide.md) -- deployment, database selection, scaling, and monitoring\n\n## Examples\n\nThe [`examples/`](./examples/) directory contains runnable examples for common integration patterns:\n\n| Example | Description |\n|---------|-------------|\n| [`basic-server/`](./examples/basic-server/) | Minimal server with payment channel middleware |\n| [`basic-client/`](./examples/basic-client/) | Minimal ChannelClient consumer |\n| [`demo/`](./examples/demo/) | Full lifecycle demo with mock wallets (no real BSV needed) |\n| [`knex-postgres/`](./examples/knex-postgres/) | PostgreSQL production setup with KnexChannelStore |\n| [`react-app/`](./examples/react-app/) | React integration with `usePaymentChannel` hook |\n| [`recovery-setup/`](./examples/recovery-setup/) | Third-party recovery signer configuration |\n| [`production-e2e/`](./examples/production-e2e/) | End-to-end tests with real BSV Desktop wallet and ARC broadcasting |\n\n## Resources\n\n- [BRC-29: Peer-to-Peer Payment Destination](https://brc.dev/29) -- payment address derivation for internalization\n- [BRC-100: Wallet Interface](https://brc.dev/100) -- wallet protocol specification\n- [BRC-103: Peer-to-Peer Authentication](https://brc.dev/103) -- request authentication\n- [BRC-105: HTTP Wallet Communications](https://brc.dev/105) -- wallet HTTP transport\n- [`@bsv/sdk`](https://github.com/bsv-blockchain/ts-sdk) -- BSV TypeScript SDK\n- [`@bsv/auth-express-middleware`](https://github.com/bsv-blockchain/auth-express-middleware) -- authentication middleware\n- [`@bsv/payment-express-middleware`](https://github.com/bsv-blockchain/payment-express-middleware) -- per-request payment middleware\n\n## License\n\nSEE LICENSE IN LICENSE.txt\n","readmeFilename":"README.md"}