@hcaptcha/react-hcaptcha 1.13.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/esm/index.js +88 -27
- package/dist/index.js +90 -27
- package/package.json +2 -2
- package/src/index.js +99 -25
package/README.md
CHANGED
|
@@ -154,6 +154,7 @@ return <HCaptcha ref={captchaRef} onLoad={onLoad} sitekey={sitekey} {...props} /
|
|
|
154
154
|
|`onVerify`|`token, eKey`|When challenge is completed. The response `token` and an `eKey` (session id) are passed along.|
|
|
155
155
|
|`onExpire`|-|When the current token expires.|
|
|
156
156
|
|`onLoad`|-|When the hCaptcha API loads.|
|
|
157
|
+
|`onReady`|-|When the hCaptcha is ready to be used.|
|
|
157
158
|
|`onOpen`|-|When the user display of a challenge starts.|
|
|
158
159
|
|`onClose`|-|When the user dismisses a challenge.|
|
|
159
160
|
|`onChalExpired`|-|When the user display of a challenge times out with no answer.|
|
package/dist/esm/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
|
|
2
1
|
import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
|
|
3
2
|
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
|
|
4
|
-
var _excluded = ["userJourneys"];
|
|
5
3
|
import * as React from 'react';
|
|
6
4
|
import { hCaptchaLoader } from '@hcaptcha/loader';
|
|
7
5
|
import { getFrame, getMountElement } from './utils.js';
|
|
@@ -39,6 +37,12 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
39
37
|
_this.apiScriptRequested = false;
|
|
40
38
|
_this.sentryHub = null;
|
|
41
39
|
_this.captchaId = '';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Tracks the currently pending async execute() promise.
|
|
43
|
+
* Stores { resolve, reject } so we can cancel on unmount/errors/etc.
|
|
44
|
+
*/
|
|
45
|
+
_this._pendingExecute = null;
|
|
42
46
|
_this.state = {
|
|
43
47
|
isApiReady: false,
|
|
44
48
|
isRemoved: false,
|
|
@@ -73,6 +77,7 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
73
77
|
_proto.componentWillUnmount = function componentWillUnmount() {
|
|
74
78
|
var hcaptcha = this._hcaptcha;
|
|
75
79
|
var captchaId = this.captchaId;
|
|
80
|
+
this._cancelPendingExecute('react-component-unmounted');
|
|
76
81
|
if (!this.isReady()) {
|
|
77
82
|
return;
|
|
78
83
|
}
|
|
@@ -143,7 +148,7 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
143
148
|
scriptSource: scriptSource,
|
|
144
149
|
secureApi: secureApi,
|
|
145
150
|
cleanup: cleanup,
|
|
146
|
-
userJourneys:
|
|
151
|
+
uj: userJourneys !== undefined ? userJourneys : false
|
|
147
152
|
};
|
|
148
153
|
hCaptchaLoader(mountParams).then(this.handleOnLoad, this.handleError)["catch"](this.handleError);
|
|
149
154
|
this.apiScriptRequested = true;
|
|
@@ -158,13 +163,6 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
158
163
|
// • API is not ready
|
|
159
164
|
// • Component has already been mounted
|
|
160
165
|
if (!isApiReady || captchaId) return;
|
|
161
|
-
|
|
162
|
-
// It is needed to pass only the props that hCaptcha supports
|
|
163
|
-
// React are able to receive userJourneys as prop but hCaptcha not
|
|
164
|
-
// hcaptcha expects to have only "uj" parameter to enable user journeys
|
|
165
|
-
var _this$props2 = this.props,
|
|
166
|
-
userJourneys = _this$props2.userJourneys,
|
|
167
|
-
basicProps = _objectWithoutPropertiesLoose(_this$props2, _excluded);
|
|
168
166
|
var renderParams = Object.assign({
|
|
169
167
|
"open-callback": this.handleOpen,
|
|
170
168
|
"close-callback": this.handleClose,
|
|
@@ -172,10 +170,9 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
172
170
|
"chalexpired-callback": this.handleChallengeExpired,
|
|
173
171
|
"expired-callback": this.handleExpire,
|
|
174
172
|
"callback": this.handleSubmit
|
|
175
|
-
},
|
|
173
|
+
}, this.props, {
|
|
176
174
|
hl: this.props.hl || this.props.languageOverride,
|
|
177
|
-
languageOverride: undefined
|
|
178
|
-
uj: userJourneys !== undefined ? userJourneys : false
|
|
175
|
+
languageOverride: undefined
|
|
179
176
|
});
|
|
180
177
|
var hcaptcha = this._hcaptcha;
|
|
181
178
|
//Render hCaptcha widget and provide necessary callbacks - hCaptcha
|
|
@@ -195,13 +192,16 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
195
192
|
if (!this.isReady()) {
|
|
196
193
|
return;
|
|
197
194
|
}
|
|
195
|
+
|
|
198
196
|
// Reset captcha state, removes stored token and unticks checkbox
|
|
199
197
|
hcaptcha.reset(captchaId);
|
|
198
|
+
this._cancelPendingExecute('hcaptcha-reset');
|
|
200
199
|
};
|
|
201
200
|
_proto.removeCaptcha = function removeCaptcha(callback) {
|
|
202
201
|
var _this5 = this;
|
|
203
202
|
var hcaptcha = this._hcaptcha;
|
|
204
203
|
var captchaId = this.captchaId;
|
|
204
|
+
this._cancelPendingExecute('hcaptcha-removed');
|
|
205
205
|
if (!this.isReady()) {
|
|
206
206
|
return;
|
|
207
207
|
}
|
|
@@ -267,6 +267,20 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
267
267
|
isApiReady = _this$state.isApiReady,
|
|
268
268
|
isRemoved = _this$state.isRemoved;
|
|
269
269
|
return isApiReady && !isRemoved;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Cancel any pending async execute() promise
|
|
274
|
+
* Called when the component unmounts, errors occur, resets, etc.
|
|
275
|
+
*/;
|
|
276
|
+
_proto._cancelPendingExecute = function _cancelPendingExecute(reason) {
|
|
277
|
+
if (!this._pendingExecute) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
var pending = this._pendingExecute;
|
|
281
|
+
this._pendingExecute = null;
|
|
282
|
+
var error = new Error(reason);
|
|
283
|
+
pending.reject(error);
|
|
270
284
|
};
|
|
271
285
|
_proto.handleOpen = function handleOpen() {
|
|
272
286
|
if (!this.isReady() || !this.props.onOpen) {
|
|
@@ -295,25 +309,71 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
295
309
|
try {
|
|
296
310
|
var hcaptcha = this._hcaptcha;
|
|
297
311
|
var captchaId = this.captchaId;
|
|
312
|
+
|
|
313
|
+
// Is an async execute and there's already 1 pending, cancel the old one.
|
|
314
|
+
if (opts && opts.async && this._pendingExecute) {
|
|
315
|
+
this._cancelPendingExecute('hcaptcha-execute-replaced');
|
|
316
|
+
}
|
|
298
317
|
if (!this.isReady()) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
318
|
+
if (opts && opts.async) {
|
|
319
|
+
return new Promise(function (resolve, reject) {
|
|
320
|
+
_this7._pendingExecute = {
|
|
321
|
+
resolve: resolve,
|
|
322
|
+
reject: reject
|
|
323
|
+
};
|
|
324
|
+
_this7._onReady = function (id) {
|
|
325
|
+
if (!_this7._pendingExecute) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
try {
|
|
329
|
+
var _result = hcaptcha.execute(id, opts);
|
|
330
|
+
if (_result && typeof _result.then === 'function') {
|
|
331
|
+
_result.then(function (val) {
|
|
332
|
+
_this7._pendingExecute = null;
|
|
333
|
+
resolve(val);
|
|
334
|
+
})["catch"](function (err) {
|
|
335
|
+
_this7._pendingExecute = null;
|
|
336
|
+
reject(err);
|
|
337
|
+
});
|
|
338
|
+
} else {
|
|
339
|
+
_this7._pendingExecute = null;
|
|
340
|
+
reject(new Error('hcaptcha-execute-no-promise'));
|
|
341
|
+
}
|
|
342
|
+
} catch (e) {
|
|
343
|
+
_this7._pendingExecute = null;
|
|
344
|
+
reject(e);
|
|
308
345
|
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
|
|
346
|
+
};
|
|
347
|
+
});
|
|
348
|
+
} else {
|
|
349
|
+
// Non-async: don't return a promise.
|
|
350
|
+
this._onReady = function (id) {
|
|
351
|
+
hcaptcha.execute(id, opts);
|
|
352
|
+
};
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// hCaptcha is ready, execute directly.
|
|
358
|
+
var result = hcaptcha.execute(captchaId, opts);
|
|
359
|
+
|
|
360
|
+
// If it's async execute, track it.
|
|
361
|
+
if (opts && opts.async && result && typeof result.then === 'function') {
|
|
362
|
+
return new Promise(function (resolve, reject) {
|
|
363
|
+
_this7._pendingExecute = {
|
|
364
|
+
resolve: resolve,
|
|
365
|
+
reject: reject
|
|
312
366
|
};
|
|
367
|
+
result.then(function (val) {
|
|
368
|
+
_this7._pendingExecute = null;
|
|
369
|
+
resolve(val);
|
|
370
|
+
})["catch"](function (err) {
|
|
371
|
+
_this7._pendingExecute = null;
|
|
372
|
+
reject(err);
|
|
373
|
+
});
|
|
313
374
|
});
|
|
314
|
-
return (_opts = opts) != null && _opts.async ? onReady : null;
|
|
315
375
|
}
|
|
316
|
-
return
|
|
376
|
+
return result;
|
|
317
377
|
} catch (error) {
|
|
318
378
|
if (opts && opts.async) {
|
|
319
379
|
return Promise.reject(error);
|
|
@@ -324,6 +384,7 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
324
384
|
_proto.close = function close() {
|
|
325
385
|
var hcaptcha = this._hcaptcha;
|
|
326
386
|
var captchaId = this.captchaId;
|
|
387
|
+
this._cancelPendingExecute('hcaptcha-closed');
|
|
327
388
|
if (!this.isReady()) {
|
|
328
389
|
return;
|
|
329
390
|
}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
});
|
|
8
8
|
exports["default"] = void 0;
|
|
9
9
|
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
10
|
-
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
11
10
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
12
11
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
13
12
|
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
@@ -17,7 +16,6 @@ var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits
|
|
|
17
16
|
var React = _interopRequireWildcard(require("react"));
|
|
18
17
|
var _loader = require("@hcaptcha/loader");
|
|
19
18
|
var _utils = require("./utils.js");
|
|
20
|
-
var _excluded = ["userJourneys"];
|
|
21
19
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
22
20
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof3(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
|
|
23
21
|
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); }
|
|
@@ -57,6 +55,12 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
57
55
|
_this.apiScriptRequested = false;
|
|
58
56
|
_this.sentryHub = null;
|
|
59
57
|
_this.captchaId = '';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Tracks the currently pending async execute() promise.
|
|
61
|
+
* Stores { resolve, reject } so we can cancel on unmount/errors/etc.
|
|
62
|
+
*/
|
|
63
|
+
_this._pendingExecute = null;
|
|
60
64
|
_this.state = {
|
|
61
65
|
isApiReady: false,
|
|
62
66
|
isRemoved: false,
|
|
@@ -94,6 +98,7 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
94
98
|
value: function componentWillUnmount() {
|
|
95
99
|
var hcaptcha = this._hcaptcha;
|
|
96
100
|
var captchaId = this.captchaId;
|
|
101
|
+
this._cancelPendingExecute('react-component-unmounted');
|
|
97
102
|
if (!this.isReady()) {
|
|
98
103
|
return;
|
|
99
104
|
}
|
|
@@ -170,7 +175,7 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
170
175
|
scriptSource: scriptSource,
|
|
171
176
|
secureApi: secureApi,
|
|
172
177
|
cleanup: cleanup,
|
|
173
|
-
userJourneys:
|
|
178
|
+
uj: userJourneys !== undefined ? userJourneys : false
|
|
174
179
|
};
|
|
175
180
|
(0, _loader.hCaptchaLoader)(mountParams).then(this.handleOnLoad, this.handleError)["catch"](this.handleError);
|
|
176
181
|
this.apiScriptRequested = true;
|
|
@@ -187,13 +192,6 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
187
192
|
// • API is not ready
|
|
188
193
|
// • Component has already been mounted
|
|
189
194
|
if (!isApiReady || captchaId) return;
|
|
190
|
-
|
|
191
|
-
// It is needed to pass only the props that hCaptcha supports
|
|
192
|
-
// React are able to receive userJourneys as prop but hCaptcha not
|
|
193
|
-
// hcaptcha expects to have only "uj" parameter to enable user journeys
|
|
194
|
-
var _this$props2 = this.props,
|
|
195
|
-
userJourneys = _this$props2.userJourneys,
|
|
196
|
-
basicProps = (0, _objectWithoutProperties2["default"])(_this$props2, _excluded);
|
|
197
195
|
var renderParams = Object.assign({
|
|
198
196
|
"open-callback": this.handleOpen,
|
|
199
197
|
"close-callback": this.handleClose,
|
|
@@ -201,10 +199,9 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
201
199
|
"chalexpired-callback": this.handleChallengeExpired,
|
|
202
200
|
"expired-callback": this.handleExpire,
|
|
203
201
|
"callback": this.handleSubmit
|
|
204
|
-
},
|
|
202
|
+
}, this.props, {
|
|
205
203
|
hl: this.props.hl || this.props.languageOverride,
|
|
206
|
-
languageOverride: undefined
|
|
207
|
-
uj: userJourneys !== undefined ? userJourneys : false
|
|
204
|
+
languageOverride: undefined
|
|
208
205
|
});
|
|
209
206
|
var hcaptcha = this._hcaptcha;
|
|
210
207
|
//Render hCaptcha widget and provide necessary callbacks - hCaptcha
|
|
@@ -226,8 +223,10 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
226
223
|
if (!this.isReady()) {
|
|
227
224
|
return;
|
|
228
225
|
}
|
|
226
|
+
|
|
229
227
|
// Reset captcha state, removes stored token and unticks checkbox
|
|
230
228
|
hcaptcha.reset(captchaId);
|
|
229
|
+
this._cancelPendingExecute('hcaptcha-reset');
|
|
231
230
|
}
|
|
232
231
|
}, {
|
|
233
232
|
key: "removeCaptcha",
|
|
@@ -235,6 +234,7 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
235
234
|
var _this5 = this;
|
|
236
235
|
var hcaptcha = this._hcaptcha;
|
|
237
236
|
var captchaId = this.captchaId;
|
|
237
|
+
this._cancelPendingExecute('hcaptcha-removed');
|
|
238
238
|
if (!this.isReady()) {
|
|
239
239
|
return;
|
|
240
240
|
}
|
|
@@ -311,6 +311,22 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
311
311
|
isRemoved = _this$state.isRemoved;
|
|
312
312
|
return isApiReady && !isRemoved;
|
|
313
313
|
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Cancel any pending async execute() promise
|
|
317
|
+
* Called when the component unmounts, errors occur, resets, etc.
|
|
318
|
+
*/
|
|
319
|
+
}, {
|
|
320
|
+
key: "_cancelPendingExecute",
|
|
321
|
+
value: function _cancelPendingExecute(reason) {
|
|
322
|
+
if (!this._pendingExecute) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
var pending = this._pendingExecute;
|
|
326
|
+
this._pendingExecute = null;
|
|
327
|
+
var error = new Error(reason);
|
|
328
|
+
pending.reject(error);
|
|
329
|
+
}
|
|
314
330
|
}, {
|
|
315
331
|
key: "handleOpen",
|
|
316
332
|
value: function handleOpen() {
|
|
@@ -344,25 +360,71 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
344
360
|
try {
|
|
345
361
|
var hcaptcha = this._hcaptcha;
|
|
346
362
|
var captchaId = this.captchaId;
|
|
363
|
+
|
|
364
|
+
// Is an async execute and there's already 1 pending, cancel the old one.
|
|
365
|
+
if (opts && opts.async && this._pendingExecute) {
|
|
366
|
+
this._cancelPendingExecute('hcaptcha-execute-replaced');
|
|
367
|
+
}
|
|
347
368
|
if (!this.isReady()) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
369
|
+
if (opts && opts.async) {
|
|
370
|
+
return new Promise(function (resolve, reject) {
|
|
371
|
+
_this7._pendingExecute = {
|
|
372
|
+
resolve: resolve,
|
|
373
|
+
reject: reject
|
|
374
|
+
};
|
|
375
|
+
_this7._onReady = function (id) {
|
|
376
|
+
if (!_this7._pendingExecute) {
|
|
377
|
+
return;
|
|
357
378
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
379
|
+
try {
|
|
380
|
+
var _result = hcaptcha.execute(id, opts);
|
|
381
|
+
if (_result && typeof _result.then === 'function') {
|
|
382
|
+
_result.then(function (val) {
|
|
383
|
+
_this7._pendingExecute = null;
|
|
384
|
+
resolve(val);
|
|
385
|
+
})["catch"](function (err) {
|
|
386
|
+
_this7._pendingExecute = null;
|
|
387
|
+
reject(err);
|
|
388
|
+
});
|
|
389
|
+
} else {
|
|
390
|
+
_this7._pendingExecute = null;
|
|
391
|
+
reject(new Error('hcaptcha-execute-no-promise'));
|
|
392
|
+
}
|
|
393
|
+
} catch (e) {
|
|
394
|
+
_this7._pendingExecute = null;
|
|
395
|
+
reject(e);
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
});
|
|
399
|
+
} else {
|
|
400
|
+
// Non-async: don't return a promise.
|
|
401
|
+
this._onReady = function (id) {
|
|
402
|
+
hcaptcha.execute(id, opts);
|
|
403
|
+
};
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// hCaptcha is ready, execute directly.
|
|
409
|
+
var result = hcaptcha.execute(captchaId, opts);
|
|
410
|
+
|
|
411
|
+
// If it's async execute, track it.
|
|
412
|
+
if (opts && opts.async && result && typeof result.then === 'function') {
|
|
413
|
+
return new Promise(function (resolve, reject) {
|
|
414
|
+
_this7._pendingExecute = {
|
|
415
|
+
resolve: resolve,
|
|
416
|
+
reject: reject
|
|
361
417
|
};
|
|
418
|
+
result.then(function (val) {
|
|
419
|
+
_this7._pendingExecute = null;
|
|
420
|
+
resolve(val);
|
|
421
|
+
})["catch"](function (err) {
|
|
422
|
+
_this7._pendingExecute = null;
|
|
423
|
+
reject(err);
|
|
424
|
+
});
|
|
362
425
|
});
|
|
363
|
-
return (_opts = opts) !== null && _opts !== void 0 && _opts.async ? onReady : null;
|
|
364
426
|
}
|
|
365
|
-
return
|
|
427
|
+
return result;
|
|
366
428
|
} catch (error) {
|
|
367
429
|
if (opts && opts.async) {
|
|
368
430
|
return Promise.reject(error);
|
|
@@ -375,6 +437,7 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
375
437
|
value: function close() {
|
|
376
438
|
var hcaptcha = this._hcaptcha;
|
|
377
439
|
var captchaId = this.captchaId;
|
|
440
|
+
this._cancelPendingExecute('hcaptcha-closed');
|
|
378
441
|
if (!this.isReady()) {
|
|
379
442
|
return;
|
|
380
443
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hcaptcha/react-hcaptcha",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"types": "types/index.d.ts",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -60,6 +60,6 @@
|
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@babel/runtime": "^7.17.9",
|
|
63
|
-
"@hcaptcha/loader": "^2.0
|
|
63
|
+
"@hcaptcha/loader": "^2.2.0"
|
|
64
64
|
}
|
|
65
65
|
}
|
package/src/index.js
CHANGED
|
@@ -38,6 +38,12 @@ class HCaptcha extends React.Component {
|
|
|
38
38
|
this.sentryHub = null;
|
|
39
39
|
this.captchaId = '';
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Tracks the currently pending async execute() promise.
|
|
43
|
+
* Stores { resolve, reject } so we can cancel on unmount/errors/etc.
|
|
44
|
+
*/
|
|
45
|
+
this._pendingExecute = null;
|
|
46
|
+
|
|
41
47
|
this.state = {
|
|
42
48
|
isApiReady: false,
|
|
43
49
|
isRemoved: false,
|
|
@@ -77,6 +83,8 @@ class HCaptcha extends React.Component {
|
|
|
77
83
|
const hcaptcha = this._hcaptcha;
|
|
78
84
|
const captchaId = this.captchaId;
|
|
79
85
|
|
|
86
|
+
this._cancelPendingExecute('react-component-unmounted');
|
|
87
|
+
|
|
80
88
|
if (!this.isReady()) {
|
|
81
89
|
return;
|
|
82
90
|
}
|
|
@@ -132,6 +140,7 @@ class HCaptcha extends React.Component {
|
|
|
132
140
|
cleanup = true,
|
|
133
141
|
userJourneys,
|
|
134
142
|
} = this.props;
|
|
143
|
+
|
|
135
144
|
const mountParams = {
|
|
136
145
|
render: 'explicit',
|
|
137
146
|
apihost,
|
|
@@ -149,9 +158,9 @@ class HCaptcha extends React.Component {
|
|
|
149
158
|
scriptSource,
|
|
150
159
|
secureApi,
|
|
151
160
|
cleanup,
|
|
152
|
-
userJourneys
|
|
161
|
+
uj: userJourneys !== undefined ? userJourneys : false,
|
|
153
162
|
};
|
|
154
|
-
|
|
163
|
+
|
|
155
164
|
hCaptchaLoader(mountParams)
|
|
156
165
|
.then(this.handleOnLoad, this.handleError)
|
|
157
166
|
.catch(this.handleError);
|
|
@@ -168,11 +177,6 @@ class HCaptcha extends React.Component {
|
|
|
168
177
|
// • API is not ready
|
|
169
178
|
// • Component has already been mounted
|
|
170
179
|
if (!isApiReady || captchaId) return;
|
|
171
|
-
|
|
172
|
-
// It is needed to pass only the props that hCaptcha supports
|
|
173
|
-
// React are able to receive userJourneys as prop but hCaptcha not
|
|
174
|
-
// hcaptcha expects to have only "uj" parameter to enable user journeys
|
|
175
|
-
const { userJourneys, ...basicProps } = this.props;
|
|
176
180
|
|
|
177
181
|
const renderParams = Object.assign({
|
|
178
182
|
"open-callback" : this.handleOpen,
|
|
@@ -181,10 +185,9 @@ class HCaptcha extends React.Component {
|
|
|
181
185
|
"chalexpired-callback": this.handleChallengeExpired,
|
|
182
186
|
"expired-callback" : this.handleExpire,
|
|
183
187
|
"callback" : this.handleSubmit,
|
|
184
|
-
},
|
|
188
|
+
}, this.props, {
|
|
185
189
|
hl: this.props.hl || this.props.languageOverride,
|
|
186
|
-
languageOverride: undefined
|
|
187
|
-
uj: userJourneys !== undefined ? userJourneys : false,
|
|
190
|
+
languageOverride: undefined
|
|
188
191
|
});
|
|
189
192
|
|
|
190
193
|
const hcaptcha = this._hcaptcha;
|
|
@@ -206,14 +209,19 @@ class HCaptcha extends React.Component {
|
|
|
206
209
|
if (!this.isReady()) {
|
|
207
210
|
return;
|
|
208
211
|
}
|
|
212
|
+
|
|
209
213
|
// Reset captcha state, removes stored token and unticks checkbox
|
|
210
214
|
hcaptcha.reset(captchaId)
|
|
215
|
+
|
|
216
|
+
this._cancelPendingExecute('hcaptcha-reset');
|
|
211
217
|
}
|
|
212
218
|
|
|
213
219
|
removeCaptcha(callback) {
|
|
214
220
|
const hcaptcha = this._hcaptcha;
|
|
215
221
|
const captchaId = this.captchaId;
|
|
216
222
|
|
|
223
|
+
this._cancelPendingExecute('hcaptcha-removed');
|
|
224
|
+
|
|
217
225
|
if (!this.isReady()) {
|
|
218
226
|
return;
|
|
219
227
|
}
|
|
@@ -222,6 +230,7 @@ class HCaptcha extends React.Component {
|
|
|
222
230
|
this.captchaId = '';
|
|
223
231
|
|
|
224
232
|
hcaptcha.remove(captchaId);
|
|
233
|
+
|
|
225
234
|
callback && callback()
|
|
226
235
|
});
|
|
227
236
|
}
|
|
@@ -290,6 +299,22 @@ class HCaptcha extends React.Component {
|
|
|
290
299
|
return isApiReady && !isRemoved;
|
|
291
300
|
}
|
|
292
301
|
|
|
302
|
+
/**
|
|
303
|
+
* Cancel any pending async execute() promise
|
|
304
|
+
* Called when the component unmounts, errors occur, resets, etc.
|
|
305
|
+
*/
|
|
306
|
+
_cancelPendingExecute(reason) {
|
|
307
|
+
if (!this._pendingExecute) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const pending = this._pendingExecute;
|
|
312
|
+
this._pendingExecute = null;
|
|
313
|
+
|
|
314
|
+
const error = new Error(reason);
|
|
315
|
+
pending.reject(error);
|
|
316
|
+
}
|
|
317
|
+
|
|
293
318
|
handleOpen () {
|
|
294
319
|
if (!this.isReady() || !this.props.onOpen) {
|
|
295
320
|
return;
|
|
@@ -314,7 +339,7 @@ class HCaptcha extends React.Component {
|
|
|
314
339
|
this.props.onChalExpired();
|
|
315
340
|
}
|
|
316
341
|
|
|
317
|
-
execute
|
|
342
|
+
execute(opts = null) {
|
|
318
343
|
|
|
319
344
|
opts = typeof opts === 'object' ? opts : null;
|
|
320
345
|
|
|
@@ -322,28 +347,75 @@ class HCaptcha extends React.Component {
|
|
|
322
347
|
const hcaptcha = this._hcaptcha;
|
|
323
348
|
const captchaId = this.captchaId;
|
|
324
349
|
|
|
350
|
+
// Is an async execute and there's already 1 pending, cancel the old one.
|
|
351
|
+
if (opts && opts.async && this._pendingExecute) {
|
|
352
|
+
this._cancelPendingExecute('hcaptcha-execute-replaced');
|
|
353
|
+
}
|
|
354
|
+
|
|
325
355
|
if (!this.isReady()) {
|
|
326
|
-
|
|
356
|
+
if (opts && opts.async) {
|
|
357
|
+
return new Promise((resolve, reject) => {
|
|
358
|
+
this._pendingExecute = { resolve, reject };
|
|
327
359
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
360
|
+
this._onReady = (id) => {
|
|
361
|
+
if (!this._pendingExecute) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
331
364
|
|
|
332
|
-
|
|
333
|
-
hcaptcha.execute(id, opts)
|
|
334
|
-
|
|
335
|
-
|
|
365
|
+
try {
|
|
366
|
+
const result = hcaptcha.execute(id, opts);
|
|
367
|
+
|
|
368
|
+
if (result && typeof result.then === 'function') {
|
|
369
|
+
result
|
|
370
|
+
.then((val) => {
|
|
371
|
+
this._pendingExecute = null;
|
|
372
|
+
resolve(val);
|
|
373
|
+
})
|
|
374
|
+
.catch((err) => {
|
|
375
|
+
this._pendingExecute = null;
|
|
376
|
+
reject(err);
|
|
377
|
+
});
|
|
378
|
+
} else {
|
|
379
|
+
this._pendingExecute = null;
|
|
380
|
+
reject(new Error('hcaptcha-execute-no-promise'));
|
|
381
|
+
}
|
|
382
|
+
} catch (e) {
|
|
383
|
+
this._pendingExecute = null;
|
|
384
|
+
reject(e);
|
|
336
385
|
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
386
|
+
};
|
|
387
|
+
});
|
|
388
|
+
} else {
|
|
389
|
+
// Non-async: don't return a promise.
|
|
390
|
+
this._onReady = (id) => {
|
|
391
|
+
hcaptcha.execute(id, opts);
|
|
340
392
|
};
|
|
341
|
-
|
|
393
|
+
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
342
397
|
|
|
343
|
-
|
|
398
|
+
// hCaptcha is ready, execute directly.
|
|
399
|
+
const result = hcaptcha.execute(captchaId, opts);
|
|
400
|
+
|
|
401
|
+
// If it's async execute, track it.
|
|
402
|
+
if (opts && opts.async && result && typeof result.then === 'function') {
|
|
403
|
+
return new Promise((resolve, reject) => {
|
|
404
|
+
this._pendingExecute = { resolve, reject };
|
|
405
|
+
|
|
406
|
+
result
|
|
407
|
+
.then((val) => {
|
|
408
|
+
this._pendingExecute = null;
|
|
409
|
+
resolve(val);
|
|
410
|
+
})
|
|
411
|
+
.catch((err) => {
|
|
412
|
+
this._pendingExecute = null;
|
|
413
|
+
reject(err);
|
|
414
|
+
});
|
|
415
|
+
});
|
|
344
416
|
}
|
|
345
417
|
|
|
346
|
-
return
|
|
418
|
+
return result;
|
|
347
419
|
} catch (error) {
|
|
348
420
|
if (opts && opts.async) {
|
|
349
421
|
return Promise.reject(error);
|
|
@@ -356,6 +428,8 @@ class HCaptcha extends React.Component {
|
|
|
356
428
|
const hcaptcha = this._hcaptcha;
|
|
357
429
|
const captchaId = this.captchaId;
|
|
358
430
|
|
|
431
|
+
this._cancelPendingExecute('hcaptcha-closed');
|
|
432
|
+
|
|
359
433
|
if (!this.isReady()) {
|
|
360
434
|
return;
|
|
361
435
|
}
|