@auth-link/web 0.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -1679,10 +1679,9 @@ function validateTicket(value, expectedMode, trustedOrigin) {
1679
1679
  }
1680
1680
  if (qr.v !== 1 || qr.requestId !== m.requestId || typeof qr.token !== "string" || !token.test(qr.token) || origin.protocol !== "https:" || origin.origin !== qr.origin || origin.origin.length > 512 || origin.username || origin.password || trustedOrigin && origin.origin !== trustedOrigin) fail("UNTRUSTED_QR");
1681
1681
  const displayCode = m.displayCode === void 0 ? void 0 : validateDisplayCode(m.displayCode);
1682
- if (m.purpose === "confirm" && !displayCode) fail("DYNAMIC_CODE_REQUIRED");
1683
1682
  const expiry = Date.parse(String(m.expiresAt));
1684
1683
  const now = displayCode ? Date.parse(displayCode.serverTime) : Date.now();
1685
- if (!Number.isFinite(expiry) || expiry > now + 18e4) fail("INVALID_EXPIRY");
1684
+ if (!Number.isFinite(expiry) || expiry > now + 36e4) fail("INVALID_EXPIRY");
1686
1685
  return {
1687
1686
  requestId: m.requestId,
1688
1687
  purpose: m.purpose,
@@ -1714,116 +1713,117 @@ function abortable(promise, signal) {
1714
1713
  }
1715
1714
  async function observeRequest(input, options) {
1716
1715
  const { client, signal, onUpdate } = options;
1717
- const interval = options.intervalMs ?? 1500;
1718
1716
  let ticket;
1719
1717
  try {
1720
- if (interval < 250 || interval > 1e4 || !Number.isFinite(interval)) fail("INVALID_INTERVAL");
1721
1718
  ticket = validateTicket(input, options.expectedMode);
1722
1719
  } catch (error) {
1723
- if (!signal.aborted) {
1724
- const e = error instanceof Error ? error : new AuthLinkError("INVALID_TICKET");
1725
- onUpdate({ ...initialSnapshot(), status: "error", error: e });
1726
- options.onError?.(e);
1727
- }
1720
+ if (!signal.aborted) options.onError?.(error);
1728
1721
  return;
1729
1722
  }
1730
- let frame = ticket.displayCode;
1731
- let serverAnchor = frame ? Date.parse(frame.serverTime) : Date.now();
1732
- let monotonicAnchor = performance.now();
1733
- const serverNow = () => serverAnchor + performance.now() - monotonicAnchor;
1734
1723
  const expiry = Date.parse(ticket.expiresAt);
1735
- let ended = false;
1724
+ const deadline = performance.now() + Math.max(0, expiry - Date.now());
1725
+ let ended = false, busy = false;
1726
+ let done;
1727
+ const finished = new Promise((resolve) => {
1728
+ done = resolve;
1729
+ });
1736
1730
  const controller = new AbortController();
1737
- const cancel = () => controller.abort(signal.reason);
1738
- signal.addEventListener("abort", cancel, { once: true });
1739
- if (signal.aborted) cancel();
1740
- let last = initialSnapshot();
1741
- const update = (value) => {
1742
- if (signal.aborted) return;
1743
- if (JSON.stringify(value) !== JSON.stringify(last)) {
1744
- last = value;
1745
- onUpdate(value);
1746
- }
1731
+ const cancel = () => {
1732
+ ended = true;
1733
+ controller.abort();
1734
+ done();
1747
1735
  };
1736
+ signal.addEventListener("abort", cancel, { once: true });
1737
+ let snapshot = initialSnapshot();
1738
+ const remaining = () => Math.max(0, (deadline - performance.now()) / 1e3);
1748
1739
  const tick = () => {
1749
1740
  if (ended || signal.aborted) return;
1750
- const now = serverNow();
1751
- if (now >= expiry) {
1752
- controller.abort(new AuthLinkError("REQUEST_EXPIRED"));
1741
+ if (remaining() <= 0) {
1742
+ ended = true;
1743
+ controller.abort();
1744
+ onUpdate({ ...snapshot, status: "expired", code: null, submitting: false });
1745
+ void Promise.resolve().then(() => options.onExpired?.()).catch(() => options.onError?.(new AuthLinkError("CALLBACK_FAILED")));
1746
+ done();
1753
1747
  return;
1754
1748
  }
1755
- const codeRemaining = Math.max(0, ((frame ? Date.parse(frame.validUntil) : expiry) - now) / 1e3);
1756
- options.onCodeTiming?.(codeRemaining * 1e3);
1757
- update({
1749
+ snapshot = {
1750
+ ...snapshot,
1758
1751
  status: "pending",
1759
- code: codeRemaining > 0 ? frame?.value ?? ticket.pairingCode : null,
1760
- secondsRemaining: Math.max(0, Math.ceil((expiry - now) / 1e3)),
1761
- codeSecondsRemaining: Math.ceil(codeRemaining),
1762
- error: null
1763
- });
1752
+ code: ticket.pairingCode,
1753
+ secondsRemaining: Math.ceil(remaining()),
1754
+ codeSecondsRemaining: Math.ceil(remaining()),
1755
+ submitting: busy
1756
+ };
1757
+ onUpdate(snapshot);
1764
1758
  };
1765
- const timer = setInterval(tick, 200);
1766
- const finish = (status, result, error) => {
1767
- if (ended || signal.aborted) return;
1768
- ended = true;
1769
- update({ ...last, status, code: null, error: error ?? null });
1770
- try {
1771
- let effect = void 0;
1772
- if (status === "confirmed") effect = options.onConfirmed?.(result);
1773
- else if (status === "rejected") effect = options.onRejected?.({ status: "rejected", code: "REJECTED", requestId: ticket.requestId, purpose: ticket.purpose });
1774
- else if (status === "expired") effect = options.onExpired?.();
1775
- else options.onError?.(error);
1776
- void Promise.resolve(effect).catch(() => {
1777
- if (!signal.aborted) options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
1778
- });
1779
- } catch {
1780
- if (status !== "error") options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
1759
+ const submit = async (confirmationCode) => {
1760
+ if (ended || signal.aborted || busy) return;
1761
+ if (!/^[0-9]{6}$/.test(confirmationCode)) {
1762
+ snapshot = { ...snapshot, error: new AuthLinkError("CONFIRMATION_CODE_REQUIRED") };
1763
+ tick();
1764
+ return;
1781
1765
  }
1782
- };
1783
- try {
1766
+ if (remaining() <= 0) {
1767
+ tick();
1768
+ return;
1769
+ }
1770
+ busy = true;
1771
+ snapshot = { ...snapshot, error: null };
1784
1772
  tick();
1785
- for (; ; ) {
1786
- controller.signal.throwIfAborted();
1787
- const value = object(await abortable(client.result(ticket, controller.signal), controller.signal));
1788
- controller.signal.throwIfAborted();
1773
+ try {
1774
+ const value = object(await abortable(client.result(ticket, controller.signal, confirmationCode), controller.signal));
1775
+ if (ended || signal.aborted) return;
1789
1776
  if (value.requestId !== ticket.requestId) fail("REQUEST_MISMATCH");
1790
1777
  if (value.status === "confirmed") {
1791
- if (!token.test(String(value.verificationId)) || !["device-presence.v1"].includes(String(value.authenticationPolicy)) || value.expiresAt !== ticket.expiresAt || value.purpose !== ticket.purpose || serverNow() >= expiry || "action" in value || "transactionHash" in value) fail("INVALID_CONFIRMATION");
1792
- finish("confirmed", value);
1793
- return;
1794
- }
1795
- if (value.status === "rejected" || value.status === "expired") {
1796
- finish(value.status);
1797
- return;
1798
- }
1799
- if (!["new", "pending", "approved", "consumed"].includes(String(value.status))) fail("INVALID_RESPONSE");
1800
- if (value.displayCode !== void 0) {
1801
- const nextFrame = validateDisplayCode(value.displayCode);
1802
- const nextExpiry = Date.parse(nextFrame.validUntil);
1803
- const currentExpiry = frame ? Date.parse(frame.validUntil) : 0;
1804
- if (!frame || nextExpiry > currentExpiry) {
1805
- serverAnchor = Math.max(serverNow(), Date.parse(nextFrame.serverTime));
1806
- monotonicAnchor = performance.now();
1778
+ if (!token.test(String(value.verificationId)) || value.authenticationPolicy !== "device-presence.v1" || value.expiresAt !== ticket.expiresAt || value.purpose !== ticket.purpose || remaining() <= 0 || "action" in value || "transactionHash" in value) fail("INVALID_CONFIRMATION");
1779
+ ended = true;
1780
+ onUpdate({ ...snapshot, status: "confirmed", code: null, submitting: false });
1781
+ try {
1782
+ await options.onConfirmed?.(value);
1783
+ } catch {
1784
+ options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
1807
1785
  }
1808
- if (!frame || nextExpiry >= currentExpiry) frame = nextFrame;
1786
+ done();
1787
+ } else if (value.status === "rejected" || value.status === "expired") {
1788
+ ended = true;
1789
+ onUpdate({ ...snapshot, status: value.status, code: null, submitting: false });
1790
+ try {
1791
+ if (value.status === "rejected") await options.onRejected?.({ status: "rejected", code: "REJECTED", requestId: ticket.requestId, purpose: ticket.purpose });
1792
+ else await options.onExpired?.();
1793
+ } catch {
1794
+ options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
1795
+ } finally {
1796
+ done();
1797
+ }
1798
+ } else {
1799
+ fail("CONFIRMATION_NOT_READY");
1809
1800
  }
1810
- tick();
1811
- let pause;
1812
- try {
1813
- await abortable(new Promise((resolve) => {
1814
- pause = setTimeout(resolve, interval);
1815
- }), controller.signal);
1816
- } finally {
1817
- clearTimeout(pause);
1801
+ } catch (error) {
1802
+ if (!ended && !signal.aborted) {
1803
+ const raw = error instanceof Error ? error : new AuthLinkError("NETWORK_ERROR");
1804
+ const code = raw.message.replace(/^AUTHLINK_/, "");
1805
+ const failure = ["CONFIRMATION_CODE_LOCKED", "CONFIRMATION_CODE_INVALID", "APPROVAL_REQUIRED", "REQUEST_EXPIRED"].includes(code) ? new AuthLinkError(code) : raw;
1806
+ snapshot = { ...snapshot, error: failure };
1807
+ if (code === "CONFIRMATION_CODE_LOCKED" || code === "REQUEST_EXPIRED") {
1808
+ ended = true;
1809
+ onUpdate({ ...snapshot, code: null, submitting: false, status: code === "REQUEST_EXPIRED" ? "expired" : "error" });
1810
+ if (code === "REQUEST_EXPIRED") void Promise.resolve().then(() => options.onExpired?.()).catch(() => options.onError?.(new AuthLinkError("CALLBACK_FAILED")));
1811
+ else options.onError?.(failure);
1812
+ done();
1813
+ } else options.onError?.(failure);
1818
1814
  }
1815
+ } finally {
1816
+ busy = false;
1817
+ tick();
1819
1818
  }
1820
- } catch (error) {
1821
- if (!signal.aborted && !ended) {
1822
- if (error instanceof AuthLinkError && error.code === "REQUEST_EXPIRED") finish("expired");
1823
- else finish("error", void 0, error instanceof AuthLinkError ? error : new AuthLinkError("NETWORK_ERROR"));
1824
- }
1819
+ };
1820
+ tick();
1821
+ options.onReady?.(submit);
1822
+ const timer = setInterval(tick, 1e3);
1823
+ if (signal.aborted) cancel();
1824
+ try {
1825
+ await finished;
1825
1826
  } finally {
1826
- ended = true;
1827
1827
  clearInterval(timer);
1828
1828
  controller.abort();
1829
1829
  signal.removeEventListener("abort", cancel);
@@ -1835,8 +1835,8 @@ var en_default = {
1835
1835
  bind: "Bind your phone",
1836
1836
  confirm: "Confirm verification",
1837
1837
  scan: "Scan with AuthLink",
1838
- code: "Matching code",
1839
- help: "Check that the numbers match in the app, then confirm on your phone.",
1838
+ code: "Matching digits",
1839
+ help: "Approve in the App, then enter its 6-digit confirmation code here.",
1840
1840
  waiting: "Waiting for your phone",
1841
1841
  loading: "Connecting",
1842
1842
  confirmed: "Confirmed",
@@ -1849,7 +1849,16 @@ var en_default = {
1849
1849
  close: "Close",
1850
1850
  cancel: "Cancel",
1851
1851
  autoUpdate: "Code updates automatically every 30 seconds",
1852
- expiring: "Request expiring soon"
1852
+ expiring: "Request expiring soon",
1853
+ confirmationCode: "App confirmation code",
1854
+ submitCode: "Verify",
1855
+ codeError: "The code could not be verified. Check the code and approval, then retry.",
1856
+ codeLocked: "Too many incorrect codes. Close this window and start a new request.",
1857
+ otpCode: "App verification code",
1858
+ otpHelp: "Open AuthLink and enter this account\u2019s current six-digit code. No approval is needed.",
1859
+ otpWaiting: "Enter the current code",
1860
+ otpError: "Verification failed. Check the account; wait for a new code if already used. After repeated failures, try again later.",
1861
+ otpSetup: "Enable verification codes on this account\u2019s card in the app first."
1853
1862
  };
1854
1863
 
1855
1864
  // src/locales/zh-CN.json
@@ -1857,8 +1866,8 @@ var zh_CN_default = {
1857
1866
  bind: "\u7ED1\u5B9A\u624B\u673A",
1858
1867
  confirm: "\u786E\u8BA4\u8EAB\u4EFD\u9A8C\u8BC1",
1859
1868
  scan: "\u4F7F\u7528 AuthLink \u626B\u63CF\u4E8C\u7EF4\u7801",
1860
- code: "\u52A8\u6001\u6838\u5BF9\u7801",
1861
- help: "\u6838\u5BF9 App \u4E2D\u7684\u6570\u5B57\u4E00\u81F4\u540E\uFF0C\u5728\u624B\u673A\u4E0A\u786E\u8BA4\u3002",
1869
+ code: "\u6838\u5BF9\u6570\u5B57",
1870
+ help: "\u5728 App \u6838\u5BF9\u5E76\u6279\u51C6\u540E\uFF0C\u5C06 App \u663E\u793A\u7684 6 \u4F4D\u786E\u8BA4\u7801\u8F93\u5165\u4E0B\u65B9\u3002",
1862
1871
  waiting: "\u7B49\u5F85\u624B\u673A\u786E\u8BA4",
1863
1872
  loading: "\u6B63\u5728\u8FDE\u63A5",
1864
1873
  confirmed: "\u5DF2\u786E\u8BA4",
@@ -1871,7 +1880,16 @@ var zh_CN_default = {
1871
1880
  close: "\u5173\u95ED",
1872
1881
  cancel: "\u53D6\u6D88",
1873
1882
  autoUpdate: "\u6838\u5BF9\u7801\u6BCF 30 \u79D2\u81EA\u52A8\u66F4\u65B0",
1874
- expiring: "\u8BF7\u6C42\u5373\u5C06\u8FC7\u671F"
1883
+ expiring: "\u8BF7\u6C42\u5373\u5C06\u8FC7\u671F",
1884
+ confirmationCode: "App \u786E\u8BA4\u7801",
1885
+ submitCode: "\u63D0\u4EA4\u9A8C\u8BC1",
1886
+ codeError: "\u9A8C\u8BC1\u672A\u901A\u8FC7\uFF0C\u8BF7\u68C0\u67E5\u786E\u8BA4\u7801\u548C\u624B\u673A\u6279\u51C6\u72B6\u6001\u540E\u91CD\u8BD5\u3002",
1887
+ codeLocked: "\u786E\u8BA4\u7801\u8F93\u5165\u9519\u8BEF\u6B21\u6570\u8FC7\u591A\uFF0C\u8BF7\u5173\u95ED\u7A97\u53E3\u540E\u91CD\u65B0\u53D1\u8D77\u8BF7\u6C42\u3002",
1888
+ otpCode: "App \u52A8\u6001\u7801",
1889
+ otpHelp: "\u6253\u5F00 AuthLink\uFF0C\u8F93\u5165\u8BE5\u8D26\u53F7\u5F53\u524D\u7684\u516D\u4F4D\u52A8\u6001\u7801\uFF0C\u65E0\u9700\u6279\u51C6\u8BF7\u6C42\u3002",
1890
+ otpWaiting: "\u8BF7\u8F93\u5165\u5F53\u524D\u52A8\u6001\u7801",
1891
+ otpError: "\u9A8C\u8BC1\u672A\u901A\u8FC7\u3002\u8BF7\u6838\u5BF9\u8D26\u53F7\uFF1B\u5DF2\u4F7F\u7528\u7684\u7801\u9700\u7B49\u5F85\u66F4\u65B0\uFF0C\u591A\u6B21\u5931\u8D25\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
1892
+ otpSetup: "\u8BF7\u5148\u5728 App \u7684\u8D26\u53F7\u5361\u7247\u4E2D\u542F\u7528\u52A8\u6001\u7801\u3002"
1875
1893
  };
1876
1894
 
1877
1895
  // src/locales/zh-TW.json
@@ -1879,8 +1897,8 @@ var zh_TW_default = {
1879
1897
  bind: "\u7D81\u5B9A\u624B\u6A5F",
1880
1898
  confirm: "\u78BA\u8A8D\u8EAB\u5206\u9A57\u8B49",
1881
1899
  scan: "\u4F7F\u7528 AuthLink \u6383\u63CF QR \u78BC",
1882
- code: "\u52D5\u614B\u6838\u5C0D\u78BC",
1883
- help: "\u6838\u5C0D App \u4E2D\u7684\u6578\u5B57\u4E00\u81F4\u5F8C\uFF0C\u5728\u624B\u6A5F\u4E0A\u78BA\u8A8D\u3002",
1900
+ code: "\u6838\u5C0D\u6578\u5B57",
1901
+ help: "\u5728 App \u6838\u5C0D\u4E26\u6279\u51C6\u5F8C\uFF0C\u5C07 App \u986F\u793A\u7684 6 \u4F4D\u78BA\u8A8D\u78BC\u8F38\u5165\u4E0B\u65B9\u3002",
1884
1902
  waiting: "\u7B49\u5F85\u624B\u6A5F\u78BA\u8A8D",
1885
1903
  loading: "\u6B63\u5728\u9023\u7DDA",
1886
1904
  confirmed: "\u5DF2\u78BA\u8A8D",
@@ -1893,7 +1911,16 @@ var zh_TW_default = {
1893
1911
  close: "\u95DC\u9589",
1894
1912
  cancel: "\u53D6\u6D88",
1895
1913
  autoUpdate: "\u6838\u5C0D\u78BC\u6BCF 30 \u79D2\u81EA\u52D5\u66F4\u65B0",
1896
- expiring: "\u8ACB\u6C42\u5373\u5C07\u5230\u671F"
1914
+ expiring: "\u8ACB\u6C42\u5373\u5C07\u5230\u671F",
1915
+ confirmationCode: "App \u78BA\u8A8D\u78BC",
1916
+ submitCode: "\u63D0\u4EA4\u9A57\u8B49",
1917
+ codeError: "\u9A57\u8B49\u672A\u901A\u904E\uFF0C\u8ACB\u6AA2\u67E5\u78BA\u8A8D\u78BC\u53CA\u624B\u6A5F\u6279\u51C6\u72C0\u614B\u5F8C\u91CD\u8A66\u3002",
1918
+ codeLocked: "\u78BA\u8A8D\u78BC\u8F38\u5165\u932F\u8AA4\u6B21\u6578\u904E\u591A\uFF0C\u8ACB\u95DC\u9589\u8996\u7A97\u5F8C\u91CD\u65B0\u767C\u8D77\u8ACB\u6C42\u3002",
1919
+ otpCode: "App \u52D5\u614B\u78BC",
1920
+ otpHelp: "\u958B\u555F AuthLink\uFF0C\u8F38\u5165\u6B64\u5E33\u865F\u76EE\u524D\u7684\u516D\u4F4D\u52D5\u614B\u78BC\uFF0C\u7121\u9700\u6279\u51C6\u8ACB\u6C42\u3002",
1921
+ otpWaiting: "\u8ACB\u8F38\u5165\u76EE\u524D\u7684\u52D5\u614B\u78BC",
1922
+ otpError: "\u9A57\u8B49\u672A\u901A\u904E\u3002\u8ACB\u6838\u5C0D\u5E33\u865F\uFF1B\u5DF2\u4F7F\u7528\u7684\u78BC\u9700\u7B49\u5F85\u66F4\u65B0\uFF0C\u591A\u6B21\u5931\u6557\u8ACB\u7A0D\u5F8C\u91CD\u8A66\u3002",
1923
+ otpSetup: "\u8ACB\u5148\u5728 App \u7684\u5E33\u865F\u5361\u7247\u4E2D\u555F\u7528\u52D5\u614B\u78BC\u3002"
1897
1924
  };
1898
1925
 
1899
1926
  // src/locales/ja.json
@@ -1901,8 +1928,8 @@ var ja_default = {
1901
1928
  bind: "\u30B9\u30DE\u30FC\u30C8\u30D5\u30A9\u30F3\u3092\u767B\u9332",
1902
1929
  confirm: "\u672C\u4EBA\u78BA\u8A8D",
1903
1930
  scan: "AuthLink \u3067 QR \u30B3\u30FC\u30C9\u3092\u30B9\u30AD\u30E3\u30F3",
1904
- code: "\u7167\u5408\u30B3\u30FC\u30C9",
1905
- help: "\u30A2\u30D7\u30EA\u306E\u6570\u5B57\u304C\u4E00\u81F4\u3059\u308B\u3053\u3068\u3092\u78BA\u8A8D\u3057\u3001\u30B9\u30DE\u30FC\u30C8\u30D5\u30A9\u30F3\u3067\u627F\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
1931
+ code: "\u7167\u5408\u7528\u306E\u6570\u5B57",
1932
+ help: "App \u3067\u627F\u8A8D\u3057\u305F\u5F8C\u3001\u8868\u793A\u3055\u308C\u305F6\u6841\u306E\u78BA\u8A8D\u30B3\u30FC\u30C9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
1906
1933
  waiting: "\u30B9\u30DE\u30FC\u30C8\u30D5\u30A9\u30F3\u306E\u78BA\u8A8D\u3092\u5F85\u3063\u3066\u3044\u307E\u3059",
1907
1934
  loading: "\u63A5\u7D9A\u4E2D",
1908
1935
  confirmed: "\u78BA\u8A8D\u6E08\u307F",
@@ -1915,7 +1942,16 @@ var ja_default = {
1915
1942
  close: "\u9589\u3058\u308B",
1916
1943
  cancel: "\u30AD\u30E3\u30F3\u30BB\u30EB",
1917
1944
  autoUpdate: "\u7167\u5408\u30B3\u30FC\u30C9\u306F30\u79D2\u3054\u3068\u306B\u81EA\u52D5\u66F4\u65B0",
1918
- expiring: "\u30EA\u30AF\u30A8\u30B9\u30C8\u306E\u6709\u52B9\u671F\u9650\u304C\u307E\u3082\u306A\u304F\u5207\u308C\u307E\u3059"
1945
+ expiring: "\u30EA\u30AF\u30A8\u30B9\u30C8\u306E\u6709\u52B9\u671F\u9650\u304C\u307E\u3082\u306A\u304F\u5207\u308C\u307E\u3059",
1946
+ confirmationCode: "App \u306E\u78BA\u8A8D\u30B3\u30FC\u30C9",
1947
+ submitCode: "\u78BA\u8A8D\u3059\u308B",
1948
+ codeError: "\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30B3\u30FC\u30C9\u3068\u627F\u8A8D\u72B6\u6CC1\u3092\u78BA\u8A8D\u3057\u3066\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
1949
+ codeLocked: "\u30B3\u30FC\u30C9\u306E\u8AA4\u5165\u529B\u304C\u591A\u3059\u304E\u307E\u3059\u3002\u753B\u9762\u3092\u9589\u3058\u3001\u65B0\u3057\u3044\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u958B\u59CB\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
1950
+ otpCode: "\u30A2\u30D7\u30EA\u306E\u8A8D\u8A3C\u30B3\u30FC\u30C9",
1951
+ otpHelp: "AuthLink \u3092\u958B\u304D\u3001\u3053\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u73FE\u5728\u306E6\u6841\u30B3\u30FC\u30C9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u627F\u8A8D\u64CD\u4F5C\u306F\u4E0D\u8981\u3067\u3059\u3002",
1952
+ otpWaiting: "\u73FE\u5728\u306E\u30B3\u30FC\u30C9\u3092\u5165\u529B",
1953
+ otpError: "\u8A8D\u8A3C\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u78BA\u8A8D\u3057\u3001\u4F7F\u7528\u6E08\u307F\u306A\u3089\u6B21\u306E\u30B3\u30FC\u30C9\u3092\u5F85\u3063\u3066\u304F\u3060\u3055\u3044\u3002\u5931\u6557\u304C\u7D9A\u304F\u5834\u5408\u306F\u6642\u9593\u3092\u304A\u3044\u3066\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
1954
+ otpSetup: "\u5148\u306B\u30A2\u30D7\u30EA\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u753B\u9762\u3067\u8A8D\u8A3C\u30B3\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
1919
1955
  };
1920
1956
 
1921
1957
  // src/locales/bn.json
@@ -1924,7 +1960,7 @@ var bn_default = {
1924
1960
  confirm: "\u09AF\u09BE\u099A\u09BE\u0987\u0995\u09B0\u09A3 \u09A8\u09BF\u09B6\u09CD\u099A\u09BF\u09A4 \u0995\u09B0\u09C1\u09A8",
1925
1961
  scan: "AuthLink \u09A6\u09BF\u09AF\u09BC\u09C7 \u09B8\u09CD\u0995\u09CD\u09AF\u09BE\u09A8 \u0995\u09B0\u09C1\u09A8",
1926
1962
  code: "\u09AE\u09BF\u09B2\u09BF\u09AF\u09BC\u09C7 \u09A6\u09C7\u0996\u09BE\u09B0 \u0995\u09CB\u09A1",
1927
- help: "\u0985\u09CD\u09AF\u09BE\u09AA\u09C7\u09B0 \u09B8\u0982\u0996\u09CD\u09AF\u09BE\u0997\u09C1\u09B2\u09CB \u09AE\u09BF\u09B2\u09C7 \u0997\u09C7\u09B2\u09C7 \u09AB\u09CB\u09A8\u09C7 \u09A8\u09BF\u09B6\u09CD\u099A\u09BF\u09A4 \u0995\u09B0\u09C1\u09A8\u0964",
1963
+ help: "\u0985\u09CD\u09AF\u09BE\u09AA\u09C7 \u0985\u09A8\u09C1\u09AE\u09CB\u09A6\u09A8 \u09A6\u09BF\u09A8, \u09A4\u09BE\u09B0\u09AA\u09B0 \u098F\u0996\u09BE\u09A8\u09C7 \u09EC \u09B8\u0982\u0996\u09CD\u09AF\u09BE\u09B0 \u09A8\u09BF\u09B6\u09CD\u099A\u09BF\u09A4\u0995\u09B0\u09A3 \u0995\u09CB\u09A1 \u09B2\u09BF\u0996\u09C1\u09A8\u0964",
1928
1964
  waiting: "\u09AB\u09CB\u09A8\u09C7 \u09A8\u09BF\u09B6\u09CD\u099A\u09BF\u09A4\u0995\u09B0\u09A3\u09C7\u09B0 \u0985\u09AA\u09C7\u0995\u09CD\u09B7\u09BE\u09AF\u09BC",
1929
1965
  loading: "\u09B8\u0982\u09AF\u09CB\u0997 \u0995\u09B0\u09BE \u09B9\u099A\u09CD\u099B\u09C7",
1930
1966
  confirmed: "\u09A8\u09BF\u09B6\u09CD\u099A\u09BF\u09A4 \u09B9\u09AF\u09BC\u09C7\u099B\u09C7",
@@ -1937,7 +1973,16 @@ var bn_default = {
1937
1973
  close: "\u09AC\u09A8\u09CD\u09A7 \u0995\u09B0\u09C1\u09A8",
1938
1974
  cancel: "\u09AC\u09BE\u09A4\u09BF\u09B2",
1939
1975
  autoUpdate: "\u0995\u09CB\u09A1 \u09AA\u09CD\u09B0\u09A4\u09BF \u09E9\u09E6 \u09B8\u09C7\u0995\u09C7\u09A8\u09CD\u09A1\u09C7 \u09B8\u09CD\u09AC\u09AF\u09BC\u0982\u0995\u09CD\u09B0\u09BF\u09AF\u09BC\u09AD\u09BE\u09AC\u09C7 \u09AC\u09A6\u09B2\u09BE\u09AF\u09BC",
1940
- expiring: "\u0985\u09A8\u09C1\u09B0\u09CB\u09A7\u09C7\u09B0 \u09AE\u09C7\u09AF\u09BC\u09BE\u09A6 \u09B6\u09C0\u0998\u09CD\u09B0\u0987 \u09B6\u09C7\u09B7 \u09B9\u09AC\u09C7"
1976
+ expiring: "\u0985\u09A8\u09C1\u09B0\u09CB\u09A7\u09C7\u09B0 \u09AE\u09C7\u09AF\u09BC\u09BE\u09A6 \u09B6\u09C0\u0998\u09CD\u09B0\u0987 \u09B6\u09C7\u09B7 \u09B9\u09AC\u09C7",
1977
+ confirmationCode: "\u0985\u09CD\u09AF\u09BE\u09AA\u09C7\u09B0 \u09A8\u09BF\u09B6\u09CD\u099A\u09BF\u09A4\u0995\u09B0\u09A3 \u0995\u09CB\u09A1",
1978
+ submitCode: "\u09AF\u09BE\u099A\u09BE\u0987 \u0995\u09B0\u09C1\u09A8",
1979
+ codeError: "\u09AF\u09BE\u099A\u09BE\u0987 \u0995\u09B0\u09BE \u09AF\u09BE\u09AF\u09BC\u09A8\u09BF\u0964 \u0995\u09CB\u09A1 \u0993 \u0985\u09A8\u09C1\u09AE\u09CB\u09A6\u09A8 \u09AA\u09B0\u09C0\u0995\u09CD\u09B7\u09BE \u0995\u09B0\u09C7 \u0986\u09AC\u09BE\u09B0 \u099A\u09C7\u09B7\u09CD\u099F\u09BE \u0995\u09B0\u09C1\u09A8\u0964",
1980
+ codeLocked: "\u0985\u09A8\u09C7\u0995\u09AC\u09BE\u09B0 \u09AD\u09C1\u09B2 \u0995\u09CB\u09A1 \u09A6\u09C7\u0993\u09AF\u09BC\u09BE \u09B9\u09AF\u09BC\u09C7\u099B\u09C7\u0964 \u0989\u0987\u09A8\u09CD\u09A1\u09CB \u09AC\u09A8\u09CD\u09A7 \u0995\u09B0\u09C7 \u09A8\u09A4\u09C1\u09A8 \u0985\u09A8\u09C1\u09B0\u09CB\u09A7 \u09B6\u09C1\u09B0\u09C1 \u0995\u09B0\u09C1\u09A8\u0964",
1981
+ otpCode: "\u0985\u09CD\u09AF\u09BE\u09AA\u09C7\u09B0 \u0995\u09CB\u09A1",
1982
+ otpHelp: "AuthLink \u0996\u09C1\u09B2\u09C7 \u098F\u0987 \u0985\u09CD\u09AF\u09BE\u0995\u09BE\u0989\u09A8\u09CD\u099F\u09C7\u09B0 \u09AC\u09B0\u09CD\u09A4\u09AE\u09BE\u09A8 \u099B\u09AF\u09BC \u0985\u0999\u09CD\u0995\u09C7\u09B0 \u0995\u09CB\u09A1 \u09B2\u09BF\u0996\u09C1\u09A8\u0964 \u0985\u09A8\u09C1\u09B0\u09CB\u09A7 \u0985\u09A8\u09C1\u09AE\u09CB\u09A6\u09A8\u09C7\u09B0 \u09AA\u09CD\u09B0\u09AF\u09BC\u09CB\u099C\u09A8 \u09A8\u09C7\u0987\u0964",
1983
+ otpWaiting: "\u09AC\u09B0\u09CD\u09A4\u09AE\u09BE\u09A8 \u0995\u09CB\u09A1 \u09B2\u09BF\u0996\u09C1\u09A8",
1984
+ otpError: "\u09AF\u09BE\u099A\u09BE\u0987 \u09AC\u09CD\u09AF\u09B0\u09CD\u09A5\u0964 \u0985\u09CD\u09AF\u09BE\u0995\u09BE\u0989\u09A8\u09CD\u099F \u09AA\u09B0\u09C0\u0995\u09CD\u09B7\u09BE \u0995\u09B0\u09C1\u09A8 \u098F\u09AC\u0982 \u09AC\u09CD\u09AF\u09AC\u09B9\u09C3\u09A4 \u0995\u09CB\u09A1 \u09B9\u09B2\u09C7 \u09A8\u09A4\u09C1\u09A8 \u0995\u09CB\u09A1\u09C7\u09B0 \u099C\u09A8\u09CD\u09AF \u0985\u09AA\u09C7\u0995\u09CD\u09B7\u09BE \u0995\u09B0\u09C1\u09A8\u0964 \u09AC\u09BE\u09B0\u09AC\u09BE\u09B0 \u09AC\u09CD\u09AF\u09B0\u09CD\u09A5 \u09B9\u09B2\u09C7 \u09AA\u09B0\u09C7 \u099A\u09C7\u09B7\u09CD\u099F\u09BE \u0995\u09B0\u09C1\u09A8\u0964",
1985
+ otpSetup: "\u09AA\u09CD\u09B0\u09A5\u09AE\u09C7 \u0985\u09CD\u09AF\u09BE\u09AA\u09C7 \u098F\u0987 \u0985\u09CD\u09AF\u09BE\u0995\u09BE\u0989\u09A8\u09CD\u099F\u09C7\u09B0 \u0995\u09BE\u09B0\u09CD\u09A1\u09C7 \u0995\u09CB\u09A1 \u099A\u09BE\u09B2\u09C1 \u0995\u09B0\u09C1\u09A8\u0964"
1941
1986
  };
1942
1987
 
1943
1988
  // src/locales/es.json
@@ -1946,7 +1991,7 @@ var es_default = {
1946
1991
  confirm: "Confirma la verificaci\xF3n",
1947
1992
  scan: "Escanea con AuthLink",
1948
1993
  code: "C\xF3digo de comparaci\xF3n",
1949
- help: "Comprueba que los n\xFAmeros coincidan en la aplicaci\xF3n y confirma en tu tel\xE9fono.",
1994
+ help: "Aprueba en la app e introduce aqu\xED su c\xF3digo de 6 d\xEDgitos.",
1950
1995
  waiting: "Esperando la confirmaci\xF3n del tel\xE9fono",
1951
1996
  loading: "Conectando",
1952
1997
  confirmed: "Confirmado",
@@ -1959,7 +2004,16 @@ var es_default = {
1959
2004
  close: "Cerrar",
1960
2005
  cancel: "Cancelar",
1961
2006
  autoUpdate: "El c\xF3digo se actualiza autom\xE1ticamente cada 30 segundos",
1962
- expiring: "La solicitud est\xE1 por caducar"
2007
+ expiring: "La solicitud est\xE1 por caducar",
2008
+ confirmationCode: "C\xF3digo de confirmaci\xF3n de la app",
2009
+ submitCode: "Verificar",
2010
+ codeError: "No se pudo verificar. Revisa el c\xF3digo y la aprobaci\xF3n.",
2011
+ codeLocked: "Demasiados c\xF3digos incorrectos. Cierra la ventana e inicia una nueva solicitud.",
2012
+ otpCode: "C\xF3digo de la app",
2013
+ otpHelp: "Abre AuthLink e introduce el c\xF3digo actual de seis d\xEDgitos de esta cuenta. No hace falta aprobar una solicitud.",
2014
+ otpWaiting: "Introduce el c\xF3digo actual",
2015
+ otpError: "No se pudo verificar. Comprueba la cuenta y espera un c\xF3digo nuevo si ya lo usaste. Si fallas varias veces, int\xE9ntalo m\xE1s tarde.",
2016
+ otpSetup: "Activa primero los c\xF3digos en la tarjeta de esta cuenta en la app."
1963
2017
  };
1964
2018
 
1965
2019
  // src/locales/fil.json
@@ -1968,7 +2022,7 @@ var fil_default = {
1968
2022
  confirm: "Kumpirmahin ang pagpapatunay",
1969
2023
  scan: "Mag-scan gamit ang AuthLink",
1970
2024
  code: "Code na paghahambingin",
1971
- help: "Tiyaking magkapareho ang mga numero sa app, pagkatapos ay kumpirmahin sa iyong telepono.",
2025
+ help: "Aprubahan sa app, saka ilagay dito ang 6-digit na confirmation code.",
1972
2026
  waiting: "Hinihintay ang kumpirmasyon sa telepono",
1973
2027
  loading: "Kumokonekta",
1974
2028
  confirmed: "Nakumpirma",
@@ -1981,7 +2035,16 @@ var fil_default = {
1981
2035
  close: "Isara",
1982
2036
  cancel: "Kanselahin",
1983
2037
  autoUpdate: "Awtomatikong nagbabago ang code kada 30 segundo",
1984
- expiring: "Malapit nang mag-expire ang kahilingan"
2038
+ expiring: "Malapit nang mag-expire ang kahilingan",
2039
+ confirmationCode: "Confirmation code ng app",
2040
+ submitCode: "I-verify",
2041
+ codeError: "Hindi ma-verify. Suriin ang code at pag-apruba at subukan muli.",
2042
+ codeLocked: "Masyadong maraming maling code. Isara ang window at magsimula ng bagong request.",
2043
+ otpCode: "Code ng app",
2044
+ otpHelp: "Buksan ang AuthLink at ilagay ang kasalukuyang anim na digit na code ng account na ito. Hindi kailangang aprubahan ang request.",
2045
+ otpWaiting: "Ilagay ang kasalukuyang code",
2046
+ otpError: "Hindi napatunayan. Tingnan ang account at maghintay ng bagong code kung nagamit na. Subukang muli mamaya kung maraming maling pagtatangka.",
2047
+ otpSetup: "Paganahin muna ang mga code sa card ng account na ito sa app."
1985
2048
  };
1986
2049
 
1987
2050
  // src/locales/hi.json
@@ -1990,7 +2053,7 @@ var hi_default = {
1990
2053
  confirm: "\u0938\u0924\u094D\u092F\u093E\u092A\u0928 \u0915\u0940 \u092A\u0941\u0937\u094D\u091F\u093F \u0915\u0930\u0947\u0902",
1991
2054
  scan: "AuthLink \u0938\u0947 \u0938\u094D\u0915\u0948\u0928 \u0915\u0930\u0947\u0902",
1992
2055
  code: "\u092E\u093F\u0932\u093E\u0928 \u0915\u094B\u0921",
1993
- help: "\u0910\u092A \u092E\u0947\u0902 \u0938\u0902\u0916\u094D\u092F\u093E\u0913\u0902 \u0915\u093E \u092E\u093F\u0932\u093E\u0928 \u0915\u0930\u0947\u0902, \u092B\u093F\u0930 \u0905\u092A\u0928\u0947 \u092B\u093C\u094B\u0928 \u092A\u0930 \u092A\u0941\u0937\u094D\u091F\u093F \u0915\u0930\u0947\u0902\u0964",
2056
+ help: "\u0910\u092A \u092E\u0947\u0902 \u0938\u094D\u0935\u0940\u0915\u0943\u0924\u093F \u0926\u0947\u0902, \u092B\u093F\u0930 \u092F\u0939\u093E\u0901 6 \u0905\u0902\u0915\u094B\u0902 \u0915\u093E \u092A\u0941\u0937\u094D\u091F\u093F \u0915\u094B\u0921 \u0926\u0930\u094D\u091C \u0915\u0930\u0947\u0902\u0964",
1994
2057
  waiting: "\u092B\u093C\u094B\u0928 \u092A\u0930 \u092A\u0941\u0937\u094D\u091F\u093F \u0915\u0940 \u092A\u094D\u0930\u0924\u0940\u0915\u094D\u0937\u093E \u0939\u0948",
1995
2058
  loading: "\u0915\u0928\u0947\u0915\u094D\u091F \u0939\u094B \u0930\u0939\u093E \u0939\u0948",
1996
2059
  confirmed: "\u092A\u0941\u0937\u094D\u091F\u093F \u0939\u094B \u0917\u0908",
@@ -2003,7 +2066,16 @@ var hi_default = {
2003
2066
  close: "\u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
2004
2067
  cancel: "\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902",
2005
2068
  autoUpdate: "\u0915\u094B\u0921 \u0939\u0930 30 \u0938\u0947\u0915\u0902\u0921 \u092E\u0947\u0902 \u0905\u092A\u0928\u0947 \u0906\u092A \u092C\u0926\u0932\u0924\u093E \u0939\u0948",
2006
- expiring: "\u0905\u0928\u0941\u0930\u094B\u0927 \u0915\u0940 \u0938\u092E\u092F-\u0938\u0940\u092E\u093E \u0938\u092E\u093E\u092A\u094D\u0924 \u0939\u094B\u0928\u0947 \u0935\u093E\u0932\u0940 \u0939\u0948"
2069
+ expiring: "\u0905\u0928\u0941\u0930\u094B\u0927 \u0915\u0940 \u0938\u092E\u092F-\u0938\u0940\u092E\u093E \u0938\u092E\u093E\u092A\u094D\u0924 \u0939\u094B\u0928\u0947 \u0935\u093E\u0932\u0940 \u0939\u0948",
2070
+ confirmationCode: "\u0910\u092A \u0915\u093E \u092A\u0941\u0937\u094D\u091F\u093F \u0915\u094B\u0921",
2071
+ submitCode: "\u0938\u0924\u094D\u092F\u093E\u092A\u093F\u0924 \u0915\u0930\u0947\u0902",
2072
+ codeError: "\u0938\u0924\u094D\u092F\u093E\u092A\u0928 \u0935\u093F\u092B\u0932 \u0930\u0939\u093E\u0964 \u0915\u094B\u0921 \u0914\u0930 \u0938\u094D\u0935\u0940\u0915\u0943\u0924\u093F \u091C\u093E\u0901\u091A\u0915\u0930 \u092A\u0941\u0928\u0903 \u092A\u094D\u0930\u092F\u093E\u0938 \u0915\u0930\u0947\u0902\u0964",
2073
+ codeLocked: "\u092C\u0939\u0941\u0924 \u0905\u0927\u093F\u0915 \u0917\u0932\u0924 \u0915\u094B\u0921\u0964 \u0935\u093F\u0902\u0921\u094B \u092C\u0902\u0926 \u0915\u0930\u0915\u0947 \u0928\u092F\u093E \u0905\u0928\u0941\u0930\u094B\u0927 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902\u0964",
2074
+ otpCode: "\u0910\u092A \u0915\u093E \u0915\u094B\u0921",
2075
+ otpHelp: "AuthLink \u0916\u094B\u0932\u0947\u0902 \u0914\u0930 \u0907\u0938 \u0916\u093E\u0924\u0947 \u0915\u093E \u0935\u0930\u094D\u0924\u092E\u093E\u0928 \u091B\u0939 \u0905\u0902\u0915\u094B\u0902 \u0915\u093E \u0915\u094B\u0921 \u0926\u0930\u094D\u091C \u0915\u0930\u0947\u0902\u0964 \u0905\u0928\u0941\u0930\u094B\u0927 \u0938\u094D\u0935\u0940\u0915\u0943\u0924 \u0915\u0930\u0928\u0947 \u0915\u0940 \u0906\u0935\u0936\u094D\u092F\u0915\u0924\u093E \u0928\u0939\u0940\u0902 \u0939\u0948\u0964",
2076
+ otpWaiting: "\u0935\u0930\u094D\u0924\u092E\u093E\u0928 \u0915\u094B\u0921 \u0926\u0930\u094D\u091C \u0915\u0930\u0947\u0902",
2077
+ otpError: "\u0938\u0924\u094D\u092F\u093E\u092A\u0928 \u0905\u0938\u092B\u0932\u0964 \u0916\u093E\u0924\u093E \u091C\u093E\u0901\u091A\u0947\u0902 \u0914\u0930 \u0909\u092A\u092F\u094B\u0917 \u0939\u094B \u091A\u0941\u0915\u093E \u0939\u094B \u0924\u094B \u0928\u090F \u0915\u094B\u0921 \u0915\u0940 \u092A\u094D\u0930\u0924\u0940\u0915\u094D\u0937\u093E \u0915\u0930\u0947\u0902\u0964 \u092C\u093E\u0930-\u092C\u093E\u0930 \u0905\u0938\u092B\u0932 \u0939\u094B\u0928\u0947 \u092A\u0930 \u092C\u093E\u0926 \u092E\u0947\u0902 \u092A\u094D\u0930\u092F\u093E\u0938 \u0915\u0930\u0947\u0902\u0964",
2078
+ otpSetup: "\u092A\u0939\u0932\u0947 \u0910\u092A \u092E\u0947\u0902 \u0907\u0938 \u0916\u093E\u0924\u0947 \u0915\u0947 \u0915\u093E\u0930\u094D\u0921 \u092A\u0930 \u0915\u094B\u0921 \u0938\u0915\u094D\u0937\u092E \u0915\u0930\u0947\u0902\u0964"
2007
2079
  };
2008
2080
 
2009
2081
  // src/locales/id.json
@@ -2012,7 +2084,7 @@ var id_default = {
2012
2084
  confirm: "Konfirmasi verifikasi",
2013
2085
  scan: "Pindai dengan AuthLink",
2014
2086
  code: "Kode pencocokan",
2015
- help: "Pastikan angka di aplikasi cocok, lalu konfirmasi di ponsel Anda.",
2087
+ help: "Setujui di aplikasi, lalu masukkan kode konfirmasi 6 digit di sini.",
2016
2088
  waiting: "Menunggu konfirmasi dari ponsel",
2017
2089
  loading: "Menghubungkan",
2018
2090
  confirmed: "Dikonfirmasi",
@@ -2025,7 +2097,16 @@ var id_default = {
2025
2097
  close: "Tutup",
2026
2098
  cancel: "Batal",
2027
2099
  autoUpdate: "Kode diperbarui otomatis setiap 30 detik",
2028
- expiring: "Permintaan akan segera kedaluwarsa"
2100
+ expiring: "Permintaan akan segera kedaluwarsa",
2101
+ confirmationCode: "Kode konfirmasi aplikasi",
2102
+ submitCode: "Verifikasi",
2103
+ codeError: "Verifikasi gagal. Periksa kode dan persetujuan, lalu coba lagi.",
2104
+ codeLocked: "Terlalu banyak kode salah. Tutup jendela dan mulai permintaan baru.",
2105
+ otpCode: "Kode aplikasi",
2106
+ otpHelp: "Buka AuthLink dan masukkan kode enam digit terkini untuk akun ini. Tidak perlu menyetujui permintaan.",
2107
+ otpWaiting: "Masukkan kode terkini",
2108
+ otpError: "Verifikasi gagal. Periksa akun dan tunggu kode baru jika sudah digunakan. Setelah beberapa kegagalan, coba lagi nanti.",
2109
+ otpSetup: "Aktifkan kode di kartu akun ini dalam aplikasi terlebih dahulu."
2029
2110
  };
2030
2111
 
2031
2112
  // src/locales/ms.json
@@ -2034,7 +2115,7 @@ var ms_default = {
2034
2115
  confirm: "Sahkan pengesahan",
2035
2116
  scan: "Imbas dengan AuthLink",
2036
2117
  code: "Kod padanan",
2037
- help: "Pastikan nombor dalam aplikasi sepadan, kemudian sahkan pada telefon anda.",
2118
+ help: "Luluskan dalam aplikasi, kemudian masukkan kod pengesahan 6 digit di sini.",
2038
2119
  waiting: "Menunggu pengesahan daripada telefon",
2039
2120
  loading: "Sedang menyambung",
2040
2121
  confirmed: "Disahkan",
@@ -2047,7 +2128,16 @@ var ms_default = {
2047
2128
  close: "Tutup",
2048
2129
  cancel: "Batal",
2049
2130
  autoUpdate: "Kod dikemas kini secara automatik setiap 30 saat",
2050
- expiring: "Permintaan akan tamat tempoh tidak lama lagi"
2131
+ expiring: "Permintaan akan tamat tempoh tidak lama lagi",
2132
+ confirmationCode: "Kod pengesahan aplikasi",
2133
+ submitCode: "Sahkan",
2134
+ codeError: "Pengesahan gagal. Semak kod dan kelulusan, kemudian cuba lagi.",
2135
+ codeLocked: "Terlalu banyak kod salah. Tutup tetingkap dan mulakan permintaan baharu.",
2136
+ otpCode: "Kod aplikasi",
2137
+ otpHelp: "Buka AuthLink dan masukkan kod enam digit semasa untuk akaun ini. Tiada kelulusan permintaan diperlukan.",
2138
+ otpWaiting: "Masukkan kod semasa",
2139
+ otpError: "Pengesahan gagal. Semak akaun dan tunggu kod baharu jika sudah digunakan. Selepas beberapa kegagalan, cuba lagi kemudian.",
2140
+ otpSetup: "Aktifkan kod pada kad akaun ini dalam aplikasi dahulu."
2051
2141
  };
2052
2142
 
2053
2143
  // src/locales/pt.json
@@ -2056,7 +2146,7 @@ var pt_default = {
2056
2146
  confirm: "Confirme a verifica\xE7\xE3o",
2057
2147
  scan: "Escaneie com o AuthLink",
2058
2148
  code: "C\xF3digo de compara\xE7\xE3o",
2059
- help: "Confira se os n\xFAmeros no aplicativo coincidem e confirme no celular.",
2149
+ help: "Aprove no app e digite aqui o c\xF3digo de 6 d\xEDgitos.",
2060
2150
  waiting: "Aguardando confirma\xE7\xE3o no celular",
2061
2151
  loading: "Conectando",
2062
2152
  confirmed: "Confirmado",
@@ -2069,7 +2159,16 @@ var pt_default = {
2069
2159
  close: "Fechar",
2070
2160
  cancel: "Cancelar",
2071
2161
  autoUpdate: "O c\xF3digo \xE9 atualizado automaticamente a cada 30 segundos",
2072
- expiring: "A solicita\xE7\xE3o est\xE1 prestes a expirar"
2162
+ expiring: "A solicita\xE7\xE3o est\xE1 prestes a expirar",
2163
+ confirmationCode: "C\xF3digo de confirma\xE7\xE3o do app",
2164
+ submitCode: "Verificar",
2165
+ codeError: "N\xE3o foi poss\xEDvel verificar. Confira o c\xF3digo e a aprova\xE7\xE3o.",
2166
+ codeLocked: "Muitos c\xF3digos incorretos. Feche a janela e inicie uma nova solicita\xE7\xE3o.",
2167
+ otpCode: "C\xF3digo do aplicativo",
2168
+ otpHelp: "Abra o AuthLink e digite o c\xF3digo atual de seis d\xEDgitos desta conta. N\xE3o \xE9 necess\xE1rio aprovar uma solicita\xE7\xE3o.",
2169
+ otpWaiting: "Digite o c\xF3digo atual",
2170
+ otpError: "Falha na verifica\xE7\xE3o. Confira a conta e aguarde um novo c\xF3digo se j\xE1 o usou. Ap\xF3s v\xE1rias falhas, tente mais tarde.",
2171
+ otpSetup: "Ative primeiro os c\xF3digos no cart\xE3o desta conta no aplicativo."
2073
2172
  };
2074
2173
 
2075
2174
  // src/locales/th.json
@@ -2078,7 +2177,7 @@ var th_default = {
2078
2177
  confirm: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A",
2079
2178
  scan: "\u0E2A\u0E41\u0E01\u0E19\u0E14\u0E49\u0E27\u0E22 AuthLink",
2080
2179
  code: "\u0E23\u0E2B\u0E31\u0E2A\u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A\u0E40\u0E1B\u0E23\u0E35\u0E22\u0E1A\u0E40\u0E17\u0E35\u0E22\u0E1A",
2081
- help: "\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E27\u0E48\u0E32\u0E15\u0E31\u0E27\u0E40\u0E25\u0E02\u0E43\u0E19\u0E41\u0E2D\u0E1B\u0E15\u0E23\u0E07\u0E01\u0E31\u0E19 \u0E41\u0E25\u0E49\u0E27\u0E08\u0E36\u0E07\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E1A\u0E19\u0E42\u0E17\u0E23\u0E28\u0E31\u0E1E\u0E17\u0E4C\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13",
2180
+ help: "\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34\u0E43\u0E19\u0E41\u0E2D\u0E1B \u0E41\u0E25\u0E49\u0E27\u0E01\u0E23\u0E2D\u0E01\u0E23\u0E2B\u0E31\u0E2A\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19 6 \u0E2B\u0E25\u0E31\u0E01\u0E17\u0E35\u0E48\u0E19\u0E35\u0E48",
2082
2181
  waiting: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E23\u0E2D\u0E01\u0E32\u0E23\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E08\u0E32\u0E01\u0E42\u0E17\u0E23\u0E28\u0E31\u0E1E\u0E17\u0E4C",
2083
2182
  loading: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D",
2084
2183
  confirmed: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E41\u0E25\u0E49\u0E27",
@@ -2091,7 +2190,16 @@ var th_default = {
2091
2190
  close: "\u0E1B\u0E34\u0E14",
2092
2191
  cancel: "\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01",
2093
2192
  autoUpdate: "\u0E23\u0E2B\u0E31\u0E2A\u0E08\u0E30\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15\u0E2D\u0E31\u0E15\u0E42\u0E19\u0E21\u0E31\u0E15\u0E34\u0E17\u0E38\u0E01 30 \u0E27\u0E34\u0E19\u0E32\u0E17\u0E35",
2094
- expiring: "\u0E04\u0E33\u0E02\u0E2D\u0E43\u0E01\u0E25\u0E49\u0E2B\u0E21\u0E14\u0E2D\u0E32\u0E22\u0E38"
2193
+ expiring: "\u0E04\u0E33\u0E02\u0E2D\u0E43\u0E01\u0E25\u0E49\u0E2B\u0E21\u0E14\u0E2D\u0E32\u0E22\u0E38",
2194
+ confirmationCode: "\u0E23\u0E2B\u0E31\u0E2A\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E08\u0E32\u0E01\u0E41\u0E2D\u0E1B",
2195
+ submitCode: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19",
2196
+ codeError: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08 \u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E23\u0E2B\u0E31\u0E2A\u0E41\u0E25\u0E30\u0E01\u0E32\u0E23\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34\u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07",
2197
+ codeLocked: "\u0E01\u0E23\u0E2D\u0E01\u0E23\u0E2B\u0E31\u0E2A\u0E1C\u0E34\u0E14\u0E2B\u0E25\u0E32\u0E22\u0E04\u0E23\u0E31\u0E49\u0E07\u0E40\u0E01\u0E34\u0E19\u0E44\u0E1B \u0E42\u0E1B\u0E23\u0E14\u0E1B\u0E34\u0E14\u0E2B\u0E19\u0E49\u0E32\u0E15\u0E48\u0E32\u0E07\u0E41\u0E25\u0E49\u0E27\u0E40\u0E23\u0E34\u0E48\u0E21\u0E04\u0E33\u0E02\u0E2D\u0E43\u0E2B\u0E21\u0E48",
2198
+ otpCode: "\u0E23\u0E2B\u0E31\u0E2A\u0E08\u0E32\u0E01\u0E41\u0E2D\u0E1B",
2199
+ otpHelp: "\u0E40\u0E1B\u0E34\u0E14 AuthLink \u0E41\u0E25\u0E30\u0E01\u0E23\u0E2D\u0E01\u0E23\u0E2B\u0E31\u0E2A\u0E2B\u0E01\u0E2B\u0E25\u0E31\u0E01\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19\u0E02\u0E2D\u0E07\u0E1A\u0E31\u0E0D\u0E0A\u0E35\u0E19\u0E35\u0E49 \u0E44\u0E21\u0E48\u0E15\u0E49\u0E2D\u0E07\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34\u0E04\u0E33\u0E02\u0E2D",
2200
+ otpWaiting: "\u0E01\u0E23\u0E2D\u0E01\u0E23\u0E2B\u0E31\u0E2A\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19",
2201
+ otpError: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08 \u0E42\u0E1B\u0E23\u0E14\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E1A\u0E31\u0E0D\u0E0A\u0E35\u0E41\u0E25\u0E30\u0E23\u0E2D\u0E23\u0E2B\u0E31\u0E2A\u0E43\u0E2B\u0E21\u0E48\u0E2B\u0E32\u0E01\u0E43\u0E0A\u0E49\u0E44\u0E1B\u0E41\u0E25\u0E49\u0E27 \u0E2B\u0E32\u0E01\u0E1C\u0E34\u0E14\u0E2B\u0E25\u0E32\u0E22\u0E04\u0E23\u0E31\u0E49\u0E07\u0E43\u0E2B\u0E49\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E20\u0E32\u0E22\u0E2B\u0E25\u0E31\u0E07",
2202
+ otpSetup: "\u0E40\u0E1B\u0E34\u0E14\u0E43\u0E0A\u0E49\u0E23\u0E2B\u0E31\u0E2A\u0E1A\u0E19\u0E01\u0E32\u0E23\u0E4C\u0E14\u0E1A\u0E31\u0E0D\u0E0A\u0E35\u0E19\u0E35\u0E49\u0E43\u0E19\u0E41\u0E2D\u0E1B\u0E01\u0E48\u0E2D\u0E19"
2095
2203
  };
2096
2204
 
2097
2205
  // src/locales/vi.json
@@ -2100,7 +2208,7 @@ var vi_default = {
2100
2208
  confirm: "X\xE1c nh\u1EADn x\xE1c th\u1EF1c",
2101
2209
  scan: "Qu\xE9t b\u1EB1ng AuthLink",
2102
2210
  code: "M\xE3 \u0111\u1ED1i chi\u1EBFu",
2103
- help: "Ki\u1EC3m tra c\xE1c ch\u1EEF s\u1ED1 trong \u1EE9ng d\u1EE5ng c\xF3 kh\u1EDBp kh\xF4ng, r\u1ED3i x\xE1c nh\u1EADn tr\xEAn \u0111i\u1EC7n tho\u1EA1i.",
2211
+ help: "Ph\xEA duy\u1EC7t trong \u1EE9ng d\u1EE5ng r\u1ED3i nh\u1EADp m\xE3 x\xE1c nh\u1EADn 6 ch\u1EEF s\u1ED1 t\u1EA1i \u0111\xE2y.",
2104
2212
  waiting: "\u0110ang ch\u1EDD x\xE1c nh\u1EADn t\u1EEB \u0111i\u1EC7n tho\u1EA1i",
2105
2213
  loading: "\u0110ang k\u1EBFt n\u1ED1i",
2106
2214
  confirmed: "\u0110\xE3 x\xE1c nh\u1EADn",
@@ -2113,7 +2221,16 @@ var vi_default = {
2113
2221
  close: "\u0110\xF3ng",
2114
2222
  cancel: "H\u1EE7y",
2115
2223
  autoUpdate: "M\xE3 t\u1EF1 \u0111\u1ED9ng c\u1EADp nh\u1EADt m\u1ED7i 30 gi\xE2y",
2116
- expiring: "Y\xEAu c\u1EA7u s\u1EAFp h\u1EBFt h\u1EA1n"
2224
+ expiring: "Y\xEAu c\u1EA7u s\u1EAFp h\u1EBFt h\u1EA1n",
2225
+ confirmationCode: "M\xE3 x\xE1c nh\u1EADn trong \u1EE9ng d\u1EE5ng",
2226
+ submitCode: "X\xE1c minh",
2227
+ codeError: "Kh\xF4ng th\u1EC3 x\xE1c minh. Ki\u1EC3m tra m\xE3 v\xE0 tr\u1EA1ng th\xE1i ph\xEA duy\u1EC7t r\u1ED3i th\u1EED l\u1EA1i.",
2228
+ codeLocked: "Nh\u1EADp sai m\xE3 qu\xE1 nhi\u1EC1u l\u1EA7n. \u0110\xF3ng c\u1EEDa s\u1ED5 v\xE0 t\u1EA1o y\xEAu c\u1EA7u m\u1EDBi.",
2229
+ otpCode: "M\xE3 \u1EE9ng d\u1EE5ng",
2230
+ otpHelp: "M\u1EDF AuthLink v\xE0 nh\u1EADp m\xE3 s\xE1u ch\u1EEF s\u1ED1 hi\u1EC7n t\u1EA1i c\u1EE7a t\xE0i kho\u1EA3n n\xE0y. Kh\xF4ng c\u1EA7n ph\xEA duy\u1EC7t y\xEAu c\u1EA7u.",
2231
+ otpWaiting: "Nh\u1EADp m\xE3 hi\u1EC7n t\u1EA1i",
2232
+ otpError: "X\xE1c minh th\u1EA5t b\u1EA1i. Ki\u1EC3m tra t\xE0i kho\u1EA3n v\xE0 ch\u1EDD m\xE3 m\u1EDBi n\u1EBFu \u0111\xE3 d\xF9ng. N\u1EBFu sai nhi\u1EC1u l\u1EA7n, h\xE3y th\u1EED l\u1EA1i sau.",
2233
+ otpSetup: "Tr\u01B0\u1EDBc ti\xEAn h\xE3y b\u1EADt m\xE3 tr\xEAn th\u1EBB t\xE0i kho\u1EA3n n\xE0y trong \u1EE9ng d\u1EE5ng."
2117
2234
  };
2118
2235
 
2119
2236
  // src/i18n.ts
@@ -2150,7 +2267,7 @@ function widgetView(options) {
2150
2267
  const locale = resolveLocale(options.locale), variant = resolveVariant(options.variant);
2151
2268
  const l = getMessages(locale);
2152
2269
  const pending = s.status === "pending", hasQr = pending && (mode === "bind" || Boolean(options.showQr)) && Boolean(options.qr);
2153
- const status = { idle: l.loading, pending: l.waiting, confirmed: l.confirmed, rejected: l.rejected, expired: l.expired, error: l.error }[s.status];
2270
+ const status = { idle: l.loading, pending: options.passcodeMode ? l.otpWaiting : l.waiting, confirmed: l.confirmed, rejected: l.rejected, expired: l.expired, error: l.error }[s.status];
2154
2271
  const expiring = pending && s.secondsRemaining <= 30;
2155
2272
  const expiryTime = `00:${String(Math.max(0, Math.ceil(s.secondsRemaining))).padStart(2, "0")}`;
2156
2273
  const statusNode = () => node(
@@ -2179,50 +2296,52 @@ function widgetView(options) {
2179
2296
  node("img", { class: "authlink-qr", src: options.qr, alt: l.scan, width: 240, height: 240 }),
2180
2297
  node("figcaption", { class: "authlink-qr-caption" }, l.scan)
2181
2298
  )] : [];
2182
- const seconds = Math.max(0, Math.min(30, s.codeSecondsRemaining));
2183
- const code = node(
2184
- "output",
2185
- {
2186
- class: "authlink-code",
2187
- "aria-label": s.code ? `${l.code}: ${s.code.split("").join(" ")}` : l.updating,
2188
- "aria-live": "polite",
2189
- "data-testid": "authlink-code"
2190
- },
2191
- node("span", { class: "authlink-code-group" }, s.code?.slice(0, 3) ?? "---"),
2192
- node("span", { class: "authlink-code-group" }, s.code?.slice(3) ?? "---")
2193
- );
2194
- const panel = node(
2195
- "div",
2196
- { class: "authlink-code-panel" },
2197
- node("div", { class: "authlink-code-values" }, node("div", { class: "authlink-code-label" }, l.code), code),
2299
+ const detail = [
2300
+ node("p", { class: "authlink-help" }, options.passcodeMode ? l.otpHelp : l.help),
2198
2301
  node(
2199
- "div",
2200
- {
2201
- class: "authlink-progress",
2202
- role: "progressbar",
2203
- "aria-valuemin": 0,
2204
- "aria-valuemax": 30,
2205
- "aria-valuenow": seconds,
2206
- "aria-label": l.autoUpdate
2207
- },
2208
- node("span", { class: "authlink-progress-fill", "aria-hidden": "true", style: `transform:scaleX(${seconds / 30})` })
2302
+ "form",
2303
+ { class: "authlink-code-form", onSubmit: (event) => {
2304
+ event.preventDefault();
2305
+ const input = event.currentTarget.querySelector("input");
2306
+ if (input) void options.submitCode?.(input.value);
2307
+ } },
2308
+ node("label", { for: "authlink-confirmation-code" }, options.passcodeMode ? l.otpCode : l.confirmationCode),
2309
+ node("input", {
2310
+ id: "authlink-confirmation-code",
2311
+ name: options.passcodeMode ? "passcode" : "confirmationCode",
2312
+ type: "text",
2313
+ inputmode: "numeric",
2314
+ autocomplete: "one-time-code",
2315
+ pattern: "[0-9]{6}",
2316
+ maxlength: 6,
2317
+ minlength: 6,
2318
+ required: true,
2319
+ "data-authlink-focus": "confirmation-code",
2320
+ value: options.inputCode ?? "",
2321
+ onInput: (event) => options.setCode?.(event.target.value)
2322
+ }),
2323
+ node(
2324
+ "button",
2325
+ { type: "submit", class: "authlink-button", ...s.submitting ? { disabled: true } : {} },
2326
+ s.submitting ? l.loading : l.submitCode
2327
+ )
2209
2328
  ),
2210
- node("p", { class: "authlink-code-caption" }, s.code ? l.autoUpdate : l.updating)
2211
- );
2212
- const detail = [panel, node("p", { class: "authlink-help" }, l.help)];
2329
+ ...s.error ? [node("p", { class: "authlink-input-error", role: "alert" }, options.passcodeMode ? s.error.message === "OTP_NOT_CONFIGURED" ? l.otpSetup : l.otpError : l.codeError)] : []
2330
+ ];
2213
2331
  children.push(node("div", { class: "authlink-body" }, ...qr, node("div", { class: "authlink-details" }, ...detail)));
2214
2332
  if (variant === "A") children.push(node("div", { class: "authlink-footer" }, statusNode()));
2215
2333
  if (variant === "B") children.push(node("div", { class: "authlink-footer" }, statusNode(), ...cancel()));
2216
2334
  if (variant === "C") children.push(node("div", { class: "authlink-footer" }, statusNode(), ...cancel()));
2217
2335
  } else {
2218
2336
  children.push(statusNode());
2219
- if (s.status === "error") children.push(node("button", {
2337
+ if (s.error?.message === "CONFIRMATION_CODE_LOCKED") children.push(node("p", { class: "authlink-input-error", role: "alert" }, l.codeLocked));
2338
+ if (s.status === "error" && s.error?.message !== "CONFIRMATION_CODE_LOCKED") children.push(node("button", {
2220
2339
  type: "button",
2221
2340
  class: "authlink-button",
2222
2341
  "data-authlink-focus": "retry",
2223
2342
  onClick: retry
2224
2343
  }, l.retry));
2225
- if (refresh && ["expired", "rejected"].includes(s.status)) children.push(node("button", {
2344
+ if (refresh && ["expired", "rejected", "error"].includes(s.status)) children.push(node("button", {
2226
2345
  type: "button",
2227
2346
  class: "authlink-button",
2228
2347
  "data-authlink-focus": "refresh",
@@ -2245,7 +2364,7 @@ function element(value, svg = false) {
2245
2364
  svg ||= value.tag === "svg";
2246
2365
  const result = svg ? document.createElementNS("http://www.w3.org/2000/svg", value.tag) : document.createElement(value.tag);
2247
2366
  for (const [key, v] of Object.entries(value.props)) {
2248
- if (key === "onClick" && typeof v === "function") result.addEventListener("click", v);
2367
+ if (key.startsWith("on") && typeof v === "function") result.addEventListener(key.slice(2).toLowerCase(), v);
2249
2368
  else if (v !== void 0 && v !== null) result.setAttribute(key, String(v));
2250
2369
  }
2251
2370
  result.append(...value.children.map((child) => element(child, svg)));
@@ -2279,6 +2398,8 @@ function openAuthLink(options) {
2279
2398
  dialog.append(header, content);
2280
2399
  let locale = options.locale, variant = resolveVariant(options.variant), snapshot = initialSnapshot(), closed = false;
2281
2400
  let abort;
2401
+ let inputCode = "";
2402
+ let submitCode;
2282
2403
  const image = qrImage(ticket);
2283
2404
  let progressFill, progressFrame, progressDeadline = 0;
2284
2405
  const motion = window.matchMedia?.("(prefers-reduced-motion: reduce)");
@@ -2318,6 +2439,11 @@ function openAuthLink(options) {
2318
2439
  snapshot,
2319
2440
  qr: image,
2320
2441
  showQr: options.showQr,
2442
+ inputCode,
2443
+ setCode: (code) => {
2444
+ inputCode = code;
2445
+ },
2446
+ submitCode: (code) => submitCode?.(code) ?? Promise.resolve(),
2321
2447
  retry,
2322
2448
  refresh: options.onRefresh,
2323
2449
  close: () => dispose(true)
@@ -2336,6 +2462,9 @@ function openAuthLink(options) {
2336
2462
  oldProgress.setAttribute("aria-label", nextProgress.getAttribute("aria-label"));
2337
2463
  nextProgress.replaceWith(oldProgress);
2338
2464
  }
2465
+ const oldInput = content.querySelector("input[name=confirmationCode]");
2466
+ const nextInput = next.querySelector("input[name=confirmationCode]");
2467
+ if (oldInput && nextInput) nextInput.replaceWith(oldInput);
2339
2468
  content.replaceChildren(next);
2340
2469
  progressFill = content.querySelector(".authlink-progress-fill") ?? void 0;
2341
2470
  drawProgress();
@@ -2377,6 +2506,9 @@ function openAuthLink(options) {
2377
2506
  intervalMs: options.intervalMs,
2378
2507
  expectedMode: mode,
2379
2508
  signal: abort.signal,
2509
+ onReady: (submit) => {
2510
+ submitCode = submit;
2511
+ },
2380
2512
  onCodeTiming: syncProgress,
2381
2513
  onUpdate: (value) => {
2382
2514
  snapshot = value;
@@ -2435,11 +2567,196 @@ function openAuthLink(options) {
2435
2567
  };
2436
2568
  }
2437
2569
 
2570
+ // src/passcode.ts
2571
+ function validateOTPResult(value) {
2572
+ if (!value || typeof value !== "object") throw new AuthLinkError("INVALID_RESPONSE");
2573
+ const result = value;
2574
+ const expiry = typeof result.expiresAt === "string" ? Date.parse(result.expiresAt) : NaN;
2575
+ if (result.status !== "confirmed" || result.authenticationPolicy !== "device-totp.v1" || typeof result.verificationId !== "string" || !/^[A-Za-z0-9_-]{43}$/.test(result.verificationId) || !Number.isFinite(expiry) || expiry <= Date.now() || expiry > Date.now() + 9e4 || "requestId" in result || "state" in result || "businessId" in result) throw new AuthLinkError("INVALID_CONFIRMATION");
2576
+ return result;
2577
+ }
2578
+ function openPasscode(options) {
2579
+ if (typeof document === "undefined" || !document.body) throw new AuthLinkError("BROWSER_REQUIRED");
2580
+ const deadline = Date.parse(options.expiresAt);
2581
+ if (!Number.isFinite(deadline) || deadline <= Date.now() || deadline > Date.now() + 3e5) throw new AuthLinkError("INVALID_EXPIRY");
2582
+ const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
2583
+ const dialog = document.createElement("dialog");
2584
+ if (typeof dialog.showModal !== "function") throw new AuthLinkError("DIALOG_UNSUPPORTED");
2585
+ dialog.className = "authlink-dialog";
2586
+ dialog.setAttribute("aria-modal", "true");
2587
+ const header = document.createElement("div");
2588
+ header.className = "authlink-header";
2589
+ const brand = document.createElement("span");
2590
+ brand.className = "authlink-brand";
2591
+ brand.textContent = "AuthLink";
2592
+ const close = document.createElement("button");
2593
+ close.type = "button";
2594
+ close.className = "authlink-close";
2595
+ const icon = document.createElement("span");
2596
+ icon.className = "authlink-close-icon";
2597
+ icon.setAttribute("aria-hidden", "true");
2598
+ close.append(icon);
2599
+ const content = document.createElement("div");
2600
+ content.className = "authlink-modal-content";
2601
+ header.append(brand, close);
2602
+ dialog.append(header, content);
2603
+ let locale = options.locale, variant = resolveVariant(options.variant), closed = false, busy = false, code = "", error;
2604
+ const mode = options.bindingQr ? "bind" : "confirm";
2605
+ let image;
2606
+ if (options.bindingQr) {
2607
+ let payload;
2608
+ try {
2609
+ payload = JSON.parse(options.bindingQr);
2610
+ } catch {
2611
+ throw new AuthLinkError("INVALID_TICKET");
2612
+ }
2613
+ image = qrImage(validateTicket({ requestId: payload.requestId, purpose: "bind", qr: options.bindingQr, pairingCode: "000000", expiresAt: options.expiresAt }, "bind", options.authLinkOrigin));
2614
+ }
2615
+ const abort = new AbortController();
2616
+ let timer;
2617
+ const dispose = (notify) => {
2618
+ if (closed) return;
2619
+ closed = true;
2620
+ abort.abort();
2621
+ clearInterval(timer);
2622
+ dialog.remove();
2623
+ previousFocus?.focus();
2624
+ if (notify) options.onClose?.();
2625
+ };
2626
+ const render = () => {
2627
+ if (closed) return;
2628
+ const l = getMessages(locale);
2629
+ dialog.lang = resolveLocale(locale);
2630
+ dialog.dataset.variant = variant;
2631
+ dialog.dataset.mode = mode;
2632
+ dialog.dataset.hasQr = String(Boolean(image));
2633
+ dialog.setAttribute("aria-label", l[mode]);
2634
+ close.setAttribute("aria-label", l.close);
2635
+ const focused = content.contains(document.activeElement);
2636
+ const remaining = Math.max(0, Math.ceil((deadline - Date.now()) / 1e3));
2637
+ const snapshot = { status: remaining ? "pending" : "expired", code: null, secondsRemaining: remaining, codeSecondsRemaining: remaining, submitting: busy, error: error ?? null };
2638
+ content.replaceChildren(element(widgetView({
2639
+ mode,
2640
+ locale,
2641
+ variant,
2642
+ passcodeMode: true,
2643
+ snapshot,
2644
+ qr: image,
2645
+ showQr: Boolean(image),
2646
+ inputCode: code,
2647
+ setCode: (value) => {
2648
+ code = value;
2649
+ },
2650
+ submitCode: submit,
2651
+ retry: () => {
2652
+ error = void 0;
2653
+ render();
2654
+ },
2655
+ close: () => dispose(true)
2656
+ })));
2657
+ if (focused) content.querySelector("input")?.focus();
2658
+ };
2659
+ const submit = async (value) => {
2660
+ if (closed || busy) return;
2661
+ if (Date.now() >= deadline) {
2662
+ render();
2663
+ return;
2664
+ }
2665
+ if (!/^[0-9]{6}$/.test(value)) {
2666
+ error = new AuthLinkError("PASSCODE_INVALID");
2667
+ render();
2668
+ return;
2669
+ }
2670
+ code = value;
2671
+ busy = true;
2672
+ error = void 0;
2673
+ render();
2674
+ try {
2675
+ const result = validateOTPResult(await options.client.verify(value, abort.signal));
2676
+ if (closed || abort.signal.aborted || Date.now() >= deadline) return;
2677
+ try {
2678
+ await options.onVerified?.(result);
2679
+ } catch {
2680
+ options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
2681
+ }
2682
+ dispose(false);
2683
+ } catch (cause) {
2684
+ if (!closed && !abort.signal.aborted) {
2685
+ error = cause instanceof Error ? cause : new AuthLinkError("NETWORK_ERROR");
2686
+ options.onError?.(error);
2687
+ }
2688
+ } finally {
2689
+ busy = false;
2690
+ render();
2691
+ }
2692
+ };
2693
+ close.addEventListener("click", () => dispose(true));
2694
+ dialog.addEventListener("cancel", (event) => {
2695
+ event.preventDefault();
2696
+ dispose(true);
2697
+ });
2698
+ document.body.append(dialog);
2699
+ render();
2700
+ dialog.showModal();
2701
+ content.querySelector("input")?.focus();
2702
+ timer = setInterval(() => {
2703
+ if (closed) return;
2704
+ if (Date.now() >= deadline) {
2705
+ render();
2706
+ clearInterval(timer);
2707
+ void Promise.resolve(options.onExpired?.()).catch(() => options.onError?.(new AuthLinkError("CALLBACK_FAILED")));
2708
+ }
2709
+ }, 1e3);
2710
+ return {
2711
+ close: () => dispose(true),
2712
+ destroy: () => dispose(false),
2713
+ setLocale: (value) => {
2714
+ locale = value;
2715
+ render();
2716
+ },
2717
+ setVariant: (value) => {
2718
+ variant = resolveVariant(value);
2719
+ render();
2720
+ },
2721
+ retry: () => {
2722
+ error = void 0;
2723
+ render();
2724
+ }
2725
+ };
2726
+ }
2727
+
2438
2728
  // src/react.tsx
2439
2729
  import { jsx } from "react/jsx-runtime";
2730
+ function AuthLinkPasscode(props) {
2731
+ const latest = useRef(props);
2732
+ latest.current = props;
2733
+ const modal = useRef(void 0);
2734
+ useEffect(() => {
2735
+ const handle = openPasscode({
2736
+ ...props,
2737
+ onVerified: (value) => latest.current.onVerified?.(value),
2738
+ onExpired: () => latest.current.onExpired?.(),
2739
+ onClose: () => latest.current.onClose?.(),
2740
+ onError: (value) => latest.current.onError?.(value)
2741
+ });
2742
+ modal.current = handle;
2743
+ return () => {
2744
+ handle.destroy();
2745
+ if (modal.current === handle) modal.current = void 0;
2746
+ };
2747
+ }, [props.client, props.expiresAt, props.bindingQr, props.authLinkOrigin]);
2748
+ useEffect(() => {
2749
+ modal.current?.setLocale(props.locale);
2750
+ }, [props.locale]);
2751
+ useEffect(() => {
2752
+ modal.current?.setVariant(props.variant);
2753
+ }, [props.variant]);
2754
+ return null;
2755
+ }
2440
2756
  function useAuthLink(options) {
2441
2757
  const latest = useRef(options);
2442
2758
  latest.current = options;
2759
+ const submit = useRef(void 0);
2443
2760
  const delivered = useRef(/* @__PURE__ */ new Set());
2444
2761
  const [snapshot, setSnapshot] = useState(initialSnapshot);
2445
2762
  const [attempt, setAttempt] = useState(0);
@@ -2459,6 +2776,9 @@ function useAuthLink(options) {
2459
2776
  intervalMs,
2460
2777
  expectedMode: mode,
2461
2778
  signal: abort.signal,
2779
+ onReady: (fn) => {
2780
+ submit.current = fn;
2781
+ },
2462
2782
  onUpdate: setSnapshot,
2463
2783
  onConfirmed: (result) => once("confirmed", () => latest.current.onConfirmed?.(result)),
2464
2784
  onRejected: (result) => once("rejected", () => latest.current.onRejected?.(result)),
@@ -2467,7 +2787,7 @@ function useAuthLink(options) {
2467
2787
  });
2468
2788
  return () => abort.abort();
2469
2789
  }, [ticket, client, intervalMs, mode, attempt]);
2470
- return { snapshot, retry };
2790
+ return { snapshot, retry, submitCode: (code) => submit.current?.(code) ?? Promise.resolve() };
2471
2791
  }
2472
2792
  function Widget(props) {
2473
2793
  const latest = useRef(props);
@@ -2514,6 +2834,7 @@ function AuthLinkConfirm(props) {
2514
2834
  export {
2515
2835
  AuthLinkBind,
2516
2836
  AuthLinkConfirm,
2837
+ AuthLinkPasscode,
2517
2838
  useAuthLink
2518
2839
  };
2519
2840
  //# sourceMappingURL=react.js.map