@hcaptcha/react-hcaptcha 1.8.0 → 1.9.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 CHANGED
@@ -138,6 +138,7 @@ return <HCaptcha ref={captchaRef} onLoad={onLoad} sitekey={sitekey} {...props} /
138
138
  |`imghost`|String|No|`-`|See enterprise docs.|
139
139
  |`reportapi`|String|No|`-`|See enterprise docs.|
140
140
  |`sentry`|String|No|`-`|See enterprise docs.|
141
+ | `cleanup` | Boolean | No | `true` | Remove script tag after setup.|
141
142
  |`custom`|Boolean|No|`-`|See enterprise docs.|
142
143
  |`loadAsync`|Boolean|No|`true`|Set if the script should be loaded asynchronously.|
143
144
  |`scriptLocation`|Element|No|`document.head`| Location of where to append the script tag. Make sure to add it to an area that will persist to prevent loading multiple times in the same document view. Note: If `null` is provided, the `document.head` will be used.|
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.breadcrumbMessages = exports.scopeTag = void 0;
7
+ var scopeTag = {
8
+ key: 'source',
9
+ value: '@hCaptcha/react'
10
+ };
11
+ exports.scopeTag = scopeTag;
12
+ var breadcrumbMessages = {
13
+ mounted: 'hCaptcha component mounted',
14
+ expired: 'hCaptcha expired',
15
+ unmounted: 'hCaptcha component unmounted',
16
+ reset: 'hCaptcha reset',
17
+ removed: 'hCaptcha removed'
18
+ };
19
+ exports.breadcrumbMessages = breadcrumbMessages;
@@ -0,0 +1,11 @@
1
+ export var scopeTag = {
2
+ key: 'source',
3
+ value: '@hCaptcha/react'
4
+ };
5
+ export var breadcrumbMessages = {
6
+ mounted: 'hCaptcha component mounted',
7
+ expired: 'hCaptcha expired',
8
+ unmounted: 'hCaptcha component unmounted',
9
+ reset: 'hCaptcha reset',
10
+ removed: 'hCaptcha removed'
11
+ };
package/dist/esm/index.js CHANGED
@@ -1,79 +1,30 @@
1
1
  import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
2
2
  import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
3
3
  import * as React from 'react';
4
- import { generateQuery, getFrame, getMountElement } from "./utils.js";
5
- var SCRIPT_ID = 'hcaptcha-api-script-id';
6
- var HCAPTCHA_LOAD_FN_NAME = 'hcaptchaOnLoad'; // Prevent loading API script multiple times
7
-
8
- var scripts = []; // Generate hCaptcha API script
9
-
10
- var mountCaptchaScript = function mountCaptchaScript(params) {
11
- if (params === void 0) {
12
- params = {};
13
- }
14
-
15
- var element = getMountElement(params.scriptLocation);
16
- delete params.scriptLocation;
17
- var frame = getFrame(element);
18
- var script = scripts.find(function (_ref) {
19
- var scope = _ref.scope;
20
- return scope === frame.window;
21
- });
22
-
23
- if (frame.document.getElementById(SCRIPT_ID) && script) {
24
- // API was already requested
25
- return script.promise;
26
- }
27
-
28
- var promise = new Promise(function (resolve, reject) {
29
- // Create global onload callback
30
- frame.window[HCAPTCHA_LOAD_FN_NAME] = resolve;
31
- var domain = params.apihost || "https://js.hcaptcha.com";
32
- delete params.apihost;
33
- var script = frame.document.createElement("script");
34
- script.id = SCRIPT_ID;
35
- script.src = domain + "/1/api.js?render=explicit&onload=" + HCAPTCHA_LOAD_FN_NAME;
36
- script.async = params.loadAsync !== undefined ? params.loadAsync : true;
37
- delete params.loadAsync;
38
-
39
- script.onerror = function (event) {
40
- return reject('script-error');
41
- };
42
-
43
- var query = generateQuery(params);
44
- script.src += query !== "" ? "&" + query : "";
45
- element.appendChild(script);
46
- });
47
- scripts.push({
48
- promise: promise,
49
- scope: frame.window
50
- });
51
- return promise;
52
- };
53
-
4
+ import { hCaptchaLoader, initSentry } from '@hcaptcha/loader';
5
+ import { getFrame, getMountElement } from './utils.js';
6
+ import { breadcrumbMessages, scopeTag } from "./constants";
54
7
  var HCaptcha = /*#__PURE__*/function (_React$Component) {
55
8
  _inheritsLoose(HCaptcha, _React$Component);
56
-
57
9
  function HCaptcha(props) {
58
10
  var _this;
59
-
60
11
  _this = _React$Component.call(this, props) || this;
61
- var element = getMountElement(_this.props.scriptLocation);
62
- var frame = getFrame(element);
12
+
63
13
  /**
64
14
  * Internal reference to track hCaptcha API
65
15
  *
66
16
  * Required as window is relative to initialization in application
67
17
  * not where the script and iFrames have been loaded.
68
18
  */
19
+ _this._hcaptcha = undefined;
69
20
 
70
- _this._hcaptcha = frame.window.hcaptcha || undefined; // API Methods
71
-
21
+ // API Methods
72
22
  _this.renderCaptcha = _this.renderCaptcha.bind(_assertThisInitialized(_this));
73
23
  _this.resetCaptcha = _this.resetCaptcha.bind(_assertThisInitialized(_this));
74
24
  _this.removeCaptcha = _this.removeCaptcha.bind(_assertThisInitialized(_this));
75
- _this.isReady = _this.isReady.bind(_assertThisInitialized(_this)); // Event Handlers
25
+ _this.isReady = _this.isReady.bind(_assertThisInitialized(_this));
76
26
 
27
+ // Event Handlers
77
28
  _this.loadCaptcha = _this.loadCaptcha.bind(_assertThisInitialized(_this));
78
29
  _this.handleOnLoad = _this.handleOnLoad.bind(_assertThisInitialized(_this));
79
30
  _this.handleSubmit = _this.handleSubmit.bind(_assertThisInitialized(_this));
@@ -82,112 +33,122 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
82
33
  _this.handleOpen = _this.handleOpen.bind(_assertThisInitialized(_this));
83
34
  _this.handleClose = _this.handleClose.bind(_assertThisInitialized(_this));
84
35
  _this.handleChallengeExpired = _this.handleChallengeExpired.bind(_assertThisInitialized(_this));
85
- var isApiReady = typeof _this._hcaptcha !== 'undefined';
86
36
  _this.ref = /*#__PURE__*/React.createRef();
87
37
  _this.apiScriptRequested = false;
38
+ _this.sentryHub = null;
88
39
  _this.state = {
89
- isApiReady: isApiReady,
40
+ isApiReady: false,
90
41
  isRemoved: false,
91
42
  elementId: props.id,
92
43
  captchaId: ''
93
44
  };
94
45
  return _this;
95
46
  }
96
-
97
47
  var _proto = HCaptcha.prototype;
98
-
99
48
  _proto.componentDidMount = function componentDidMount() {
49
+ var _this2 = this;
100
50
  // Once captcha is mounted intialize hCaptcha - hCaptcha
101
- var isApiReady = this.state.isApiReady;
51
+ var element = getMountElement(this.props.scriptLocation);
52
+ var frame = getFrame(element);
53
+ this._hcaptcha = frame.window.hcaptcha || undefined;
54
+ var isApiReady = typeof this._hcaptcha !== 'undefined';
55
+ this.sentryHub = initSentry(this.props.sentry, scopeTag);
56
+ this.sentryHub.addBreadcrumb({
57
+ category: scopeTag.value,
58
+ message: breadcrumbMessages.mounted
59
+ });
60
+
102
61
  /*
103
62
  * Check if hCaptcha has already been loaded,
104
63
  * If Yes, render the captcha
105
64
  * If No, create script tag and wait to render the captcha
106
65
  */
107
-
108
66
  if (isApiReady) {
109
- this.renderCaptcha();
67
+ this.setState({
68
+ isApiReady: true
69
+ }, function () {
70
+ _this2.renderCaptcha();
71
+ });
110
72
  return;
111
73
  }
112
-
113
74
  this.loadCaptcha();
114
75
  };
115
-
116
76
  _proto.componentWillUnmount = function componentWillUnmount() {
117
77
  var captchaId = this.state.captchaId;
118
78
  var hcaptcha = this._hcaptcha;
119
-
120
79
  if (!this.isReady()) {
121
80
  return;
122
- } // Reset any stored variables / timers when unmounting
123
-
81
+ }
124
82
 
83
+ // Reset any stored variables / timers when unmounting
125
84
  hcaptcha.reset(captchaId);
126
85
  hcaptcha.remove(captchaId);
86
+ this.sentryHub.addBreadcrumb({
87
+ category: scopeTag.value,
88
+ message: breadcrumbMessages.unmounted
89
+ });
127
90
  };
128
-
129
91
  _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) {
130
92
  // Prevent component re-rendering when these internal state variables are updated
131
93
  if (this.state.isApiReady !== nextState.isApiReady || this.state.isRemoved !== nextState.isRemoved) {
132
94
  return false;
133
95
  }
134
-
135
96
  return true;
136
97
  };
137
-
138
98
  _proto.componentDidUpdate = function componentDidUpdate(prevProps) {
139
- var _this2 = this;
140
-
99
+ var _this3 = this;
141
100
  // Prop Keys that could change
142
- var keys = ['sitekey', 'size', 'theme', 'tabindex', 'languageOverride', 'endpoint']; // See if any props changed during component update
143
-
101
+ var keys = ['sitekey', 'size', 'theme', 'tabindex', 'languageOverride', 'endpoint'];
102
+ // See if any props changed during component update
144
103
  var match = keys.every(function (key) {
145
- return prevProps[key] === _this2.props[key];
146
- }); // If they have changed, remove current captcha and render a new one
104
+ return prevProps[key] === _this3.props[key];
105
+ });
147
106
 
107
+ // If they have changed, remove current captcha and render a new one
148
108
  if (!match) {
149
109
  this.removeCaptcha(function () {
150
- _this2.renderCaptcha();
110
+ _this3.renderCaptcha();
151
111
  });
152
112
  }
153
113
  };
154
-
155
114
  _proto.loadCaptcha = function loadCaptcha() {
156
115
  if (this.apiScriptRequested) {
157
116
  return;
158
117
  }
159
-
160
118
  var _this$props = this.props,
161
- apihost = _this$props.apihost,
162
- assethost = _this$props.assethost,
163
- endpoint = _this$props.endpoint,
164
- host = _this$props.host,
165
- imghost = _this$props.imghost,
166
- hl = _this$props.languageOverride,
167
- reCaptchaCompat = _this$props.reCaptchaCompat,
168
- reportapi = _this$props.reportapi,
169
- sentry = _this$props.sentry,
170
- custom = _this$props.custom,
171
- loadAsync = _this$props.loadAsync,
172
- scriptLocation = _this$props.scriptLocation;
119
+ apihost = _this$props.apihost,
120
+ assethost = _this$props.assethost,
121
+ endpoint = _this$props.endpoint,
122
+ host = _this$props.host,
123
+ imghost = _this$props.imghost,
124
+ hl = _this$props.languageOverride,
125
+ reCaptchaCompat = _this$props.reCaptchaCompat,
126
+ reportapi = _this$props.reportapi,
127
+ sentry = _this$props.sentry,
128
+ custom = _this$props.custom,
129
+ loadAsync = _this$props.loadAsync,
130
+ scriptLocation = _this$props.scriptLocation,
131
+ _this$props$cleanup = _this$props.cleanup,
132
+ cleanup = _this$props$cleanup === void 0 ? true : _this$props$cleanup;
173
133
  var mountParams = {
134
+ render: 'explicit',
174
135
  apihost: apihost,
175
136
  assethost: assethost,
176
137
  endpoint: endpoint,
177
138
  hl: hl,
178
139
  host: host,
179
140
  imghost: imghost,
180
- recaptchacompat: reCaptchaCompat === false ? "off" : null,
141
+ recaptchacompat: reCaptchaCompat === false ? 'off' : null,
181
142
  reportapi: reportapi,
182
143
  sentry: sentry,
183
144
  custom: custom,
184
145
  loadAsync: loadAsync,
185
- scriptLocation: scriptLocation
146
+ scriptLocation: scriptLocation,
147
+ cleanup: cleanup
186
148
  };
187
- mountCaptchaScript(mountParams).then(this.handleOnLoad)["catch"](this.handleError);
149
+ hCaptchaLoader(mountParams).then(this.handleOnLoad, this.handleError)["catch"](this.handleError);
188
150
  this.apiScriptRequested = true;
189
151
  };
190
-
191
152
  _proto.renderCaptcha = function renderCaptcha(onReady) {
192
153
  var isApiReady = this.state.isApiReady;
193
154
  if (!isApiReady) return;
@@ -202,8 +163,8 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
202
163
  hl: this.props.hl || this.props.languageOverride,
203
164
  languageOverride: undefined
204
165
  });
205
- var hcaptcha = this._hcaptcha; //Render hCaptcha widget and provide necessary callbacks - hCaptcha
206
-
166
+ var hcaptcha = this._hcaptcha;
167
+ //Render hCaptcha widget and provide necessary callbacks - hCaptcha
207
168
  var captchaId = hcaptcha.render(this.ref.current, renderParams);
208
169
  this.setState({
209
170
  isRemoved: false,
@@ -212,169 +173,154 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
212
173
  onReady && onReady();
213
174
  });
214
175
  };
215
-
216
176
  _proto.resetCaptcha = function resetCaptcha() {
217
177
  var captchaId = this.state.captchaId;
218
178
  var hcaptcha = this._hcaptcha;
219
-
220
179
  if (!this.isReady()) {
221
180
  return;
222
- } // Reset captcha state, removes stored token and unticks checkbox
223
-
224
-
181
+ }
182
+ // Reset captcha state, removes stored token and unticks checkbox
225
183
  hcaptcha.reset(captchaId);
184
+ this.sentryHub.addBreadcrumb({
185
+ category: scopeTag.value,
186
+ message: breadcrumbMessages.reset
187
+ });
226
188
  };
227
-
228
189
  _proto.removeCaptcha = function removeCaptcha(callback) {
229
190
  var captchaId = this.state.captchaId;
230
191
  var hcaptcha = this._hcaptcha;
231
-
232
192
  if (!this.isReady()) {
233
193
  return;
234
194
  }
235
-
236
195
  this.setState({
237
196
  isRemoved: true
238
197
  }, function () {
239
198
  hcaptcha.remove(captchaId);
240
199
  callback && callback();
241
200
  });
201
+ this.sentryHub.addBreadcrumb({
202
+ category: scopeTag.value,
203
+ message: breadcrumbMessages.removed
204
+ });
242
205
  };
243
-
244
206
  _proto.handleOnLoad = function handleOnLoad() {
245
- var _this3 = this;
246
-
207
+ var _this4 = this;
247
208
  this.setState({
248
209
  isApiReady: true
249
210
  }, function () {
250
- var element = getMountElement(_this3.props.scriptLocation);
251
- var frame = getFrame(element);
252
- _this3._hcaptcha = frame.window.hcaptcha; // render captcha and wait for captcha id
253
-
254
- _this3.renderCaptcha(function () {
255
- // trigger onLoad if it exists
256
- var onLoad = _this3.props.onLoad;
257
- if (onLoad) onLoad();
258
- });
211
+ try {
212
+ var element = getMountElement(_this4.props.scriptLocation);
213
+ var frame = getFrame(element);
214
+ _this4._hcaptcha = frame.window.hcaptcha;
215
+
216
+ // render captcha and wait for captcha id
217
+ _this4.renderCaptcha(function () {
218
+ // trigger onLoad if it exists
219
+ var onLoad = _this4.props.onLoad;
220
+ if (onLoad) onLoad();
221
+ });
222
+ } catch (error) {
223
+ _this4.sentryHub.captureException(error);
224
+ }
259
225
  });
260
226
  };
261
-
262
227
  _proto.handleSubmit = function handleSubmit(event) {
263
228
  var onVerify = this.props.onVerify;
264
229
  var _this$state = this.state,
265
- isRemoved = _this$state.isRemoved,
266
- captchaId = _this$state.captchaId;
230
+ isRemoved = _this$state.isRemoved,
231
+ captchaId = _this$state.captchaId;
267
232
  var hcaptcha = this._hcaptcha;
268
233
  if (typeof hcaptcha === 'undefined' || isRemoved) return;
269
234
  var token = hcaptcha.getResponse(captchaId); //Get response token from hCaptcha widget
270
-
271
235
  var ekey = hcaptcha.getRespKey(captchaId); //Get current challenge session id from hCaptcha widget
272
-
273
236
  if (onVerify) onVerify(token, ekey); //Dispatch event to verify user response
274
237
  };
275
-
276
238
  _proto.handleExpire = function handleExpire() {
277
239
  var onExpire = this.props.onExpire;
278
240
  var captchaId = this.state.captchaId;
279
241
  var hcaptcha = this._hcaptcha;
280
-
281
242
  if (!this.isReady()) {
282
243
  return;
283
244
  }
284
-
285
245
  hcaptcha.reset(captchaId); // If hCaptcha runs into error, reset captcha - hCaptcha
286
246
 
287
247
  if (onExpire) onExpire();
248
+ this.sentryHub.addBreadcrumb({
249
+ category: scopeTag.value,
250
+ message: breadcrumbMessages.expired
251
+ });
288
252
  };
289
-
290
253
  _proto.handleError = function handleError(event) {
291
254
  var onError = this.props.onError;
292
255
  var captchaId = this.state.captchaId;
293
256
  var hcaptcha = this._hcaptcha;
294
-
295
257
  if (this.isReady()) {
296
258
  // If hCaptcha runs into error, reset captcha - hCaptcha
297
259
  hcaptcha.reset(captchaId);
298
260
  }
299
-
300
261
  if (onError) onError(event);
301
262
  };
302
-
303
263
  _proto.isReady = function isReady() {
304
264
  var _this$state2 = this.state,
305
- isApiReady = _this$state2.isApiReady,
306
- isRemoved = _this$state2.isRemoved;
265
+ isApiReady = _this$state2.isApiReady,
266
+ isRemoved = _this$state2.isRemoved;
307
267
  return isApiReady && !isRemoved;
308
268
  };
309
-
310
269
  _proto.handleOpen = function handleOpen() {
311
270
  if (!this.isReady() || !this.props.onOpen) {
312
271
  return;
313
272
  }
314
-
315
273
  this.props.onOpen();
316
274
  };
317
-
318
275
  _proto.handleClose = function handleClose() {
319
276
  if (!this.isReady() || !this.props.onClose) {
320
277
  return;
321
278
  }
322
-
323
279
  this.props.onClose();
324
280
  };
325
-
326
281
  _proto.handleChallengeExpired = function handleChallengeExpired() {
327
282
  if (!this.isReady() || !this.props.onChalExpired) {
328
283
  return;
329
284
  }
330
-
331
285
  this.props.onChalExpired();
332
286
  };
333
-
334
287
  _proto.execute = function execute(opts) {
335
288
  if (opts === void 0) {
336
289
  opts = null;
337
290
  }
338
-
339
- var captchaId = this.state.captchaId;
340
- var hcaptcha = this._hcaptcha;
341
-
342
- if (!this.isReady()) {
343
- return;
344
- }
345
-
346
- if (opts && typeof opts !== "object") {
347
- opts = null;
291
+ try {
292
+ var captchaId = this.state.captchaId;
293
+ var hcaptcha = this._hcaptcha;
294
+ if (!this.isReady()) {
295
+ return;
296
+ }
297
+ if (opts && typeof opts !== "object") {
298
+ opts = null;
299
+ }
300
+ return hcaptcha.execute(captchaId, opts);
301
+ } catch (error) {
302
+ this.sentryHub.captureException(error);
348
303
  }
349
-
350
- return hcaptcha.execute(captchaId, opts);
351
304
  };
352
-
353
305
  _proto.setData = function setData(data) {
354
306
  var captchaId = this.state.captchaId;
355
307
  var hcaptcha = this._hcaptcha;
356
-
357
308
  if (!this.isReady()) {
358
309
  return;
359
310
  }
360
-
361
311
  if (data && typeof data !== "object") {
362
312
  data = null;
363
313
  }
364
-
365
314
  hcaptcha.setData(captchaId, data);
366
315
  };
367
-
368
316
  _proto.getResponse = function getResponse() {
369
317
  var hcaptcha = this._hcaptcha;
370
318
  return hcaptcha.getResponse(this.state.captchaId);
371
319
  };
372
-
373
320
  _proto.getRespKey = function getRespKey() {
374
321
  var hcaptcha = this._hcaptcha;
375
322
  return hcaptcha.getRespKey(this.state.captchaId);
376
323
  };
377
-
378
324
  _proto.render = function render() {
379
325
  var elementId = this.state.elementId;
380
326
  return /*#__PURE__*/React.createElement("div", {
@@ -382,8 +328,6 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
382
328
  id: elementId
383
329
  });
384
330
  };
385
-
386
331
  return HCaptcha;
387
332
  }(React.Component);
388
-
389
333
  export default HCaptcha;
package/dist/esm/utils.js CHANGED
@@ -1,28 +1,12 @@
1
- function generateQuery(params) {
2
- return Object.entries(params).filter(function (_ref) {
3
- var key = _ref[0],
4
- value = _ref[1];
5
- return value || value === false;
6
- }).map(function (_ref2) {
7
- var key = _ref2[0],
8
- value = _ref2[1];
9
- return encodeURIComponent(key) + "=" + encodeURIComponent(value);
10
- }).join("&");
11
- }
12
-
13
- ;
14
-
15
1
  function getFrame(element) {
16
2
  var doc = element && element.ownerDocument || document;
17
- var win = doc.defaultView || doc.parentWindow;
3
+ var win = doc.defaultView || doc.parentWindow || window;
18
4
  return {
19
5
  document: doc,
20
6
  window: win
21
7
  };
22
8
  }
23
-
24
9
  function getMountElement(element) {
25
10
  return element || document.head;
26
11
  }
27
-
28
- export { generateQuery, getFrame, getMountElement };
12
+ export { getFrame, getMountElement };