@authsignal/browser 0.3.5 → 0.3.7

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/dist/index.js CHANGED
@@ -90,663 +90,125 @@ var AuthsignalWindowMessage;
90
90
  AuthsignalWindowMessage["AUTHSIGNAL_CLOSE_POPUP"] = "AUTHSIGNAL_CLOSE_POPUP";
91
91
  })(AuthsignalWindowMessage || (AuthsignalWindowMessage = {}));
92
92
 
93
- var DEFAULT_WIDTH$1 = 400;
94
- var DEFAULT_HEIGHT = 500;
95
- var WindowHandler = /** @class */ (function () {
96
- function WindowHandler() {
97
- this.windowRef = null;
98
- }
99
- WindowHandler.prototype.show = function (_a) {
100
- var url = _a.url, _b = _a.width, width = _b === void 0 ? DEFAULT_WIDTH$1 : _b, _c = _a.height, height = _c === void 0 ? DEFAULT_HEIGHT : _c;
101
- var windowRef = openWindow({ url: url, width: width, height: height, win: window });
102
- if (!windowRef) {
103
- throw new Error("Window is not initialized");
104
- }
105
- this.windowRef = windowRef;
106
- return windowRef;
107
- };
108
- WindowHandler.prototype.close = function () {
109
- if (!this.windowRef) {
110
- throw new Error("Window is not initialized");
111
- }
112
- this.windowRef.close();
113
- };
114
- return WindowHandler;
115
- }());
116
- function openWindow(_a) {
117
- var url = _a.url, width = _a.width, height = _a.height, win = _a.win;
118
- if (!win.top) {
119
- return null;
120
- }
121
- var y = win.top.outerHeight / 2 + win.top.screenY - height / 2;
122
- var x = win.top.outerWidth / 2 + win.top.screenX - width / 2;
123
- return window.open(url, "", "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=".concat(width, ", height=").concat(height, ", top=").concat(y, ", left=").concat(x));
93
+ /******************************************************************************
94
+ Copyright (c) Microsoft Corporation.
95
+
96
+ Permission to use, copy, modify, and/or distribute this software for any
97
+ purpose with or without fee is hereby granted.
98
+
99
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
100
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
101
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
102
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
103
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
104
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
105
+ PERFORMANCE OF THIS SOFTWARE.
106
+ ***************************************************************************** */
107
+
108
+ function __rest(s, e) {
109
+ var t = {};
110
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
111
+ t[p] = s[p];
112
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
113
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
114
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
115
+ t[p[i]] = s[p[i]];
116
+ }
117
+ return t;
118
+ }
119
+
120
+ function __awaiter(thisArg, _arguments, P, generator) {
121
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
122
+ return new (P || (P = Promise))(function (resolve, reject) {
123
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
124
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
125
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
126
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
127
+ });
128
+ }
129
+
130
+ function __generator(thisArg, body) {
131
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
132
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
133
+ function verb(n) { return function (v) { return step([n, v]); }; }
134
+ function step(op) {
135
+ if (f) throw new TypeError("Generator is already executing.");
136
+ while (_) try {
137
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
138
+ if (y = 0, t) op = [op[0] & 2, t.value];
139
+ switch (op[0]) {
140
+ case 0: case 1: t = op; break;
141
+ case 4: _.label++; return { value: op[1], done: false };
142
+ case 5: _.label++; y = op[1]; op = [0]; continue;
143
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
144
+ default:
145
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
146
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
147
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
148
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
149
+ if (t[2]) _.ops.pop();
150
+ _.trys.pop(); continue;
151
+ }
152
+ op = body.call(thisArg, _);
153
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
154
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
155
+ }
124
156
  }
125
157
 
126
- var focusableSelectors = [
127
- 'a[href]:not([tabindex^="-"])',
128
- 'area[href]:not([tabindex^="-"])',
129
- 'input:not([type="hidden"]):not([type="radio"]):not([disabled]):not([tabindex^="-"])',
130
- 'input[type="radio"]:not([disabled]):not([tabindex^="-"])',
131
- 'select:not([disabled]):not([tabindex^="-"])',
132
- 'textarea:not([disabled]):not([tabindex^="-"])',
133
- 'button:not([disabled]):not([tabindex^="-"])',
134
- 'iframe:not([tabindex^="-"])',
135
- 'audio[controls]:not([tabindex^="-"])',
136
- 'video[controls]:not([tabindex^="-"])',
137
- '[contenteditable]:not([tabindex^="-"])',
138
- '[tabindex]:not([tabindex^="-"])',
139
- ];
140
-
141
- var TAB_KEY = 'Tab';
142
- var ESCAPE_KEY = 'Escape';
143
-
144
- /**
145
- * Define the constructor to instantiate a dialog
146
- *
147
- * @constructor
148
- * @param {Element} element
149
- */
150
- function A11yDialog(element) {
151
- // Prebind the functions that will be bound in addEventListener and
152
- // removeEventListener to avoid losing references
153
- this._show = this.show.bind(this);
154
- this._hide = this.hide.bind(this);
155
- this._maintainFocus = this._maintainFocus.bind(this);
156
- this._bindKeypress = this._bindKeypress.bind(this);
157
-
158
- this.$el = element;
159
- this.shown = false;
160
- this._id = this.$el.getAttribute('data-a11y-dialog') || this.$el.id;
161
- this._previouslyFocused = null;
162
- this._listeners = {};
163
-
164
- // Initialise everything needed for the dialog to work properly
165
- this.create();
158
+ /* [@simplewebauthn/browser@9.0.1] */
159
+ function utf8StringToBuffer(value) {
160
+ return new TextEncoder().encode(value);
166
161
  }
167
162
 
168
- /**
169
- * Set up everything necessary for the dialog to be functioning
170
- *
171
- * @param {(NodeList | Element | string)} targets
172
- * @return {this}
173
- */
174
- A11yDialog.prototype.create = function () {
175
- this.$el.setAttribute('aria-hidden', true);
176
- this.$el.setAttribute('aria-modal', true);
177
- this.$el.setAttribute('tabindex', -1);
178
-
179
- if (!this.$el.hasAttribute('role')) {
180
- this.$el.setAttribute('role', 'dialog');
181
- }
182
-
183
- // Keep a collection of dialog openers, each of which will be bound a click
184
- // event listener to open the dialog
185
- this._openers = $$('[data-a11y-dialog-show="' + this._id + '"]');
186
- this._openers.forEach(
187
- function (opener) {
188
- opener.addEventListener('click', this._show);
189
- }.bind(this)
190
- );
191
-
192
- // Keep a collection of dialog closers, each of which will be bound a click
193
- // event listener to close the dialog
194
- const $el = this.$el;
195
-
196
- this._closers = $$('[data-a11y-dialog-hide]', this.$el)
197
- // This filter is necessary in case there are nested dialogs, so that
198
- // only closers from the current dialog are retrieved and effective
199
- .filter(function (closer) {
200
- // Testing for `[aria-modal="true"]` is not enough since this attribute
201
- // and the collect of closers is done at instantation time, when nested
202
- // dialogs might not have yet been instantiated. Note that if the dialogs
203
- // are manually instantiated, this could still fail because none of these
204
- // selectors would match; this would cause closers to close all parent
205
- // dialogs instead of just the current one
206
- return closer.closest('[aria-modal="true"], [data-a11y-dialog]') === $el
207
- })
208
- .concat($$('[data-a11y-dialog-hide="' + this._id + '"]'));
209
-
210
- this._closers.forEach(
211
- function (closer) {
212
- closer.addEventListener('click', this._hide);
213
- }.bind(this)
214
- );
163
+ function bufferToBase64URLString(buffer) {
164
+ const bytes = new Uint8Array(buffer);
165
+ let str = '';
166
+ for (const charCode of bytes) {
167
+ str += String.fromCharCode(charCode);
168
+ }
169
+ const base64String = btoa(str);
170
+ return base64String.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
171
+ }
215
172
 
216
- // Execute all callbacks registered for the `create` event
217
- this._fire('create');
173
+ function base64URLStringToBuffer(base64URLString) {
174
+ const base64 = base64URLString.replace(/-/g, '+').replace(/_/g, '/');
175
+ const padLength = (4 - (base64.length % 4)) % 4;
176
+ const padded = base64.padEnd(base64.length + padLength, '=');
177
+ const binary = atob(padded);
178
+ const buffer = new ArrayBuffer(binary.length);
179
+ const bytes = new Uint8Array(buffer);
180
+ for (let i = 0; i < binary.length; i++) {
181
+ bytes[i] = binary.charCodeAt(i);
182
+ }
183
+ return buffer;
184
+ }
218
185
 
219
- return this
220
- };
186
+ function browserSupportsWebAuthn() {
187
+ return (window?.PublicKeyCredential !== undefined &&
188
+ typeof window.PublicKeyCredential === 'function');
189
+ }
221
190
 
222
- /**
223
- * Show the dialog element, disable all the targets (siblings), trap the
224
- * current focus within it, listen for some specific key presses and fire all
225
- * registered callbacks for `show` event
226
- *
227
- * @param {CustomEvent} event
228
- * @return {this}
229
- */
230
- A11yDialog.prototype.show = function (event) {
231
- // If the dialog is already open, abort
232
- if (this.shown) {
233
- return this
234
- }
191
+ function toPublicKeyCredentialDescriptor(descriptor) {
192
+ const { id } = descriptor;
193
+ return {
194
+ ...descriptor,
195
+ id: base64URLStringToBuffer(id),
196
+ transports: descriptor.transports,
197
+ };
198
+ }
235
199
 
236
- // Keep a reference to the currently focused element to be able to restore
237
- // it later
238
- this._previouslyFocused = document.activeElement;
239
- this.$el.removeAttribute('aria-hidden');
240
- this.shown = true;
200
+ function isValidDomain(hostname) {
201
+ return (hostname === 'localhost' ||
202
+ /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(hostname));
203
+ }
241
204
 
242
- // Set the focus to the dialog element
243
- moveFocusToDialog(this.$el);
244
-
245
- // Bind a focus event listener to the body element to make sure the focus
246
- // stays trapped inside the dialog while open, and start listening for some
247
- // specific key presses (TAB and ESC)
248
- document.body.addEventListener('focus', this._maintainFocus, true);
249
- document.addEventListener('keydown', this._bindKeypress);
250
-
251
- // Execute all callbacks registered for the `show` event
252
- this._fire('show', event);
253
-
254
- return this
255
- };
256
-
257
- /**
258
- * Hide the dialog element, enable all the targets (siblings), restore the
259
- * focus to the previously active element, stop listening for some specific
260
- * key presses and fire all registered callbacks for `hide` event
261
- *
262
- * @param {CustomEvent} event
263
- * @return {this}
264
- */
265
- A11yDialog.prototype.hide = function (event) {
266
- // If the dialog is already closed, abort
267
- if (!this.shown) {
268
- return this
269
- }
270
-
271
- this.shown = false;
272
- this.$el.setAttribute('aria-hidden', 'true');
273
-
274
- // If there was a focused element before the dialog was opened (and it has a
275
- // `focus` method), restore the focus back to it
276
- // See: https://github.com/KittyGiraudel/a11y-dialog/issues/108
277
- if (this._previouslyFocused && this._previouslyFocused.focus) {
278
- this._previouslyFocused.focus();
279
- }
280
-
281
- // Remove the focus event listener to the body element and stop listening
282
- // for specific key presses
283
- document.body.removeEventListener('focus', this._maintainFocus, true);
284
- document.removeEventListener('keydown', this._bindKeypress);
285
-
286
- // Execute all callbacks registered for the `hide` event
287
- this._fire('hide', event);
288
-
289
- return this
290
- };
291
-
292
- /**
293
- * Destroy the current instance (after making sure the dialog has been hidden)
294
- * and remove all associated listeners from dialog openers and closers
295
- *
296
- * @return {this}
297
- */
298
- A11yDialog.prototype.destroy = function () {
299
- // Hide the dialog to avoid destroying an open instance
300
- this.hide();
301
-
302
- // Remove the click event listener from all dialog openers
303
- this._openers.forEach(
304
- function (opener) {
305
- opener.removeEventListener('click', this._show);
306
- }.bind(this)
307
- );
308
-
309
- // Remove the click event listener from all dialog closers
310
- this._closers.forEach(
311
- function (closer) {
312
- closer.removeEventListener('click', this._hide);
313
- }.bind(this)
314
- );
315
-
316
- // Execute all callbacks registered for the `destroy` event
317
- this._fire('destroy');
318
-
319
- // Keep an object of listener types mapped to callback functions
320
- this._listeners = {};
321
-
322
- return this
323
- };
324
-
325
- /**
326
- * Register a new callback for the given event type
327
- *
328
- * @param {string} type
329
- * @param {Function} handler
330
- */
331
- A11yDialog.prototype.on = function (type, handler) {
332
- if (typeof this._listeners[type] === 'undefined') {
333
- this._listeners[type] = [];
334
- }
335
-
336
- this._listeners[type].push(handler);
337
-
338
- return this
339
- };
340
-
341
- /**
342
- * Unregister an existing callback for the given event type
343
- *
344
- * @param {string} type
345
- * @param {Function} handler
346
- */
347
- A11yDialog.prototype.off = function (type, handler) {
348
- var index = (this._listeners[type] || []).indexOf(handler);
349
-
350
- if (index > -1) {
351
- this._listeners[type].splice(index, 1);
352
- }
353
-
354
- return this
355
- };
356
-
357
- /**
358
- * Iterate over all registered handlers for given type and call them all with
359
- * the dialog element as first argument, event as second argument (if any). Also
360
- * dispatch a custom event on the DOM element itself to make it possible to
361
- * react to the lifecycle of auto-instantiated dialogs.
362
- *
363
- * @access private
364
- * @param {string} type
365
- * @param {CustomEvent} event
366
- */
367
- A11yDialog.prototype._fire = function (type, event) {
368
- var listeners = this._listeners[type] || [];
369
- var domEvent = new CustomEvent(type, { detail: event });
370
-
371
- this.$el.dispatchEvent(domEvent);
372
-
373
- listeners.forEach(
374
- function (listener) {
375
- listener(this.$el, event);
376
- }.bind(this)
377
- );
378
- };
379
-
380
- /**
381
- * Private event handler used when listening to some specific key presses
382
- * (namely ESCAPE and TAB)
383
- *
384
- * @access private
385
- * @param {Event} event
386
- */
387
- A11yDialog.prototype._bindKeypress = function (event) {
388
- // This is an escape hatch in case there are nested dialogs, so the keypresses
389
- // are only reacted to for the most recent one
390
- const focused = document.activeElement;
391
- if (focused && focused.closest('[aria-modal="true"]') !== this.$el) return
392
-
393
- // If the dialog is shown and the ESCAPE key is being pressed, prevent any
394
- // further effects from the ESCAPE key and hide the dialog, unless its role
395
- // is 'alertdialog', which should be modal
396
- if (
397
- this.shown &&
398
- event.key === ESCAPE_KEY &&
399
- this.$el.getAttribute('role') !== 'alertdialog'
400
- ) {
401
- event.preventDefault();
402
- this.hide(event);
403
- }
404
-
405
- // If the dialog is shown and the TAB key is being pressed, make sure the
406
- // focus stays trapped within the dialog element
407
- if (this.shown && event.key === TAB_KEY) {
408
- trapTabKey(this.$el, event);
409
- }
410
- };
411
-
412
- /**
413
- * Private event handler used when making sure the focus stays within the
414
- * currently open dialog
415
- *
416
- * @access private
417
- * @param {Event} event
418
- */
419
- A11yDialog.prototype._maintainFocus = function (event) {
420
- // If the dialog is shown and the focus is not within a dialog element (either
421
- // this one or another one in case of nested dialogs) or within an element
422
- // with the `data-a11y-dialog-focus-trap-ignore` attribute, move it back to
423
- // its first focusable child.
424
- // See: https://github.com/KittyGiraudel/a11y-dialog/issues/177
425
- if (
426
- this.shown &&
427
- !event.target.closest('[aria-modal="true"]') &&
428
- !event.target.closest('[data-a11y-dialog-ignore-focus-trap]')
429
- ) {
430
- moveFocusToDialog(this.$el);
431
- }
432
- };
433
-
434
- /**
435
- * Convert a NodeList into an array
436
- *
437
- * @param {NodeList} collection
438
- * @return {Array<Element>}
439
- */
440
- function toArray(collection) {
441
- return Array.prototype.slice.call(collection)
442
- }
443
-
444
- /**
445
- * Query the DOM for nodes matching the given selector, scoped to context (or
446
- * the whole document)
447
- *
448
- * @param {String} selector
449
- * @param {Element} [context = document]
450
- * @return {Array<Element>}
451
- */
452
- function $$(selector, context) {
453
- return toArray((context || document).querySelectorAll(selector))
454
- }
455
-
456
- /**
457
- * Set the focus to the first element with `autofocus` with the element or the
458
- * element itself
459
- *
460
- * @param {Element} node
461
- */
462
- function moveFocusToDialog(node) {
463
- var focused = node.querySelector('[autofocus]') || node;
464
-
465
- focused.focus();
466
- }
467
-
468
- /**
469
- * Get the focusable children of the given element
470
- *
471
- * @param {Element} node
472
- * @return {Array<Element>}
473
- */
474
- function getFocusableChildren(node) {
475
- return $$(focusableSelectors.join(','), node).filter(function (child) {
476
- return !!(
477
- child.offsetWidth ||
478
- child.offsetHeight ||
479
- child.getClientRects().length
480
- )
481
- })
482
- }
483
-
484
- /**
485
- * Trap the focus inside the given element
486
- *
487
- * @param {Element} node
488
- * @param {Event} event
489
- */
490
- function trapTabKey(node, event) {
491
- var focusableChildren = getFocusableChildren(node);
492
- var focusedItemIndex = focusableChildren.indexOf(document.activeElement);
493
-
494
- // If the SHIFT key is being pressed while tabbing (moving backwards) and
495
- // the currently focused item is the first one, move the focus to the last
496
- // focusable item from the dialog element
497
- if (event.shiftKey && focusedItemIndex === 0) {
498
- focusableChildren[focusableChildren.length - 1].focus();
499
- event.preventDefault();
500
- // If the SHIFT key is not being pressed (moving forwards) and the currently
501
- // focused item is the last one, move the focus to the first focusable item
502
- // from the dialog element
503
- } else if (
504
- !event.shiftKey &&
505
- focusedItemIndex === focusableChildren.length - 1
506
- ) {
507
- focusableChildren[0].focus();
508
- event.preventDefault();
509
- }
510
- }
511
-
512
- function instantiateDialogs() {
513
- $$('[data-a11y-dialog]').forEach(function (node) {
514
- new A11yDialog(node);
515
- });
516
- }
517
-
518
- if (typeof document !== 'undefined') {
519
- if (document.readyState === 'loading') {
520
- document.addEventListener('DOMContentLoaded', instantiateDialogs);
521
- } else {
522
- if (window.requestAnimationFrame) {
523
- window.requestAnimationFrame(instantiateDialogs);
524
- } else {
525
- window.setTimeout(instantiateDialogs, 16);
526
- }
527
- }
528
- }
529
-
530
- var CONTAINER_ID = "__authsignal-popup-container";
531
- var CONTENT_ID = "__authsignal-popup-content";
532
- var OVERLAY_ID = "__authsignal-popup-overlay";
533
- var STYLE_ID = "__authsignal-popup-style";
534
- var IFRAME_ID = "__authsignal-popup-iframe";
535
- var DEFAULT_WIDTH = "385px";
536
- var INITIAL_HEIGHT = "384px";
537
- var PopupHandler = /** @class */ (function () {
538
- function PopupHandler(_a) {
539
- var width = _a.width;
540
- this.popup = null;
541
- if (document.querySelector("#".concat(CONTAINER_ID))) {
542
- throw new Error("Multiple instances of Authsignal popup is not supported.");
543
- }
544
- this.create({ width: width });
545
- }
546
- PopupHandler.prototype.create = function (_a) {
547
- var _this = this;
548
- var _b = _a.width, width = _b === void 0 ? DEFAULT_WIDTH : _b;
549
- var isWidthValidCSSValue = CSS.supports("width", width);
550
- var popupWidth = width;
551
- if (!isWidthValidCSSValue) {
552
- console.warn("Invalid CSS value for `popupOptions.width`. Using default value instead.");
553
- popupWidth = DEFAULT_WIDTH;
554
- }
555
- // Create dialog container
556
- var container = document.createElement("div");
557
- container.setAttribute("id", CONTAINER_ID);
558
- container.setAttribute("aria-hidden", "true");
559
- // Create dialog overlay
560
- var overlay = document.createElement("div");
561
- overlay.setAttribute("id", OVERLAY_ID);
562
- overlay.setAttribute("data-a11y-dialog-hide", "true");
563
- // Create dialog content
564
- var content = document.createElement("div");
565
- content.setAttribute("id", CONTENT_ID);
566
- document.body.appendChild(container);
567
- // Create CSS for dialog
568
- var style = document.createElement("style");
569
- style.setAttribute("id", STYLE_ID);
570
- style.textContent = "\n #".concat(CONTAINER_ID, ",\n #").concat(OVERLAY_ID, " {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n\n #").concat(CONTAINER_ID, " {\n z-index: 2147483647;\n display: flex;\n }\n\n #").concat(CONTAINER_ID, "[aria-hidden='true'] {\n display: none;\n }\n\n #").concat(OVERLAY_ID, " {\n background-color: rgba(0, 0, 0, 0.18);\n }\n\n #").concat(CONTENT_ID, " {\n margin: auto;\n z-index: 2147483647;\n position: relative;\n background-color: transparent;\n border-radius: 8px;\n width: ").concat(popupWidth, ";\n }\n\n #").concat(CONTENT_ID, " iframe {\n width: 1px;\n min-width: 100%;\n border-radius: inherit;\n max-height: 95vh;\n height: ").concat(INITIAL_HEIGHT, ";\n }\n ");
571
- // Attach the created elements
572
- document.head.insertAdjacentElement("beforeend", style);
573
- container.appendChild(overlay);
574
- container.appendChild(content);
575
- this.popup = new A11yDialog(container);
576
- // Make sure to remove any trace of the dialog on hide
577
- this.popup.on("hide", function () {
578
- _this.destroy();
579
- });
580
- };
581
- PopupHandler.prototype.destroy = function () {
582
- var dialogEl = document.querySelector("#".concat(CONTAINER_ID));
583
- var styleEl = document.querySelector("#".concat(STYLE_ID));
584
- if (dialogEl && styleEl) {
585
- document.body.removeChild(dialogEl);
586
- document.head.removeChild(styleEl);
587
- }
588
- window.removeEventListener("message", resizeIframe);
589
- };
590
- PopupHandler.prototype.show = function (_a) {
591
- var _b;
592
- var url = _a.url;
593
- if (!this.popup) {
594
- throw new Error("Popup is not initialized");
595
- }
596
- var iframe = document.createElement("iframe");
597
- iframe.setAttribute("id", IFRAME_ID);
598
- iframe.setAttribute("name", "authsignal");
599
- iframe.setAttribute("title", "Authsignal multi-factor authentication");
600
- iframe.setAttribute("src", url);
601
- iframe.setAttribute("frameborder", "0");
602
- iframe.setAttribute("allow", "publickey-credentials-get *; publickey-credentials-create *; clipboard-write");
603
- var dialogContent = document.querySelector("#".concat(CONTENT_ID));
604
- if (dialogContent) {
605
- dialogContent.appendChild(iframe);
606
- }
607
- window.addEventListener("message", resizeIframe);
608
- (_b = this.popup) === null || _b === void 0 ? void 0 : _b.show();
609
- };
610
- PopupHandler.prototype.close = function () {
611
- if (!this.popup) {
612
- throw new Error("Popup is not initialized");
613
- }
614
- this.popup.hide();
615
- };
616
- PopupHandler.prototype.on = function (event, handler) {
617
- if (!this.popup) {
618
- throw new Error("Popup is not initialized");
619
- }
620
- this.popup.on(event, handler);
621
- };
622
- return PopupHandler;
623
- }());
624
- function resizeIframe(event) {
625
- var iframeEl = document.querySelector("#".concat(IFRAME_ID));
626
- if (iframeEl && event.data.height) {
627
- iframeEl.style.height = event.data.height + "px";
628
- }
629
- }
630
-
631
- /******************************************************************************
632
- Copyright (c) Microsoft Corporation.
633
-
634
- Permission to use, copy, modify, and/or distribute this software for any
635
- purpose with or without fee is hereby granted.
636
-
637
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
638
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
639
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
640
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
641
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
642
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
643
- PERFORMANCE OF THIS SOFTWARE.
644
- ***************************************************************************** */
645
-
646
- function __rest(s, e) {
647
- var t = {};
648
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
649
- t[p] = s[p];
650
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
651
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
652
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
653
- t[p[i]] = s[p[i]];
654
- }
655
- return t;
656
- }
657
-
658
- function __awaiter(thisArg, _arguments, P, generator) {
659
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
660
- return new (P || (P = Promise))(function (resolve, reject) {
661
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
662
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
663
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
664
- step((generator = generator.apply(thisArg, _arguments || [])).next());
665
- });
666
- }
667
-
668
- function __generator(thisArg, body) {
669
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
670
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
671
- function verb(n) { return function (v) { return step([n, v]); }; }
672
- function step(op) {
673
- if (f) throw new TypeError("Generator is already executing.");
674
- while (_) try {
675
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
676
- if (y = 0, t) op = [op[0] & 2, t.value];
677
- switch (op[0]) {
678
- case 0: case 1: t = op; break;
679
- case 4: _.label++; return { value: op[1], done: false };
680
- case 5: _.label++; y = op[1]; op = [0]; continue;
681
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
682
- default:
683
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
684
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
685
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
686
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
687
- if (t[2]) _.ops.pop();
688
- _.trys.pop(); continue;
689
- }
690
- op = body.call(thisArg, _);
691
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
692
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
693
- }
694
- }
695
-
696
- /* [@simplewebauthn/browser@8.2.1] */
697
- function utf8StringToBuffer(value) {
698
- return new TextEncoder().encode(value);
699
- }
700
-
701
- function bufferToBase64URLString(buffer) {
702
- const bytes = new Uint8Array(buffer);
703
- let str = '';
704
- for (const charCode of bytes) {
705
- str += String.fromCharCode(charCode);
706
- }
707
- const base64String = btoa(str);
708
- return base64String.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
709
- }
710
-
711
- function base64URLStringToBuffer(base64URLString) {
712
- const base64 = base64URLString.replace(/-/g, '+').replace(/_/g, '/');
713
- const padLength = (4 - (base64.length % 4)) % 4;
714
- const padded = base64.padEnd(base64.length + padLength, '=');
715
- const binary = atob(padded);
716
- const buffer = new ArrayBuffer(binary.length);
717
- const bytes = new Uint8Array(buffer);
718
- for (let i = 0; i < binary.length; i++) {
719
- bytes[i] = binary.charCodeAt(i);
720
- }
721
- return buffer;
722
- }
723
-
724
- function browserSupportsWebAuthn() {
725
- return (window?.PublicKeyCredential !== undefined &&
726
- typeof window.PublicKeyCredential === 'function');
727
- }
728
-
729
- function toPublicKeyCredentialDescriptor(descriptor) {
730
- const { id } = descriptor;
731
- return {
732
- ...descriptor,
733
- id: base64URLStringToBuffer(id),
734
- transports: descriptor.transports,
735
- };
736
- }
737
-
738
- function isValidDomain(hostname) {
739
- return (hostname === 'localhost' ||
740
- /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(hostname));
741
- }
742
-
743
- class WebAuthnError extends Error {
744
- constructor({ message, code, cause, name, }) {
745
- super(message, { cause });
746
- this.name = name ?? cause.name;
747
- this.code = code;
748
- }
749
- }
205
+ class WebAuthnError extends Error {
206
+ constructor({ message, code, cause, name, }) {
207
+ super(message, { cause });
208
+ this.name = name ?? cause.name;
209
+ this.code = code;
210
+ }
211
+ }
750
212
 
751
213
  function identifyRegistrationError({ error, options, }) {
752
214
  const { publicKey } = options;
@@ -843,7 +305,7 @@ function identifyRegistrationError({ error, options, }) {
843
305
  return error;
844
306
  }
845
307
 
846
- class WebAuthnAbortService {
308
+ class BaseWebAuthnAbortService {
847
309
  createNewAbortSignal() {
848
310
  if (this.controller) {
849
311
  const abortError = new Error('Cancelling existing WebAuthn API call for new one');
@@ -854,8 +316,16 @@ class WebAuthnAbortService {
854
316
  this.controller = newController;
855
317
  return newController.signal;
856
318
  }
319
+ cancelCeremony() {
320
+ if (this.controller) {
321
+ const abortError = new Error('Manually cancelling existing WebAuthn API call');
322
+ abortError.name = 'AbortError';
323
+ this.controller.abort(abortError);
324
+ this.controller = undefined;
325
+ }
326
+ }
857
327
  }
858
- const webauthnAbortService = new WebAuthnAbortService();
328
+ const WebAuthnAbortService = new BaseWebAuthnAbortService();
859
329
 
860
330
  const attachments = ['cross-platform', 'platform'];
861
331
  function toAuthenticatorAttachment(attachment) {
@@ -882,7 +352,7 @@ async function startRegistration(creationOptionsJSON) {
882
352
  excludeCredentials: creationOptionsJSON.excludeCredentials?.map(toPublicKeyCredentialDescriptor),
883
353
  };
884
354
  const options = { publicKey };
885
- options.signal = webauthnAbortService.createNewAbortSignal();
355
+ options.signal = WebAuthnAbortService.createNewAbortSignal();
886
356
  let credential;
887
357
  try {
888
358
  credential = (await navigator.credentials.create(options));
@@ -997,754 +467,769 @@ function identifyAuthenticationError({ error, options, }) {
997
467
  code: 'ERROR_INVALID_RP_ID',
998
468
  cause: error,
999
469
  });
1000
- }
1001
- }
1002
- else if (error.name === 'UnknownError') {
1003
- return new WebAuthnError({
1004
- message: 'The authenticator was unable to process the specified options, or could not create a new assertion signature',
1005
- code: 'ERROR_AUTHENTICATOR_GENERAL_ERROR',
1006
- cause: error,
470
+ }
471
+ }
472
+ else if (error.name === 'UnknownError') {
473
+ return new WebAuthnError({
474
+ message: 'The authenticator was unable to process the specified options, or could not create a new assertion signature',
475
+ code: 'ERROR_AUTHENTICATOR_GENERAL_ERROR',
476
+ cause: error,
477
+ });
478
+ }
479
+ return error;
480
+ }
481
+
482
+ async function startAuthentication(requestOptionsJSON, useBrowserAutofill = false) {
483
+ if (!browserSupportsWebAuthn()) {
484
+ throw new Error('WebAuthn is not supported in this browser');
485
+ }
486
+ let allowCredentials;
487
+ if (requestOptionsJSON.allowCredentials?.length !== 0) {
488
+ allowCredentials = requestOptionsJSON.allowCredentials?.map(toPublicKeyCredentialDescriptor);
489
+ }
490
+ const publicKey = {
491
+ ...requestOptionsJSON,
492
+ challenge: base64URLStringToBuffer(requestOptionsJSON.challenge),
493
+ allowCredentials,
494
+ };
495
+ const options = {};
496
+ if (useBrowserAutofill) {
497
+ if (!(await browserSupportsWebAuthnAutofill())) {
498
+ throw Error('Browser does not support WebAuthn autofill');
499
+ }
500
+ const eligibleInputs = document.querySelectorAll('input[autocomplete$=\'webauthn\']');
501
+ if (eligibleInputs.length < 1) {
502
+ throw Error('No <input> with "webauthn" as the only or last value in its `autocomplete` attribute was detected');
503
+ }
504
+ options.mediation = 'conditional';
505
+ publicKey.allowCredentials = [];
506
+ }
507
+ options.publicKey = publicKey;
508
+ options.signal = WebAuthnAbortService.createNewAbortSignal();
509
+ let credential;
510
+ try {
511
+ credential = (await navigator.credentials.get(options));
512
+ }
513
+ catch (err) {
514
+ throw identifyAuthenticationError({ error: err, options });
515
+ }
516
+ if (!credential) {
517
+ throw new Error('Authentication was not completed');
518
+ }
519
+ const { id, rawId, response, type } = credential;
520
+ let userHandle = undefined;
521
+ if (response.userHandle) {
522
+ userHandle = bufferToUTF8String(response.userHandle);
523
+ }
524
+ return {
525
+ id,
526
+ rawId: bufferToBase64URLString(rawId),
527
+ response: {
528
+ authenticatorData: bufferToBase64URLString(response.authenticatorData),
529
+ clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
530
+ signature: bufferToBase64URLString(response.signature),
531
+ userHandle,
532
+ },
533
+ type,
534
+ clientExtensionResults: credential.getClientExtensionResults(),
535
+ authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment),
536
+ };
537
+ }
538
+
539
+ var PasskeyApiClient = /** @class */ (function () {
540
+ function PasskeyApiClient(_a) {
541
+ var baseUrl = _a.baseUrl, tenantId = _a.tenantId;
542
+ this.tenantId = tenantId;
543
+ this.baseUrl = baseUrl;
544
+ }
545
+ PasskeyApiClient.prototype.registrationOptions = function (_a) {
546
+ var token = _a.token, userName = _a.userName;
547
+ return __awaiter(this, void 0, void 0, function () {
548
+ var request;
549
+ return __generator(this, function (_b) {
550
+ switch (_b.label) {
551
+ case 0:
552
+ request = fetch("".concat(this.baseUrl, "/client/user-authenticators/passkey/registration-options"), {
553
+ method: "POST",
554
+ headers: this.buildHeaders(token),
555
+ body: JSON.stringify({ username: userName })
556
+ });
557
+ return [4 /*yield*/, request];
558
+ case 1: return [2 /*return*/, (_b.sent()).json()];
559
+ }
560
+ });
561
+ });
562
+ };
563
+ PasskeyApiClient.prototype.authenticationOptions = function (_a) {
564
+ var token = _a.token;
565
+ return __awaiter(this, void 0, void 0, function () {
566
+ var request;
567
+ return __generator(this, function (_b) {
568
+ switch (_b.label) {
569
+ case 0:
570
+ request = fetch("".concat(this.baseUrl, "/client/user-authenticators/passkey/authentication-options"), {
571
+ method: "POST",
572
+ headers: this.buildHeaders(token),
573
+ body: JSON.stringify({})
574
+ });
575
+ return [4 /*yield*/, request];
576
+ case 1: return [2 /*return*/, (_b.sent()).json()];
577
+ }
578
+ });
579
+ });
580
+ };
581
+ PasskeyApiClient.prototype.addAuthenticator = function (_a) {
582
+ var token = _a.token, rest = __rest(_a, ["token"]);
583
+ return __awaiter(this, void 0, void 0, function () {
584
+ var request;
585
+ return __generator(this, function (_b) {
586
+ switch (_b.label) {
587
+ case 0:
588
+ request = fetch("".concat(this.baseUrl, "/client/user-authenticators/passkey"), {
589
+ method: "POST",
590
+ headers: this.buildHeaders(token),
591
+ body: JSON.stringify(rest)
592
+ });
593
+ return [4 /*yield*/, request];
594
+ case 1: return [2 /*return*/, (_b.sent()).json()];
595
+ }
596
+ });
597
+ });
598
+ };
599
+ PasskeyApiClient.prototype.verify = function (_a) {
600
+ var token = _a.token, rest = __rest(_a, ["token"]);
601
+ return __awaiter(this, void 0, void 0, function () {
602
+ var request;
603
+ return __generator(this, function (_b) {
604
+ switch (_b.label) {
605
+ case 0:
606
+ request = fetch("".concat(this.baseUrl, "/client/verify/passkey"), {
607
+ method: "POST",
608
+ headers: this.buildHeaders(token),
609
+ body: JSON.stringify(rest)
610
+ });
611
+ return [4 /*yield*/, request];
612
+ case 1: return [2 /*return*/, (_b.sent()).json()];
613
+ }
614
+ });
615
+ });
616
+ };
617
+ PasskeyApiClient.prototype.buildHeaders = function (token) {
618
+ var authorizationHeader = token ? "Bearer ".concat(token) : "Basic ".concat(window.btoa(encodeURIComponent(this.tenantId)));
619
+ return {
620
+ "Content-Type": "application/json",
621
+ Authorization: authorizationHeader
622
+ };
623
+ };
624
+ return PasskeyApiClient;
625
+ }());
626
+
627
+ var Passkey = /** @class */ (function () {
628
+ function Passkey(_a) {
629
+ var baseUrl = _a.baseUrl, tenantId = _a.tenantId;
630
+ this.api = new PasskeyApiClient({ baseUrl: baseUrl, tenantId: tenantId });
631
+ }
632
+ Passkey.prototype.signUp = function (_a) {
633
+ var userName = _a.userName, token = _a.token;
634
+ return __awaiter(this, void 0, void 0, function () {
635
+ var optionsResponse, registrationResponse, addAuthenticatorResponse;
636
+ return __generator(this, function (_b) {
637
+ switch (_b.label) {
638
+ case 0: return [4 /*yield*/, this.api.registrationOptions({ userName: userName, token: token })];
639
+ case 1:
640
+ optionsResponse = _b.sent();
641
+ return [4 /*yield*/, startRegistration(optionsResponse.options)];
642
+ case 2:
643
+ registrationResponse = _b.sent();
644
+ return [4 /*yield*/, this.api.addAuthenticator({
645
+ challengeId: optionsResponse.challengeId,
646
+ registrationCredential: registrationResponse,
647
+ token: token
648
+ })];
649
+ case 3:
650
+ addAuthenticatorResponse = _b.sent();
651
+ return [2 /*return*/, addAuthenticatorResponse === null || addAuthenticatorResponse === void 0 ? void 0 : addAuthenticatorResponse.accessToken];
652
+ }
653
+ });
654
+ });
655
+ };
656
+ Passkey.prototype.signIn = function (params) {
657
+ return __awaiter(this, void 0, void 0, function () {
658
+ var optionsResponse, authenticationResponse, verifyResponse;
659
+ return __generator(this, function (_a) {
660
+ switch (_a.label) {
661
+ case 0:
662
+ if ((params === null || params === void 0 ? void 0 : params.token) && params.autofill) {
663
+ throw new Error("Autofill is not supported when providing a token");
664
+ }
665
+ return [4 /*yield*/, this.api.authenticationOptions({ token: params === null || params === void 0 ? void 0 : params.token })];
666
+ case 1:
667
+ optionsResponse = _a.sent();
668
+ return [4 /*yield*/, startAuthentication(optionsResponse.options, params === null || params === void 0 ? void 0 : params.autofill)];
669
+ case 2:
670
+ authenticationResponse = _a.sent();
671
+ return [4 /*yield*/, this.api.verify({
672
+ challengeId: optionsResponse.challengeId,
673
+ authenticationCredential: authenticationResponse,
674
+ token: params === null || params === void 0 ? void 0 : params.token
675
+ })];
676
+ case 3:
677
+ verifyResponse = _a.sent();
678
+ return [2 /*return*/, verifyResponse === null || verifyResponse === void 0 ? void 0 : verifyResponse.accessToken];
679
+ }
680
+ });
1007
681
  });
1008
- }
1009
- return error;
1010
- }
682
+ };
683
+ return Passkey;
684
+ }());
1011
685
 
1012
- async function startAuthentication(requestOptionsJSON, useBrowserAutofill = false) {
1013
- if (!browserSupportsWebAuthn()) {
1014
- throw new Error('WebAuthn is not supported in this browser');
1015
- }
1016
- let allowCredentials;
1017
- if (requestOptionsJSON.allowCredentials?.length !== 0) {
1018
- allowCredentials = requestOptionsJSON.allowCredentials?.map(toPublicKeyCredentialDescriptor);
686
+ var DEFAULT_WIDTH$1 = 400;
687
+ var DEFAULT_HEIGHT = 500;
688
+ var WindowHandler = /** @class */ (function () {
689
+ function WindowHandler() {
690
+ this.windowRef = null;
1019
691
  }
1020
- const publicKey = {
1021
- ...requestOptionsJSON,
1022
- challenge: base64URLStringToBuffer(requestOptionsJSON.challenge),
1023
- allowCredentials,
1024
- };
1025
- const options = {};
1026
- if (useBrowserAutofill) {
1027
- if (!(await browserSupportsWebAuthnAutofill())) {
1028
- throw Error('Browser does not support WebAuthn autofill');
692
+ WindowHandler.prototype.show = function (_a) {
693
+ var url = _a.url, _b = _a.width, width = _b === void 0 ? DEFAULT_WIDTH$1 : _b, _c = _a.height, height = _c === void 0 ? DEFAULT_HEIGHT : _c;
694
+ var windowRef = openWindow({ url: url, width: width, height: height, win: window });
695
+ if (!windowRef) {
696
+ throw new Error("Window is not initialized");
1029
697
  }
1030
- const eligibleInputs = document.querySelectorAll('input[autocomplete*=\'webauthn\']');
1031
- if (eligibleInputs.length < 1) {
1032
- throw Error('No <input> with `"webauthn"` in its `autocomplete` attribute was detected');
698
+ this.windowRef = windowRef;
699
+ return windowRef;
700
+ };
701
+ WindowHandler.prototype.close = function () {
702
+ if (!this.windowRef) {
703
+ throw new Error("Window is not initialized");
1033
704
  }
1034
- options.mediation = 'conditional';
1035
- publicKey.allowCredentials = [];
1036
- }
1037
- options.publicKey = publicKey;
1038
- options.signal = webauthnAbortService.createNewAbortSignal();
1039
- let credential;
1040
- try {
1041
- credential = (await navigator.credentials.get(options));
1042
- }
1043
- catch (err) {
1044
- throw identifyAuthenticationError({ error: err, options });
1045
- }
1046
- if (!credential) {
1047
- throw new Error('Authentication was not completed');
1048
- }
1049
- const { id, rawId, response, type } = credential;
1050
- let userHandle = undefined;
1051
- if (response.userHandle) {
1052
- userHandle = bufferToUTF8String(response.userHandle);
1053
- }
1054
- return {
1055
- id,
1056
- rawId: bufferToBase64URLString(rawId),
1057
- response: {
1058
- authenticatorData: bufferToBase64URLString(response.authenticatorData),
1059
- clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
1060
- signature: bufferToBase64URLString(response.signature),
1061
- userHandle,
1062
- },
1063
- type,
1064
- clientExtensionResults: credential.getClientExtensionResults(),
1065
- authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment),
705
+ this.windowRef.close();
1066
706
  };
707
+ return WindowHandler;
708
+ }());
709
+ function openWindow(_a) {
710
+ var url = _a.url, width = _a.width, height = _a.height, win = _a.win;
711
+ if (!win.top) {
712
+ return null;
713
+ }
714
+ var y = win.top.outerHeight / 2 + win.top.screenY - height / 2;
715
+ var x = win.top.outerWidth / 2 + win.top.screenX - width / 2;
716
+ return window.open(url, "", "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=".concat(width, ", height=").concat(height, ", top=").concat(y, ", left=").concat(x));
717
+ }
718
+
719
+ var focusableSelectors = [
720
+ 'a[href]:not([tabindex^="-"])',
721
+ 'area[href]:not([tabindex^="-"])',
722
+ 'input:not([type="hidden"]):not([type="radio"]):not([disabled]):not([tabindex^="-"])',
723
+ 'input[type="radio"]:not([disabled]):not([tabindex^="-"])',
724
+ 'select:not([disabled]):not([tabindex^="-"])',
725
+ 'textarea:not([disabled]):not([tabindex^="-"])',
726
+ 'button:not([disabled]):not([tabindex^="-"])',
727
+ 'iframe:not([tabindex^="-"])',
728
+ 'audio[controls]:not([tabindex^="-"])',
729
+ 'video[controls]:not([tabindex^="-"])',
730
+ '[contenteditable]:not([tabindex^="-"])',
731
+ '[tabindex]:not([tabindex^="-"])',
732
+ ];
733
+
734
+ var TAB_KEY = 'Tab';
735
+ var ESCAPE_KEY = 'Escape';
736
+
737
+ /**
738
+ * Define the constructor to instantiate a dialog
739
+ *
740
+ * @constructor
741
+ * @param {Element} element
742
+ */
743
+ function A11yDialog(element) {
744
+ // Prebind the functions that will be bound in addEventListener and
745
+ // removeEventListener to avoid losing references
746
+ this._show = this.show.bind(this);
747
+ this._hide = this.hide.bind(this);
748
+ this._maintainFocus = this._maintainFocus.bind(this);
749
+ this._bindKeypress = this._bindKeypress.bind(this);
750
+
751
+ this.$el = element;
752
+ this.shown = false;
753
+ this._id = this.$el.getAttribute('data-a11y-dialog') || this.$el.id;
754
+ this._previouslyFocused = null;
755
+ this._listeners = {};
756
+
757
+ // Initialise everything needed for the dialog to work properly
758
+ this.create();
1067
759
  }
1068
760
 
1069
- // eslint-lint-disable-next-line @typescript-eslint/naming-convention
1070
- class HTTPError extends Error {
1071
- constructor(response, request, options) {
1072
- const code = (response.status || response.status === 0) ? response.status : '';
1073
- const title = response.statusText || '';
1074
- const status = `${code} ${title}`.trim();
1075
- const reason = status ? `status code ${status}` : 'an unknown error';
1076
- super(`Request failed with ${reason}`);
1077
- Object.defineProperty(this, "response", {
1078
- enumerable: true,
1079
- configurable: true,
1080
- writable: true,
1081
- value: void 0
1082
- });
1083
- Object.defineProperty(this, "request", {
1084
- enumerable: true,
1085
- configurable: true,
1086
- writable: true,
1087
- value: void 0
1088
- });
1089
- Object.defineProperty(this, "options", {
1090
- enumerable: true,
1091
- configurable: true,
1092
- writable: true,
1093
- value: void 0
1094
- });
1095
- this.name = 'HTTPError';
1096
- this.response = response;
1097
- this.request = request;
1098
- this.options = options;
1099
- }
1100
- }
761
+ /**
762
+ * Set up everything necessary for the dialog to be functioning
763
+ *
764
+ * @param {(NodeList | Element | string)} targets
765
+ * @return {this}
766
+ */
767
+ A11yDialog.prototype.create = function () {
768
+ this.$el.setAttribute('aria-hidden', true);
769
+ this.$el.setAttribute('aria-modal', true);
770
+ this.$el.setAttribute('tabindex', -1);
771
+
772
+ if (!this.$el.hasAttribute('role')) {
773
+ this.$el.setAttribute('role', 'dialog');
774
+ }
775
+
776
+ // Keep a collection of dialog openers, each of which will be bound a click
777
+ // event listener to open the dialog
778
+ this._openers = $$('[data-a11y-dialog-show="' + this._id + '"]');
779
+ this._openers.forEach(
780
+ function (opener) {
781
+ opener.addEventListener('click', this._show);
782
+ }.bind(this)
783
+ );
784
+
785
+ // Keep a collection of dialog closers, each of which will be bound a click
786
+ // event listener to close the dialog
787
+ const $el = this.$el;
788
+
789
+ this._closers = $$('[data-a11y-dialog-hide]', this.$el)
790
+ // This filter is necessary in case there are nested dialogs, so that
791
+ // only closers from the current dialog are retrieved and effective
792
+ .filter(function (closer) {
793
+ // Testing for `[aria-modal="true"]` is not enough since this attribute
794
+ // and the collect of closers is done at instantation time, when nested
795
+ // dialogs might not have yet been instantiated. Note that if the dialogs
796
+ // are manually instantiated, this could still fail because none of these
797
+ // selectors would match; this would cause closers to close all parent
798
+ // dialogs instead of just the current one
799
+ return closer.closest('[aria-modal="true"], [data-a11y-dialog]') === $el
800
+ })
801
+ .concat($$('[data-a11y-dialog-hide="' + this._id + '"]'));
802
+
803
+ this._closers.forEach(
804
+ function (closer) {
805
+ closer.addEventListener('click', this._hide);
806
+ }.bind(this)
807
+ );
808
+
809
+ // Execute all callbacks registered for the `create` event
810
+ this._fire('create');
811
+
812
+ return this
813
+ };
814
+
815
+ /**
816
+ * Show the dialog element, disable all the targets (siblings), trap the
817
+ * current focus within it, listen for some specific key presses and fire all
818
+ * registered callbacks for `show` event
819
+ *
820
+ * @param {CustomEvent} event
821
+ * @return {this}
822
+ */
823
+ A11yDialog.prototype.show = function (event) {
824
+ // If the dialog is already open, abort
825
+ if (this.shown) {
826
+ return this
827
+ }
828
+
829
+ // Keep a reference to the currently focused element to be able to restore
830
+ // it later
831
+ this._previouslyFocused = document.activeElement;
832
+ this.$el.removeAttribute('aria-hidden');
833
+ this.shown = true;
834
+
835
+ // Set the focus to the dialog element
836
+ moveFocusToDialog(this.$el);
837
+
838
+ // Bind a focus event listener to the body element to make sure the focus
839
+ // stays trapped inside the dialog while open, and start listening for some
840
+ // specific key presses (TAB and ESC)
841
+ document.body.addEventListener('focus', this._maintainFocus, true);
842
+ document.addEventListener('keydown', this._bindKeypress);
843
+
844
+ // Execute all callbacks registered for the `show` event
845
+ this._fire('show', event);
846
+
847
+ return this
848
+ };
849
+
850
+ /**
851
+ * Hide the dialog element, enable all the targets (siblings), restore the
852
+ * focus to the previously active element, stop listening for some specific
853
+ * key presses and fire all registered callbacks for `hide` event
854
+ *
855
+ * @param {CustomEvent} event
856
+ * @return {this}
857
+ */
858
+ A11yDialog.prototype.hide = function (event) {
859
+ // If the dialog is already closed, abort
860
+ if (!this.shown) {
861
+ return this
862
+ }
863
+
864
+ this.shown = false;
865
+ this.$el.setAttribute('aria-hidden', 'true');
866
+
867
+ // If there was a focused element before the dialog was opened (and it has a
868
+ // `focus` method), restore the focus back to it
869
+ // See: https://github.com/KittyGiraudel/a11y-dialog/issues/108
870
+ if (this._previouslyFocused && this._previouslyFocused.focus) {
871
+ this._previouslyFocused.focus();
872
+ }
873
+
874
+ // Remove the focus event listener to the body element and stop listening
875
+ // for specific key presses
876
+ document.body.removeEventListener('focus', this._maintainFocus, true);
877
+ document.removeEventListener('keydown', this._bindKeypress);
878
+
879
+ // Execute all callbacks registered for the `hide` event
880
+ this._fire('hide', event);
881
+
882
+ return this
883
+ };
884
+
885
+ /**
886
+ * Destroy the current instance (after making sure the dialog has been hidden)
887
+ * and remove all associated listeners from dialog openers and closers
888
+ *
889
+ * @return {this}
890
+ */
891
+ A11yDialog.prototype.destroy = function () {
892
+ // Hide the dialog to avoid destroying an open instance
893
+ this.hide();
1101
894
 
1102
- class TimeoutError extends Error {
1103
- constructor(request) {
1104
- super('Request timed out');
1105
- Object.defineProperty(this, "request", {
1106
- enumerable: true,
1107
- configurable: true,
1108
- writable: true,
1109
- value: void 0
1110
- });
1111
- this.name = 'TimeoutError';
1112
- this.request = request;
1113
- }
1114
- }
895
+ // Remove the click event listener from all dialog openers
896
+ this._openers.forEach(
897
+ function (opener) {
898
+ opener.removeEventListener('click', this._show);
899
+ }.bind(this)
900
+ );
1115
901
 
1116
- // eslint-disable-next-line @typescript-eslint/ban-types
1117
- const isObject = (value) => value !== null && typeof value === 'object';
902
+ // Remove the click event listener from all dialog closers
903
+ this._closers.forEach(
904
+ function (closer) {
905
+ closer.removeEventListener('click', this._hide);
906
+ }.bind(this)
907
+ );
1118
908
 
1119
- const validateAndMerge = (...sources) => {
1120
- for (const source of sources) {
1121
- if ((!isObject(source) || Array.isArray(source)) && typeof source !== 'undefined') {
1122
- throw new TypeError('The `options` argument must be an object');
1123
- }
1124
- }
1125
- return deepMerge({}, ...sources);
909
+ // Execute all callbacks registered for the `destroy` event
910
+ this._fire('destroy');
911
+
912
+ // Keep an object of listener types mapped to callback functions
913
+ this._listeners = {};
914
+
915
+ return this
1126
916
  };
1127
- const mergeHeaders = (source1 = {}, source2 = {}) => {
1128
- const result = new globalThis.Headers(source1);
1129
- const isHeadersInstance = source2 instanceof globalThis.Headers;
1130
- const source = new globalThis.Headers(source2);
1131
- for (const [key, value] of source.entries()) {
1132
- if ((isHeadersInstance && value === 'undefined') || value === undefined) {
1133
- result.delete(key);
1134
- }
1135
- else {
1136
- result.set(key, value);
1137
- }
1138
- }
1139
- return result;
917
+
918
+ /**
919
+ * Register a new callback for the given event type
920
+ *
921
+ * @param {string} type
922
+ * @param {Function} handler
923
+ */
924
+ A11yDialog.prototype.on = function (type, handler) {
925
+ if (typeof this._listeners[type] === 'undefined') {
926
+ this._listeners[type] = [];
927
+ }
928
+
929
+ this._listeners[type].push(handler);
930
+
931
+ return this
1140
932
  };
1141
- // TODO: Make this strongly-typed (no `any`).
1142
- const deepMerge = (...sources) => {
1143
- let returnValue = {};
1144
- let headers = {};
1145
- for (const source of sources) {
1146
- if (Array.isArray(source)) {
1147
- if (!Array.isArray(returnValue)) {
1148
- returnValue = [];
1149
- }
1150
- returnValue = [...returnValue, ...source];
1151
- }
1152
- else if (isObject(source)) {
1153
- for (let [key, value] of Object.entries(source)) {
1154
- if (isObject(value) && key in returnValue) {
1155
- value = deepMerge(returnValue[key], value);
1156
- }
1157
- returnValue = { ...returnValue, [key]: value };
1158
- }
1159
- if (isObject(source.headers)) {
1160
- headers = mergeHeaders(headers, source.headers);
1161
- returnValue.headers = headers;
1162
- }
1163
- }
1164
- }
1165
- return returnValue;
933
+
934
+ /**
935
+ * Unregister an existing callback for the given event type
936
+ *
937
+ * @param {string} type
938
+ * @param {Function} handler
939
+ */
940
+ A11yDialog.prototype.off = function (type, handler) {
941
+ var index = (this._listeners[type] || []).indexOf(handler);
942
+
943
+ if (index > -1) {
944
+ this._listeners[type].splice(index, 1);
945
+ }
946
+
947
+ return this
1166
948
  };
1167
949
 
1168
- const supportsRequestStreams = (() => {
1169
- let duplexAccessed = false;
1170
- let hasContentType = false;
1171
- const supportsReadableStream = typeof globalThis.ReadableStream === 'function';
1172
- const supportsRequest = typeof globalThis.Request === 'function';
1173
- if (supportsReadableStream && supportsRequest) {
1174
- hasContentType = new globalThis.Request('https://a.com', {
1175
- body: new globalThis.ReadableStream(),
1176
- method: 'POST',
1177
- // @ts-expect-error - Types are outdated.
1178
- get duplex() {
1179
- duplexAccessed = true;
1180
- return 'half';
1181
- },
1182
- }).headers.has('Content-Type');
1183
- }
1184
- return duplexAccessed && !hasContentType;
1185
- })();
1186
- const supportsAbortController = typeof globalThis.AbortController === 'function';
1187
- const supportsResponseStreams = typeof globalThis.ReadableStream === 'function';
1188
- const supportsFormData = typeof globalThis.FormData === 'function';
1189
- const requestMethods = ['get', 'post', 'put', 'patch', 'head', 'delete'];
1190
- const responseTypes = {
1191
- json: 'application/json',
1192
- text: 'text/*',
1193
- formData: 'multipart/form-data',
1194
- arrayBuffer: '*/*',
1195
- blob: '*/*',
950
+ /**
951
+ * Iterate over all registered handlers for given type and call them all with
952
+ * the dialog element as first argument, event as second argument (if any). Also
953
+ * dispatch a custom event on the DOM element itself to make it possible to
954
+ * react to the lifecycle of auto-instantiated dialogs.
955
+ *
956
+ * @access private
957
+ * @param {string} type
958
+ * @param {CustomEvent} event
959
+ */
960
+ A11yDialog.prototype._fire = function (type, event) {
961
+ var listeners = this._listeners[type] || [];
962
+ var domEvent = new CustomEvent(type, { detail: event });
963
+
964
+ this.$el.dispatchEvent(domEvent);
965
+
966
+ listeners.forEach(
967
+ function (listener) {
968
+ listener(this.$el, event);
969
+ }.bind(this)
970
+ );
1196
971
  };
1197
- // The maximum value of a 32bit int (see issue #117)
1198
- const maxSafeTimeout = 2147483647;
1199
- const stop = Symbol('stop');
1200
-
1201
- const normalizeRequestMethod = (input) => requestMethods.includes(input) ? input.toUpperCase() : input;
1202
- const retryMethods = ['get', 'put', 'head', 'delete', 'options', 'trace'];
1203
- const retryStatusCodes = [408, 413, 429, 500, 502, 503, 504];
1204
- const retryAfterStatusCodes = [413, 429, 503];
1205
- const defaultRetryOptions = {
1206
- limit: 2,
1207
- methods: retryMethods,
1208
- statusCodes: retryStatusCodes,
1209
- afterStatusCodes: retryAfterStatusCodes,
1210
- maxRetryAfter: Number.POSITIVE_INFINITY,
1211
- backoffLimit: Number.POSITIVE_INFINITY,
972
+
973
+ /**
974
+ * Private event handler used when listening to some specific key presses
975
+ * (namely ESCAPE and TAB)
976
+ *
977
+ * @access private
978
+ * @param {Event} event
979
+ */
980
+ A11yDialog.prototype._bindKeypress = function (event) {
981
+ // This is an escape hatch in case there are nested dialogs, so the keypresses
982
+ // are only reacted to for the most recent one
983
+ const focused = document.activeElement;
984
+ if (focused && focused.closest('[aria-modal="true"]') !== this.$el) return
985
+
986
+ // If the dialog is shown and the ESCAPE key is being pressed, prevent any
987
+ // further effects from the ESCAPE key and hide the dialog, unless its role
988
+ // is 'alertdialog', which should be modal
989
+ if (
990
+ this.shown &&
991
+ event.key === ESCAPE_KEY &&
992
+ this.$el.getAttribute('role') !== 'alertdialog'
993
+ ) {
994
+ event.preventDefault();
995
+ this.hide(event);
996
+ }
997
+
998
+ // If the dialog is shown and the TAB key is being pressed, make sure the
999
+ // focus stays trapped within the dialog element
1000
+ if (this.shown && event.key === TAB_KEY) {
1001
+ trapTabKey(this.$el, event);
1002
+ }
1212
1003
  };
1213
- const normalizeRetryOptions = (retry = {}) => {
1214
- if (typeof retry === 'number') {
1215
- return {
1216
- ...defaultRetryOptions,
1217
- limit: retry,
1218
- };
1219
- }
1220
- if (retry.methods && !Array.isArray(retry.methods)) {
1221
- throw new Error('retry.methods must be an array');
1222
- }
1223
- if (retry.statusCodes && !Array.isArray(retry.statusCodes)) {
1224
- throw new Error('retry.statusCodes must be an array');
1225
- }
1226
- return {
1227
- ...defaultRetryOptions,
1228
- ...retry,
1229
- afterStatusCodes: retryAfterStatusCodes,
1230
- };
1004
+
1005
+ /**
1006
+ * Private event handler used when making sure the focus stays within the
1007
+ * currently open dialog
1008
+ *
1009
+ * @access private
1010
+ * @param {Event} event
1011
+ */
1012
+ A11yDialog.prototype._maintainFocus = function (event) {
1013
+ // If the dialog is shown and the focus is not within a dialog element (either
1014
+ // this one or another one in case of nested dialogs) or within an element
1015
+ // with the `data-a11y-dialog-focus-trap-ignore` attribute, move it back to
1016
+ // its first focusable child.
1017
+ // See: https://github.com/KittyGiraudel/a11y-dialog/issues/177
1018
+ if (
1019
+ this.shown &&
1020
+ !event.target.closest('[aria-modal="true"]') &&
1021
+ !event.target.closest('[data-a11y-dialog-ignore-focus-trap]')
1022
+ ) {
1023
+ moveFocusToDialog(this.$el);
1024
+ }
1231
1025
  };
1232
1026
 
1233
- // `Promise.race()` workaround (#91)
1234
- async function timeout(request, abortController, options) {
1235
- return new Promise((resolve, reject) => {
1236
- const timeoutId = setTimeout(() => {
1237
- if (abortController) {
1238
- abortController.abort();
1239
- }
1240
- reject(new TimeoutError(request));
1241
- }, options.timeout);
1242
- void options
1243
- .fetch(request)
1244
- .then(resolve)
1245
- .catch(reject)
1246
- .then(() => {
1247
- clearTimeout(timeoutId);
1248
- });
1249
- });
1027
+ /**
1028
+ * Convert a NodeList into an array
1029
+ *
1030
+ * @param {NodeList} collection
1031
+ * @return {Array<Element>}
1032
+ */
1033
+ function toArray(collection) {
1034
+ return Array.prototype.slice.call(collection)
1250
1035
  }
1251
1036
 
1252
- // DOMException is supported on most modern browsers and Node.js 18+.
1253
- // @see https://developer.mozilla.org/en-US/docs/Web/API/DOMException#browser_compatibility
1254
- const isDomExceptionSupported = Boolean(globalThis.DOMException);
1255
- // TODO: When targeting Node.js 18, use `signal.throwIfAborted()` (https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted)
1256
- function composeAbortError(signal) {
1257
- /*
1258
- NOTE: Use DomException with AbortError name as specified in MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort)
1259
- > When abort() is called, the fetch() promise rejects with an Error of type DOMException, with name AbortError.
1260
- */
1261
- if (isDomExceptionSupported) {
1262
- return new DOMException(signal?.reason ?? 'The operation was aborted.', 'AbortError');
1263
- }
1264
- // DOMException not supported. Fall back to use of error and override name.
1265
- const error = new Error(signal?.reason ?? 'The operation was aborted.');
1266
- error.name = 'AbortError';
1267
- return error;
1037
+ /**
1038
+ * Query the DOM for nodes matching the given selector, scoped to context (or
1039
+ * the whole document)
1040
+ *
1041
+ * @param {String} selector
1042
+ * @param {Element} [context = document]
1043
+ * @return {Array<Element>}
1044
+ */
1045
+ function $$(selector, context) {
1046
+ return toArray((context || document).querySelectorAll(selector))
1268
1047
  }
1269
1048
 
1270
- // https://github.com/sindresorhus/delay/tree/ab98ae8dfcb38e1593286c94d934e70d14a4e111
1271
- async function delay(ms, { signal }) {
1272
- return new Promise((resolve, reject) => {
1273
- if (signal) {
1274
- if (signal.aborted) {
1275
- reject(composeAbortError(signal));
1276
- return;
1277
- }
1278
- signal.addEventListener('abort', handleAbort, { once: true });
1279
- }
1280
- function handleAbort() {
1281
- reject(composeAbortError(signal));
1282
- clearTimeout(timeoutId);
1283
- }
1284
- const timeoutId = setTimeout(() => {
1285
- signal?.removeEventListener('abort', handleAbort);
1286
- resolve();
1287
- }, ms);
1288
- });
1049
+ /**
1050
+ * Set the focus to the first element with `autofocus` with the element or the
1051
+ * element itself
1052
+ *
1053
+ * @param {Element} node
1054
+ */
1055
+ function moveFocusToDialog(node) {
1056
+ var focused = node.querySelector('[autofocus]') || node;
1057
+
1058
+ focused.focus();
1289
1059
  }
1290
1060
 
1291
- class Ky {
1292
- // eslint-disable-next-line @typescript-eslint/promise-function-async
1293
- static create(input, options) {
1294
- const ky = new Ky(input, options);
1295
- const fn = async () => {
1296
- if (ky._options.timeout > maxSafeTimeout) {
1297
- throw new RangeError(`The \`timeout\` option cannot be greater than ${maxSafeTimeout}`);
1298
- }
1299
- // Delay the fetch so that body method shortcuts can set the Accept header
1300
- await Promise.resolve();
1301
- let response = await ky._fetch();
1302
- for (const hook of ky._options.hooks.afterResponse) {
1303
- // eslint-disable-next-line no-await-in-loop
1304
- const modifiedResponse = await hook(ky.request, ky._options, ky._decorateResponse(response.clone()));
1305
- if (modifiedResponse instanceof globalThis.Response) {
1306
- response = modifiedResponse;
1307
- }
1308
- }
1309
- ky._decorateResponse(response);
1310
- if (!response.ok && ky._options.throwHttpErrors) {
1311
- let error = new HTTPError(response, ky.request, ky._options);
1312
- for (const hook of ky._options.hooks.beforeError) {
1313
- // eslint-disable-next-line no-await-in-loop
1314
- error = await hook(error);
1315
- }
1316
- throw error;
1317
- }
1318
- // If `onDownloadProgress` is passed, it uses the stream API internally
1319
- /* istanbul ignore next */
1320
- if (ky._options.onDownloadProgress) {
1321
- if (typeof ky._options.onDownloadProgress !== 'function') {
1322
- throw new TypeError('The `onDownloadProgress` option must be a function');
1323
- }
1324
- if (!supportsResponseStreams) {
1325
- throw new Error('Streams are not supported in your environment. `ReadableStream` is missing.');
1326
- }
1327
- return ky._stream(response.clone(), ky._options.onDownloadProgress);
1328
- }
1329
- return response;
1330
- };
1331
- const isRetriableMethod = ky._options.retry.methods.includes(ky.request.method.toLowerCase());
1332
- const result = (isRetriableMethod ? ky._retry(fn) : fn());
1333
- for (const [type, mimeType] of Object.entries(responseTypes)) {
1334
- result[type] = async () => {
1335
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
1336
- ky.request.headers.set('accept', ky.request.headers.get('accept') || mimeType);
1337
- const awaitedResult = await result;
1338
- const response = awaitedResult.clone();
1339
- if (type === 'json') {
1340
- if (response.status === 204) {
1341
- return '';
1342
- }
1343
- const arrayBuffer = await response.clone().arrayBuffer();
1344
- const responseSize = arrayBuffer.byteLength;
1345
- if (responseSize === 0) {
1346
- return '';
1347
- }
1348
- if (options.parseJson) {
1349
- return options.parseJson(await response.text());
1350
- }
1351
- }
1352
- return response[type]();
1353
- };
1354
- }
1355
- return result;
1356
- }
1357
- // eslint-disable-next-line complexity
1358
- constructor(input, options = {}) {
1359
- Object.defineProperty(this, "request", {
1360
- enumerable: true,
1361
- configurable: true,
1362
- writable: true,
1363
- value: void 0
1364
- });
1365
- Object.defineProperty(this, "abortController", {
1366
- enumerable: true,
1367
- configurable: true,
1368
- writable: true,
1369
- value: void 0
1370
- });
1371
- Object.defineProperty(this, "_retryCount", {
1372
- enumerable: true,
1373
- configurable: true,
1374
- writable: true,
1375
- value: 0
1376
- });
1377
- Object.defineProperty(this, "_input", {
1378
- enumerable: true,
1379
- configurable: true,
1380
- writable: true,
1381
- value: void 0
1382
- });
1383
- Object.defineProperty(this, "_options", {
1384
- enumerable: true,
1385
- configurable: true,
1386
- writable: true,
1387
- value: void 0
1388
- });
1389
- this._input = input;
1390
- this._options = {
1391
- // TODO: credentials can be removed when the spec change is implemented in all browsers. Context: https://www.chromestatus.com/feature/4539473312350208
1392
- credentials: this._input.credentials || 'same-origin',
1393
- ...options,
1394
- headers: mergeHeaders(this._input.headers, options.headers),
1395
- hooks: deepMerge({
1396
- beforeRequest: [],
1397
- beforeRetry: [],
1398
- beforeError: [],
1399
- afterResponse: [],
1400
- }, options.hooks),
1401
- method: normalizeRequestMethod(options.method ?? this._input.method),
1402
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
1403
- prefixUrl: String(options.prefixUrl || ''),
1404
- retry: normalizeRetryOptions(options.retry),
1405
- throwHttpErrors: options.throwHttpErrors !== false,
1406
- timeout: typeof options.timeout === 'undefined' ? 10000 : options.timeout,
1407
- fetch: options.fetch ?? globalThis.fetch.bind(globalThis),
1408
- };
1409
- if (typeof this._input !== 'string' && !(this._input instanceof URL || this._input instanceof globalThis.Request)) {
1410
- throw new TypeError('`input` must be a string, URL, or Request');
1411
- }
1412
- if (this._options.prefixUrl && typeof this._input === 'string') {
1413
- if (this._input.startsWith('/')) {
1414
- throw new Error('`input` must not begin with a slash when using `prefixUrl`');
1415
- }
1416
- if (!this._options.prefixUrl.endsWith('/')) {
1417
- this._options.prefixUrl += '/';
1418
- }
1419
- this._input = this._options.prefixUrl + this._input;
1420
- }
1421
- if (supportsAbortController) {
1422
- this.abortController = new globalThis.AbortController();
1423
- if (this._options.signal) {
1424
- const originalSignal = this._options.signal;
1425
- this._options.signal.addEventListener('abort', () => {
1426
- this.abortController.abort(originalSignal.reason);
1427
- });
1428
- }
1429
- this._options.signal = this.abortController.signal;
1430
- }
1431
- if (supportsRequestStreams) {
1432
- // @ts-expect-error - Types are outdated.
1433
- this._options.duplex = 'half';
1434
- }
1435
- this.request = new globalThis.Request(this._input, this._options);
1436
- if (this._options.searchParams) {
1437
- // eslint-disable-next-line unicorn/prevent-abbreviations
1438
- const textSearchParams = typeof this._options.searchParams === 'string'
1439
- ? this._options.searchParams.replace(/^\?/, '')
1440
- : new URLSearchParams(this._options.searchParams).toString();
1441
- // eslint-disable-next-line unicorn/prevent-abbreviations
1442
- const searchParams = '?' + textSearchParams;
1443
- const url = this.request.url.replace(/(?:\?.*?)?(?=#|$)/, searchParams);
1444
- // To provide correct form boundary, Content-Type header should be deleted each time when new Request instantiated from another one
1445
- if (((supportsFormData && this._options.body instanceof globalThis.FormData)
1446
- || this._options.body instanceof URLSearchParams) && !(this._options.headers && this._options.headers['content-type'])) {
1447
- this.request.headers.delete('content-type');
1448
- }
1449
- // The spread of `this.request` is required as otherwise it misses the `duplex` option for some reason and throws.
1450
- this.request = new globalThis.Request(new globalThis.Request(url, { ...this.request }), this._options);
1451
- }
1452
- if (this._options.json !== undefined) {
1453
- this._options.body = JSON.stringify(this._options.json);
1454
- this.request.headers.set('content-type', this._options.headers.get('content-type') ?? 'application/json');
1455
- this.request = new globalThis.Request(this.request, { body: this._options.body });
1456
- }
1457
- }
1458
- _calculateRetryDelay(error) {
1459
- this._retryCount++;
1460
- if (this._retryCount < this._options.retry.limit && !(error instanceof TimeoutError)) {
1461
- if (error instanceof HTTPError) {
1462
- if (!this._options.retry.statusCodes.includes(error.response.status)) {
1463
- return 0;
1464
- }
1465
- const retryAfter = error.response.headers.get('Retry-After');
1466
- if (retryAfter && this._options.retry.afterStatusCodes.includes(error.response.status)) {
1467
- let after = Number(retryAfter);
1468
- if (Number.isNaN(after)) {
1469
- after = Date.parse(retryAfter) - Date.now();
1470
- }
1471
- else {
1472
- after *= 1000;
1473
- }
1474
- if (typeof this._options.retry.maxRetryAfter !== 'undefined' && after > this._options.retry.maxRetryAfter) {
1475
- return 0;
1476
- }
1477
- return after;
1478
- }
1479
- if (error.response.status === 413) {
1480
- return 0;
1481
- }
1482
- }
1483
- const BACKOFF_FACTOR = 0.3;
1484
- return Math.min(this._options.retry.backoffLimit, BACKOFF_FACTOR * (2 ** (this._retryCount - 1)) * 1000);
1485
- }
1486
- return 0;
1487
- }
1488
- _decorateResponse(response) {
1489
- if (this._options.parseJson) {
1490
- response.json = async () => this._options.parseJson(await response.text());
1491
- }
1492
- return response;
1493
- }
1494
- async _retry(fn) {
1495
- try {
1496
- return await fn();
1497
- // eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
1498
- }
1499
- catch (error) {
1500
- const ms = Math.min(this._calculateRetryDelay(error), maxSafeTimeout);
1501
- if (ms !== 0 && this._retryCount > 0) {
1502
- await delay(ms, { signal: this._options.signal });
1503
- for (const hook of this._options.hooks.beforeRetry) {
1504
- // eslint-disable-next-line no-await-in-loop
1505
- const hookResult = await hook({
1506
- request: this.request,
1507
- options: this._options,
1508
- error: error,
1509
- retryCount: this._retryCount,
1510
- });
1511
- // If `stop` is returned from the hook, the retry process is stopped
1512
- if (hookResult === stop) {
1513
- return;
1514
- }
1515
- }
1516
- return this._retry(fn);
1517
- }
1518
- throw error;
1519
- }
1520
- }
1521
- async _fetch() {
1522
- for (const hook of this._options.hooks.beforeRequest) {
1523
- // eslint-disable-next-line no-await-in-loop
1524
- const result = await hook(this.request, this._options);
1525
- if (result instanceof Request) {
1526
- this.request = result;
1527
- break;
1528
- }
1529
- if (result instanceof Response) {
1530
- return result;
1531
- }
1532
- }
1533
- if (this._options.timeout === false) {
1534
- return this._options.fetch(this.request.clone());
1535
- }
1536
- return timeout(this.request.clone(), this.abortController, this._options);
1537
- }
1538
- /* istanbul ignore next */
1539
- _stream(response, onDownloadProgress) {
1540
- const totalBytes = Number(response.headers.get('content-length')) || 0;
1541
- let transferredBytes = 0;
1542
- if (response.status === 204) {
1543
- if (onDownloadProgress) {
1544
- onDownloadProgress({ percent: 1, totalBytes, transferredBytes }, new Uint8Array());
1545
- }
1546
- return new globalThis.Response(null, {
1547
- status: response.status,
1548
- statusText: response.statusText,
1549
- headers: response.headers,
1550
- });
1551
- }
1552
- return new globalThis.Response(new globalThis.ReadableStream({
1553
- async start(controller) {
1554
- const reader = response.body.getReader();
1555
- if (onDownloadProgress) {
1556
- onDownloadProgress({ percent: 0, transferredBytes: 0, totalBytes }, new Uint8Array());
1557
- }
1558
- async function read() {
1559
- const { done, value } = await reader.read();
1560
- if (done) {
1561
- controller.close();
1562
- return;
1563
- }
1564
- if (onDownloadProgress) {
1565
- transferredBytes += value.byteLength;
1566
- const percent = totalBytes === 0 ? 0 : transferredBytes / totalBytes;
1567
- onDownloadProgress({ percent, transferredBytes, totalBytes }, value);
1568
- }
1569
- controller.enqueue(value);
1570
- await read();
1571
- }
1572
- await read();
1573
- },
1574
- }), {
1575
- status: response.status,
1576
- statusText: response.statusText,
1577
- headers: response.headers,
1578
- });
1579
- }
1061
+ /**
1062
+ * Get the focusable children of the given element
1063
+ *
1064
+ * @param {Element} node
1065
+ * @return {Array<Element>}
1066
+ */
1067
+ function getFocusableChildren(node) {
1068
+ return $$(focusableSelectors.join(','), node).filter(function (child) {
1069
+ return !!(
1070
+ child.offsetWidth ||
1071
+ child.offsetHeight ||
1072
+ child.getClientRects().length
1073
+ )
1074
+ })
1075
+ }
1076
+
1077
+ /**
1078
+ * Trap the focus inside the given element
1079
+ *
1080
+ * @param {Element} node
1081
+ * @param {Event} event
1082
+ */
1083
+ function trapTabKey(node, event) {
1084
+ var focusableChildren = getFocusableChildren(node);
1085
+ var focusedItemIndex = focusableChildren.indexOf(document.activeElement);
1086
+
1087
+ // If the SHIFT key is being pressed while tabbing (moving backwards) and
1088
+ // the currently focused item is the first one, move the focus to the last
1089
+ // focusable item from the dialog element
1090
+ if (event.shiftKey && focusedItemIndex === 0) {
1091
+ focusableChildren[focusableChildren.length - 1].focus();
1092
+ event.preventDefault();
1093
+ // If the SHIFT key is not being pressed (moving forwards) and the currently
1094
+ // focused item is the last one, move the focus to the first focusable item
1095
+ // from the dialog element
1096
+ } else if (
1097
+ !event.shiftKey &&
1098
+ focusedItemIndex === focusableChildren.length - 1
1099
+ ) {
1100
+ focusableChildren[0].focus();
1101
+ event.preventDefault();
1102
+ }
1580
1103
  }
1581
1104
 
1582
- /*! MIT License © Sindre Sorhus */
1583
- const createInstance = (defaults) => {
1584
- // eslint-disable-next-line @typescript-eslint/promise-function-async
1585
- const ky = (input, options) => Ky.create(input, validateAndMerge(defaults, options));
1586
- for (const method of requestMethods) {
1587
- // eslint-disable-next-line @typescript-eslint/promise-function-async
1588
- ky[method] = (input, options) => Ky.create(input, validateAndMerge(defaults, options, { method }));
1105
+ function instantiateDialogs() {
1106
+ $$('[data-a11y-dialog]').forEach(function (node) {
1107
+ new A11yDialog(node);
1108
+ });
1109
+ }
1110
+
1111
+ if (typeof document !== 'undefined') {
1112
+ if (document.readyState === 'loading') {
1113
+ document.addEventListener('DOMContentLoaded', instantiateDialogs);
1114
+ } else {
1115
+ if (window.requestAnimationFrame) {
1116
+ window.requestAnimationFrame(instantiateDialogs);
1117
+ } else {
1118
+ window.setTimeout(instantiateDialogs, 16);
1589
1119
  }
1590
- ky.create = (newDefaults) => createInstance(validateAndMerge(newDefaults));
1591
- ky.extend = (newDefaults) => createInstance(validateAndMerge(defaults, newDefaults));
1592
- ky.stop = stop;
1593
- return ky;
1594
- };
1595
- const ky = createInstance();
1596
- var ky$1 = ky;
1120
+ }
1121
+ }
1597
1122
 
1598
- var PasskeyApiClient = /** @class */ (function () {
1599
- function PasskeyApiClient(_a) {
1600
- var baseUrl = _a.baseUrl, tenantId = _a.tenantId;
1601
- this.tenantId = tenantId;
1602
- this.api = ky$1.create({
1603
- prefixUrl: baseUrl
1604
- });
1123
+ var CONTAINER_ID = "__authsignal-popup-container";
1124
+ var CONTENT_ID = "__authsignal-popup-content";
1125
+ var OVERLAY_ID = "__authsignal-popup-overlay";
1126
+ var STYLE_ID = "__authsignal-popup-style";
1127
+ var IFRAME_ID = "__authsignal-popup-iframe";
1128
+ var DEFAULT_WIDTH = "385px";
1129
+ var INITIAL_HEIGHT = "384px";
1130
+ var PopupHandler = /** @class */ (function () {
1131
+ function PopupHandler(_a) {
1132
+ var width = _a.width;
1133
+ this.popup = null;
1134
+ if (document.querySelector("#".concat(CONTAINER_ID))) {
1135
+ throw new Error("Multiple instances of Authsignal popup is not supported.");
1136
+ }
1137
+ this.create({ width: width });
1605
1138
  }
1606
- PasskeyApiClient.prototype.registrationOptions = function (_a) {
1607
- var token = _a.token, userName = _a.userName;
1608
- return __awaiter(this, void 0, void 0, function () {
1609
- var response;
1610
- return __generator(this, function (_b) {
1611
- switch (_b.label) {
1612
- case 0: return [4 /*yield*/, this.api.post("client/user-authenticators/passkey/registration-options", {
1613
- json: { username: userName },
1614
- headers: this.buildHeaders(token)
1615
- })];
1616
- case 1:
1617
- response = _b.sent();
1618
- return [2 /*return*/, response.json()];
1619
- }
1620
- });
1139
+ PopupHandler.prototype.create = function (_a) {
1140
+ var _this = this;
1141
+ var _b = _a.width, width = _b === void 0 ? DEFAULT_WIDTH : _b;
1142
+ var isWidthValidCSSValue = CSS.supports("width", width);
1143
+ var popupWidth = width;
1144
+ if (!isWidthValidCSSValue) {
1145
+ console.warn("Invalid CSS value for `popupOptions.width`. Using default value instead.");
1146
+ popupWidth = DEFAULT_WIDTH;
1147
+ }
1148
+ // Create dialog container
1149
+ var container = document.createElement("div");
1150
+ container.setAttribute("id", CONTAINER_ID);
1151
+ container.setAttribute("aria-hidden", "true");
1152
+ // Create dialog overlay
1153
+ var overlay = document.createElement("div");
1154
+ overlay.setAttribute("id", OVERLAY_ID);
1155
+ overlay.setAttribute("data-a11y-dialog-hide", "true");
1156
+ // Create dialog content
1157
+ var content = document.createElement("div");
1158
+ content.setAttribute("id", CONTENT_ID);
1159
+ document.body.appendChild(container);
1160
+ // Create CSS for dialog
1161
+ var style = document.createElement("style");
1162
+ style.setAttribute("id", STYLE_ID);
1163
+ style.textContent = "\n #".concat(CONTAINER_ID, ",\n #").concat(OVERLAY_ID, " {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n\n #").concat(CONTAINER_ID, " {\n z-index: 2147483647;\n display: flex;\n }\n\n #").concat(CONTAINER_ID, "[aria-hidden='true'] {\n display: none;\n }\n\n #").concat(OVERLAY_ID, " {\n background-color: rgba(0, 0, 0, 0.18);\n }\n\n #").concat(CONTENT_ID, " {\n margin: auto;\n z-index: 2147483647;\n position: relative;\n background-color: transparent;\n border-radius: 8px;\n width: ").concat(popupWidth, ";\n }\n\n #").concat(CONTENT_ID, " iframe {\n width: 1px;\n min-width: 100%;\n border-radius: inherit;\n max-height: 95vh;\n height: ").concat(INITIAL_HEIGHT, ";\n }\n ");
1164
+ // Attach the created elements
1165
+ document.head.insertAdjacentElement("beforeend", style);
1166
+ container.appendChild(overlay);
1167
+ container.appendChild(content);
1168
+ this.popup = new A11yDialog(container);
1169
+ // Make sure to remove any trace of the dialog on hide
1170
+ this.popup.on("hide", function () {
1171
+ _this.destroy();
1621
1172
  });
1622
1173
  };
1623
- PasskeyApiClient.prototype.authenticationOptions = function (_a) {
1624
- var token = _a.token;
1625
- return __awaiter(this, void 0, void 0, function () {
1626
- var response;
1627
- return __generator(this, function (_b) {
1628
- switch (_b.label) {
1629
- case 0: return [4 /*yield*/, this.api.post("client/user-authenticators/passkey/authentication-options", {
1630
- json: {},
1631
- headers: this.buildHeaders(token)
1632
- })];
1633
- case 1:
1634
- response = _b.sent();
1635
- return [2 /*return*/, response.json()];
1636
- }
1637
- });
1638
- });
1174
+ PopupHandler.prototype.destroy = function () {
1175
+ var dialogEl = document.querySelector("#".concat(CONTAINER_ID));
1176
+ var styleEl = document.querySelector("#".concat(STYLE_ID));
1177
+ if (dialogEl && styleEl) {
1178
+ document.body.removeChild(dialogEl);
1179
+ document.head.removeChild(styleEl);
1180
+ }
1181
+ window.removeEventListener("message", resizeIframe);
1639
1182
  };
1640
- PasskeyApiClient.prototype.addAuthenticator = function (_a) {
1641
- var token = _a.token, rest = __rest(_a, ["token"]);
1642
- return __awaiter(this, void 0, void 0, function () {
1643
- var response;
1644
- return __generator(this, function (_b) {
1645
- switch (_b.label) {
1646
- case 0: return [4 /*yield*/, this.api.post("client/user-authenticators/passkey", {
1647
- json: rest,
1648
- headers: this.buildHeaders(token)
1649
- })];
1650
- case 1:
1651
- response = _b.sent();
1652
- return [2 /*return*/, response.json()];
1653
- }
1654
- });
1655
- });
1183
+ PopupHandler.prototype.show = function (_a) {
1184
+ var _b;
1185
+ var url = _a.url;
1186
+ if (!this.popup) {
1187
+ throw new Error("Popup is not initialized");
1188
+ }
1189
+ var iframe = document.createElement("iframe");
1190
+ iframe.setAttribute("id", IFRAME_ID);
1191
+ iframe.setAttribute("name", "authsignal");
1192
+ iframe.setAttribute("title", "Authsignal multi-factor authentication");
1193
+ iframe.setAttribute("src", url);
1194
+ iframe.setAttribute("frameborder", "0");
1195
+ iframe.setAttribute("allow", "publickey-credentials-get *; publickey-credentials-create *; clipboard-write");
1196
+ var dialogContent = document.querySelector("#".concat(CONTENT_ID));
1197
+ if (dialogContent) {
1198
+ dialogContent.appendChild(iframe);
1199
+ }
1200
+ window.addEventListener("message", resizeIframe);
1201
+ (_b = this.popup) === null || _b === void 0 ? void 0 : _b.show();
1656
1202
  };
1657
- PasskeyApiClient.prototype.verify = function (_a) {
1658
- var token = _a.token, rest = __rest(_a, ["token"]);
1659
- return __awaiter(this, void 0, void 0, function () {
1660
- var response;
1661
- return __generator(this, function (_b) {
1662
- switch (_b.label) {
1663
- case 0: return [4 /*yield*/, this.api.post("client/verify/passkey", {
1664
- json: rest,
1665
- headers: this.buildHeaders(token)
1666
- })];
1667
- case 1:
1668
- response = _b.sent();
1669
- return [2 /*return*/, response.json()];
1670
- }
1671
- });
1672
- });
1203
+ PopupHandler.prototype.close = function () {
1204
+ if (!this.popup) {
1205
+ throw new Error("Popup is not initialized");
1206
+ }
1207
+ this.popup.hide();
1673
1208
  };
1674
- PasskeyApiClient.prototype.buildHeaders = function (token) {
1675
- var authorizationHeader = token ? "Bearer ".concat(token) : "Basic ".concat(window.btoa(encodeURIComponent(this.tenantId)));
1676
- return {
1677
- Authorization: authorizationHeader
1678
- };
1209
+ PopupHandler.prototype.on = function (event, handler) {
1210
+ if (!this.popup) {
1211
+ throw new Error("Popup is not initialized");
1212
+ }
1213
+ this.popup.on(event, handler);
1679
1214
  };
1680
- return PasskeyApiClient;
1215
+ return PopupHandler;
1681
1216
  }());
1682
-
1683
- var Passkey = /** @class */ (function () {
1684
- function Passkey(_a) {
1685
- var baseUrl = _a.baseUrl, tenantId = _a.tenantId;
1686
- this.api = new PasskeyApiClient({ baseUrl: baseUrl, tenantId: tenantId });
1217
+ function resizeIframe(event) {
1218
+ var iframeEl = document.querySelector("#".concat(IFRAME_ID));
1219
+ if (iframeEl && event.data.height) {
1220
+ iframeEl.style.height = event.data.height + "px";
1687
1221
  }
1688
- Passkey.prototype.signUp = function (_a) {
1689
- var userName = _a.userName, token = _a.token;
1690
- return __awaiter(this, void 0, void 0, function () {
1691
- var optionsResponse, registrationResponse, addAuthenticatorResponse;
1692
- return __generator(this, function (_b) {
1693
- switch (_b.label) {
1694
- case 0: return [4 /*yield*/, this.api.registrationOptions({ userName: userName, token: token })];
1695
- case 1:
1696
- optionsResponse = _b.sent();
1697
- return [4 /*yield*/, startRegistration(optionsResponse.options)];
1698
- case 2:
1699
- registrationResponse = _b.sent();
1700
- return [4 /*yield*/, this.api.addAuthenticator({
1701
- challengeId: optionsResponse.challengeId,
1702
- registrationCredential: registrationResponse,
1703
- token: token
1704
- })];
1705
- case 3:
1706
- addAuthenticatorResponse = _b.sent();
1707
- return [2 /*return*/, addAuthenticatorResponse === null || addAuthenticatorResponse === void 0 ? void 0 : addAuthenticatorResponse.accessToken];
1708
- }
1709
- });
1710
- });
1711
- };
1712
- Passkey.prototype.signIn = function (params) {
1713
- return __awaiter(this, void 0, void 0, function () {
1714
- var optionsResponse, authenticationResponse, verifyResponse;
1715
- return __generator(this, function (_a) {
1716
- switch (_a.label) {
1717
- case 0:
1718
- if ((params === null || params === void 0 ? void 0 : params.token) && params.autofill) {
1719
- throw new Error("Autofill is not supported when providing a token");
1720
- }
1721
- return [4 /*yield*/, this.api.authenticationOptions({ token: params === null || params === void 0 ? void 0 : params.token })];
1722
- case 1:
1723
- optionsResponse = _a.sent();
1724
- return [4 /*yield*/, startAuthentication(optionsResponse.options, params === null || params === void 0 ? void 0 : params.autofill)];
1725
- case 2:
1726
- authenticationResponse = _a.sent();
1727
- return [4 /*yield*/, this.api.verify({
1728
- challengeId: optionsResponse.challengeId,
1729
- authenticationCredential: authenticationResponse,
1730
- token: params === null || params === void 0 ? void 0 : params.token
1731
- })];
1732
- case 3:
1733
- verifyResponse = _a.sent();
1734
- return [2 /*return*/, verifyResponse === null || verifyResponse === void 0 ? void 0 : verifyResponse.accessToken];
1735
- }
1736
- });
1737
- });
1738
- };
1739
- return Passkey;
1740
- }());
1222
+ }
1741
1223
 
1742
1224
  var DEFAULT_COOKIE_NAME = "__as_aid";
1225
+ var DEFAULT_PROFILING_COOKIE_NAME = "__as_pid";
1743
1226
  var DEFAULT_BASE_URL = "https://api.authsignal.com/v1";
1227
+ var TMX_ORG_ID = "4a08uqve";
1744
1228
  var Authsignal = /** @class */ (function () {
1745
1229
  function Authsignal(_a) {
1746
1230
  var cookieDomain = _a.cookieDomain, _b = _a.cookieName, cookieName = _b === void 0 ? DEFAULT_COOKIE_NAME : _b, _c = _a.baseUrl, baseUrl = _c === void 0 ? DEFAULT_BASE_URL : _c, tenantId = _a.tenantId;
1747
1231
  this.anonymousId = "";
1232
+ this.profilingId = "";
1748
1233
  this.cookieDomain = "";
1749
1234
  this.anonymousIdCookieName = "";
1750
1235
  this._token = undefined;
@@ -1780,6 +1265,40 @@ var Authsignal = /** @class */ (function () {
1780
1265
  this.launchWithRedirect(url);
1781
1266
  }
1782
1267
  };
1268
+ Authsignal.prototype.initAdvancedProfiling = function (baseUrl) {
1269
+ var profilingId = v4();
1270
+ this.profilingId = profilingId;
1271
+ setCookie({
1272
+ name: DEFAULT_PROFILING_COOKIE_NAME,
1273
+ value: profilingId,
1274
+ expire: Infinity,
1275
+ domain: this.cookieDomain,
1276
+ secure: document.location.protocol !== "http:"
1277
+ });
1278
+ var tmxProfilingScruiptUrl = baseUrl
1279
+ ? "".concat(baseUrl, "/fp/tags.js?org_id=").concat(TMX_ORG_ID, "&session_id=").concat(profilingId)
1280
+ : "https://h.online-metrix.net/fp/tags.js?org_id=".concat(TMX_ORG_ID, "&session_id=").concat(profilingId);
1281
+ var script = document.createElement("script");
1282
+ script.src = tmxProfilingScruiptUrl;
1283
+ script.async = false;
1284
+ script.id = "as_adv_profile";
1285
+ document.head.appendChild(script);
1286
+ var pixelContainer = document.createElement("noscript");
1287
+ pixelContainer.setAttribute("id", "as_adv_profile_pixel");
1288
+ pixelContainer.setAttribute("aria-hidden", "true");
1289
+ // Instantiate Pixel
1290
+ var iframe = document.createElement("iframe");
1291
+ var profilingPixelUrl = baseUrl
1292
+ ? "".concat(baseUrl, "/fp/tags?org_id=").concat(TMX_ORG_ID, "&session_id=").concat(profilingId)
1293
+ : "https://h.online-metrix.net/fp/tags?org_id=".concat(TMX_ORG_ID, "&session_id=").concat(profilingId);
1294
+ iframe.setAttribute("id", "as_adv_profile_pixel");
1295
+ iframe.setAttribute("src", profilingPixelUrl);
1296
+ iframe.setAttribute("style", "width: 100px; height: 100px; border: 0; position: absolute; top: -5000px;");
1297
+ if (pixelContainer) {
1298
+ pixelContainer.appendChild(iframe);
1299
+ document.body.prepend(pixelContainer);
1300
+ }
1301
+ };
1783
1302
  Authsignal.prototype.launchWithRedirect = function (url) {
1784
1303
  window.location.href = url;
1785
1304
  };