{"_id":"@businessflow/leads","_rev":"9-b93bbe361a80c3c17e3f72ae62fa1a01","name":"@businessflow/leads","dist-tags":{"latest":"2.6.0"},"versions":{"1.0.0":{"name":"@businessflow/leads","version":"1.0.0","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha"],"author":{"name":"BusinessFlow"},"license":"MIT","_id":"@businessflow/leads@1.0.0","maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"homepage":"https://github.com/businessflow/leads#readme","bugs":{"url":"https://github.com/businessflow/leads/issues"},"dist":{"shasum":"6a0f7b85eaf4069b7a07914aeb6bb9bcc69b2b0f","tarball":"https://registry.npmjs.org/@businessflow/leads/-/leads-1.0.0.tgz","fileCount":32,"integrity":"sha512-ixiNEE5nFAGuLpsyjvINzUhwz2JmJzzxWyFnqVhyEz2rykf7Wz/pWvW6BF+iu1XWSbR/XhZEANtk3mtc/1yWmA==","signatures":[{"sig":"MEYCIQDffhzOnNE9TjSw+OIOkwi67jvQnA139mE6mr0FAvfScAIhAMZ/DgWWPBirE/Q4cgohX+b/6qRJqqOzYkQuFjV2WkQO","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":439595},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.esm.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.esm.js","require":"./dist/react/index.js"},"./types":{"types":"./dist/types/index.d.ts"},"./client":{"types":"./dist/client/index.d.ts","import":"./dist/client/index.esm.js","require":"./dist/client/index.js"},"./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.esm.js","require":"./dist/server/index.js"}},"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsup","test:ui":"vitest --ui","lint:fix":"eslint src --ext .ts,.tsx --fix","typecheck":"tsc --noEmit","test:watch":"vitest --watch","prepublishOnly":"npm run build && npm run typecheck"},"_npmUser":{"name":"carefulcoder42","email":"steyn.dc@gmail.com"},"repository":{"url":"git+https://github.com/businessflow/leads.git","type":"git"},"_npmVersion":"10.5.0","description":"Generic lead collection and form submission utilities with server-side API route handlers","directories":{},"_nodeVersion":"20.12.2","dependencies":{"tslib":"^2.6.2"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","tsup":"^8.0.1","eslint":"^8.55.0","vitest":"^1.0.4","prettier":"^3.1.0","@vitest/ui":"^1.0.4","typescript":"^5.3.2","@types/node":"^20.10.0","@types/react":"^18.2.42","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.33.2","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^6.13.1","eslint-plugin-react-hooks":"^4.6.0","@typescript-eslint/eslint-plugin":"^6.13.1"},"peerDependencies":{"next":">=13.0.0","react":">=16.8.0","react-dom":">=16.8.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/leads_1.0.0_1755768589224_0.09151259777026044","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@businessflow/leads","version":"1.0.1","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha"],"author":{"name":"BusinessFlow"},"license":"MIT","_id":"@businessflow/leads@1.0.1","maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"homepage":"https://github.com/businessflow/leads#readme","bugs":{"url":"https://github.com/businessflow/leads/issues"},"dist":{"shasum":"39c471c04d28dd3086057e8a7091936e8bce58d0","tarball":"https://registry.npmjs.org/@businessflow/leads/-/leads-1.0.1.tgz","fileCount":32,"integrity":"sha512-8xqe/xl89Da6hka/6Hqdih/dkCYeaIL7XZdUWwcRiTgNj7a2LTWUbdNdEMT0c/8Gdu3X4V5LlincVbaZRsj7ZQ==","signatures":[{"sig":"MEQCICLuUM3laHcImouKF48/TG9fJQVbz0f7uhQ0ArRqyPpjAiAJaK/Iuqkss0mFHGnyoXBIp+c0Qey93ER7HHvcyMW8IQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":439580},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.mjs","require":"./dist/react/index.js"},"./types":{"types":"./dist/types/index.d.ts"},"./client":{"types":"./dist/client/index.d.ts","import":"./dist/client/index.mjs","require":"./dist/client/index.js"},"./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.mjs","require":"./dist/server/index.js"}},"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsup","test:ui":"vitest --ui","lint:fix":"eslint src --ext .ts,.tsx --fix","typecheck":"tsc --noEmit","test:watch":"vitest --watch","prepublishOnly":"npm run build && npm run typecheck"},"_npmUser":{"name":"carefulcoder42","email":"steyn.dc@gmail.com"},"repository":{"url":"git+https://github.com/businessflow/leads.git","type":"git"},"_npmVersion":"10.5.0","description":"Generic lead collection and form submission utilities with server-side API route handlers","directories":{},"_nodeVersion":"20.12.2","dependencies":{"tslib":"^2.6.2"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","tsup":"^8.0.1","eslint":"^8.55.0","vitest":"^1.0.4","prettier":"^3.1.0","@vitest/ui":"^1.0.4","typescript":"^5.3.2","@types/node":"^20.10.0","@types/react":"^18.2.42","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.33.2","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^6.13.1","eslint-plugin-react-hooks":"^4.6.0","@typescript-eslint/eslint-plugin":"^6.13.1"},"peerDependencies":{"next":">=13.0.0","react":">=16.8.0","react-dom":">=16.8.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/leads_1.0.1_1755768963210_0.23747157155016851","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@businessflow/leads","version":"1.0.2","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha"],"author":{"name":"BusinessFlow"},"license":"MIT","_id":"@businessflow/leads@1.0.2","maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"homepage":"https://github.com/businessflow/leads#readme","bugs":{"url":"https://github.com/businessflow/leads/issues"},"dist":{"shasum":"cb730a4dcae87092176f990f768805b212b70415","tarball":"https://registry.npmjs.org/@businessflow/leads/-/leads-1.0.2.tgz","fileCount":32,"integrity":"sha512-XlM+L3OW6RWJ6v2wUQwO0xGhz43ZDr49VJ2/tVUOvlAUPEkWRSdx/1ZRWdW6fTRbVDMCbWlALeoQgV8win8rDQ==","signatures":[{"sig":"MEQCIFH9nDC8nYKRvtPV7iFvwJPWnVSqagGTvoCkGsTg8S1EAiARvSZfYY+671CB5mSYVtTV5H3f05Sdq4UCn2rgdv7KtA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":444183},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.mjs","require":"./dist/react/index.js"},"./types":{"types":"./dist/types/index.d.ts"},"./client":{"types":"./dist/client/index.d.ts","import":"./dist/client/index.mjs","require":"./dist/client/index.js"},"./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.mjs","require":"./dist/server/index.js"}},"gitHead":"3a861702837122991c8787e85248f434a3d1b1d9","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsup","test:ui":"vitest --ui","lint:fix":"eslint src --ext .ts,.tsx --fix","typecheck":"tsc --noEmit","test:watch":"vitest --watch","prepublishOnly":"npm run build && npm run typecheck"},"_npmUser":{"name":"carefulcoder42","email":"steyn.dc@gmail.com"},"repository":{"url":"git+https://github.com/businessflow/leads.git","type":"git"},"_npmVersion":"10.5.0","description":"Generic lead collection and form submission utilities with server-side API route handlers","directories":{},"_nodeVersion":"20.12.2","dependencies":{"tslib":"^2.6.2"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","tsup":"^8.0.1","eslint":"^8.55.0","vitest":"^1.0.4","prettier":"^3.1.0","@vitest/ui":"^1.0.4","typescript":"^5.3.2","@types/node":"^20.10.0","@types/react":"^18.2.42","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.33.2","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^6.13.1","eslint-plugin-react-hooks":"^4.6.0","@typescript-eslint/eslint-plugin":"^6.13.1"},"peerDependencies":{"next":">=13.0.0","react":">=16.8.0","react-dom":">=16.8.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/leads_1.0.2_1757014995371_0.8732612051638848","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@businessflow/leads","version":"2.1.0","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha"],"author":{"name":"BusinessFlow"},"license":"MIT","_id":"@businessflow/leads@2.1.0","maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"homepage":"https://github.com/businessflow/leads#readme","bugs":{"url":"https://github.com/businessflow/leads/issues"},"dist":{"shasum":"7f5d87adf49da0f78a90e5cda2bc6ac221a336f1","tarball":"https://registry.npmjs.org/@businessflow/leads/-/leads-2.1.0.tgz","fileCount":40,"integrity":"sha512-vKXt9ETNDhvkeLkoFf8qfIQ9Zt4HwCh2H4ylaU5SzKKPfAH6Fv8Nb+pWYZX9WZ6k22Y2AWWovRMUxr4KhD7i/g==","signatures":[{"sig":"MEYCIQCLhusiDpPGRXHF5M72UxqKfGPyZnKNr3OQohasb2+2HQIhAJuCYimALLBrsrPEXtQ6wH7LzMQ7o5PgSgOqYYg/vWjz","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":499485},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.mjs","require":"./dist/react/index.js"},"./types":{"types":"./dist/types/index.d.ts"},"./client":{"types":"./dist/client/index.d.ts","import":"./dist/client/index.mjs","require":"./dist/client/index.js"},"./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.mjs","require":"./dist/server/index.js"}},"gitHead":"162d143ba7605d335f716910f965962198633b37","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsup","test:ui":"vitest --ui","lint:fix":"eslint src --ext .ts,.tsx --fix","typecheck":"tsc --noEmit","test:watch":"vitest --watch","prepublishOnly":"npm run build && npm run typecheck"},"_npmUser":{"name":"carefulcoder42","email":"steyn.dc@gmail.com"},"repository":{"url":"git+https://github.com/businessflow/leads.git","type":"git"},"_npmVersion":"10.9.3","description":"Marketing website lead collection and form submission utilities with server-side API route handlers for BusinessFlow CRM","directories":{},"_nodeVersion":"22.19.0","dependencies":{"tslib":"^2.6.2"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","tsup":"^8.0.1","eslint":"^8.55.0","vitest":"^1.0.4","prettier":"^3.1.0","@vitest/ui":"^1.0.4","typescript":"^5.3.2","@types/node":"^20.10.0","@types/react":"^18.2.42","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.33.2","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^6.13.1","eslint-plugin-react-hooks":"^4.6.0","@typescript-eslint/eslint-plugin":"^6.13.1"},"peerDependencies":{"next":">=13.0.0","react":">=16.8.0","react-dom":">=16.8.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/leads_2.1.0_1758792241170_0.0062098174330293965","host":"s3://npm-registry-packages-npm-production"}},"2.2.0":{"name":"@businessflow/leads","version":"2.2.0","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha"],"author":{"name":"BusinessFlow"},"license":"MIT","_id":"@businessflow/leads@2.2.0","maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"homepage":"https://github.com/businessflow/leads#readme","bugs":{"url":"https://github.com/businessflow/leads/issues"},"dist":{"shasum":"012cf1bc0db2cdcd47b99af5b5c29e5b39e7edf5","tarball":"https://registry.npmjs.org/@businessflow/leads/-/leads-2.2.0.tgz","fileCount":40,"integrity":"sha512-uYj9ci8IEvUwF1hds3mVktnwAdb4+IUfVpaLYGNYoE7fmObKNGjym3bQjjUOjIrNOQmM+MQ/sVmZzW4DxSOyqQ==","signatures":[{"sig":"MEUCIFE6twPLRMTKcCHCR0Ruvzq44kBeo2vuuyAyHDMZq2AyAiEAxJF8/++3AWm0E7R2G1lQDZDkBdJS3HUh296sr2YoOJI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":499483},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.mjs","require":"./dist/react/index.js"},"./types":{"types":"./dist/types/index.d.ts"},"./client":{"types":"./dist/client/index.d.ts","import":"./dist/client/index.mjs","require":"./dist/client/index.js"},"./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.mjs","require":"./dist/server/index.js"}},"gitHead":"162d143ba7605d335f716910f965962198633b37","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsup","test:ui":"vitest --ui","lint:fix":"eslint src --ext .ts,.tsx --fix","typecheck":"tsc --noEmit","test:watch":"vitest --watch","prepublishOnly":"npm run build && npm run typecheck"},"_npmUser":{"name":"carefulcoder42","email":"steyn.dc@gmail.com"},"repository":{"url":"git+https://github.com/businessflow/leads.git","type":"git"},"_npmVersion":"10.9.3","description":"Marketing website lead collection and form submission utilities with server-side API route handlers for BusinessFlow CRM","directories":{},"_nodeVersion":"22.19.0","dependencies":{"tslib":"^2.6.2"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","tsup":"^8.0.1","eslint":"^8.55.0","vitest":"^1.0.4","prettier":"^3.1.0","@vitest/ui":"^1.0.4","typescript":"^5.3.2","@types/node":"^20.10.0","@types/react":"^18.2.42","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.33.2","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^6.13.1","eslint-plugin-react-hooks":"^4.6.0","@typescript-eslint/eslint-plugin":"^6.13.1"},"peerDependencies":{"next":">=13.0.0","react":">=16.8.0","react-dom":">=16.8.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/leads_2.2.0_1760447454090_0.7397863849529511","host":"s3://npm-registry-packages-npm-production"}},"2.3.0":{"name":"@businessflow/leads","version":"2.3.0","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha"],"author":{"name":"BusinessFlow"},"license":"MIT","_id":"@businessflow/leads@2.3.0","maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"homepage":"https://github.com/businessflow/leads#readme","bugs":{"url":"https://github.com/businessflow/leads/issues"},"dist":{"shasum":"d7d4498445fc8e46e29ffc30da000756b871bba3","tarball":"https://registry.npmjs.org/@businessflow/leads/-/leads-2.3.0.tgz","fileCount":40,"integrity":"sha512-LArIy11HHQvxw3CQzera5GZmWh1O65AgdHOkKB2UoM3m5dr5DtLY2/app5mssPaaoIbmQ5QXyRBxe/MZopdx7g==","signatures":[{"sig":"MEUCIQDud8f2aGpKd1i3A8mFIojI+Z4PticUDyhc4kzk6K+GjgIgFLrJOCo1xEAwh7E7n+rEM9aIkXxwj0zvsgPPBmG12XA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":507093},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.mjs","require":"./dist/react/index.js"},"./types":{"types":"./dist/types/index.d.ts"},"./client":{"types":"./dist/client/index.d.ts","import":"./dist/client/index.mjs","require":"./dist/client/index.js"},"./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.mjs","require":"./dist/server/index.js"}},"gitHead":"264740471825c43959e6be0339cb8311a5084cdb","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsup","test:ui":"vitest --ui","lint:fix":"eslint src --ext .ts,.tsx --fix","typecheck":"tsc --noEmit","test:watch":"vitest --watch","prepublishOnly":"npm run build && npm run typecheck"},"_npmUser":{"name":"carefulcoder42","email":"steyn.dc@gmail.com"},"repository":{"url":"git+https://github.com/businessflow/leads.git","type":"git"},"_npmVersion":"10.9.3","description":"Marketing website lead collection and form submission utilities with server-side API route handlers for BusinessFlow CRM","directories":{},"_nodeVersion":"22.19.0","dependencies":{"tslib":"^2.6.2"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","tsup":"^8.0.1","eslint":"^8.55.0","vitest":"^1.0.4","prettier":"^3.1.0","@vitest/ui":"^1.0.4","typescript":"^5.3.2","@types/node":"^20.10.0","@types/react":"^18.2.42","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.33.2","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^6.13.1","eslint-plugin-react-hooks":"^4.6.0","@typescript-eslint/eslint-plugin":"^6.13.1"},"peerDependencies":{"next":">=13.0.0","react":">=16.8.0","react-dom":">=16.8.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/leads_2.3.0_1761140775959_0.7366983101866784","host":"s3://npm-registry-packages-npm-production"}},"2.4.0":{"name":"@businessflow/leads","version":"2.4.0","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha"],"author":{"name":"BusinessFlow"},"license":"MIT","_id":"@businessflow/leads@2.4.0","maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"homepage":"https://github.com/DeClercqS/business-flow/tree/master/packages/npm/leads#readme","bugs":{"url":"https://github.com/DeClercqS/business-flow/issues"},"dist":{"shasum":"dcbf5b16a94d5e081b0770a7ce22b667af0524ae","tarball":"https://registry.npmjs.org/@businessflow/leads/-/leads-2.4.0.tgz","fileCount":40,"integrity":"sha512-LbGDilJkU7cxvq7faRcfx+KAFhYVCTWlr8sJtq0y7EzhD+8wXmRD16PddKo/avfp7O69e9iQ0EHPcKKbRTDEeA==","signatures":[{"sig":"MEUCIBpbhg9k4dy4QCM08jt7vRgc05KK4zMMgLtStlOIDdmHAiEA2/Vtpps1BWIgM+OBUVeXS96O0P+/T6AHNXXQbv1eG4w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":513046},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.mjs","require":"./dist/react/index.js"},"./types":{"types":"./dist/types/index.d.ts"},"./client":{"types":"./dist/client/index.d.ts","import":"./dist/client/index.mjs","require":"./dist/client/index.js"},"./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.mjs","require":"./dist/server/index.js"}},"gitHead":"8c5e6702a8e553db2fc271902c7e7c205757cabc","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsup","test:ui":"vitest --ui","lint:fix":"eslint src --ext .ts,.tsx --fix","typecheck":"tsc --noEmit","test:watch":"vitest --watch","prepublishOnly":"npm run build && npm run typecheck"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1931e4d0-7da7-4215-9b32-775964f1538b"}},"repository":{"url":"git+https://github.com/DeClercqS/business-flow.git","type":"git","directory":"packages/npm/leads"},"_npmVersion":"11.11.0","description":"Marketing website lead collection and form submission utilities with server-side API route handlers for BusinessFlow CRM","directories":{},"_nodeVersion":"24.14.1","dependencies":{"tslib":"^2.6.2"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.5.9","tsup":"^8.0.1","eslint":"^8.55.0","vitest":"^1.0.4","prettier":"^3.1.0","@vitest/ui":"^1.0.4","typescript":"^5.3.2","@types/node":"^20.10.0","@types/react":"^18.2.42","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.33.2","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^6.13.1","eslint-plugin-react-hooks":"^4.6.0","@typescript-eslint/eslint-plugin":"^6.13.1"},"peerDependencies":{"next":">=13.0.0","react":">=16.8.0","react-dom":">=16.8.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/leads_2.4.0_1775153008069_0.3872620043894126","host":"s3://npm-registry-packages-npm-production"}},"2.5.0":{"name":"@businessflow/leads","version":"2.5.0","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha"],"author":{"name":"BusinessFlow"},"license":"MIT","_id":"@businessflow/leads@2.5.0","maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"homepage":"https://github.com/DeClercqS/business-flow/tree/master/packages/npm/leads#readme","bugs":{"url":"https://github.com/DeClercqS/business-flow/issues"},"dist":{"shasum":"a935d87cbe92f5ce3fa2d23d626d95c652b9aa09","tarball":"https://registry.npmjs.org/@businessflow/leads/-/leads-2.5.0.tgz","fileCount":40,"integrity":"sha512-D8J85sA2egiBeO+zhRpQ09i3lpHPxVAp9YeFxFEujYBh4Rn7PtRYMbwVOya5wJeMSybNoipGA835aJHrl/r2zg==","signatures":[{"sig":"MEUCICsweyXXEeEhStc5DufJMX1G7AyCW/qwWQuk/As5VuslAiEAy8zlEeSvEcVH/u8/XpGT3fSNhvdmWxmPbGMpHHjOtI8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":699658},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.mjs","require":"./dist/react/index.js"},"./types":{"types":"./dist/types/index.d.ts"},"./client":{"types":"./dist/client/index.d.ts","import":"./dist/client/index.mjs","require":"./dist/client/index.js"},"./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.mjs","require":"./dist/server/index.js"}},"gitHead":"e2680f9deb784ea5350ce0274ea8027964fbea47","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsup","test:ui":"vitest --ui","lint:fix":"eslint src --ext .ts,.tsx --fix","typecheck":"tsc --noEmit","test:watch":"vitest --watch","prepublishOnly":"npm run build && npm run typecheck"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1931e4d0-7da7-4215-9b32-775964f1538b"}},"repository":{"url":"git+https://github.com/DeClercqS/business-flow.git","type":"git","directory":"packages/npm/leads"},"_npmVersion":"11.16.0","description":"Marketing website lead collection and form submission utilities with server-side API route handlers for BusinessFlow CRM","directories":{},"_nodeVersion":"24.18.0","dependencies":{"tslib":"^2.6.2"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.5.9","tsup":"^8.0.1","eslint":"^8.55.0","vitest":"^1.0.4","prettier":"^3.1.0","@vitest/ui":"^1.0.4","typescript":"^5.3.2","@types/node":"^20.10.0","@types/react":"^18.2.42","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.33.2","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^6.13.1","eslint-plugin-react-hooks":"^4.6.0","@typescript-eslint/eslint-plugin":"^6.13.1"},"peerDependencies":{"next":">=13.0.0","react":">=16.8.0","react-dom":">=16.8.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/leads_2.5.0_1784839556561_0.6859943370323072","host":"s3://npm-registry-packages-npm-production"}},"2.6.0":{"_id":"@businessflow/leads@2.6.0","bugs":{"url":"https://github.com/DeClercqS/business-flow/issues"},"dist":{"shasum":"383c50f2fbcf6e1e90db16efdca4f9c7df7cbba2","tarball":"https://registry.npmjs.org/@businessflow/leads/-/leads-2.6.0.tgz","fileCount":40,"integrity":"sha512-yMHkZvSWeN3LrcagNLaqSUlYH+iVmBP/gkiiQ9t9vhX2T7SZO5ah83y9ZdFRLfMore4a8QlQaEUMC56lYAvTbA==","signatures":[{"sig":"MEUCIQCIjbOVes1jwLbBf2pazAp+PcQt5BzHV6L4AVwOUBcAPwIgLDQ8QCfLFM12SuaAT2D5IpzaKYt3tq8MWOmvMptzFaQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDSAindDfFEyd1CQ2jJHdp64ReUW/9nA9Zl15MVVhC71QIgKJ2drs9C5OM/nMoRgXHSSBE2u6NFmLu/46m0JKltw+I="}],"unpackedSize":772168},"main":"./dist/index.js","name":"@businessflow/leads","types":"./dist/index.d.ts","author":{"name":"BusinessFlow"},"module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.mjs","require":"./dist/react/index.js"},"./types":{"types":"./dist/types/index.d.ts"},"./client":{"types":"./dist/client/index.d.ts","import":"./dist/client/index.mjs","require":"./dist/client/index.js"},"./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.mjs","require":"./dist/server/index.js"}},"gitHead":"cc1e86f63b320cea7acfcd405ca3b9f8083b1dd9","license":"MIT","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsup","test:ui":"vitest --ui","lint:fix":"eslint src --ext .ts,.tsx --fix","typecheck":"tsc --noEmit","test:watch":"vitest --watch","prepublishOnly":"npm run build && npm run typecheck","typecheck:tests":"tsc -p tsconfig.test.json"},"version":"2.6.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1931e4d0-7da7-4215-9b32-775964f1538b"}},"homepage":"https://github.com/DeClercqS/business-flow/tree/master/packages/npm/leads#readme","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha","turnstile"],"repository":{"url":"git+https://github.com/DeClercqS/business-flow.git","type":"git","directory":"packages/npm/leads"},"_npmVersion":"11.19.0","description":"Marketing website lead collection and form submission utilities with server-side API route handlers for BusinessFlow CRM","directories":{},"maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"_nodeVersion":"24.20.0","dependencies":{"tslib":"^2.6.2"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.5.9","tsup":"^8.0.1","eslint":"^8.55.0","vitest":"^1.0.4","prettier":"^3.1.0","@vitest/ui":"^1.0.4","typescript":"^5.3.2","@types/node":"^20.10.0","@types/react":"^18.2.42","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.33.2","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^6.13.1","eslint-plugin-react-hooks":"^4.6.0","@typescript-eslint/eslint-plugin":"^6.13.1"},"peerDependencies":{"next":">=13.0.0","react":">=16.8.0","react-dom":">=16.8.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/leads_2.6.0_1789904086124_0.8410021131049228"}}},"time":{"created":"2025-08-21T09:29:49.145Z","modified":"2026-09-20T11:34:46.414Z","1.0.0":"2025-08-21T09:29:49.396Z","1.0.1":"2025-08-21T09:36:03.397Z","1.0.2":"2025-09-04T19:43:15.585Z","2.1.0":"2025-09-25T09:24:01.366Z","2.2.0":"2025-10-14T13:10:54.309Z","2.3.0":"2025-10-22T13:46:16.177Z","2.4.0":"2026-04-02T18:03:28.271Z","2.5.0":"2026-07-23T20:45:56.719Z","2.6.0":"2026-09-20T11:34:46.227Z"},"bugs":{"url":"https://github.com/DeClercqS/business-flow/issues"},"author":{"name":"BusinessFlow"},"license":"MIT","homepage":"https://github.com/DeClercqS/business-flow/tree/master/packages/npm/leads#readme","keywords":["leads","contact-form","form-submission","nextjs","react","typescript","recaptcha","turnstile"],"repository":{"url":"git+https://github.com/DeClercqS/business-flow.git","type":"git","directory":"packages/npm/leads"},"description":"Marketing website lead collection and form submission utilities with server-side API route handlers for BusinessFlow CRM","maintainers":[{"name":"carefulcoder42","email":"steyn.dc@gmail.com"}],"readme":"# @businessflow/leads\n\nMarketing website lead collection and form submission utilities for React and NextJS applications that integrate with BusinessFlow CRM.\n\n## Features\n\n- 🚀 **Framework Agnostic**: Works with React, NextJS, and vanilla JavaScript\n- 🔒 **Secure**: Server-side API key handling, Cloudflare Turnstile (v2.6+) or reCAPTCHA verification\n- 📱 **Responsive**: Mobile-friendly form components\n- 🎨 **Customizable**: Flexible styling and field configuration\n- 📝 **TypeScript**: Full type safety and IntelliSense support\n- ⚡ **Modern**: Built with latest React patterns and NextJS features\n- 🏢 **BusinessFlow Ready**: Pre-configured for BusinessFlow CRM integration\n\n## Installation\n\n```bash\nnpm install @businessflow/leads\n```\n\n## Quick Start\n\n### 1. Simple BusinessFlow Integration\n\n```typescript\n// app/api/lead/route.ts\nimport { createBusinessFlowHandler } from '@businessflow/leads/server';\n\nexport const POST = createBusinessFlowHandler({\n  apiUrl: process.env.BUSINESS_FLOW_API_URL!,\n  apiKey: process.env.BUSINESS_FLOW_API_KEY!,\n  sourceUrl: process.env.SITE_URL!,\n  // One of these is required in production (Turnstile wins if both are set):\n  turnstileSecret: process.env.TURNSTILE_SECRET_KEY,\n  // recaptchaSecret: process.env.RECAPTCHA_SECRET_KEY,\n});\n```\n\n### 2. Even Simpler with Environment Variables\n\n```typescript\n// app/api/lead/route.ts\nimport { createSimpleBusinessFlowHandler } from '@businessflow/leads/server';\n\n// Uses BUSINESS_FLOW_API_URL, BUSINESS_FLOW_API_KEY, and TURNSTILE_SECRET_KEY or RECAPTCHA_SECRET_KEY from env\nexport const POST = createSimpleBusinessFlowHandler();\n```\n\n### 3. Custom Integration (Advanced)\n\n```typescript\n// app/api/lead/route.ts\nimport { createLeadHandler } from '@businessflow/leads/server';\n\nexport const POST = createLeadHandler({\n  onSubmit: async (data) => {\n    // Your custom business logic here\n    const response = await fetch('https://your-api.com/leads', {\n      method: 'POST',\n      headers: {\n        'Authorization': `Bearer ${process.env.YOUR_API_KEY}`,\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify(data)\n    });\n\n    return {\n      success: response.ok,\n      message: response.ok ? 'Lead submitted successfully' : 'Submission failed',\n      id: response.ok ? await response.json().then(r => r.id) : undefined\n    };\n  },\n  recaptcha: {\n    secretKey: process.env.RECAPTCHA_SECRET_KEY!\n  }\n});\n```\n\n### 2. Use in Your Components\n\n#### Pre-built Component\n```typescript\nimport { ContactForm } from '@businessflow/leads/react';\n\nexport default function ContactPage() {\n  return (\n    <ContactForm\n      recaptcha={{ siteKey: process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY! }}\n      onSuccess={(response) => console.log('Success!', response)}\n      onError={(error) => console.error('Error:', error)}\n    />\n  );\n}\n```\n\n#### Custom Hook for Custom Forms\n```typescript\nimport { useContactForm } from '@businessflow/leads/react';\n\nexport default function CustomContactForm() {\n  const {\n    formData,\n    errors,\n    state,\n    handleChange,\n    handleSubmit,\n    handleRetry,\n    resetForm\n  } = useContactForm({\n    endpoint: '/api/lead',\n    recaptcha: { \n      siteKey: process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY!,\n      action: 'contact_form'\n    },\n    onSuccess: (response) => console.log('Success!', response),\n    onError: (error) => console.error('Error:', error),\n    maxRetries: 3\n  });\n\n  return (\n    <form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}>\n      <input\n        type=\"text\"\n        placeholder=\"First Name\"\n        value={formData.firstName}\n        onChange={(e) => handleChange('firstName', e.target.value)}\n      />\n      {errors.firstName && <span>{errors.firstName}</span>}\n      \n      <input\n        type=\"text\"\n        placeholder=\"Last Name\"\n        value={formData.lastName}\n        onChange={(e) => handleChange('lastName', e.target.value)}\n      />\n      {errors.lastName && <span>{errors.lastName}</span>}\n      \n      <input\n        type=\"email\"\n        placeholder=\"Email\"\n        value={formData.email}\n        onChange={(e) => handleChange('email', e.target.value)}\n      />\n      {errors.email && <span>{errors.email}</span>}\n      \n      <button type=\"submit\" disabled={state.isSubmitting}>\n        {state.isSubmitting ? 'Submitting...' : 'Submit'}\n      </button>\n      \n      {state.error && state.canRetry && (\n        <button onClick={handleRetry} disabled={state.isSubmitting}>\n          Retry ({state.retryCount}/{3})\n        </button>\n      )}\n      \n      {state.isSuccess && <div>Form submitted successfully!</div>}\n      {state.error && <div>Error: {state.error}</div>}\n    </form>\n  );\n}\n```\n\n## Bot protection\n\nThe route handler always applies a honeypot check (`_website` / `_honeypot`), and applies a\ntiming check when the client sends `_t` (page-load timestamp; submissions under 3 s are\ndropped). On top of that, configure **one** captcha verifier. In production\n(`NODE_ENV=production`) the BusinessFlow handlers (`createBusinessFlowHandler` /\n`createSimpleBusinessFlowHandler`) refuse to start with neither, unless you pass\n`allowMissingCaptcha: true` deliberately. The generic `createLeadHandler` applies no such\nrule — it runs whatever verifier block you give it, or none.\n\n| | Cloudflare Turnstile (v2.6+, recommended) | Google reCAPTCHA v3 |\n|---|---|---|\n| Wrapper option | `turnstileSecret` | `recaptchaSecret`, `minimumScore` |\n| Env var (simple handler) | `TURNSTILE_SECRET_KEY` | `RECAPTCHA_SECRET_KEY` |\n| Body field the route reads | `token` (or `Token`) | `token` (or `Token`) |\n| Failure response | 400 `Security verification failed: …` | 400 `reCAPTCHA verification failed: …` |\n| Client helper in this package | none — render the widget yourself (below) | `useRecaptcha` hook |\n\nIf both secrets are set (typical for one deploy while migrating), **Turnstile wins** and the\nhandler logs one warning at startup. Remove `RECAPTCHA_SECRET_KEY` once Turnstile is verified.\n\nThe captcha secret is only ever read inside your API route. The browser posts a one-time\ntoken to your own `/api/lead`; the route verifies it with Cloudflare or Google, strips it,\nand only then forwards the lead to BusinessFlow. BusinessFlow never sees captcha configuration.\n\n### Turnstile keys per environment\n\nTurnstile's trust boundary is the **widget's hostname allow-list** in the Cloudflare dashboard —\nthe package does not check `hostname`/`action` itself, so there is nothing to configure per\nenvironment in code.\n\n| Environment | Site key | Secret key |\n|---|---|---|\n| Production | the widget you created for your domain | its secret |\n| Local / preview / staging | `1x00000000000000000000BB` (Cloudflare's always-pass key for **invisible** widgets) | `1x0000000000000000000000000000000AA` |\n\nThe test keys work on any hostname, including `localhost` and Vercel preview URLs, and always\nverify. (`1x00000000000000000000AA` is the visible-widget equivalent.) Never ship them to production.\n\n### Turnstile on the client\n\nThis package does not ship a Turnstile widget. Render it with `@marsidev/react-turnstile` in\ninvisible/execute mode, and post the token as `token`. The pattern below is the one used in\nproduction on businessflow.co.za: it guards against the script never loading, retries widget\nerrors, resets on expiry, and unsticks the form if Cloudflare never answers.\n\n```tsx\n'use client';\nimport { useRef, useState } from 'react';\nimport { Turnstile, type TurnstileInstance } from '@marsidev/react-turnstile';\n\n// Module-level constant: an inline literal makes the widget re-render on every parent render.\n// responseField:false stops the widget injecting a hidden <input name=\"cf-turnstile-response\">\n// into the form, which FormData below would otherwise post as a stray lead field.\nconst TURNSTILE_OPTIONS = { size: 'invisible', execution: 'execute', responseField: false } as const;\nconst MAX_TURNSTILE_RETRIES = 3;\nconst TURNSTILE_SAFETY_TIMEOUT_MS = 15_000;\n\ntype Lead = { firstName: string; lastName?: string; email: string; phone: string; comments: string };\n\nexport function QuickConnectForm() {\n  const turnstile = useRef<TurnstileInstance | null>(null);\n  const pending = useRef<Lead | null>(null);\n  const retries = useRef(0);\n  const safetyTimer = useRef<number | null>(null);\n  const loadedAt = useRef(Date.now());\n  const [submitting, setSubmitting] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n  const [done, setDone] = useState(false);\n\n  function clearSafetyTimer() {\n    if (safetyTimer.current !== null) {\n      window.clearTimeout(safetyTimer.current);\n      safetyTimer.current = null;\n    }\n  }\n\n  async function submitWithToken(token: string) {\n    clearSafetyTimer();\n    const data = pending.current;\n    pending.current = null;\n    if (!data) return;\n    try {\n      const res = await fetch('/api/lead', {\n        method: 'POST',\n        headers: { 'content-type': 'application/json' },\n        body: JSON.stringify({ ...data, token, _t: loadedAt.current, _website: '' }),\n      });\n      if (!res.ok) throw new Error((await res.json()).error ?? 'Submission failed');\n      setDone(true);\n    } catch (e) {\n      setError(e instanceof Error ? e.message : 'Submission failed. Please try again.');\n    } finally {\n      setSubmitting(false);\n    }\n  }\n\n  function onTurnstileError() {\n    if (!pending.current) return;\n    retries.current += 1;\n    if (retries.current < MAX_TURNSTILE_RETRIES) {\n      setTimeout(() => { turnstile.current?.reset(); turnstile.current?.execute(); }, 1000);\n      return;\n    }\n    clearSafetyTimer();\n    pending.current = null;\n    retries.current = 0;\n    setSubmitting(false);\n    setError('The security check could not complete. Please try again or contact us directly.');\n  }\n\n  function onSubmit(event: React.FormEvent<HTMLFormElement>) {\n    event.preventDefault();\n    const data = Object.fromEntries(new FormData(event.currentTarget)) as unknown as Lead;\n\n    // Script-load guard: a blocked network or privacy extension leaves the ref null, and\n    // execute() would silently no-op — tell the user instead of showing a dead button.\n    if (!turnstile.current) {\n      setError('The security check could not load. Please refresh and try again.');\n      return;\n    }\n    setError(null);\n    setSubmitting(true);\n    pending.current = data;\n    retries.current = 0;\n    turnstile.current.reset();\n    turnstile.current.execute();\n    // Safety timeout: if neither onSuccess nor onError fires, unstick the form. One timer per\n    // attempt — a stale timer from an earlier attempt must never cancel a newer one.\n    clearSafetyTimer();\n    safetyTimer.current = window.setTimeout(() => {\n      safetyTimer.current = null;\n      if (pending.current) {\n        pending.current = null;\n        setSubmitting(false);\n        setError('The security check timed out. Please try again.');\n      }\n    }, TURNSTILE_SAFETY_TIMEOUT_MS);\n  }\n\n  if (done) return <p>Thanks — we will be in touch shortly.</p>;\n\n  return (\n    <form onSubmit={onSubmit}>\n      <input name=\"firstName\" required placeholder=\"Name\" />\n      <input name=\"lastName\" placeholder=\"Surname\" />\n      <input name=\"email\" type=\"email\" required placeholder=\"Email\" />\n      <input name=\"phone\" type=\"tel\" required placeholder=\"Phone (+27…)\" />\n      <textarea name=\"comments\" required placeholder=\"How can we help?\" />\n      <Turnstile\n        ref={turnstile}\n        siteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY!}\n        options={TURNSTILE_OPTIONS}\n        onSuccess={(token) => { retries.current = 0; submitWithToken(token); }}\n        onError={onTurnstileError}\n        onExpire={() => turnstile.current?.reset()}\n      />\n      <button type=\"submit\" disabled={submitting}>{submitting ? 'Sending…' : 'Send'}</button>\n      {error && <p role=\"alert\">{error}</p>}\n    </form>\n  );\n}\n```\n\nTurnstile tokens are single-use and expire after 300 s, so the form calls `reset()` +\n`execute()` per submission rather than reusing a token.\n\n### Server route\n\n```ts\n// app/api/lead/route.ts\nimport { createBusinessFlowHandler } from '@businessflow/leads/server';\n\nexport const POST = createBusinessFlowHandler({\n  apiUrl: process.env.BUSINESS_FLOW_API_URL!,\n  apiKey: process.env.BUSINESS_FLOW_API_KEY!,\n  sourceUrl: process.env.NEXT_PUBLIC_SITE_URL,\n  turnstileSecret: process.env.TURNSTILE_SECRET_KEY,\n});\n```\n\nUsing the generic handler directly:\n\n```ts\nimport { createLeadHandler } from '@businessflow/leads/server';\n\nexport const POST = createLeadHandler({\n  turnstile: { secretKey: process.env.TURNSTILE_SECRET_KEY! },\n  onSubmit: async (lead) => { /* … */ return { success: true }; },\n});\n```\n\n`verifyTurnstile(token, { secretKey })` and `getTurnstileErrorMessage(codes)` are also exported\nfor custom routes; the result carries `hostname` and `action` if you want to check them yourself.\n\n## File attachments (v2.5+)\n\nLets a visitor attach plans or documents to a lead. Files go **direct from the browser\nto the BusinessFlow API**, not through your Next.js function — that clears Vercel's\n4.5 MB request-body cap. Your server route only mints a short-lived ticket, so the API\nkey never reaches the browser.\n\nServer-enforced limits: **10 MB** per file (decimal), **5 files** per ticket,\nextensions `.pdf .jpg .jpeg .png .dwg`. The API also sniffs the leading bytes, so a\nrenamed executable is rejected regardless of its extension. Uploaded files are\nmalware-scanned; the dashboard only serves a file once it comes back clean.\n\n### 1. Add the ticket route\n\n```typescript\n// app/api/lead-upload-ticket/route.ts\nimport { createUploadTicketHandler } from '@businessflow/leads/server';\n\nexport const POST = createUploadTicketHandler();\n```\n\nRequires `BUSINESS_FLOW_API_URL` and `BUSINESS_FLOW_API_KEY` (throws at construction if\neither is missing). The handler throttles per visitor IP — without that, one scripted\nvisitor would spend your site's entire shared API-key budget, because the API sees only\nyour host's egress address.\n\n### 2. Upload from the form\n\n```typescript\nimport { uploadLeadAttachments } from '@businessflow/leads/client';\n\nconst result = await uploadLeadAttachments(files, {\n  ticketUrl: '/api/lead-upload-ticket',\n  apiUrl: process.env.NEXT_PUBLIC_BUSINESS_FLOW_API_URL!,\n  // Thread the session's ticket back in on every later batch — see below.\n  existingTicket: ticket ? { token: ticket, usedSlots } : undefined,\n  onProgress: (fileIndex, pct) => setRowProgress(fileIndex, pct),\n});\n```\n\n**Keep the whole form session on one ticket.** Mint on the first file selection, then\npass `existingTicket` into every subsequent call. The API binds attachments to a lead\nper ticket, so a submission carrying ids from two different tickets is rejected.\n\n**It never throws.** Everything that fails comes back in `result.failures`, each entry\ncarrying `index` (maps to your UI row), a user-facing `error`, and `permanent` — `true`\nfor oversize/wrong-type/over-cap (offer no retry), `false` for network and 5xx (offer a\nretry). Submit the lead even when every upload failed; losing the enquiry is far worse\nthan losing the file.\n\n### 3. Submit the lead\n\n```typescript\nawait fetch('/api/lead', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    name, email, phone, comments, token: recaptchaToken,\n    // Send all three together, or omit all three.\n    ...(result.attachmentIds.length > 0 && {\n      attachmentIds: result.attachmentIds,\n      uploadTicket: result.ticket,\n      popiaConsentVersion: 'your-site-2026-07-v1',\n    }),\n  }),\n});\n```\n\nConsent is **mandatory** whenever `attachmentIds` is non-empty — the API rejects the\nsubmission otherwise. Gate your consent checkbox on there being at least one file, and\nclear it when the last file is removed.\n\n## Documentation\n\n- [API Reference](./docs/api.md)\n- [Examples](./examples/)\n- [Migration Guide](./docs/migration.md)\n\n## License\n\nMIT","readmeFilename":"README.md"}