@strands.gg/accui 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const vue = require("vue");
4
4
  const useStrandsConfig = require("./useStrandsConfig-CjQTmiYi.cjs");
5
- const useStrandsAuth = require("./useStrandsAuth-DsgsSSDi.cjs");
5
+ const useStrandsAuth = require("./useStrandsAuth-DK6bMycB.cjs");
6
6
  const _sfc_main$r = /* @__PURE__ */ vue.defineComponent({
7
7
  __name: "UiAlert",
8
8
  props: {
@@ -1325,7 +1325,13 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
1325
1325
  verificationError.value = "";
1326
1326
  };
1327
1327
  const onBackupCodeInput = (value) => {
1328
- backupCode.value = value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
1328
+ let cleaned = value.replace(/[^a-zA-Z0-9-]/g, "").toLowerCase();
1329
+ if (!/[-]/.test(cleaned) && cleaned.length > 4) {
1330
+ cleaned = cleaned.match(/.{1,4}/g)?.join("-") || cleaned;
1331
+ }
1332
+ if (cleaned.replace(/-/g, "").length <= 16) {
1333
+ backupCode.value = cleaned;
1334
+ }
1329
1335
  backupCodeError.value = "";
1330
1336
  };
1331
1337
  const sendEmailCode = async () => {
@@ -1374,7 +1380,7 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
1374
1380
  };
1375
1381
  const authenticateHardwareKey = async () => {
1376
1382
  const sessionId = props.sessionId || authMfaSessionId.value;
1377
- if (!selectedMethod.value || selectedMethod.value.device_type !== "hardware" || !sessionId) {
1383
+ if (!selectedMethod.value || selectedMethod.value.device_type !== "hardware" && selectedMethod.value.device_type !== "passkey" || !sessionId) {
1378
1384
  emit("error", "Missing requirements for hardware key authentication");
1379
1385
  return;
1380
1386
  }
@@ -1384,19 +1390,21 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
1384
1390
  }
1385
1391
  const challenge = new Uint8Array(32);
1386
1392
  crypto.getRandomValues(challenge);
1393
+ const isPasskey = selectedMethod.value.device_type === "passkey";
1387
1394
  const publicKeyCredentialRequestOptions = {
1388
1395
  challenge,
1389
- timeout: 6e4,
1396
+ timeout: isPasskey ? 3e5 : 6e4,
1397
+ // Longer timeout for passkeys
1390
1398
  rpId: window.location.hostname,
1391
1399
  allowCredentials: [],
1392
1400
  // Empty to allow any registered credential
1393
- userVerification: "preferred"
1401
+ userVerification: isPasskey ? "required" : "discouraged"
1394
1402
  };
1395
1403
  const credential = await navigator.credentials.get({
1396
1404
  publicKey: publicKeyCredentialRequestOptions
1397
1405
  });
1398
1406
  if (!credential) {
1399
- throw new Error("Hardware key authentication was cancelled");
1407
+ throw new Error(`${selectedMethod.value.device_type === "passkey" ? "Passkey" : "Hardware key"} authentication was cancelled`);
1400
1408
  }
1401
1409
  const authenticatorData = new Uint8Array(credential.response.authenticatorData);
1402
1410
  let deviceInfo = "Security Key";
@@ -1480,39 +1488,49 @@ const _hoisted_18$6 = {
1480
1488
  key: 2,
1481
1489
  class: "text-center"
1482
1490
  };
1483
- const _hoisted_19$5 = {
1491
+ const _hoisted_19$6 = {
1484
1492
  key: 3,
1485
1493
  class: "text-center space-y-4"
1486
1494
  };
1487
- const _hoisted_20$3 = {
1495
+ const _hoisted_20$4 = { class: "bg-blue-50 border border-blue-200 rounded-lg p-4" };
1496
+ const _hoisted_21$4 = { class: "flex items-center space-x-3" };
1497
+ const _hoisted_22$3 = { class: "text-left" };
1498
+ const _hoisted_23$2 = { class: "font-medium text-blue-900" };
1499
+ const _hoisted_24$2 = { class: "text-sm text-blue-700" };
1500
+ const _hoisted_25$2 = { class: "pt-4 border-t border-gray-200" };
1501
+ const _hoisted_26$2 = {
1502
+ key: 0,
1503
+ class: "space-y-4 bg-amber-50 border border-amber-200 rounded-lg p-4"
1504
+ };
1505
+ const _hoisted_27$2 = {
1488
1506
  key: 4,
1489
1507
  class: "space-y-4"
1490
1508
  };
1491
- const _hoisted_21$3 = {
1509
+ const _hoisted_28$2 = {
1492
1510
  key: 0,
1493
1511
  class: "bg-green-50 border border-green-200 rounded-lg p-4"
1494
1512
  };
1495
- const _hoisted_22$3 = {
1513
+ const _hoisted_29$2 = {
1496
1514
  key: 1,
1497
1515
  class: "text-sm text-gray-600"
1498
1516
  };
1499
- const _hoisted_23$2 = {
1517
+ const _hoisted_30$2 = {
1500
1518
  key: 2,
1501
1519
  class: "flex justify-between text-sm"
1502
1520
  };
1503
- const _hoisted_24$2 = ["disabled"];
1504
- const _hoisted_25$2 = { class: "pt-4 border-t border-gray-200" };
1505
- const _hoisted_26$2 = {
1521
+ const _hoisted_31$2 = ["disabled"];
1522
+ const _hoisted_32$2 = { class: "pt-4 border-t border-gray-200" };
1523
+ const _hoisted_33$2 = {
1506
1524
  key: 3,
1507
- class: "space-y-4"
1525
+ class: "space-y-4 bg-amber-50 border border-amber-200 rounded-lg p-4"
1508
1526
  };
1509
- const _hoisted_27$2 = { class: "flex justify-between" };
1527
+ const _hoisted_34$1 = { class: "flex justify-between" };
1510
1528
  function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1511
1529
  return vue.openBlock(), vue.createBlock($setup["UiModal"], {
1512
1530
  open: $props.show,
1513
1531
  "card-class": "max-w-md"
1514
1532
  }, {
1515
- header: vue.withCtx(() => _cache[4] || (_cache[4] = [
1533
+ header: vue.withCtx(() => _cache[6] || (_cache[6] = [
1516
1534
  vue.createElementVNode(
1517
1535
  "div",
1518
1536
  { class: "text-center" },
@@ -1525,13 +1543,13 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1525
1543
  )
1526
1544
  ])),
1527
1545
  footer: vue.withCtx(() => [
1528
- vue.createElementVNode("div", _hoisted_27$2, [
1546
+ vue.createElementVNode("div", _hoisted_34$1, [
1529
1547
  vue.createVNode($setup["StrandsUiButton"], {
1530
1548
  variant: "secondary",
1531
1549
  onClick: $setup.closeModal,
1532
1550
  disabled: $setup.loading
1533
1551
  }, {
1534
- default: vue.withCtx(() => _cache[13] || (_cache[13] = [
1552
+ default: vue.withCtx(() => _cache[17] || (_cache[17] = [
1535
1553
  vue.createTextVNode(
1536
1554
  " Cancel ",
1537
1555
  -1
@@ -1539,24 +1557,24 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1539
1557
  )
1540
1558
  ])),
1541
1559
  _: 1,
1542
- __: [13]
1560
+ __: [17]
1543
1561
  }, 8, ["disabled"]),
1544
- $setup.selectedMethod && $setup.selectedMethod.device_type !== "hardware" && ($setup.selectedMethod.device_type !== "email" || $setup.emailCodeSent) ? (vue.openBlock(), vue.createBlock($setup["StrandsUiButton"], {
1562
+ $setup.selectedMethod && $setup.selectedMethod.device_type !== "hardware" && $setup.selectedMethod.device_type !== "passkey" && ($setup.selectedMethod.device_type !== "email" || $setup.emailCodeSent) || ($setup.selectedMethod?.device_type === "hardware" || $setup.selectedMethod?.device_type === "passkey") && $setup.showBackupCodeInput ? (vue.openBlock(), vue.createBlock($setup["StrandsUiButton"], {
1545
1563
  key: 0,
1546
1564
  variant: "primary",
1547
- onClick: _cache[3] || (_cache[3] = ($event) => $setup.showBackupCodeInput ? $setup.verifyBackupCode() : $setup.verify()),
1565
+ onClick: _cache[5] || (_cache[5] = ($event) => $setup.showBackupCodeInput ? $setup.verifyBackupCode() : $setup.verify()),
1548
1566
  disabled: !$setup.verificationCode.trim() && !$setup.backupCode.trim() || $setup.loading,
1549
1567
  loading: $setup.loading
1550
1568
  }, {
1551
- default: vue.withCtx(() => _cache[14] || (_cache[14] = [
1569
+ default: vue.withCtx(() => [
1552
1570
  vue.createTextVNode(
1553
- " Verify ",
1554
- -1
1555
- /* CACHED */
1571
+ vue.toDisplayString($setup.showBackupCodeInput ? "Verify Backup Code" : "Verify"),
1572
+ 1
1573
+ /* TEXT */
1556
1574
  )
1557
- ])),
1558
- _: 1,
1559
- __: [14]
1575
+ ]),
1576
+ _: 1
1577
+ /* STABLE */
1560
1578
  }, 8, ["disabled", "loading"])) : vue.createCommentVNode("v-if", true)
1561
1579
  ])
1562
1580
  ]),
@@ -1580,7 +1598,7 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1580
1598
  vue.createElementVNode("div", _hoisted_4$d, [
1581
1599
  vue.createCommentVNode(" Available MFA Methods "),
1582
1600
  $setup.availableMethods.length > 1 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$c, [
1583
- _cache[6] || (_cache[6] = vue.createElementVNode(
1601
+ _cache[8] || (_cache[8] = vue.createElementVNode(
1584
1602
  "p",
1585
1603
  { class: "text-sm font-medium text-gray-700" },
1586
1604
  "Choose verification method:",
@@ -1623,7 +1641,7 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1623
1641
  /* TEXT */
1624
1642
  )
1625
1643
  ]),
1626
- $setup.selectedMethod?.id === method.id ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12$a, [..._cache[5] || (_cache[5] = [
1644
+ $setup.selectedMethod?.id === method.id ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12$a, [..._cache[7] || (_cache[7] = [
1627
1645
  vue.createElementVNode(
1628
1646
  "svg",
1629
1647
  {
@@ -1685,7 +1703,7 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1685
1703
  )) : vue.createCommentVNode("v-if", true),
1686
1704
  vue.createCommentVNode(" Email MFA Code Request "),
1687
1705
  $setup.selectedMethod?.device_type === "email" && !$setup.emailCodeSent ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_18$6, [
1688
- _cache[8] || (_cache[8] = vue.createElementVNode(
1706
+ _cache[10] || (_cache[10] = vue.createElementVNode(
1689
1707
  "p",
1690
1708
  { class: "text-sm text-gray-600 mb-4" },
1691
1709
  "Click below to receive your verification code",
@@ -1698,7 +1716,7 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1698
1716
  disabled: $setup.loading,
1699
1717
  loading: $setup.loading
1700
1718
  }, {
1701
- default: vue.withCtx(() => _cache[7] || (_cache[7] = [
1719
+ default: vue.withCtx(() => _cache[9] || (_cache[9] = [
1702
1720
  vue.createTextVNode(
1703
1721
  " Send Verification Code ",
1704
1722
  -1
@@ -1706,17 +1724,17 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1706
1724
  )
1707
1725
  ])),
1708
1726
  _: 1,
1709
- __: [7]
1727
+ __: [9]
1710
1728
  }, 8, ["disabled", "loading"])
1711
1729
  ])) : vue.createCommentVNode("v-if", true),
1712
- vue.createCommentVNode(" Hardware Key Authentication "),
1713
- $setup.selectedMethod?.device_type === "hardware" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_19$5, [
1714
- _cache[10] || (_cache[10] = vue.createElementVNode(
1715
- "div",
1716
- { class: "bg-blue-50 border border-blue-200 rounded-lg p-4" },
1717
- [
1718
- vue.createElementVNode("div", { class: "flex items-center space-x-3" }, [
1719
- vue.createElementVNode("div", { class: "w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center" }, [
1730
+ vue.createCommentVNode(" Hardware Key & Passkey Authentication "),
1731
+ $setup.selectedMethod?.device_type === "hardware" || $setup.selectedMethod?.device_type === "passkey" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_19$6, [
1732
+ vue.createElementVNode("div", _hoisted_20$4, [
1733
+ vue.createElementVNode("div", _hoisted_21$4, [
1734
+ _cache[11] || (_cache[11] = vue.createElementVNode(
1735
+ "div",
1736
+ { class: "w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center" },
1737
+ [
1720
1738
  vue.createElementVNode("svg", {
1721
1739
  class: "w-6 h-6 text-blue-600",
1722
1740
  fill: "none",
@@ -1730,37 +1748,118 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1730
1748
  d: "M15 7a2 2 0 012 2m0 0a2 2 0 012 2v6a2 2 0 01-2 2H9a2 2 0 01-2-2V9a2 2 0 012-2m0 0V7a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h3m0 0v8m0-8h8m-8 8h8"
1731
1749
  })
1732
1750
  ])
1733
- ]),
1734
- vue.createElementVNode("div", { class: "text-left" }, [
1735
- vue.createElementVNode("h4", { class: "font-medium text-blue-900" }, "Touch your hardware key"),
1736
- vue.createElementVNode("p", { class: "text-sm text-blue-700" }, "Insert and touch your hardware key to authenticate")
1737
- ])
1751
+ ],
1752
+ -1
1753
+ /* CACHED */
1754
+ )),
1755
+ vue.createElementVNode("div", _hoisted_22$3, [
1756
+ vue.createElementVNode(
1757
+ "h4",
1758
+ _hoisted_23$2,
1759
+ vue.toDisplayString($setup.selectedMethod.device_type === "passkey" ? "Use your passkey" : "Touch your hardware key"),
1760
+ 1
1761
+ /* TEXT */
1762
+ ),
1763
+ vue.createElementVNode(
1764
+ "p",
1765
+ _hoisted_24$2,
1766
+ vue.toDisplayString($setup.selectedMethod.device_type === "passkey" ? "Use biometrics, PIN, or device security to authenticate" : "Insert and touch your hardware key to authenticate"),
1767
+ 1
1768
+ /* TEXT */
1769
+ )
1738
1770
  ])
1739
- ],
1740
- -1
1741
- /* CACHED */
1742
- )),
1771
+ ])
1772
+ ]),
1743
1773
  vue.createVNode($setup["StrandsUiButton"], {
1744
1774
  variant: "primary",
1745
1775
  onClick: $setup.authenticateHardwareKey,
1746
1776
  disabled: $setup.loading,
1747
1777
  loading: $setup.loading
1748
1778
  }, {
1749
- default: vue.withCtx(() => _cache[9] || (_cache[9] = [
1779
+ default: vue.withCtx(() => [
1750
1780
  vue.createTextVNode(
1751
- " Authenticate with Hardware Key ",
1781
+ vue.toDisplayString($setup.selectedMethod.device_type === "passkey" ? "Authenticate with Passkey" : "Authenticate with Hardware Key"),
1782
+ 1
1783
+ /* TEXT */
1784
+ )
1785
+ ]),
1786
+ _: 1
1787
+ /* STABLE */
1788
+ }, 8, ["disabled", "loading"]),
1789
+ vue.createCommentVNode(" Backup Codes Option for Hardware Keys "),
1790
+ vue.createElementVNode("div", _hoisted_25$2, [
1791
+ vue.createElementVNode("button", {
1792
+ onClick: _cache[0] || (_cache[0] = ($event) => $setup.showBackupCodeInput = !$setup.showBackupCodeInput),
1793
+ class: "flex items-center text-sm text-gray-600 hover:text-gray-800 transition-colors"
1794
+ }, [
1795
+ _cache[12] || (_cache[12] = vue.createElementVNode(
1796
+ "svg",
1797
+ {
1798
+ class: "w-4 h-4 mr-2",
1799
+ fill: "none",
1800
+ stroke: "currentColor",
1801
+ viewBox: "0 0 24 24"
1802
+ },
1803
+ [
1804
+ vue.createElementVNode("path", {
1805
+ "stroke-linecap": "round",
1806
+ "stroke-linejoin": "round",
1807
+ "stroke-width": "2",
1808
+ d: "M15 7a2 2 0 012 2m0 0a2 2 0 012 2v6a2 2 0 01-2 2H9a2 2 0 01-2-2V9a2 2 0 012-2m0 0V7a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h3m0 0v8m0-8h8m-8 8h8"
1809
+ })
1810
+ ],
1752
1811
  -1
1753
1812
  /* CACHED */
1813
+ )),
1814
+ vue.createTextVNode(
1815
+ " " + vue.toDisplayString($setup.showBackupCodeInput ? "Hide backup code" : $setup.selectedMethod.device_type === "passkey" ? "Can't access your passkey? Use backup code" : "Can't access your key? Use backup code"),
1816
+ 1
1817
+ /* TEXT */
1754
1818
  )
1755
- ])),
1756
- _: 1,
1757
- __: [9]
1758
- }, 8, ["disabled", "loading"])
1819
+ ])
1820
+ ]),
1821
+ vue.createCommentVNode(" Backup Code Input for Hardware Keys "),
1822
+ $setup.showBackupCodeInput ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_26$2, [
1823
+ _cache[13] || (_cache[13] = vue.createElementVNode(
1824
+ "div",
1825
+ { class: "flex items-start space-x-2 mb-3" },
1826
+ [
1827
+ vue.createElementVNode("svg", {
1828
+ class: "w-5 h-5 text-amber-600 mt-0.5 flex-shrink-0",
1829
+ fill: "currentColor",
1830
+ viewBox: "0 0 20 20"
1831
+ }, [
1832
+ vue.createElementVNode("path", {
1833
+ "fill-rule": "evenodd",
1834
+ d: "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z",
1835
+ "clip-rule": "evenodd"
1836
+ })
1837
+ ]),
1838
+ vue.createElementVNode("div", null, [
1839
+ vue.createElementVNode("p", { class: "text-sm font-medium text-amber-800" }, "Backup Code Recovery"),
1840
+ vue.createElementVNode("p", { class: "text-sm text-amber-700 mt-1" }, " Enter one of your backup codes. Each code can only be used once. ")
1841
+ ])
1842
+ ],
1843
+ -1
1844
+ /* CACHED */
1845
+ )),
1846
+ vue.createVNode($setup["StrandsUiInput"], {
1847
+ modelValue: $setup.backupCode,
1848
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => $setup.backupCode = $event),
1849
+ label: "Backup Code",
1850
+ placeholder: "abcd-efgh-ijkl",
1851
+ error: $setup.backupCodeError,
1852
+ disabled: $setup.loading,
1853
+ onInput: $setup.onBackupCodeInput,
1854
+ onKeydown: vue.withKeys($setup.verifyBackupCode, ["enter"]),
1855
+ class: "font-mono"
1856
+ }, null, 8, ["modelValue", "error", "disabled"])
1857
+ ])) : vue.createCommentVNode("v-if", true)
1759
1858
  ])) : vue.createCommentVNode("v-if", true),
1760
1859
  vue.createCommentVNode(" Code Input "),
1761
- $setup.selectedMethod && $setup.selectedMethod.device_type !== "hardware" && ($setup.selectedMethod.device_type !== "email" || $setup.emailCodeSent) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_20$3, [
1860
+ $setup.selectedMethod && $setup.selectedMethod.device_type !== "hardware" && $setup.selectedMethod.device_type !== "passkey" && ($setup.selectedMethod.device_type !== "email" || $setup.emailCodeSent) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_27$2, [
1762
1861
  vue.createCommentVNode(" Email confirmation "),
1763
- $setup.selectedMethod.device_type === "email" && $setup.emailCodeSent ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_21$3, _cache[11] || (_cache[11] = [
1862
+ $setup.selectedMethod.device_type === "email" && $setup.emailCodeSent ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_28$2, _cache[14] || (_cache[14] = [
1764
1863
  vue.createElementVNode(
1765
1864
  "div",
1766
1865
  { class: "flex items-start space-x-2" },
@@ -1788,7 +1887,7 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1788
1887
  vue.createCommentVNode(" Code Input Field "),
1789
1888
  vue.createVNode($setup["StrandsUiInput"], {
1790
1889
  modelValue: $setup.verificationCode,
1791
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $setup.verificationCode = $event),
1890
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => $setup.verificationCode = $event),
1792
1891
  label: "Verification Code",
1793
1892
  placeholder: $setup.selectedMethod.device_type === "totp" ? "123456" : "123456",
1794
1893
  maxlength: "6",
@@ -1801,45 +1900,87 @@ function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) {
1801
1900
  vue.createCommentVNode(" TOTP Help "),
1802
1901
  $setup.selectedMethod.device_type === "totp" ? (vue.openBlock(), vue.createElementBlock(
1803
1902
  "div",
1804
- _hoisted_22$3,
1903
+ _hoisted_29$2,
1805
1904
  ' Open your authenticator app and enter the 6-digit code for "' + vue.toDisplayString($setup.selectedMethod.device_name) + '" ',
1806
1905
  1
1807
1906
  /* TEXT */
1808
1907
  )) : vue.createCommentVNode("v-if", true),
1809
1908
  vue.createCommentVNode(" Email Resend "),
1810
- $setup.selectedMethod.device_type === "email" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_23$2, [
1909
+ $setup.selectedMethod.device_type === "email" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_30$2, [
1811
1910
  vue.createElementVNode("button", {
1812
1911
  onClick: $setup.sendEmailCode,
1813
1912
  disabled: $setup.loading || $setup.cooldownActive,
1814
1913
  class: "text-strands-600 hover:text-strands-800 disabled:text-gray-400 disabled:cursor-not-allowed"
1815
- }, vue.toDisplayString($setup.cooldownActive ? `Resend in ${$setup.cooldownSeconds}s` : "Resend Code"), 9, _hoisted_24$2)
1914
+ }, vue.toDisplayString($setup.cooldownActive ? `Resend in ${$setup.cooldownSeconds}s` : "Resend Code"), 9, _hoisted_31$2)
1816
1915
  ])) : vue.createCommentVNode("v-if", true),
1817
1916
  vue.createCommentVNode(" Backup Codes Option "),
1818
- vue.createElementVNode("div", _hoisted_25$2, [
1917
+ vue.createElementVNode("div", _hoisted_32$2, [
1819
1918
  vue.createElementVNode("button", {
1820
- onClick: _cache[1] || (_cache[1] = ($event) => $setup.showBackupCodeInput = !$setup.showBackupCodeInput),
1821
- class: "text-sm text-gray-600 hover:text-gray-800 underline"
1822
- }, " Use backup code instead ")
1919
+ onClick: _cache[3] || (_cache[3] = ($event) => $setup.showBackupCodeInput = !$setup.showBackupCodeInput),
1920
+ class: "flex items-center text-sm text-gray-600 hover:text-gray-800 transition-colors"
1921
+ }, [
1922
+ _cache[15] || (_cache[15] = vue.createElementVNode(
1923
+ "svg",
1924
+ {
1925
+ class: "w-4 h-4 mr-2",
1926
+ fill: "none",
1927
+ stroke: "currentColor",
1928
+ viewBox: "0 0 24 24"
1929
+ },
1930
+ [
1931
+ vue.createElementVNode("path", {
1932
+ "stroke-linecap": "round",
1933
+ "stroke-linejoin": "round",
1934
+ "stroke-width": "2",
1935
+ d: "M15 7a2 2 0 012 2m0 0a2 2 0 012 2v6a2 2 0 01-2 2H9a2 2 0 01-2-2V9a2 2 0 012-2m0 0V7a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h3m0 0v8m0-8h8m-8 8h8"
1936
+ })
1937
+ ],
1938
+ -1
1939
+ /* CACHED */
1940
+ )),
1941
+ vue.createTextVNode(
1942
+ " " + vue.toDisplayString($setup.showBackupCodeInput ? "Hide backup code" : "Use backup code instead"),
1943
+ 1
1944
+ /* TEXT */
1945
+ )
1946
+ ])
1823
1947
  ]),
1824
1948
  vue.createCommentVNode(" Backup Code Input "),
1825
- $setup.showBackupCodeInput ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_26$2, [
1949
+ $setup.showBackupCodeInput ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_33$2, [
1950
+ _cache[16] || (_cache[16] = vue.createElementVNode(
1951
+ "div",
1952
+ { class: "flex items-start space-x-2 mb-3" },
1953
+ [
1954
+ vue.createElementVNode("svg", {
1955
+ class: "w-5 h-5 text-amber-600 mt-0.5 flex-shrink-0",
1956
+ fill: "currentColor",
1957
+ viewBox: "0 0 20 20"
1958
+ }, [
1959
+ vue.createElementVNode("path", {
1960
+ "fill-rule": "evenodd",
1961
+ d: "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z",
1962
+ "clip-rule": "evenodd"
1963
+ })
1964
+ ]),
1965
+ vue.createElementVNode("div", null, [
1966
+ vue.createElementVNode("p", { class: "text-sm font-medium text-amber-800" }, "Backup Code Recovery"),
1967
+ vue.createElementVNode("p", { class: "text-sm text-amber-700 mt-1" }, " Enter one of your backup codes. Each code can only be used once. ")
1968
+ ])
1969
+ ],
1970
+ -1
1971
+ /* CACHED */
1972
+ )),
1826
1973
  vue.createVNode($setup["StrandsUiInput"], {
1827
1974
  modelValue: $setup.backupCode,
1828
- "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => $setup.backupCode = $event),
1975
+ "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => $setup.backupCode = $event),
1829
1976
  label: "Backup Code",
1830
- placeholder: "Enter backup code",
1977
+ placeholder: "abcd-efgh-ijkl",
1831
1978
  error: $setup.backupCodeError,
1832
1979
  disabled: $setup.loading,
1833
1980
  onInput: $setup.onBackupCodeInput,
1834
- onKeydown: vue.withKeys($setup.verifyBackupCode, ["enter"])
1835
- }, null, 8, ["modelValue", "error", "disabled"]),
1836
- _cache[12] || (_cache[12] = vue.createElementVNode(
1837
- "p",
1838
- { class: "text-xs text-gray-500" },
1839
- " Enter one of your backup codes. Each code can only be used once. ",
1840
- -1
1841
- /* CACHED */
1842
- ))
1981
+ onKeydown: vue.withKeys($setup.verifyBackupCode, ["enter"]),
1982
+ class: "font-mono"
1983
+ }, null, 8, ["modelValue", "error", "disabled"])
1843
1984
  ])) : vue.createCommentVNode("v-if", true)
1844
1985
  ])) : vue.createCommentVNode("v-if", true)
1845
1986
  ])
@@ -3246,9 +3387,9 @@ const _hoisted_15$6 = {
3246
3387
  const _hoisted_16$5 = { class: "alert-error" };
3247
3388
  const _hoisted_17$5 = { class: "flex items-start gap-3" };
3248
3389
  const _hoisted_18$5 = { class: "font-medium" };
3249
- const _hoisted_19$4 = { class: "mt-8 text-center" };
3250
- const _hoisted_20$2 = { class: "text-sm text-neutral-600" };
3251
- const _hoisted_21$2 = { key: 0 };
3390
+ const _hoisted_19$5 = { class: "mt-8 text-center" };
3391
+ const _hoisted_20$3 = { class: "text-sm text-neutral-600" };
3392
+ const _hoisted_21$3 = { key: 0 };
3252
3393
  const _hoisted_22$2 = { class: "text-neutral-400 text-sm" };
3253
3394
  function _sfc_render$f(_ctx, _cache, $props, $setup, $data, $options) {
3254
3395
  return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$d, [
@@ -3511,8 +3652,8 @@ function _sfc_render$f(_ctx, _cache, $props, $setup, $data, $options) {
3511
3652
  ])
3512
3653
  ])) : vue.createCommentVNode("v-if", true),
3513
3654
  vue.createCommentVNode(" Sign in link "),
3514
- vue.createElementVNode("div", _hoisted_19$4, [
3515
- vue.createElementVNode("p", _hoisted_20$2, [
3655
+ vue.createElementVNode("div", _hoisted_19$5, [
3656
+ vue.createElementVNode("p", _hoisted_20$3, [
3516
3657
  _cache[10] || (_cache[10] = vue.createTextVNode(
3517
3658
  " Already have an account? ",
3518
3659
  -1
@@ -3531,7 +3672,7 @@ function _sfc_render$f(_ctx, _cache, $props, $setup, $data, $options) {
3531
3672
  }, {
3532
3673
  default: vue.withCtx(() => [
3533
3674
  vue.createCommentVNode(" Need help "),
3534
- $setup.getSupportEmail() ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_21$2, [
3675
+ $setup.getSupportEmail() ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_21$3, [
3535
3676
  vue.createElementVNode("p", _hoisted_22$2, [
3536
3677
  _cache[12] || (_cache[12] = vue.createTextVNode(
3537
3678
  " Need help? ",
@@ -6560,7 +6701,7 @@ const _hoisted_15$5 = { class: "bg-red-50 border border-red-200 rounded-lg p-4"
6560
6701
  const _hoisted_16$4 = { class: "bg-white rounded border p-3" };
6561
6702
  const _hoisted_17$4 = { class: "grid grid-cols-2 gap-2 text-sm font-mono text-gray-900" };
6562
6703
  const _hoisted_18$4 = { class: "flex justify-center mt-3" };
6563
- const _hoisted_19$3 = { class: "flex justify-end pt-4" };
6704
+ const _hoisted_19$4 = { class: "flex justify-end pt-4" };
6564
6705
  function _sfc_render$d(_ctx, _cache, $props, $setup, $data, $options) {
6565
6706
  return vue.openBlock(), vue.createBlock($setup["UiModal"], {
6566
6707
  open: $props.show,
@@ -6901,7 +7042,7 @@ function _sfc_render$d(_ctx, _cache, $props, $setup, $data, $options) {
6901
7042
  })
6902
7043
  ])
6903
7044
  ]),
6904
- vue.createElementVNode("div", _hoisted_19$3, [
7045
+ vue.createElementVNode("div", _hoisted_19$4, [
6905
7046
  vue.createVNode($setup["StrandsUiButton"], {
6906
7047
  variant: "primary",
6907
7048
  onClick: $setup.finish
@@ -7386,7 +7527,7 @@ const _sfc_main$b = /* @__PURE__ */ vue.defineComponent({
7386
7527
  const closeModal = () => {
7387
7528
  emit("close");
7388
7529
  };
7389
- const createMinimalWebAuthnChallenge = (challenge) => {
7530
+ const createOptimizedWebAuthnChallenge = (challenge, deviceType) => {
7390
7531
  const safeBufferConvert = (data) => {
7391
7532
  try {
7392
7533
  if (!data) {
@@ -7427,15 +7568,31 @@ const _sfc_main$b = /* @__PURE__ */ vue.defineComponent({
7427
7568
  challenge: safeBufferConvert(challenge.challenge),
7428
7569
  pubKeyCredParams: challenge.pubKeyCredParams || [
7429
7570
  { type: "public-key", alg: -7 },
7430
- // ES256
7431
- { type: "public-key", alg: -257 }
7432
- // RS256
7571
+ // ES256 (ECDSA w/ SHA-256)
7572
+ { type: "public-key", alg: -35 },
7573
+ // ES384 (ECDSA w/ SHA-384)
7574
+ { type: "public-key", alg: -36 },
7575
+ // ES512 (ECDSA w/ SHA-512)
7576
+ { type: "public-key", alg: -257 },
7577
+ // RS256 (RSASSA-PKCS1-v1_5 w/ SHA-256)
7578
+ { type: "public-key", alg: -258 },
7579
+ // RS384 (RSASSA-PKCS1-v1_5 w/ SHA-384)
7580
+ { type: "public-key", alg: -259 },
7581
+ // RS512 (RSASSA-PKCS1-v1_5 w/ SHA-512)
7582
+ { type: "public-key", alg: -37 },
7583
+ // PS256 (RSASSA-PSS w/ SHA-256)
7584
+ { type: "public-key", alg: -38 },
7585
+ // PS384 (RSASSA-PSS w/ SHA-384)
7586
+ { type: "public-key", alg: -39 },
7587
+ // PS512 (RSASSA-PSS w/ SHA-512)
7588
+ { type: "public-key", alg: -8 }
7589
+ // EdDSA (Ed25519)
7433
7590
  ],
7434
- timeout: challenge.timeout || 6e4,
7435
- authenticatorSelection: challenge.authenticatorSelection || {
7436
- userVerification: "preferred"
7437
- },
7438
- attestation: challenge.attestation || "none"
7591
+ timeout: challenge.timeout || (deviceType === "passkey" ? 3e5 : 12e4),
7592
+ // Longer timeout for passkeys
7593
+ authenticatorSelection: challenge.authenticatorSelection || getOptimalAuthenticatorSelection(deviceType),
7594
+ attestation: challenge.attestation || (deviceType === "passkey" ? "none" : "direct")
7595
+ // Different attestation preferences
7439
7596
  };
7440
7597
  if (challenge.excludeCredentials && Array.isArray(challenge.excludeCredentials) && challenge.excludeCredentials.length > 0) {
7441
7598
  cleanChallenge.excludeCredentials = challenge.excludeCredentials.map((cred) => ({
@@ -7460,11 +7617,21 @@ const _sfc_main$b = /* @__PURE__ */ vue.defineComponent({
7460
7617
  const handleRegisterHardwareKey = async () => {
7461
7618
  internalLoading.value = true;
7462
7619
  step.value = 3;
7463
- registrationMessage.value = "Starting hardware key registration...";
7620
+ registrationMessage.value = `Starting ${props.deviceType === "passkey" ? "passkey" : "hardware key"} registration...`;
7464
7621
  try {
7465
7622
  if (!window.navigator.credentials || !window.PublicKeyCredential) {
7466
7623
  throw new Error("WebAuthn is not supported in this browser");
7467
7624
  }
7625
+ try {
7626
+ const available = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable?.();
7627
+ console.log("Platform authenticator available:", available);
7628
+ if (PublicKeyCredential.isConditionalMediationAvailable) {
7629
+ const conditionalMediationAvailable = await PublicKeyCredential.isConditionalMediationAvailable();
7630
+ console.log("Conditional mediation available:", conditionalMediationAvailable);
7631
+ }
7632
+ } catch (checkError) {
7633
+ console.warn("Could not check authenticator availability:", checkError);
7634
+ }
7468
7635
  if (!currentSession.value?.accessToken) {
7469
7636
  throw new Error("Not authenticated. Please sign in again.");
7470
7637
  }
@@ -7480,7 +7647,7 @@ const _sfc_main$b = /* @__PURE__ */ vue.defineComponent({
7480
7647
  if (challenge.user) {
7481
7648
  console.log("Challenge.user.id type:", typeof challenge.user.id, challenge.user.id);
7482
7649
  }
7483
- const processedChallenge = createMinimalWebAuthnChallenge(challenge);
7650
+ const processedChallenge = createOptimizedWebAuthnChallenge(challenge, props.deviceType);
7484
7651
  console.log("Processed challenge for WebAuthn:", processedChallenge);
7485
7652
  registrationMessage.value = "Please touch your hardware key now...";
7486
7653
  const credential = await navigator.credentials.create({
@@ -7531,7 +7698,26 @@ const _sfc_main$b = /* @__PURE__ */ vue.defineComponent({
7531
7698
  }
7532
7699
  } catch (error) {
7533
7700
  console.error("Hardware key registration error:", error);
7534
- errorMessage.value = error instanceof Error ? error.message : "Hardware key registration failed";
7701
+ let userErrorMessage = "Hardware key registration failed";
7702
+ if (error instanceof Error) {
7703
+ const errorMsg = error.message.toLowerCase();
7704
+ if (errorMsg.includes("not supported") || errorMsg.includes("webauthn")) {
7705
+ userErrorMessage = "WebAuthn is not supported in this browser. Please use Chrome, Firefox, Safari, or Edge.";
7706
+ } else if (errorMsg.includes("cancelled") || errorMsg.includes("aborted")) {
7707
+ userErrorMessage = "Hardware key registration was cancelled. Please try again and touch your key when prompted.";
7708
+ } else if (errorMsg.includes("timeout")) {
7709
+ userErrorMessage = "Hardware key registration timed out. Please ensure your key is connected and try again.";
7710
+ } else if (errorMsg.includes("not allowed") || errorMsg.includes("invalid state")) {
7711
+ userErrorMessage = "This hardware key may already be registered or cannot be used. Try a different key or contact support.";
7712
+ } else if (errorMsg.includes("can't be used") || errorMsg.includes("newer or different")) {
7713
+ userErrorMessage = "Your hardware key is not compatible. Please ensure you have a FIDO2/WebAuthn compatible key like YubiKey 5 Series, and that it's properly connected.";
7714
+ } else if (errorMsg.includes("user verification") || errorMsg.includes("pin")) {
7715
+ userErrorMessage = "Hardware key verification failed. If your key has a PIN, please enter it when prompted.";
7716
+ } else {
7717
+ userErrorMessage = error.message;
7718
+ }
7719
+ }
7720
+ errorMessage.value = userErrorMessage;
7535
7721
  step.value = 5;
7536
7722
  } finally {
7537
7723
  internalLoading.value = false;
@@ -7550,7 +7736,7 @@ const _sfc_main$b = /* @__PURE__ */ vue.defineComponent({
7550
7736
  const finish = () => {
7551
7737
  emit("success");
7552
7738
  };
7553
- const __returned__ = { props, emit, mfaLoading, registerHardwareKey, completeHardwareKeyRegistration, currentSession, internalLoading, loading: loading2, step, deviceName, deviceNameError, registrationMessage, errorMessage, backupCodes, closeModal, createMinimalWebAuthnChallenge, startSetup, handleRegisterHardwareKey, copyBackupCodes, finish, get StrandsUiButton() {
7739
+ const __returned__ = { props, emit, mfaLoading, registerHardwareKey, completeHardwareKeyRegistration, currentSession, internalLoading, loading: loading2, step, deviceName, deviceNameError, registrationMessage, errorMessage, backupCodes, closeModal, createOptimizedWebAuthnChallenge, startSetup, handleRegisterHardwareKey, copyBackupCodes, finish, get StrandsUiButton() {
7554
7740
  return StrandsUiButton;
7555
7741
  }, get StrandsUiInput() {
7556
7742
  return StrandsUiInput;
@@ -7570,30 +7756,33 @@ const _hoisted_3$8 = {
7570
7756
  key: 1,
7571
7757
  class: "space-y-4"
7572
7758
  };
7573
- const _hoisted_4$6 = { class: "flex justify-end space-x-3 pt-4" };
7574
- const _hoisted_5$5 = {
7759
+ const _hoisted_4$6 = { class: "bg-blue-50 border border-blue-200 rounded-lg p-4" };
7760
+ const _hoisted_5$5 = { class: "flex items-start space-x-2" };
7761
+ const _hoisted_6$4 = { class: "text-sm text-blue-700 mt-1 space-y-1" };
7762
+ const _hoisted_7$4 = { class: "flex justify-end space-x-3 pt-4" };
7763
+ const _hoisted_8$4 = {
7575
7764
  key: 2,
7576
7765
  class: "space-y-4"
7577
7766
  };
7578
- const _hoisted_6$4 = { class: "text-center" };
7579
- const _hoisted_7$4 = { class: "w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4" };
7580
- const _hoisted_8$4 = { class: "text-sm text-gray-600 mb-6" };
7581
- const _hoisted_9$4 = {
7767
+ const _hoisted_9$4 = { class: "text-center" };
7768
+ const _hoisted_10$4 = { class: "w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4" };
7769
+ const _hoisted_11$4 = { class: "text-sm text-gray-600 mb-6" };
7770
+ const _hoisted_12$4 = {
7582
7771
  key: 3,
7583
7772
  class: "space-y-4"
7584
7773
  };
7585
- const _hoisted_10$4 = { class: "bg-red-50 border border-red-200 rounded-lg p-4" };
7586
- const _hoisted_11$4 = { class: "bg-white rounded border p-3" };
7587
- const _hoisted_12$4 = { class: "grid grid-cols-2 gap-2 text-sm font-mono text-gray-900" };
7588
- const _hoisted_13$4 = { class: "flex justify-center mt-3" };
7589
- const _hoisted_14$4 = { class: "flex justify-end pt-4" };
7590
- const _hoisted_15$4 = {
7774
+ const _hoisted_13$4 = { class: "bg-red-50 border border-red-200 rounded-lg p-4" };
7775
+ const _hoisted_14$4 = { class: "bg-white rounded border p-3" };
7776
+ const _hoisted_15$4 = { class: "grid grid-cols-2 gap-2 text-sm font-mono text-gray-900" };
7777
+ const _hoisted_16$3 = { class: "flex justify-center mt-3" };
7778
+ const _hoisted_17$3 = { class: "flex justify-end pt-4" };
7779
+ const _hoisted_18$3 = {
7591
7780
  key: 4,
7592
7781
  class: "space-y-4"
7593
7782
  };
7594
- const _hoisted_16$3 = { class: "text-center" };
7595
- const _hoisted_17$3 = { class: "text-sm text-gray-600 mb-6" };
7596
- const _hoisted_18$3 = { class: "flex justify-end space-x-3 pt-4" };
7783
+ const _hoisted_19$3 = { class: "text-center" };
7784
+ const _hoisted_20$2 = { class: "text-sm text-gray-600 mb-6" };
7785
+ const _hoisted_21$2 = { class: "flex justify-end space-x-3 pt-4" };
7597
7786
  function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7598
7787
  return vue.openBlock(), vue.createBlock($setup["UiModal"], {
7599
7788
  open: $props.show,
@@ -7690,7 +7879,7 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7690
7879
  ])
7691
7880
  ])) : vue.createCommentVNode("v-if", true),
7692
7881
  $setup.step === 2 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$8, [
7693
- _cache[10] || (_cache[10] = vue.createElementVNode(
7882
+ _cache[18] || (_cache[18] = vue.createElementVNode(
7694
7883
  "div",
7695
7884
  null,
7696
7885
  [
@@ -7701,7 +7890,7 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7701
7890
  /* CACHED */
7702
7891
  )),
7703
7892
  vue.createCommentVNode(" Hardware Key Illustration "),
7704
- _cache[11] || (_cache[11] = vue.createElementVNode(
7893
+ _cache[19] || (_cache[19] = vue.createElementVNode(
7705
7894
  "div",
7706
7895
  { class: "flex justify-center bg-gray-50 p-6 rounded-lg" },
7707
7896
  [
@@ -7729,42 +7918,102 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7729
7918
  /* CACHED */
7730
7919
  )),
7731
7920
  vue.createCommentVNode(" Instructions "),
7732
- _cache[12] || (_cache[12] = vue.createElementVNode(
7733
- "div",
7734
- { class: "bg-blue-50 border border-blue-200 rounded-lg p-4" },
7735
- [
7736
- vue.createElementVNode("div", { class: "flex items-start space-x-2" }, [
7737
- vue.createElementVNode("svg", {
7921
+ vue.createElementVNode("div", _hoisted_4$6, [
7922
+ vue.createElementVNode("div", _hoisted_5$5, [
7923
+ _cache[15] || (_cache[15] = vue.createElementVNode(
7924
+ "svg",
7925
+ {
7738
7926
  class: "w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0",
7739
7927
  fill: "currentColor",
7740
7928
  viewBox: "0 0 20 20"
7741
- }, [
7929
+ },
7930
+ [
7742
7931
  vue.createElementVNode("path", {
7743
7932
  "fill-rule": "evenodd",
7744
7933
  d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z",
7745
7934
  "clip-rule": "evenodd"
7746
7935
  })
7747
- ]),
7748
- vue.createElementVNode("div", null, [
7749
- vue.createElementVNode("p", { class: "text-sm font-medium text-blue-800" }, "Setup Instructions"),
7750
- vue.createElementVNode("ul", { class: "text-sm text-blue-700 mt-1 space-y-1" }, [
7751
- vue.createElementVNode("li", null, "• Insert your hardware key into a USB port"),
7752
- vue.createElementVNode("li", null, "• Your browser will prompt you to interact with the key"),
7753
- vue.createElementVNode("li", null, "• Touch the key's button or sensor when prompted")
7754
- ])
7936
+ ],
7937
+ -1
7938
+ /* CACHED */
7939
+ )),
7940
+ vue.createElementVNode("div", null, [
7941
+ _cache[14] || (_cache[14] = vue.createElementVNode(
7942
+ "p",
7943
+ { class: "text-sm font-medium text-blue-800" },
7944
+ "Setup Instructions",
7945
+ -1
7946
+ /* CACHED */
7947
+ )),
7948
+ vue.createElementVNode("ul", _hoisted_6$4, [
7949
+ $setup.props.deviceType === "passkey" ? (vue.openBlock(), vue.createElementBlock(
7950
+ vue.Fragment,
7951
+ { key: 0 },
7952
+ [
7953
+ _cache[8] || (_cache[8] = vue.createElementVNode(
7954
+ "li",
7955
+ null,
7956
+ "• Your browser will prompt you to create a passkey",
7957
+ -1
7958
+ /* CACHED */
7959
+ )),
7960
+ _cache[9] || (_cache[9] = vue.createElementVNode(
7961
+ "li",
7962
+ null,
7963
+ "• Use Touch ID, Face ID, Windows Hello, or PIN",
7964
+ -1
7965
+ /* CACHED */
7966
+ )),
7967
+ _cache[10] || (_cache[10] = vue.createElementVNode(
7968
+ "li",
7969
+ null,
7970
+ "• Follow the prompts to complete setup",
7971
+ -1
7972
+ /* CACHED */
7973
+ ))
7974
+ ],
7975
+ 64
7976
+ /* STABLE_FRAGMENT */
7977
+ )) : (vue.openBlock(), vue.createElementBlock(
7978
+ vue.Fragment,
7979
+ { key: 1 },
7980
+ [
7981
+ _cache[11] || (_cache[11] = vue.createElementVNode(
7982
+ "li",
7983
+ null,
7984
+ "• Insert your hardware key into a USB port",
7985
+ -1
7986
+ /* CACHED */
7987
+ )),
7988
+ _cache[12] || (_cache[12] = vue.createElementVNode(
7989
+ "li",
7990
+ null,
7991
+ "• Your browser will prompt you to interact with the key",
7992
+ -1
7993
+ /* CACHED */
7994
+ )),
7995
+ _cache[13] || (_cache[13] = vue.createElementVNode(
7996
+ "li",
7997
+ null,
7998
+ "• Touch the key's button or sensor when prompted",
7999
+ -1
8000
+ /* CACHED */
8001
+ ))
8002
+ ],
8003
+ 64
8004
+ /* STABLE_FRAGMENT */
8005
+ ))
7755
8006
  ])
7756
8007
  ])
7757
- ],
7758
- -1
7759
- /* CACHED */
7760
- )),
7761
- vue.createElementVNode("div", _hoisted_4$6, [
8008
+ ])
8009
+ ]),
8010
+ vue.createElementVNode("div", _hoisted_7$4, [
7762
8011
  vue.createVNode($setup["StrandsUiButton"], {
7763
8012
  variant: "secondary",
7764
8013
  onClick: _cache[1] || (_cache[1] = ($event) => $setup.step = 1),
7765
8014
  disabled: $setup.loading
7766
8015
  }, {
7767
- default: vue.withCtx(() => _cache[8] || (_cache[8] = [
8016
+ default: vue.withCtx(() => _cache[16] || (_cache[16] = [
7768
8017
  vue.createTextVNode(
7769
8018
  " Back ",
7770
8019
  -1
@@ -7772,7 +8021,7 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7772
8021
  )
7773
8022
  ])),
7774
8023
  _: 1,
7775
- __: [8]
8024
+ __: [16]
7776
8025
  }, 8, ["disabled"]),
7777
8026
  vue.createVNode($setup["StrandsUiButton"], {
7778
8027
  variant: "primary",
@@ -7780,7 +8029,7 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7780
8029
  disabled: $setup.loading,
7781
8030
  loading: $setup.loading
7782
8031
  }, {
7783
- default: vue.withCtx(() => _cache[9] || (_cache[9] = [
8032
+ default: vue.withCtx(() => _cache[17] || (_cache[17] = [
7784
8033
  vue.createTextVNode(
7785
8034
  " Register Key ",
7786
8035
  -1
@@ -7788,19 +8037,19 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7788
8037
  )
7789
8038
  ])),
7790
8039
  _: 1,
7791
- __: [9]
8040
+ __: [17]
7792
8041
  }, 8, ["disabled", "loading"])
7793
8042
  ])
7794
8043
  ])) : vue.createCommentVNode("v-if", true),
7795
- $setup.step === 3 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$5, [
7796
- vue.createElementVNode("div", _hoisted_6$4, [
7797
- vue.createElementVNode("div", _hoisted_7$4, [
8044
+ $setup.step === 3 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_8$4, [
8045
+ vue.createElementVNode("div", _hoisted_9$4, [
8046
+ vue.createElementVNode("div", _hoisted_10$4, [
7798
8047
  vue.createVNode($setup["StrandsUiLoader"], {
7799
8048
  size: 24,
7800
8049
  class: "text-blue-600"
7801
8050
  })
7802
8051
  ]),
7803
- _cache[13] || (_cache[13] = vue.createElementVNode(
8052
+ _cache[20] || (_cache[20] = vue.createElementVNode(
7804
8053
  "h3",
7805
8054
  { class: "text-lg font-semibold text-gray-900 mb-2" },
7806
8055
  "Registering Hardware Key",
@@ -7809,14 +8058,14 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7809
8058
  )),
7810
8059
  vue.createElementVNode(
7811
8060
  "p",
7812
- _hoisted_8$4,
8061
+ _hoisted_11$4,
7813
8062
  vue.toDisplayString($setup.registrationMessage),
7814
8063
  1
7815
8064
  /* TEXT */
7816
8065
  )
7817
8066
  ]),
7818
8067
  vue.createCommentVNode(" Dynamic Progress Indicator "),
7819
- _cache[14] || (_cache[14] = vue.createElementVNode(
8068
+ _cache[21] || (_cache[21] = vue.createElementVNode(
7820
8069
  "div",
7821
8070
  { class: "bg-gray-50 p-4 rounded-lg" },
7822
8071
  [
@@ -7845,8 +8094,8 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7845
8094
  /* CACHED */
7846
8095
  ))
7847
8096
  ])) : vue.createCommentVNode("v-if", true),
7848
- $setup.step === 4 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$4, [
7849
- _cache[18] || (_cache[18] = vue.createElementVNode(
8097
+ $setup.step === 4 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12$4, [
8098
+ _cache[25] || (_cache[25] = vue.createElementVNode(
7850
8099
  "div",
7851
8100
  { class: "text-center" },
7852
8101
  [
@@ -7872,8 +8121,8 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7872
8121
  /* CACHED */
7873
8122
  )),
7874
8123
  vue.createCommentVNode(" Backup Codes "),
7875
- vue.createElementVNode("div", _hoisted_10$4, [
7876
- _cache[16] || (_cache[16] = vue.createElementVNode(
8124
+ vue.createElementVNode("div", _hoisted_13$4, [
8125
+ _cache[23] || (_cache[23] = vue.createElementVNode(
7877
8126
  "div",
7878
8127
  { class: "flex items-start space-x-2 mb-3" },
7879
8128
  [
@@ -7896,8 +8145,8 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7896
8145
  -1
7897
8146
  /* CACHED */
7898
8147
  )),
7899
- vue.createElementVNode("div", _hoisted_11$4, [
7900
- vue.createElementVNode("div", _hoisted_12$4, [
8148
+ vue.createElementVNode("div", _hoisted_14$4, [
8149
+ vue.createElementVNode("div", _hoisted_15$4, [
7901
8150
  (vue.openBlock(true), vue.createElementBlock(
7902
8151
  vue.Fragment,
7903
8152
  null,
@@ -7918,13 +8167,13 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7918
8167
  ))
7919
8168
  ])
7920
8169
  ]),
7921
- vue.createElementVNode("div", _hoisted_13$4, [
8170
+ vue.createElementVNode("div", _hoisted_16$3, [
7922
8171
  vue.createVNode($setup["StrandsUiButton"], {
7923
8172
  variant: "secondary",
7924
8173
  size: "sm",
7925
8174
  onClick: $setup.copyBackupCodes
7926
8175
  }, {
7927
- default: vue.withCtx(() => _cache[15] || (_cache[15] = [
8176
+ default: vue.withCtx(() => _cache[22] || (_cache[22] = [
7928
8177
  vue.createTextVNode(
7929
8178
  " 📋 Copy Codes ",
7930
8179
  -1
@@ -7932,16 +8181,16 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7932
8181
  )
7933
8182
  ])),
7934
8183
  _: 1,
7935
- __: [15]
8184
+ __: [22]
7936
8185
  })
7937
8186
  ])
7938
8187
  ]),
7939
- vue.createElementVNode("div", _hoisted_14$4, [
8188
+ vue.createElementVNode("div", _hoisted_17$3, [
7940
8189
  vue.createVNode($setup["StrandsUiButton"], {
7941
8190
  variant: "primary",
7942
8191
  onClick: $setup.finish
7943
8192
  }, {
7944
- default: vue.withCtx(() => _cache[17] || (_cache[17] = [
8193
+ default: vue.withCtx(() => _cache[24] || (_cache[24] = [
7945
8194
  vue.createTextVNode(
7946
8195
  " Done ",
7947
8196
  -1
@@ -7949,13 +8198,13 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7949
8198
  )
7950
8199
  ])),
7951
8200
  _: 1,
7952
- __: [17]
8201
+ __: [24]
7953
8202
  })
7954
8203
  ])
7955
8204
  ])) : vue.createCommentVNode("v-if", true),
7956
- $setup.step === 5 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_15$4, [
7957
- vue.createElementVNode("div", _hoisted_16$3, [
7958
- _cache[19] || (_cache[19] = vue.createElementVNode(
8205
+ $setup.step === 5 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_18$3, [
8206
+ vue.createElementVNode("div", _hoisted_19$3, [
8207
+ _cache[26] || (_cache[26] = vue.createElementVNode(
7959
8208
  "div",
7960
8209
  { class: "w-12 h-12 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4" },
7961
8210
  [
@@ -7976,7 +8225,7 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7976
8225
  -1
7977
8226
  /* CACHED */
7978
8227
  )),
7979
- _cache[20] || (_cache[20] = vue.createElementVNode(
8228
+ _cache[27] || (_cache[27] = vue.createElementVNode(
7980
8229
  "h3",
7981
8230
  { class: "text-lg font-semibold text-gray-900 mb-2" },
7982
8231
  "Registration Failed",
@@ -7985,18 +8234,18 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
7985
8234
  )),
7986
8235
  vue.createElementVNode(
7987
8236
  "p",
7988
- _hoisted_17$3,
8237
+ _hoisted_20$2,
7989
8238
  vue.toDisplayString($setup.errorMessage),
7990
8239
  1
7991
8240
  /* TEXT */
7992
8241
  )
7993
8242
  ]),
7994
- vue.createElementVNode("div", _hoisted_18$3, [
8243
+ vue.createElementVNode("div", _hoisted_21$2, [
7995
8244
  vue.createVNode($setup["StrandsUiButton"], {
7996
8245
  variant: "secondary",
7997
8246
  onClick: _cache[2] || (_cache[2] = ($event) => $setup.step = 1)
7998
8247
  }, {
7999
- default: vue.withCtx(() => _cache[21] || (_cache[21] = [
8248
+ default: vue.withCtx(() => _cache[28] || (_cache[28] = [
8000
8249
  vue.createTextVNode(
8001
8250
  " Start Over ",
8002
8251
  -1
@@ -8004,13 +8253,13 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
8004
8253
  )
8005
8254
  ])),
8006
8255
  _: 1,
8007
- __: [21]
8256
+ __: [28]
8008
8257
  }),
8009
8258
  vue.createVNode($setup["StrandsUiButton"], {
8010
8259
  variant: "primary",
8011
8260
  onClick: $setup.closeModal
8012
8261
  }, {
8013
- default: vue.withCtx(() => _cache[22] || (_cache[22] = [
8262
+ default: vue.withCtx(() => _cache[29] || (_cache[29] = [
8014
8263
  vue.createTextVNode(
8015
8264
  " Close ",
8016
8265
  -1
@@ -8018,7 +8267,7 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
8018
8267
  )
8019
8268
  ])),
8020
8269
  _: 1,
8021
- __: [22]
8270
+ __: [29]
8022
8271
  })
8023
8272
  ])
8024
8273
  ])) : vue.createCommentVNode("v-if", true)
@@ -8557,6 +8806,7 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
8557
8806
  const showTotpSetup = vue.ref(false);
8558
8807
  const showEmailMfaSetup = vue.ref(false);
8559
8808
  const showHardwareKeySetup = vue.ref(false);
8809
+ const showPasskeySetup = vue.ref(false);
8560
8810
  const showBackupCodesModal = vue.ref(false);
8561
8811
  const showConfirmDisable = vue.ref(false);
8562
8812
  const selectedDevice = vue.ref(null);
@@ -8582,6 +8832,9 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
8582
8832
  const startHardwareKeySetup = () => {
8583
8833
  showHardwareKeySetup.value = true;
8584
8834
  };
8835
+ const startPasskeySetup = () => {
8836
+ showPasskeySetup.value = true;
8837
+ };
8585
8838
  const showBackupCodes = (device) => {
8586
8839
  selectedDevice.value = device;
8587
8840
  showBackupCodesModal.value = true;
@@ -8628,6 +8881,12 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
8628
8881
  activeTab.value = "manage";
8629
8882
  emit("mfa-updated");
8630
8883
  };
8884
+ const handlePasskeySetupSuccess = async () => {
8885
+ showPasskeySetup.value = false;
8886
+ await fetchMfaDevices();
8887
+ activeTab.value = "manage";
8888
+ emit("mfa-updated");
8889
+ };
8631
8890
  const getDeviceIconBackground = (deviceType) => {
8632
8891
  switch (deviceType) {
8633
8892
  case "totp":
@@ -8635,8 +8894,9 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
8635
8894
  case "email":
8636
8895
  return "bg-green-50 group-hover:bg-green-100";
8637
8896
  case "hardware":
8638
- case "passkey":
8639
8897
  return "bg-purple-50 group-hover:bg-purple-100";
8898
+ case "passkey":
8899
+ return "bg-indigo-50 group-hover:bg-indigo-100";
8640
8900
  default:
8641
8901
  return "bg-gray-50 group-hover:bg-gray-100";
8642
8902
  }
@@ -8648,13 +8908,14 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
8648
8908
  case "email":
8649
8909
  return Mail;
8650
8910
  case "hardware":
8651
- case "passkey":
8652
8911
  return KeyRound;
8912
+ case "passkey":
8913
+ return Shield;
8653
8914
  default:
8654
8915
  return Shield;
8655
8916
  }
8656
8917
  };
8657
- const __returned__ = { props, emit, mfaDevices: mfaDevices2, mfaEnabled: mfaEnabled2, mfaLoading, activeMfaDevices, fetchMfaDevices, disableMfaDevice, sendEmailMfaCode, getDeviceTypeIcon, getDeviceTypeName, formatLastUsed, showModal, activeTab, showTotpSetup, showEmailMfaSetup, showHardwareKeySetup, showBackupCodesModal, showConfirmDisable, selectedDevice, closeModal, startTotpSetup, startEmailMfaSetup, startHardwareKeySetup, showBackupCodes, testEmailMfa, confirmDisableDevice, handleDisableDevice, handleTotpSetupSuccess, handleEmailMfaSetupSuccess, handleHardwareKeySetupSuccess, getDeviceIconBackground, getDeviceIconComponent, get StrandsUiButton() {
8918
+ const __returned__ = { props, emit, mfaDevices: mfaDevices2, mfaEnabled: mfaEnabled2, mfaLoading, activeMfaDevices, fetchMfaDevices, disableMfaDevice, sendEmailMfaCode, getDeviceTypeIcon, getDeviceTypeName, formatLastUsed, showModal, activeTab, showTotpSetup, showEmailMfaSetup, showHardwareKeySetup, showPasskeySetup, showBackupCodesModal, showConfirmDisable, selectedDevice, closeModal, startTotpSetup, startEmailMfaSetup, startHardwareKeySetup, startPasskeySetup, showBackupCodes, testEmailMfa, confirmDisableDevice, handleDisableDevice, handleTotpSetupSuccess, handleEmailMfaSetupSuccess, handleHardwareKeySetupSuccess, handlePasskeySetupSuccess, getDeviceIconBackground, getDeviceIconComponent, get StrandsUiButton() {
8658
8919
  return StrandsUiButton;
8659
8920
  }, get StrandsUiLoader() {
8660
8921
  return StrandsUiLoader;
@@ -8709,15 +8970,18 @@ const _hoisted_18$2 = { class: "flex flex-col space-y-2 ml-4" };
8709
8970
  const _hoisted_19$2 = { class: "flex items-center justify-between" };
8710
8971
  const _hoisted_20$1 = { class: "flex-shrink-0 w-14 h-14 bg-[var(--strands-primary)] bg-opacity-10 rounded-xl flex items-center justify-center group-hover:bg-[var(--strands-primary)] group-hover:bg-opacity-15 transition-colors" };
8711
8972
  const _hoisted_21$1 = { class: "flex flex-col space-y-2 ml-4" };
8712
- const _hoisted_22$1 = { class: "space-y-6" };
8713
- const _hoisted_23$1 = { class: "max-h-96 overflow-y-auto space-y-4 pr-2" };
8714
- const _hoisted_24$1 = { class: "flex items-start justify-between" };
8715
- const _hoisted_25$1 = { class: "flex items-start space-x-4" };
8716
- const _hoisted_26$1 = { class: "min-w-0 flex-1" };
8717
- const _hoisted_27$1 = { class: "font-semibold text-gray-900 text-lg" };
8718
- const _hoisted_28$1 = { class: "text-sm text-gray-600 mt-1" };
8719
- const _hoisted_29$1 = { class: "text-xs text-gray-500 mt-2" };
8720
- const _hoisted_30$1 = { class: "flex flex-col space-y-2 ml-4" };
8973
+ const _hoisted_22$1 = { class: "flex items-center justify-between" };
8974
+ const _hoisted_23$1 = { class: "flex-shrink-0 w-14 h-14 bg-[var(--strands-primary)] bg-opacity-10 rounded-xl flex items-center justify-center group-hover:bg-[var(--strands-primary)] group-hover:bg-opacity-15 transition-colors" };
8975
+ const _hoisted_24$1 = { class: "flex flex-col space-y-2 ml-4" };
8976
+ const _hoisted_25$1 = { class: "space-y-6" };
8977
+ const _hoisted_26$1 = { class: "max-h-96 overflow-y-auto space-y-4 pr-2" };
8978
+ const _hoisted_27$1 = { class: "flex items-start justify-between" };
8979
+ const _hoisted_28$1 = { class: "flex items-start space-x-4" };
8980
+ const _hoisted_29$1 = { class: "min-w-0 flex-1" };
8981
+ const _hoisted_30$1 = { class: "font-semibold text-gray-900 text-lg" };
8982
+ const _hoisted_31$1 = { class: "text-sm text-gray-600 mt-1" };
8983
+ const _hoisted_32$1 = { class: "text-xs text-gray-500 mt-2" };
8984
+ const _hoisted_33$1 = { class: "flex flex-col space-y-2 ml-4" };
8721
8985
  function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8722
8986
  return vue.openBlock(), vue.createElementBlock(
8723
8987
  vue.Fragment,
@@ -8730,7 +8994,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8730
8994
  }, {
8731
8995
  header: vue.withCtx(() => [
8732
8996
  vue.createElementVNode("div", { class: "flex items-center justify-between" }, [
8733
- _cache[8] || (_cache[8] = vue.createElementVNode(
8997
+ _cache[9] || (_cache[9] = vue.createElementVNode(
8734
8998
  "h2",
8735
8999
  { class: "text-2xl font-bold text-gray-900" },
8736
9000
  "Two-Factor Authentication",
@@ -8740,7 +9004,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8740
9004
  vue.createElementVNode("button", {
8741
9005
  onClick: $setup.closeModal,
8742
9006
  class: "text-gray-400 hover:text-gray-600 transition-colors duration-200"
8743
- }, _cache[7] || (_cache[7] = [
9007
+ }, _cache[8] || (_cache[8] = [
8744
9008
  vue.createElementVNode(
8745
9009
  "svg",
8746
9010
  {
@@ -8766,7 +9030,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8766
9030
  default: vue.withCtx(() => [
8767
9031
  $setup.mfaLoading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$6, [
8768
9032
  vue.createVNode($setup["StrandsUiLoader"], { size: 32 }),
8769
- _cache[9] || (_cache[9] = vue.createElementVNode(
9033
+ _cache[10] || (_cache[10] = vue.createElementVNode(
8770
9034
  "span",
8771
9035
  { class: "ml-3 text-gray-600" },
8772
9036
  "Loading MFA settings...",
@@ -8783,7 +9047,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8783
9047
  vue.createElementVNode("div", _hoisted_3$5, [
8784
9048
  vue.createElementVNode("div", _hoisted_4$4, [
8785
9049
  vue.createElementVNode("div", null, [
8786
- _cache[10] || (_cache[10] = vue.createElementVNode(
9050
+ _cache[11] || (_cache[11] = vue.createElementVNode(
8787
9051
  "h3",
8788
9052
  { class: "font-semibold text-gray-900" },
8789
9053
  "Two-Factor Authentication",
@@ -8804,7 +9068,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8804
9068
  size: 12,
8805
9069
  class: "mr-1"
8806
9070
  }),
8807
- _cache[11] || (_cache[11] = vue.createTextVNode(
9071
+ _cache[12] || (_cache[12] = vue.createTextVNode(
8808
9072
  " Enabled ",
8809
9073
  -1
8810
9074
  /* CACHED */
@@ -8848,7 +9112,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8848
9112
  vue.createCommentVNode(" Tab Content: Add New Device "),
8849
9113
  $setup.activeTab === "add" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11$2, [
8850
9114
  vue.createElementVNode("div", null, [
8851
- _cache[18] || (_cache[18] = vue.createElementVNode(
9115
+ _cache[21] || (_cache[21] = vue.createElementVNode(
8852
9116
  "h3",
8853
9117
  { class: "text-xl font-semibold text-gray-900 mb-6" },
8854
9118
  "Choose Your Authentication Method",
@@ -8868,7 +9132,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8868
9132
  class: "text-[var(--strands-primary)]"
8869
9133
  })
8870
9134
  ]),
8871
- _cache[13] || (_cache[13] = vue.createElementVNode(
9135
+ _cache[14] || (_cache[14] = vue.createElementVNode(
8872
9136
  "div",
8873
9137
  { class: "flex items-start space-x-4" },
8874
9138
  [
@@ -8887,7 +9151,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8887
9151
  onClick: vue.withModifiers($setup.startTotpSetup, ["stop"]),
8888
9152
  disabled: $setup.mfaLoading
8889
9153
  }, {
8890
- default: vue.withCtx(() => _cache[12] || (_cache[12] = [
9154
+ default: vue.withCtx(() => _cache[13] || (_cache[13] = [
8891
9155
  vue.createTextVNode(
8892
9156
  " Setup ",
8893
9157
  -1
@@ -8895,7 +9159,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8895
9159
  )
8896
9160
  ])),
8897
9161
  _: 1,
8898
- __: [12]
9162
+ __: [13]
8899
9163
  }, 8, ["disabled"])
8900
9164
  ])
8901
9165
  ])
@@ -8912,7 +9176,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8912
9176
  class: "text-[var(--strands-primary)]"
8913
9177
  })
8914
9178
  ]),
8915
- _cache[15] || (_cache[15] = vue.createElementVNode(
9179
+ _cache[16] || (_cache[16] = vue.createElementVNode(
8916
9180
  "div",
8917
9181
  { class: "flex items-start space-x-4" },
8918
9182
  [
@@ -8931,7 +9195,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8931
9195
  onClick: vue.withModifiers($setup.startEmailMfaSetup, ["stop"]),
8932
9196
  disabled: $setup.mfaLoading
8933
9197
  }, {
8934
- default: vue.withCtx(() => _cache[14] || (_cache[14] = [
9198
+ default: vue.withCtx(() => _cache[15] || (_cache[15] = [
8935
9199
  vue.createTextVNode(
8936
9200
  " Setup ",
8937
9201
  -1
@@ -8939,12 +9203,12 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8939
9203
  )
8940
9204
  ])),
8941
9205
  _: 1,
8942
- __: [14]
9206
+ __: [15]
8943
9207
  }, 8, ["disabled"])
8944
9208
  ])
8945
9209
  ])
8946
9210
  ]),
8947
- vue.createCommentVNode(" Hardware Key & Passkeys Setup "),
9211
+ vue.createCommentVNode(" Hardware Key Setup "),
8948
9212
  vue.createElementVNode("div", {
8949
9213
  class: "group p-6 bg-white border border-gray-200 rounded-xl hover:border-gray-300 hover:shadow-md transition-all duration-200 cursor-pointer",
8950
9214
  onClick: $setup.startHardwareKeySetup
@@ -8956,13 +9220,13 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8956
9220
  class: "text-[var(--strands-primary)]"
8957
9221
  })
8958
9222
  ]),
8959
- _cache[17] || (_cache[17] = vue.createElementVNode(
9223
+ _cache[18] || (_cache[18] = vue.createElementVNode(
8960
9224
  "div",
8961
9225
  { class: "flex items-start space-x-4" },
8962
9226
  [
8963
9227
  vue.createElementVNode("div", { class: "min-w-0 flex-1" }, [
8964
- vue.createElementVNode("h4", { class: "font-semibold text-gray-900 text-lg" }, "Hardware Key & Passkeys"),
8965
- vue.createElementVNode("p", { class: "text-xs text-gray-500 mt-2" }, " Use YubiKey, FIDO2 devices, WebAuthn, or built-in passkeys for maximum security ")
9228
+ vue.createElementVNode("h4", { class: "font-semibold text-gray-900 text-lg" }, "Hardware Security Key"),
9229
+ vue.createElementVNode("p", { class: "text-xs text-gray-500 mt-2" }, " Use YubiKey, FIDO2, or other physical security keys for ultimate protection ")
8966
9230
  ])
8967
9231
  ],
8968
9232
  -1
@@ -8975,7 +9239,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8975
9239
  onClick: vue.withModifiers($setup.startHardwareKeySetup, ["stop"]),
8976
9240
  disabled: $setup.mfaLoading
8977
9241
  }, {
8978
- default: vue.withCtx(() => _cache[16] || (_cache[16] = [
9242
+ default: vue.withCtx(() => _cache[17] || (_cache[17] = [
8979
9243
  vue.createTextVNode(
8980
9244
  " Setup ",
8981
9245
  -1
@@ -8983,7 +9247,51 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8983
9247
  )
8984
9248
  ])),
8985
9249
  _: 1,
8986
- __: [16]
9250
+ __: [17]
9251
+ }, 8, ["disabled"])
9252
+ ])
9253
+ ])
9254
+ ]),
9255
+ vue.createCommentVNode(" Passkey Setup "),
9256
+ vue.createElementVNode("div", {
9257
+ class: "group p-6 bg-white border border-gray-200 rounded-xl hover:border-gray-300 hover:shadow-md transition-all duration-200 cursor-pointer",
9258
+ onClick: $setup.startPasskeySetup
9259
+ }, [
9260
+ vue.createElementVNode("div", _hoisted_22$1, [
9261
+ vue.createElementVNode("div", _hoisted_23$1, [
9262
+ vue.createVNode($setup["Shield"], {
9263
+ size: 24,
9264
+ class: "text-[var(--strands-primary)]"
9265
+ })
9266
+ ]),
9267
+ _cache[20] || (_cache[20] = vue.createElementVNode(
9268
+ "div",
9269
+ { class: "flex items-start space-x-4" },
9270
+ [
9271
+ vue.createElementVNode("div", { class: "min-w-0 flex-1" }, [
9272
+ vue.createElementVNode("h4", { class: "font-semibold text-gray-900 text-lg" }, "Passkey"),
9273
+ vue.createElementVNode("p", { class: "text-xs text-gray-500 mt-2" }, " Use your device's built-in biometrics, PIN, or cross-device passkeys ")
9274
+ ])
9275
+ ],
9276
+ -1
9277
+ /* CACHED */
9278
+ )),
9279
+ vue.createElementVNode("div", _hoisted_24$1, [
9280
+ vue.createVNode($setup["StrandsUiButton"], {
9281
+ variant: "primary",
9282
+ size: "md",
9283
+ onClick: vue.withModifiers($setup.startPasskeySetup, ["stop"]),
9284
+ disabled: $setup.mfaLoading
9285
+ }, {
9286
+ default: vue.withCtx(() => _cache[19] || (_cache[19] = [
9287
+ vue.createTextVNode(
9288
+ " Setup ",
9289
+ -1
9290
+ /* CACHED */
9291
+ )
9292
+ ])),
9293
+ _: 1,
9294
+ __: [19]
8987
9295
  }, 8, ["disabled"])
8988
9296
  ])
8989
9297
  ])
@@ -8995,16 +9303,16 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
8995
9303
  { key: 1 },
8996
9304
  [
8997
9305
  vue.createCommentVNode(" Tab Content: Active Devices "),
8998
- vue.createElementVNode("div", _hoisted_22$1, [
9306
+ vue.createElementVNode("div", _hoisted_25$1, [
8999
9307
  vue.createElementVNode("div", null, [
9000
- _cache[22] || (_cache[22] = vue.createElementVNode(
9308
+ _cache[25] || (_cache[25] = vue.createElementVNode(
9001
9309
  "h3",
9002
9310
  { class: "text-xl font-semibold text-gray-900 mb-6" },
9003
9311
  "Manage Your Active Devices",
9004
9312
  -1
9005
9313
  /* CACHED */
9006
9314
  )),
9007
- vue.createElementVNode("div", _hoisted_23$1, [
9315
+ vue.createElementVNode("div", _hoisted_26$1, [
9008
9316
  (vue.openBlock(true), vue.createElementBlock(
9009
9317
  vue.Fragment,
9010
9318
  null,
@@ -9013,8 +9321,8 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
9013
9321
  key: device.id,
9014
9322
  class: "group p-6 bg-white border border-gray-200 rounded-xl hover:border-gray-300 hover:shadow-md transition-all duration-200"
9015
9323
  }, [
9016
- vue.createElementVNode("div", _hoisted_24$1, [
9017
- vue.createElementVNode("div", _hoisted_25$1, [
9324
+ vue.createElementVNode("div", _hoisted_27$1, [
9325
+ vue.createElementVNode("div", _hoisted_28$1, [
9018
9326
  vue.createElementVNode(
9019
9327
  "div",
9020
9328
  {
@@ -9029,33 +9337,33 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
9029
9337
  2
9030
9338
  /* CLASS */
9031
9339
  ),
9032
- vue.createElementVNode("div", _hoisted_26$1, [
9340
+ vue.createElementVNode("div", _hoisted_29$1, [
9033
9341
  vue.createElementVNode(
9034
9342
  "h4",
9035
- _hoisted_27$1,
9343
+ _hoisted_30$1,
9036
9344
  vue.toDisplayString(device.device_name),
9037
9345
  1
9038
9346
  /* TEXT */
9039
9347
  ),
9040
9348
  vue.createElementVNode(
9041
9349
  "p",
9042
- _hoisted_28$1,
9350
+ _hoisted_31$1,
9043
9351
  vue.toDisplayString($setup.getDeviceTypeName(device.device_type)),
9044
9352
  1
9045
9353
  /* TEXT */
9046
9354
  ),
9047
9355
  vue.createElementVNode(
9048
9356
  "p",
9049
- _hoisted_29$1,
9357
+ _hoisted_32$1,
9050
9358
  " Last used " + vue.toDisplayString($setup.formatLastUsed(device.last_used_at)),
9051
9359
  1
9052
9360
  /* TEXT */
9053
9361
  )
9054
9362
  ])
9055
9363
  ]),
9056
- vue.createElementVNode("div", _hoisted_30$1, [
9057
- vue.createCommentVNode(" Backup codes button for TOTP and Hardware Key devices "),
9058
- device.device_type === "totp" || device.device_type === "hardware" ? (vue.openBlock(), vue.createBlock($setup["StrandsUiButton"], {
9364
+ vue.createElementVNode("div", _hoisted_33$1, [
9365
+ vue.createCommentVNode(" Backup codes button for TOTP, Hardware Key, and Passkey devices "),
9366
+ device.device_type === "totp" || device.device_type === "hardware" || device.device_type === "passkey" ? (vue.openBlock(), vue.createBlock($setup["StrandsUiButton"], {
9059
9367
  key: 0,
9060
9368
  variant: "secondary",
9061
9369
  size: "sm",
@@ -9067,14 +9375,14 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
9067
9375
  size: 14,
9068
9376
  class: "mr-2"
9069
9377
  }),
9070
- _cache[19] || (_cache[19] = vue.createTextVNode(
9378
+ _cache[22] || (_cache[22] = vue.createTextVNode(
9071
9379
  " Backup Codes ",
9072
9380
  -1
9073
9381
  /* CACHED */
9074
9382
  ))
9075
9383
  ]),
9076
9384
  _: 2,
9077
- __: [19]
9385
+ __: [22]
9078
9386
  }, 1032, ["onClick", "disabled"])) : vue.createCommentVNode("v-if", true),
9079
9387
  vue.createCommentVNode(" Test email MFA "),
9080
9388
  device.device_type === "email" ? (vue.openBlock(), vue.createBlock($setup["StrandsUiButton"], {
@@ -9089,14 +9397,14 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
9089
9397
  size: 14,
9090
9398
  class: "mr-2"
9091
9399
  }),
9092
- _cache[20] || (_cache[20] = vue.createTextVNode(
9400
+ _cache[23] || (_cache[23] = vue.createTextVNode(
9093
9401
  " Send Test Code ",
9094
9402
  -1
9095
9403
  /* CACHED */
9096
9404
  ))
9097
9405
  ]),
9098
9406
  _: 2,
9099
- __: [20]
9407
+ __: [23]
9100
9408
  }, 1032, ["onClick", "disabled"])) : vue.createCommentVNode("v-if", true),
9101
9409
  vue.createCommentVNode(" Remove device "),
9102
9410
  vue.createVNode($setup["StrandsUiButton"], {
@@ -9111,14 +9419,14 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
9111
9419
  size: 14,
9112
9420
  class: "mr-2"
9113
9421
  }),
9114
- _cache[21] || (_cache[21] = vue.createTextVNode(
9422
+ _cache[24] || (_cache[24] = vue.createTextVNode(
9115
9423
  " Remove ",
9116
9424
  -1
9117
9425
  /* CACHED */
9118
9426
  ))
9119
9427
  ]),
9120
9428
  _: 2,
9121
- __: [21]
9429
+ __: [24]
9122
9430
  }, 1032, ["onClick", "disabled"])
9123
9431
  ])
9124
9432
  ])
@@ -9154,14 +9462,22 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
9154
9462
  $setup.showHardwareKeySetup ? (vue.openBlock(), vue.createBlock($setup["StrandsHardwareKeySetupModal"], {
9155
9463
  key: 4,
9156
9464
  show: $setup.showHardwareKeySetup,
9465
+ "device-type": "hardware",
9157
9466
  onClose: _cache[4] || (_cache[4] = ($event) => $setup.showHardwareKeySetup = false),
9158
9467
  onSuccess: $setup.handleHardwareKeySetupSuccess
9159
9468
  }, null, 8, ["show"])) : vue.createCommentVNode("v-if", true),
9160
- $setup.showBackupCodesModal ? (vue.openBlock(), vue.createBlock($setup["StrandsBackupCodesModal"], {
9469
+ $setup.showPasskeySetup ? (vue.openBlock(), vue.createBlock($setup["StrandsHardwareKeySetupModal"], {
9161
9470
  key: 5,
9471
+ show: $setup.showPasskeySetup,
9472
+ "device-type": "passkey",
9473
+ onClose: _cache[5] || (_cache[5] = ($event) => $setup.showPasskeySetup = false),
9474
+ onSuccess: $setup.handlePasskeySetupSuccess
9475
+ }, null, 8, ["show"])) : vue.createCommentVNode("v-if", true),
9476
+ $setup.showBackupCodesModal ? (vue.openBlock(), vue.createBlock($setup["StrandsBackupCodesModal"], {
9477
+ key: 6,
9162
9478
  show: $setup.showBackupCodesModal,
9163
9479
  device: $setup.selectedDevice,
9164
- onClose: _cache[5] || (_cache[5] = ($event) => $setup.showBackupCodesModal = false)
9480
+ onClose: _cache[6] || (_cache[6] = ($event) => $setup.showBackupCodesModal = false)
9165
9481
  }, null, 8, ["show", "device"])) : vue.createCommentVNode("v-if", true)
9166
9482
  ]),
9167
9483
  _: 1
@@ -9177,7 +9493,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
9177
9493
  "cancel-text": "Keep Device",
9178
9494
  variant: "secondary",
9179
9495
  onConfirm: $setup.handleDisableDevice,
9180
- onCancel: _cache[6] || (_cache[6] = ($event) => $setup.showConfirmDisable = false)
9496
+ onCancel: _cache[7] || (_cache[7] = ($event) => $setup.showConfirmDisable = false)
9181
9497
  }, null, 8, ["show", "message"])) : vue.createCommentVNode("v-if", true)
9182
9498
  ],
9183
9499
  64