Repository navigation
Releases
Release 2.4.1
v2.4.1 — npm metadata refresh & contributor docs
A docs- and metadata-only patch. No code changes — same library as 2.4.0.
This release primarily makes the v2.4.0 positioning work visible on the npm registry, where most prospective users discover the package.
What's new
📦 npm-visible metadata
- New description leads with "v3 score-based (invisible)" so users discovering the package via npm search immediately know it's the score-based variant (not v2 challenges or hCaptcha).
- Expanded keywords: added
recaptcha-v3,score-based,invisible,abort-signal,enterprise,typescript,bot-protection,ios,android, and others — improves discoverability for the actual use cases. - Declared
engines.node >=18to match the CI test matrix. Older Node runtimes will see a warning during install but installs will still complete.
📚 Documentation
- README: full rewrite with clearer positioning, a "Picking the right package" table for v2/v3/Enterprise/hCaptcha, an honest "About the WebView approach" section, per-error reference table, and an FAQ comparing this package to alternatives.
- CONTRIBUTING.md: rewrite — removed stale references to a monorepo, an
example/directory, and pre-commit hooks that didn't exist in the project. - SECURITY.md (new): private vulnerability reporting flow via GitHub security advisories; supported-versions table; explicit scope.
🧱 Repo hygiene (for contributors)
- Issue templates (
bug.yml,feature.yml) with structured fields and pre-flight checks that redirect "wrong package" reports before they're filed. - Pull request template with a Conventional Commits checklist.
- Issue
config.ymlthat disables blank issues and points security reports, v2 challenge seekers, and hCaptcha seekers to the right destinations.
🔌 Migrating from 2.4.0
- "@valture/react-native-recaptcha-v3": "^2.4.0"
+ "@valture/react-native-recaptcha-v3": "^2.4.1"No source changes required. Identical runtime behavior.
If you're upgrading from a version older than 2.4.0, the meaningful changes are in the v2.4.0 release notes.
Full Changelog: v2.4.0...v2.4.1
Release 2.4.0
v2.4.0 — Lifecycle hardening, security defaults, enterprise & abort signals
A comprehensive audit-and-improve pass. All changes are non-breaking — existing code continues to work; new features are additive; behavior changes have escape-hatch props.
See PR #6 for the full review.
✨ New features
AbortSignalsupport — cancel an in-flightgetToken():const controller = new AbortController(); recaptchaRef.current?.getToken('checkout', { signal: controller.signal }); controller.abort(); // promise rejects with 'Token request was aborted.'
- reCAPTCHA Enterprise — opt in with the new
useEnterpriseprop. Switches toenterprise.jsandgrecaptcha.enterprise.execute. onVerifynow receives the action —onVerify?: (token, action) => void. Useful when one component handles multiple actions. Existing handlers that ignore the extra arg keep working.
🐛 Bug fixes
onLoadEndfires exactly once per load cycle (was 2–3×).- Concurrent
reset()calls no longer leak the first promise — all queued resolvers now fire on the next load. reset()rejects in-flight and queued token requests immediately with a clearRESETerror (used to hang until the request's own timeout).- Superseded requests now reject with a
SUPERSEDEDerror instead of the misleadingTOKEN_REQUEST_TIMEOUT. - Force-READY timer no longer reads closure-stale
isReady/hasError— uses refs so the latest values win. handleLoadStartno longer wipespendingRequests— previously droppedgetToken()calls queued between mount and the WebView's firstonLoadStart.- Unmount cleanup — all timers (init, force-READY, in-flight, queued) and abort listeners are now cleared on unmount, fixing a real memory leak when the component unmounts mid-flight.
🛡️ Security
These change defaults but each has an opt-out prop, so existing setups can pin the old behavior if needed.
mixedContentModeis now configurable, defaulting to'never'(was hard-coded'always'). PassmixedContentMode="always"to restore.originWhitelistis now configurable, defaulting to['https://www.google.com', 'https://www.gstatic.com', baseUrl](was['*']). PassoriginWhitelist={['*']}to restore.siteKeyis regex-validated at mount (/^[A-Za-z0-9_-]{20,80}$/). Invalid keys surface viaonErrorinstead of being interpolated into the WebView's HTML/URL.
🧱 Internal
- HTML template memoized (was rebuilt every render).
- Magic numbers extracted to named constants.
NodeJS.Timeout→ portableReturnType<typeof setTimeout>.
🧪 Tests & CI (new)
- 32 unit tests covering all bug fixes and the public API, using
jest+@testing-library/react-nativewith a controllable WebView mock. - GitHub Actions CI runs lint · typecheck · test · build on every PR across Node 20 and 22.
🔌 Migrating
- "@valture/react-native-recaptcha-v3": "^2.3.0"
+ "@valture/react-native-recaptcha-v3": "^2.4.0"No source changes required.
Full Changelog: v2.3.0...v2.4.0
Release 2.3.0
What's Changed
🐛 Bug Fixes
- Fix double WebView reload when
siteKeyorbaseUrlprops change.reset()already reloads the WebView, so the redundant follow-up reload has been removed. - Fix orphaned token promise on concurrent
getToken()calls. Previously, if you calledgetToken()twice before the first resolved, the first promise would hang until its own 15s timeout fired. It's now rejected immediately when superseded.
🧹 Internal
- Migrated to ESLint 9 flat config so
yarn lintworks (the legacy config referenced a preset that wasn't installed). - Removed deprecated
@types/react-nativedevDep (RN ships its own types since 0.71). - Removed unused
eslint-plugin-prettierdevDep. - Bumped
react-native-webviewdevDep to 13.16.1 (peer-dep range unchanged). - Refactored minified inline
onload/onerrorscript handlers into named functions for readability.
📦 Package
- No public API changes
- No breaking changes
- Package size unchanged: 10.6 kB tarball / 37.6 kB unpacked
Full Changelog: v2.2.0...v2.3.0