@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/vue.js CHANGED
@@ -1676,10 +1676,9 @@ function validateTicket(value, expectedMode, trustedOrigin) {
1676
1676
  }
1677
1677
  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");
1678
1678
  const displayCode = m.displayCode === void 0 ? void 0 : validateDisplayCode(m.displayCode);
1679
- if (m.purpose === "confirm" && !displayCode) fail("DYNAMIC_CODE_REQUIRED");
1680
1679
  const expiry = Date.parse(String(m.expiresAt));
1681
1680
  const now = displayCode ? Date.parse(displayCode.serverTime) : Date.now();
1682
- if (!Number.isFinite(expiry) || expiry > now + 18e4) fail("INVALID_EXPIRY");
1681
+ if (!Number.isFinite(expiry) || expiry > now + 36e4) fail("INVALID_EXPIRY");
1683
1682
  return {
1684
1683
  requestId: m.requestId,
1685
1684
  purpose: m.purpose,
@@ -1711,116 +1710,117 @@ function abortable(promise, signal) {
1711
1710
  }
1712
1711
  async function observeRequest(input, options) {
1713
1712
  const { client, signal, onUpdate } = options;
1714
- const interval = options.intervalMs ?? 1500;
1715
1713
  let ticket;
1716
1714
  try {
1717
- if (interval < 250 || interval > 1e4 || !Number.isFinite(interval)) fail("INVALID_INTERVAL");
1718
1715
  ticket = validateTicket(input, options.expectedMode);
1719
1716
  } catch (error) {
1720
- if (!signal.aborted) {
1721
- const e = error instanceof Error ? error : new AuthLinkError("INVALID_TICKET");
1722
- onUpdate({ ...initialSnapshot(), status: "error", error: e });
1723
- options.onError?.(e);
1724
- }
1717
+ if (!signal.aborted) options.onError?.(error);
1725
1718
  return;
1726
1719
  }
1727
- let frame = ticket.displayCode;
1728
- let serverAnchor = frame ? Date.parse(frame.serverTime) : Date.now();
1729
- let monotonicAnchor = performance.now();
1730
- const serverNow = () => serverAnchor + performance.now() - monotonicAnchor;
1731
1720
  const expiry = Date.parse(ticket.expiresAt);
1732
- let ended = false;
1721
+ const deadline = performance.now() + Math.max(0, expiry - Date.now());
1722
+ let ended = false, busy = false;
1723
+ let done;
1724
+ const finished = new Promise((resolve) => {
1725
+ done = resolve;
1726
+ });
1733
1727
  const controller = new AbortController();
1734
- const cancel = () => controller.abort(signal.reason);
1735
- signal.addEventListener("abort", cancel, { once: true });
1736
- if (signal.aborted) cancel();
1737
- let last = initialSnapshot();
1738
- const update = (value) => {
1739
- if (signal.aborted) return;
1740
- if (JSON.stringify(value) !== JSON.stringify(last)) {
1741
- last = value;
1742
- onUpdate(value);
1743
- }
1728
+ const cancel = () => {
1729
+ ended = true;
1730
+ controller.abort();
1731
+ done();
1744
1732
  };
1733
+ signal.addEventListener("abort", cancel, { once: true });
1734
+ let snapshot = initialSnapshot();
1735
+ const remaining = () => Math.max(0, (deadline - performance.now()) / 1e3);
1745
1736
  const tick = () => {
1746
1737
  if (ended || signal.aborted) return;
1747
- const now = serverNow();
1748
- if (now >= expiry) {
1749
- controller.abort(new AuthLinkError("REQUEST_EXPIRED"));
1738
+ if (remaining() <= 0) {
1739
+ ended = true;
1740
+ controller.abort();
1741
+ onUpdate({ ...snapshot, status: "expired", code: null, submitting: false });
1742
+ void Promise.resolve().then(() => options.onExpired?.()).catch(() => options.onError?.(new AuthLinkError("CALLBACK_FAILED")));
1743
+ done();
1750
1744
  return;
1751
1745
  }
1752
- const codeRemaining = Math.max(0, ((frame ? Date.parse(frame.validUntil) : expiry) - now) / 1e3);
1753
- options.onCodeTiming?.(codeRemaining * 1e3);
1754
- update({
1746
+ snapshot = {
1747
+ ...snapshot,
1755
1748
  status: "pending",
1756
- code: codeRemaining > 0 ? frame?.value ?? ticket.pairingCode : null,
1757
- secondsRemaining: Math.max(0, Math.ceil((expiry - now) / 1e3)),
1758
- codeSecondsRemaining: Math.ceil(codeRemaining),
1759
- error: null
1760
- });
1749
+ code: ticket.pairingCode,
1750
+ secondsRemaining: Math.ceil(remaining()),
1751
+ codeSecondsRemaining: Math.ceil(remaining()),
1752
+ submitting: busy
1753
+ };
1754
+ onUpdate(snapshot);
1761
1755
  };
1762
- const timer = setInterval(tick, 200);
1763
- const finish = (status, result, error) => {
1764
- if (ended || signal.aborted) return;
1765
- ended = true;
1766
- update({ ...last, status, code: null, error: error ?? null });
1767
- try {
1768
- let effect = void 0;
1769
- if (status === "confirmed") effect = options.onConfirmed?.(result);
1770
- else if (status === "rejected") effect = options.onRejected?.({ status: "rejected", code: "REJECTED", requestId: ticket.requestId, purpose: ticket.purpose });
1771
- else if (status === "expired") effect = options.onExpired?.();
1772
- else options.onError?.(error);
1773
- void Promise.resolve(effect).catch(() => {
1774
- if (!signal.aborted) options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
1775
- });
1776
- } catch {
1777
- if (status !== "error") options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
1756
+ const submit = async (confirmationCode) => {
1757
+ if (ended || signal.aborted || busy) return;
1758
+ if (!/^[0-9]{6}$/.test(confirmationCode)) {
1759
+ snapshot = { ...snapshot, error: new AuthLinkError("CONFIRMATION_CODE_REQUIRED") };
1760
+ tick();
1761
+ return;
1778
1762
  }
1779
- };
1780
- try {
1763
+ if (remaining() <= 0) {
1764
+ tick();
1765
+ return;
1766
+ }
1767
+ busy = true;
1768
+ snapshot = { ...snapshot, error: null };
1781
1769
  tick();
1782
- for (; ; ) {
1783
- controller.signal.throwIfAborted();
1784
- const value = object(await abortable(client.result(ticket, controller.signal), controller.signal));
1785
- controller.signal.throwIfAborted();
1770
+ try {
1771
+ const value = object(await abortable(client.result(ticket, controller.signal, confirmationCode), controller.signal));
1772
+ if (ended || signal.aborted) return;
1786
1773
  if (value.requestId !== ticket.requestId) fail("REQUEST_MISMATCH");
1787
1774
  if (value.status === "confirmed") {
1788
- 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");
1789
- finish("confirmed", value);
1790
- return;
1791
- }
1792
- if (value.status === "rejected" || value.status === "expired") {
1793
- finish(value.status);
1794
- return;
1795
- }
1796
- if (!["new", "pending", "approved", "consumed"].includes(String(value.status))) fail("INVALID_RESPONSE");
1797
- if (value.displayCode !== void 0) {
1798
- const nextFrame = validateDisplayCode(value.displayCode);
1799
- const nextExpiry = Date.parse(nextFrame.validUntil);
1800
- const currentExpiry = frame ? Date.parse(frame.validUntil) : 0;
1801
- if (!frame || nextExpiry > currentExpiry) {
1802
- serverAnchor = Math.max(serverNow(), Date.parse(nextFrame.serverTime));
1803
- monotonicAnchor = performance.now();
1775
+ 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");
1776
+ ended = true;
1777
+ onUpdate({ ...snapshot, status: "confirmed", code: null, submitting: false });
1778
+ try {
1779
+ await options.onConfirmed?.(value);
1780
+ } catch {
1781
+ options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
1782
+ }
1783
+ done();
1784
+ } else if (value.status === "rejected" || value.status === "expired") {
1785
+ ended = true;
1786
+ onUpdate({ ...snapshot, status: value.status, code: null, submitting: false });
1787
+ try {
1788
+ if (value.status === "rejected") await options.onRejected?.({ status: "rejected", code: "REJECTED", requestId: ticket.requestId, purpose: ticket.purpose });
1789
+ else await options.onExpired?.();
1790
+ } catch {
1791
+ options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
1792
+ } finally {
1793
+ done();
1804
1794
  }
1805
- if (!frame || nextExpiry >= currentExpiry) frame = nextFrame;
1795
+ } else {
1796
+ fail("CONFIRMATION_NOT_READY");
1806
1797
  }
1807
- tick();
1808
- let pause;
1809
- try {
1810
- await abortable(new Promise((resolve) => {
1811
- pause = setTimeout(resolve, interval);
1812
- }), controller.signal);
1813
- } finally {
1814
- clearTimeout(pause);
1798
+ } catch (error) {
1799
+ if (!ended && !signal.aborted) {
1800
+ const raw = error instanceof Error ? error : new AuthLinkError("NETWORK_ERROR");
1801
+ const code = raw.message.replace(/^AUTHLINK_/, "");
1802
+ const failure = ["CONFIRMATION_CODE_LOCKED", "CONFIRMATION_CODE_INVALID", "APPROVAL_REQUIRED", "REQUEST_EXPIRED"].includes(code) ? new AuthLinkError(code) : raw;
1803
+ snapshot = { ...snapshot, error: failure };
1804
+ if (code === "CONFIRMATION_CODE_LOCKED" || code === "REQUEST_EXPIRED") {
1805
+ ended = true;
1806
+ onUpdate({ ...snapshot, code: null, submitting: false, status: code === "REQUEST_EXPIRED" ? "expired" : "error" });
1807
+ if (code === "REQUEST_EXPIRED") void Promise.resolve().then(() => options.onExpired?.()).catch(() => options.onError?.(new AuthLinkError("CALLBACK_FAILED")));
1808
+ else options.onError?.(failure);
1809
+ done();
1810
+ } else options.onError?.(failure);
1815
1811
  }
1812
+ } finally {
1813
+ busy = false;
1814
+ tick();
1816
1815
  }
1817
- } catch (error) {
1818
- if (!signal.aborted && !ended) {
1819
- if (error instanceof AuthLinkError && error.code === "REQUEST_EXPIRED") finish("expired");
1820
- else finish("error", void 0, error instanceof AuthLinkError ? error : new AuthLinkError("NETWORK_ERROR"));
1821
- }
1816
+ };
1817
+ tick();
1818
+ options.onReady?.(submit);
1819
+ const timer = setInterval(tick, 1e3);
1820
+ if (signal.aborted) cancel();
1821
+ try {
1822
+ await finished;
1822
1823
  } finally {
1823
- ended = true;
1824
1824
  clearInterval(timer);
1825
1825
  controller.abort();
1826
1826
  signal.removeEventListener("abort", cancel);
@@ -1832,8 +1832,8 @@ var en_default = {
1832
1832
  bind: "Bind your phone",
1833
1833
  confirm: "Confirm verification",
1834
1834
  scan: "Scan with AuthLink",
1835
- code: "Matching code",
1836
- help: "Check that the numbers match in the app, then confirm on your phone.",
1835
+ code: "Matching digits",
1836
+ help: "Approve in the App, then enter its 6-digit confirmation code here.",
1837
1837
  waiting: "Waiting for your phone",
1838
1838
  loading: "Connecting",
1839
1839
  confirmed: "Confirmed",
@@ -1846,7 +1846,16 @@ var en_default = {
1846
1846
  close: "Close",
1847
1847
  cancel: "Cancel",
1848
1848
  autoUpdate: "Code updates automatically every 30 seconds",
1849
- expiring: "Request expiring soon"
1849
+ expiring: "Request expiring soon",
1850
+ confirmationCode: "App confirmation code",
1851
+ submitCode: "Verify",
1852
+ codeError: "The code could not be verified. Check the code and approval, then retry.",
1853
+ codeLocked: "Too many incorrect codes. Close this window and start a new request.",
1854
+ otpCode: "App verification code",
1855
+ otpHelp: "Open AuthLink and enter this account\u2019s current six-digit code. No approval is needed.",
1856
+ otpWaiting: "Enter the current code",
1857
+ otpError: "Verification failed. Check the account; wait for a new code if already used. After repeated failures, try again later.",
1858
+ otpSetup: "Enable verification codes on this account\u2019s card in the app first."
1850
1859
  };
1851
1860
 
1852
1861
  // src/locales/zh-CN.json
@@ -1854,8 +1863,8 @@ var zh_CN_default = {
1854
1863
  bind: "\u7ED1\u5B9A\u624B\u673A",
1855
1864
  confirm: "\u786E\u8BA4\u8EAB\u4EFD\u9A8C\u8BC1",
1856
1865
  scan: "\u4F7F\u7528 AuthLink \u626B\u63CF\u4E8C\u7EF4\u7801",
1857
- code: "\u52A8\u6001\u6838\u5BF9\u7801",
1858
- help: "\u6838\u5BF9 App \u4E2D\u7684\u6570\u5B57\u4E00\u81F4\u540E\uFF0C\u5728\u624B\u673A\u4E0A\u786E\u8BA4\u3002",
1866
+ code: "\u6838\u5BF9\u6570\u5B57",
1867
+ 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",
1859
1868
  waiting: "\u7B49\u5F85\u624B\u673A\u786E\u8BA4",
1860
1869
  loading: "\u6B63\u5728\u8FDE\u63A5",
1861
1870
  confirmed: "\u5DF2\u786E\u8BA4",
@@ -1868,7 +1877,16 @@ var zh_CN_default = {
1868
1877
  close: "\u5173\u95ED",
1869
1878
  cancel: "\u53D6\u6D88",
1870
1879
  autoUpdate: "\u6838\u5BF9\u7801\u6BCF 30 \u79D2\u81EA\u52A8\u66F4\u65B0",
1871
- expiring: "\u8BF7\u6C42\u5373\u5C06\u8FC7\u671F"
1880
+ expiring: "\u8BF7\u6C42\u5373\u5C06\u8FC7\u671F",
1881
+ confirmationCode: "App \u786E\u8BA4\u7801",
1882
+ submitCode: "\u63D0\u4EA4\u9A8C\u8BC1",
1883
+ codeError: "\u9A8C\u8BC1\u672A\u901A\u8FC7\uFF0C\u8BF7\u68C0\u67E5\u786E\u8BA4\u7801\u548C\u624B\u673A\u6279\u51C6\u72B6\u6001\u540E\u91CD\u8BD5\u3002",
1884
+ 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",
1885
+ otpCode: "App \u52A8\u6001\u7801",
1886
+ 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",
1887
+ otpWaiting: "\u8BF7\u8F93\u5165\u5F53\u524D\u52A8\u6001\u7801",
1888
+ 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",
1889
+ otpSetup: "\u8BF7\u5148\u5728 App \u7684\u8D26\u53F7\u5361\u7247\u4E2D\u542F\u7528\u52A8\u6001\u7801\u3002"
1872
1890
  };
1873
1891
 
1874
1892
  // src/locales/zh-TW.json
@@ -1876,8 +1894,8 @@ var zh_TW_default = {
1876
1894
  bind: "\u7D81\u5B9A\u624B\u6A5F",
1877
1895
  confirm: "\u78BA\u8A8D\u8EAB\u5206\u9A57\u8B49",
1878
1896
  scan: "\u4F7F\u7528 AuthLink \u6383\u63CF QR \u78BC",
1879
- code: "\u52D5\u614B\u6838\u5C0D\u78BC",
1880
- help: "\u6838\u5C0D App \u4E2D\u7684\u6578\u5B57\u4E00\u81F4\u5F8C\uFF0C\u5728\u624B\u6A5F\u4E0A\u78BA\u8A8D\u3002",
1897
+ code: "\u6838\u5C0D\u6578\u5B57",
1898
+ 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",
1881
1899
  waiting: "\u7B49\u5F85\u624B\u6A5F\u78BA\u8A8D",
1882
1900
  loading: "\u6B63\u5728\u9023\u7DDA",
1883
1901
  confirmed: "\u5DF2\u78BA\u8A8D",
@@ -1890,7 +1908,16 @@ var zh_TW_default = {
1890
1908
  close: "\u95DC\u9589",
1891
1909
  cancel: "\u53D6\u6D88",
1892
1910
  autoUpdate: "\u6838\u5C0D\u78BC\u6BCF 30 \u79D2\u81EA\u52D5\u66F4\u65B0",
1893
- expiring: "\u8ACB\u6C42\u5373\u5C07\u5230\u671F"
1911
+ expiring: "\u8ACB\u6C42\u5373\u5C07\u5230\u671F",
1912
+ confirmationCode: "App \u78BA\u8A8D\u78BC",
1913
+ submitCode: "\u63D0\u4EA4\u9A57\u8B49",
1914
+ codeError: "\u9A57\u8B49\u672A\u901A\u904E\uFF0C\u8ACB\u6AA2\u67E5\u78BA\u8A8D\u78BC\u53CA\u624B\u6A5F\u6279\u51C6\u72C0\u614B\u5F8C\u91CD\u8A66\u3002",
1915
+ 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",
1916
+ otpCode: "App \u52D5\u614B\u78BC",
1917
+ 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",
1918
+ otpWaiting: "\u8ACB\u8F38\u5165\u76EE\u524D\u7684\u52D5\u614B\u78BC",
1919
+ 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",
1920
+ otpSetup: "\u8ACB\u5148\u5728 App \u7684\u5E33\u865F\u5361\u7247\u4E2D\u555F\u7528\u52D5\u614B\u78BC\u3002"
1894
1921
  };
1895
1922
 
1896
1923
  // src/locales/ja.json
@@ -1898,8 +1925,8 @@ var ja_default = {
1898
1925
  bind: "\u30B9\u30DE\u30FC\u30C8\u30D5\u30A9\u30F3\u3092\u767B\u9332",
1899
1926
  confirm: "\u672C\u4EBA\u78BA\u8A8D",
1900
1927
  scan: "AuthLink \u3067 QR \u30B3\u30FC\u30C9\u3092\u30B9\u30AD\u30E3\u30F3",
1901
- code: "\u7167\u5408\u30B3\u30FC\u30C9",
1902
- 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",
1928
+ code: "\u7167\u5408\u7528\u306E\u6570\u5B57",
1929
+ 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",
1903
1930
  waiting: "\u30B9\u30DE\u30FC\u30C8\u30D5\u30A9\u30F3\u306E\u78BA\u8A8D\u3092\u5F85\u3063\u3066\u3044\u307E\u3059",
1904
1931
  loading: "\u63A5\u7D9A\u4E2D",
1905
1932
  confirmed: "\u78BA\u8A8D\u6E08\u307F",
@@ -1912,7 +1939,16 @@ var ja_default = {
1912
1939
  close: "\u9589\u3058\u308B",
1913
1940
  cancel: "\u30AD\u30E3\u30F3\u30BB\u30EB",
1914
1941
  autoUpdate: "\u7167\u5408\u30B3\u30FC\u30C9\u306F30\u79D2\u3054\u3068\u306B\u81EA\u52D5\u66F4\u65B0",
1915
- expiring: "\u30EA\u30AF\u30A8\u30B9\u30C8\u306E\u6709\u52B9\u671F\u9650\u304C\u307E\u3082\u306A\u304F\u5207\u308C\u307E\u3059"
1942
+ expiring: "\u30EA\u30AF\u30A8\u30B9\u30C8\u306E\u6709\u52B9\u671F\u9650\u304C\u307E\u3082\u306A\u304F\u5207\u308C\u307E\u3059",
1943
+ confirmationCode: "App \u306E\u78BA\u8A8D\u30B3\u30FC\u30C9",
1944
+ submitCode: "\u78BA\u8A8D\u3059\u308B",
1945
+ 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",
1946
+ 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",
1947
+ otpCode: "\u30A2\u30D7\u30EA\u306E\u8A8D\u8A3C\u30B3\u30FC\u30C9",
1948
+ 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",
1949
+ otpWaiting: "\u73FE\u5728\u306E\u30B3\u30FC\u30C9\u3092\u5165\u529B",
1950
+ 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",
1951
+ 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"
1916
1952
  };
1917
1953
 
1918
1954
  // src/locales/bn.json
@@ -1921,7 +1957,7 @@ var bn_default = {
1921
1957
  confirm: "\u09AF\u09BE\u099A\u09BE\u0987\u0995\u09B0\u09A3 \u09A8\u09BF\u09B6\u09CD\u099A\u09BF\u09A4 \u0995\u09B0\u09C1\u09A8",
1922
1958
  scan: "AuthLink \u09A6\u09BF\u09AF\u09BC\u09C7 \u09B8\u09CD\u0995\u09CD\u09AF\u09BE\u09A8 \u0995\u09B0\u09C1\u09A8",
1923
1959
  code: "\u09AE\u09BF\u09B2\u09BF\u09AF\u09BC\u09C7 \u09A6\u09C7\u0996\u09BE\u09B0 \u0995\u09CB\u09A1",
1924
- 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",
1960
+ 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",
1925
1961
  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",
1926
1962
  loading: "\u09B8\u0982\u09AF\u09CB\u0997 \u0995\u09B0\u09BE \u09B9\u099A\u09CD\u099B\u09C7",
1927
1963
  confirmed: "\u09A8\u09BF\u09B6\u09CD\u099A\u09BF\u09A4 \u09B9\u09AF\u09BC\u09C7\u099B\u09C7",
@@ -1934,7 +1970,16 @@ var bn_default = {
1934
1970
  close: "\u09AC\u09A8\u09CD\u09A7 \u0995\u09B0\u09C1\u09A8",
1935
1971
  cancel: "\u09AC\u09BE\u09A4\u09BF\u09B2",
1936
1972
  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",
1937
- 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"
1973
+ 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",
1974
+ confirmationCode: "\u0985\u09CD\u09AF\u09BE\u09AA\u09C7\u09B0 \u09A8\u09BF\u09B6\u09CD\u099A\u09BF\u09A4\u0995\u09B0\u09A3 \u0995\u09CB\u09A1",
1975
+ submitCode: "\u09AF\u09BE\u099A\u09BE\u0987 \u0995\u09B0\u09C1\u09A8",
1976
+ 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",
1977
+ 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",
1978
+ otpCode: "\u0985\u09CD\u09AF\u09BE\u09AA\u09C7\u09B0 \u0995\u09CB\u09A1",
1979
+ 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",
1980
+ otpWaiting: "\u09AC\u09B0\u09CD\u09A4\u09AE\u09BE\u09A8 \u0995\u09CB\u09A1 \u09B2\u09BF\u0996\u09C1\u09A8",
1981
+ 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",
1982
+ 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"
1938
1983
  };
1939
1984
 
1940
1985
  // src/locales/es.json
@@ -1943,7 +1988,7 @@ var es_default = {
1943
1988
  confirm: "Confirma la verificaci\xF3n",
1944
1989
  scan: "Escanea con AuthLink",
1945
1990
  code: "C\xF3digo de comparaci\xF3n",
1946
- help: "Comprueba que los n\xFAmeros coincidan en la aplicaci\xF3n y confirma en tu tel\xE9fono.",
1991
+ help: "Aprueba en la app e introduce aqu\xED su c\xF3digo de 6 d\xEDgitos.",
1947
1992
  waiting: "Esperando la confirmaci\xF3n del tel\xE9fono",
1948
1993
  loading: "Conectando",
1949
1994
  confirmed: "Confirmado",
@@ -1956,7 +2001,16 @@ var es_default = {
1956
2001
  close: "Cerrar",
1957
2002
  cancel: "Cancelar",
1958
2003
  autoUpdate: "El c\xF3digo se actualiza autom\xE1ticamente cada 30 segundos",
1959
- expiring: "La solicitud est\xE1 por caducar"
2004
+ expiring: "La solicitud est\xE1 por caducar",
2005
+ confirmationCode: "C\xF3digo de confirmaci\xF3n de la app",
2006
+ submitCode: "Verificar",
2007
+ codeError: "No se pudo verificar. Revisa el c\xF3digo y la aprobaci\xF3n.",
2008
+ codeLocked: "Demasiados c\xF3digos incorrectos. Cierra la ventana e inicia una nueva solicitud.",
2009
+ otpCode: "C\xF3digo de la app",
2010
+ otpHelp: "Abre AuthLink e introduce el c\xF3digo actual de seis d\xEDgitos de esta cuenta. No hace falta aprobar una solicitud.",
2011
+ otpWaiting: "Introduce el c\xF3digo actual",
2012
+ 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.",
2013
+ otpSetup: "Activa primero los c\xF3digos en la tarjeta de esta cuenta en la app."
1960
2014
  };
1961
2015
 
1962
2016
  // src/locales/fil.json
@@ -1965,7 +2019,7 @@ var fil_default = {
1965
2019
  confirm: "Kumpirmahin ang pagpapatunay",
1966
2020
  scan: "Mag-scan gamit ang AuthLink",
1967
2021
  code: "Code na paghahambingin",
1968
- help: "Tiyaking magkapareho ang mga numero sa app, pagkatapos ay kumpirmahin sa iyong telepono.",
2022
+ help: "Aprubahan sa app, saka ilagay dito ang 6-digit na confirmation code.",
1969
2023
  waiting: "Hinihintay ang kumpirmasyon sa telepono",
1970
2024
  loading: "Kumokonekta",
1971
2025
  confirmed: "Nakumpirma",
@@ -1978,7 +2032,16 @@ var fil_default = {
1978
2032
  close: "Isara",
1979
2033
  cancel: "Kanselahin",
1980
2034
  autoUpdate: "Awtomatikong nagbabago ang code kada 30 segundo",
1981
- expiring: "Malapit nang mag-expire ang kahilingan"
2035
+ expiring: "Malapit nang mag-expire ang kahilingan",
2036
+ confirmationCode: "Confirmation code ng app",
2037
+ submitCode: "I-verify",
2038
+ codeError: "Hindi ma-verify. Suriin ang code at pag-apruba at subukan muli.",
2039
+ codeLocked: "Masyadong maraming maling code. Isara ang window at magsimula ng bagong request.",
2040
+ otpCode: "Code ng app",
2041
+ otpHelp: "Buksan ang AuthLink at ilagay ang kasalukuyang anim na digit na code ng account na ito. Hindi kailangang aprubahan ang request.",
2042
+ otpWaiting: "Ilagay ang kasalukuyang code",
2043
+ otpError: "Hindi napatunayan. Tingnan ang account at maghintay ng bagong code kung nagamit na. Subukang muli mamaya kung maraming maling pagtatangka.",
2044
+ otpSetup: "Paganahin muna ang mga code sa card ng account na ito sa app."
1982
2045
  };
1983
2046
 
1984
2047
  // src/locales/hi.json
@@ -1987,7 +2050,7 @@ var hi_default = {
1987
2050
  confirm: "\u0938\u0924\u094D\u092F\u093E\u092A\u0928 \u0915\u0940 \u092A\u0941\u0937\u094D\u091F\u093F \u0915\u0930\u0947\u0902",
1988
2051
  scan: "AuthLink \u0938\u0947 \u0938\u094D\u0915\u0948\u0928 \u0915\u0930\u0947\u0902",
1989
2052
  code: "\u092E\u093F\u0932\u093E\u0928 \u0915\u094B\u0921",
1990
- 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",
2053
+ 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",
1991
2054
  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",
1992
2055
  loading: "\u0915\u0928\u0947\u0915\u094D\u091F \u0939\u094B \u0930\u0939\u093E \u0939\u0948",
1993
2056
  confirmed: "\u092A\u0941\u0937\u094D\u091F\u093F \u0939\u094B \u0917\u0908",
@@ -2000,7 +2063,16 @@ var hi_default = {
2000
2063
  close: "\u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
2001
2064
  cancel: "\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902",
2002
2065
  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",
2003
- 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"
2066
+ 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",
2067
+ confirmationCode: "\u0910\u092A \u0915\u093E \u092A\u0941\u0937\u094D\u091F\u093F \u0915\u094B\u0921",
2068
+ submitCode: "\u0938\u0924\u094D\u092F\u093E\u092A\u093F\u0924 \u0915\u0930\u0947\u0902",
2069
+ 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",
2070
+ 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",
2071
+ otpCode: "\u0910\u092A \u0915\u093E \u0915\u094B\u0921",
2072
+ 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",
2073
+ otpWaiting: "\u0935\u0930\u094D\u0924\u092E\u093E\u0928 \u0915\u094B\u0921 \u0926\u0930\u094D\u091C \u0915\u0930\u0947\u0902",
2074
+ 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",
2075
+ 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"
2004
2076
  };
2005
2077
 
2006
2078
  // src/locales/id.json
@@ -2009,7 +2081,7 @@ var id_default = {
2009
2081
  confirm: "Konfirmasi verifikasi",
2010
2082
  scan: "Pindai dengan AuthLink",
2011
2083
  code: "Kode pencocokan",
2012
- help: "Pastikan angka di aplikasi cocok, lalu konfirmasi di ponsel Anda.",
2084
+ help: "Setujui di aplikasi, lalu masukkan kode konfirmasi 6 digit di sini.",
2013
2085
  waiting: "Menunggu konfirmasi dari ponsel",
2014
2086
  loading: "Menghubungkan",
2015
2087
  confirmed: "Dikonfirmasi",
@@ -2022,7 +2094,16 @@ var id_default = {
2022
2094
  close: "Tutup",
2023
2095
  cancel: "Batal",
2024
2096
  autoUpdate: "Kode diperbarui otomatis setiap 30 detik",
2025
- expiring: "Permintaan akan segera kedaluwarsa"
2097
+ expiring: "Permintaan akan segera kedaluwarsa",
2098
+ confirmationCode: "Kode konfirmasi aplikasi",
2099
+ submitCode: "Verifikasi",
2100
+ codeError: "Verifikasi gagal. Periksa kode dan persetujuan, lalu coba lagi.",
2101
+ codeLocked: "Terlalu banyak kode salah. Tutup jendela dan mulai permintaan baru.",
2102
+ otpCode: "Kode aplikasi",
2103
+ otpHelp: "Buka AuthLink dan masukkan kode enam digit terkini untuk akun ini. Tidak perlu menyetujui permintaan.",
2104
+ otpWaiting: "Masukkan kode terkini",
2105
+ otpError: "Verifikasi gagal. Periksa akun dan tunggu kode baru jika sudah digunakan. Setelah beberapa kegagalan, coba lagi nanti.",
2106
+ otpSetup: "Aktifkan kode di kartu akun ini dalam aplikasi terlebih dahulu."
2026
2107
  };
2027
2108
 
2028
2109
  // src/locales/ms.json
@@ -2031,7 +2112,7 @@ var ms_default = {
2031
2112
  confirm: "Sahkan pengesahan",
2032
2113
  scan: "Imbas dengan AuthLink",
2033
2114
  code: "Kod padanan",
2034
- help: "Pastikan nombor dalam aplikasi sepadan, kemudian sahkan pada telefon anda.",
2115
+ help: "Luluskan dalam aplikasi, kemudian masukkan kod pengesahan 6 digit di sini.",
2035
2116
  waiting: "Menunggu pengesahan daripada telefon",
2036
2117
  loading: "Sedang menyambung",
2037
2118
  confirmed: "Disahkan",
@@ -2044,7 +2125,16 @@ var ms_default = {
2044
2125
  close: "Tutup",
2045
2126
  cancel: "Batal",
2046
2127
  autoUpdate: "Kod dikemas kini secara automatik setiap 30 saat",
2047
- expiring: "Permintaan akan tamat tempoh tidak lama lagi"
2128
+ expiring: "Permintaan akan tamat tempoh tidak lama lagi",
2129
+ confirmationCode: "Kod pengesahan aplikasi",
2130
+ submitCode: "Sahkan",
2131
+ codeError: "Pengesahan gagal. Semak kod dan kelulusan, kemudian cuba lagi.",
2132
+ codeLocked: "Terlalu banyak kod salah. Tutup tetingkap dan mulakan permintaan baharu.",
2133
+ otpCode: "Kod aplikasi",
2134
+ otpHelp: "Buka AuthLink dan masukkan kod enam digit semasa untuk akaun ini. Tiada kelulusan permintaan diperlukan.",
2135
+ otpWaiting: "Masukkan kod semasa",
2136
+ otpError: "Pengesahan gagal. Semak akaun dan tunggu kod baharu jika sudah digunakan. Selepas beberapa kegagalan, cuba lagi kemudian.",
2137
+ otpSetup: "Aktifkan kod pada kad akaun ini dalam aplikasi dahulu."
2048
2138
  };
2049
2139
 
2050
2140
  // src/locales/pt.json
@@ -2053,7 +2143,7 @@ var pt_default = {
2053
2143
  confirm: "Confirme a verifica\xE7\xE3o",
2054
2144
  scan: "Escaneie com o AuthLink",
2055
2145
  code: "C\xF3digo de compara\xE7\xE3o",
2056
- help: "Confira se os n\xFAmeros no aplicativo coincidem e confirme no celular.",
2146
+ help: "Aprove no app e digite aqui o c\xF3digo de 6 d\xEDgitos.",
2057
2147
  waiting: "Aguardando confirma\xE7\xE3o no celular",
2058
2148
  loading: "Conectando",
2059
2149
  confirmed: "Confirmado",
@@ -2066,7 +2156,16 @@ var pt_default = {
2066
2156
  close: "Fechar",
2067
2157
  cancel: "Cancelar",
2068
2158
  autoUpdate: "O c\xF3digo \xE9 atualizado automaticamente a cada 30 segundos",
2069
- expiring: "A solicita\xE7\xE3o est\xE1 prestes a expirar"
2159
+ expiring: "A solicita\xE7\xE3o est\xE1 prestes a expirar",
2160
+ confirmationCode: "C\xF3digo de confirma\xE7\xE3o do app",
2161
+ submitCode: "Verificar",
2162
+ codeError: "N\xE3o foi poss\xEDvel verificar. Confira o c\xF3digo e a aprova\xE7\xE3o.",
2163
+ codeLocked: "Muitos c\xF3digos incorretos. Feche a janela e inicie uma nova solicita\xE7\xE3o.",
2164
+ otpCode: "C\xF3digo do aplicativo",
2165
+ 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.",
2166
+ otpWaiting: "Digite o c\xF3digo atual",
2167
+ 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.",
2168
+ otpSetup: "Ative primeiro os c\xF3digos no cart\xE3o desta conta no aplicativo."
2070
2169
  };
2071
2170
 
2072
2171
  // src/locales/th.json
@@ -2075,7 +2174,7 @@ var th_default = {
2075
2174
  confirm: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A",
2076
2175
  scan: "\u0E2A\u0E41\u0E01\u0E19\u0E14\u0E49\u0E27\u0E22 AuthLink",
2077
2176
  code: "\u0E23\u0E2B\u0E31\u0E2A\u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A\u0E40\u0E1B\u0E23\u0E35\u0E22\u0E1A\u0E40\u0E17\u0E35\u0E22\u0E1A",
2078
- 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",
2177
+ 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",
2079
2178
  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",
2080
2179
  loading: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D",
2081
2180
  confirmed: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E41\u0E25\u0E49\u0E27",
@@ -2088,7 +2187,16 @@ var th_default = {
2088
2187
  close: "\u0E1B\u0E34\u0E14",
2089
2188
  cancel: "\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01",
2090
2189
  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",
2091
- expiring: "\u0E04\u0E33\u0E02\u0E2D\u0E43\u0E01\u0E25\u0E49\u0E2B\u0E21\u0E14\u0E2D\u0E32\u0E22\u0E38"
2190
+ expiring: "\u0E04\u0E33\u0E02\u0E2D\u0E43\u0E01\u0E25\u0E49\u0E2B\u0E21\u0E14\u0E2D\u0E32\u0E22\u0E38",
2191
+ confirmationCode: "\u0E23\u0E2B\u0E31\u0E2A\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E08\u0E32\u0E01\u0E41\u0E2D\u0E1B",
2192
+ submitCode: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19",
2193
+ 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",
2194
+ 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",
2195
+ otpCode: "\u0E23\u0E2B\u0E31\u0E2A\u0E08\u0E32\u0E01\u0E41\u0E2D\u0E1B",
2196
+ 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",
2197
+ otpWaiting: "\u0E01\u0E23\u0E2D\u0E01\u0E23\u0E2B\u0E31\u0E2A\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19",
2198
+ 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",
2199
+ 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"
2092
2200
  };
2093
2201
 
2094
2202
  // src/locales/vi.json
@@ -2097,7 +2205,7 @@ var vi_default = {
2097
2205
  confirm: "X\xE1c nh\u1EADn x\xE1c th\u1EF1c",
2098
2206
  scan: "Qu\xE9t b\u1EB1ng AuthLink",
2099
2207
  code: "M\xE3 \u0111\u1ED1i chi\u1EBFu",
2100
- 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.",
2208
+ 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.",
2101
2209
  waiting: "\u0110ang ch\u1EDD x\xE1c nh\u1EADn t\u1EEB \u0111i\u1EC7n tho\u1EA1i",
2102
2210
  loading: "\u0110ang k\u1EBFt n\u1ED1i",
2103
2211
  confirmed: "\u0110\xE3 x\xE1c nh\u1EADn",
@@ -2110,7 +2218,16 @@ var vi_default = {
2110
2218
  close: "\u0110\xF3ng",
2111
2219
  cancel: "H\u1EE7y",
2112
2220
  autoUpdate: "M\xE3 t\u1EF1 \u0111\u1ED9ng c\u1EADp nh\u1EADt m\u1ED7i 30 gi\xE2y",
2113
- expiring: "Y\xEAu c\u1EA7u s\u1EAFp h\u1EBFt h\u1EA1n"
2221
+ expiring: "Y\xEAu c\u1EA7u s\u1EAFp h\u1EBFt h\u1EA1n",
2222
+ confirmationCode: "M\xE3 x\xE1c nh\u1EADn trong \u1EE9ng d\u1EE5ng",
2223
+ submitCode: "X\xE1c minh",
2224
+ 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.",
2225
+ 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.",
2226
+ otpCode: "M\xE3 \u1EE9ng d\u1EE5ng",
2227
+ 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.",
2228
+ otpWaiting: "Nh\u1EADp m\xE3 hi\u1EC7n t\u1EA1i",
2229
+ 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.",
2230
+ 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."
2114
2231
  };
2115
2232
 
2116
2233
  // src/i18n.ts
@@ -2147,7 +2264,7 @@ function widgetView(options) {
2147
2264
  const locale = resolveLocale(options.locale), variant = resolveVariant(options.variant);
2148
2265
  const l = getMessages(locale);
2149
2266
  const pending = s.status === "pending", hasQr = pending && (mode === "bind" || Boolean(options.showQr)) && Boolean(options.qr);
2150
- const status = { idle: l.loading, pending: l.waiting, confirmed: l.confirmed, rejected: l.rejected, expired: l.expired, error: l.error }[s.status];
2267
+ 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];
2151
2268
  const expiring = pending && s.secondsRemaining <= 30;
2152
2269
  const expiryTime = `00:${String(Math.max(0, Math.ceil(s.secondsRemaining))).padStart(2, "0")}`;
2153
2270
  const statusNode = () => node(
@@ -2176,50 +2293,52 @@ function widgetView(options) {
2176
2293
  node("img", { class: "authlink-qr", src: options.qr, alt: l.scan, width: 240, height: 240 }),
2177
2294
  node("figcaption", { class: "authlink-qr-caption" }, l.scan)
2178
2295
  )] : [];
2179
- const seconds = Math.max(0, Math.min(30, s.codeSecondsRemaining));
2180
- const code = node(
2181
- "output",
2182
- {
2183
- class: "authlink-code",
2184
- "aria-label": s.code ? `${l.code}: ${s.code.split("").join(" ")}` : l.updating,
2185
- "aria-live": "polite",
2186
- "data-testid": "authlink-code"
2187
- },
2188
- node("span", { class: "authlink-code-group" }, s.code?.slice(0, 3) ?? "---"),
2189
- node("span", { class: "authlink-code-group" }, s.code?.slice(3) ?? "---")
2190
- );
2191
- const panel = node(
2192
- "div",
2193
- { class: "authlink-code-panel" },
2194
- node("div", { class: "authlink-code-values" }, node("div", { class: "authlink-code-label" }, l.code), code),
2296
+ const detail = [
2297
+ node("p", { class: "authlink-help" }, options.passcodeMode ? l.otpHelp : l.help),
2195
2298
  node(
2196
- "div",
2197
- {
2198
- class: "authlink-progress",
2199
- role: "progressbar",
2200
- "aria-valuemin": 0,
2201
- "aria-valuemax": 30,
2202
- "aria-valuenow": seconds,
2203
- "aria-label": l.autoUpdate
2204
- },
2205
- node("span", { class: "authlink-progress-fill", "aria-hidden": "true", style: `transform:scaleX(${seconds / 30})` })
2299
+ "form",
2300
+ { class: "authlink-code-form", onSubmit: (event) => {
2301
+ event.preventDefault();
2302
+ const input = event.currentTarget.querySelector("input");
2303
+ if (input) void options.submitCode?.(input.value);
2304
+ } },
2305
+ node("label", { for: "authlink-confirmation-code" }, options.passcodeMode ? l.otpCode : l.confirmationCode),
2306
+ node("input", {
2307
+ id: "authlink-confirmation-code",
2308
+ name: options.passcodeMode ? "passcode" : "confirmationCode",
2309
+ type: "text",
2310
+ inputmode: "numeric",
2311
+ autocomplete: "one-time-code",
2312
+ pattern: "[0-9]{6}",
2313
+ maxlength: 6,
2314
+ minlength: 6,
2315
+ required: true,
2316
+ "data-authlink-focus": "confirmation-code",
2317
+ value: options.inputCode ?? "",
2318
+ onInput: (event) => options.setCode?.(event.target.value)
2319
+ }),
2320
+ node(
2321
+ "button",
2322
+ { type: "submit", class: "authlink-button", ...s.submitting ? { disabled: true } : {} },
2323
+ s.submitting ? l.loading : l.submitCode
2324
+ )
2206
2325
  ),
2207
- node("p", { class: "authlink-code-caption" }, s.code ? l.autoUpdate : l.updating)
2208
- );
2209
- const detail = [panel, node("p", { class: "authlink-help" }, l.help)];
2326
+ ...s.error ? [node("p", { class: "authlink-input-error", role: "alert" }, options.passcodeMode ? s.error.message === "OTP_NOT_CONFIGURED" ? l.otpSetup : l.otpError : l.codeError)] : []
2327
+ ];
2210
2328
  children.push(node("div", { class: "authlink-body" }, ...qr, node("div", { class: "authlink-details" }, ...detail)));
2211
2329
  if (variant === "A") children.push(node("div", { class: "authlink-footer" }, statusNode()));
2212
2330
  if (variant === "B") children.push(node("div", { class: "authlink-footer" }, statusNode(), ...cancel()));
2213
2331
  if (variant === "C") children.push(node("div", { class: "authlink-footer" }, statusNode(), ...cancel()));
2214
2332
  } else {
2215
2333
  children.push(statusNode());
2216
- if (s.status === "error") children.push(node("button", {
2334
+ if (s.error?.message === "CONFIRMATION_CODE_LOCKED") children.push(node("p", { class: "authlink-input-error", role: "alert" }, l.codeLocked));
2335
+ if (s.status === "error" && s.error?.message !== "CONFIRMATION_CODE_LOCKED") children.push(node("button", {
2217
2336
  type: "button",
2218
2337
  class: "authlink-button",
2219
2338
  "data-authlink-focus": "retry",
2220
2339
  onClick: retry
2221
2340
  }, l.retry));
2222
- if (refresh && ["expired", "rejected"].includes(s.status)) children.push(node("button", {
2341
+ if (refresh && ["expired", "rejected", "error"].includes(s.status)) children.push(node("button", {
2223
2342
  type: "button",
2224
2343
  class: "authlink-button",
2225
2344
  "data-authlink-focus": "refresh",
@@ -2242,7 +2361,7 @@ function element(value, svg = false) {
2242
2361
  svg ||= value.tag === "svg";
2243
2362
  const result = svg ? document.createElementNS("http://www.w3.org/2000/svg", value.tag) : document.createElement(value.tag);
2244
2363
  for (const [key, v] of Object.entries(value.props)) {
2245
- if (key === "onClick" && typeof v === "function") result.addEventListener("click", v);
2364
+ if (key.startsWith("on") && typeof v === "function") result.addEventListener(key.slice(2).toLowerCase(), v);
2246
2365
  else if (v !== void 0 && v !== null) result.setAttribute(key, String(v));
2247
2366
  }
2248
2367
  result.append(...value.children.map((child) => element(child, svg)));
@@ -2276,6 +2395,8 @@ function openAuthLink(options) {
2276
2395
  dialog.append(header, content);
2277
2396
  let locale = options.locale, variant = resolveVariant(options.variant), snapshot = initialSnapshot(), closed = false;
2278
2397
  let abort;
2398
+ let inputCode = "";
2399
+ let submitCode;
2279
2400
  const image = qrImage(ticket);
2280
2401
  let progressFill, progressFrame, progressDeadline = 0;
2281
2402
  const motion = window.matchMedia?.("(prefers-reduced-motion: reduce)");
@@ -2315,6 +2436,11 @@ function openAuthLink(options) {
2315
2436
  snapshot,
2316
2437
  qr: image,
2317
2438
  showQr: options.showQr,
2439
+ inputCode,
2440
+ setCode: (code) => {
2441
+ inputCode = code;
2442
+ },
2443
+ submitCode: (code) => submitCode?.(code) ?? Promise.resolve(),
2318
2444
  retry,
2319
2445
  refresh: options.onRefresh,
2320
2446
  close: () => dispose(true)
@@ -2333,6 +2459,9 @@ function openAuthLink(options) {
2333
2459
  oldProgress.setAttribute("aria-label", nextProgress.getAttribute("aria-label"));
2334
2460
  nextProgress.replaceWith(oldProgress);
2335
2461
  }
2462
+ const oldInput = content.querySelector("input[name=confirmationCode]");
2463
+ const nextInput = next.querySelector("input[name=confirmationCode]");
2464
+ if (oldInput && nextInput) nextInput.replaceWith(oldInput);
2336
2465
  content.replaceChildren(next);
2337
2466
  progressFill = content.querySelector(".authlink-progress-fill") ?? void 0;
2338
2467
  drawProgress();
@@ -2374,6 +2503,9 @@ function openAuthLink(options) {
2374
2503
  intervalMs: options.intervalMs,
2375
2504
  expectedMode: mode,
2376
2505
  signal: abort.signal,
2506
+ onReady: (submit) => {
2507
+ submitCode = submit;
2508
+ },
2377
2509
  onCodeTiming: syncProgress,
2378
2510
  onUpdate: (value) => {
2379
2511
  snapshot = value;
@@ -2432,9 +2564,206 @@ function openAuthLink(options) {
2432
2564
  };
2433
2565
  }
2434
2566
 
2567
+ // src/passcode.ts
2568
+ function validateOTPResult(value) {
2569
+ if (!value || typeof value !== "object") throw new AuthLinkError("INVALID_RESPONSE");
2570
+ const result = value;
2571
+ const expiry = typeof result.expiresAt === "string" ? Date.parse(result.expiresAt) : NaN;
2572
+ 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");
2573
+ return result;
2574
+ }
2575
+ function openPasscode(options) {
2576
+ if (typeof document === "undefined" || !document.body) throw new AuthLinkError("BROWSER_REQUIRED");
2577
+ const deadline = Date.parse(options.expiresAt);
2578
+ if (!Number.isFinite(deadline) || deadline <= Date.now() || deadline > Date.now() + 3e5) throw new AuthLinkError("INVALID_EXPIRY");
2579
+ const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
2580
+ const dialog = document.createElement("dialog");
2581
+ if (typeof dialog.showModal !== "function") throw new AuthLinkError("DIALOG_UNSUPPORTED");
2582
+ dialog.className = "authlink-dialog";
2583
+ dialog.setAttribute("aria-modal", "true");
2584
+ const header = document.createElement("div");
2585
+ header.className = "authlink-header";
2586
+ const brand = document.createElement("span");
2587
+ brand.className = "authlink-brand";
2588
+ brand.textContent = "AuthLink";
2589
+ const close = document.createElement("button");
2590
+ close.type = "button";
2591
+ close.className = "authlink-close";
2592
+ const icon = document.createElement("span");
2593
+ icon.className = "authlink-close-icon";
2594
+ icon.setAttribute("aria-hidden", "true");
2595
+ close.append(icon);
2596
+ const content = document.createElement("div");
2597
+ content.className = "authlink-modal-content";
2598
+ header.append(brand, close);
2599
+ dialog.append(header, content);
2600
+ let locale = options.locale, variant = resolveVariant(options.variant), closed = false, busy = false, code = "", error;
2601
+ const mode = options.bindingQr ? "bind" : "confirm";
2602
+ let image;
2603
+ if (options.bindingQr) {
2604
+ let payload;
2605
+ try {
2606
+ payload = JSON.parse(options.bindingQr);
2607
+ } catch {
2608
+ throw new AuthLinkError("INVALID_TICKET");
2609
+ }
2610
+ image = qrImage(validateTicket({ requestId: payload.requestId, purpose: "bind", qr: options.bindingQr, pairingCode: "000000", expiresAt: options.expiresAt }, "bind", options.authLinkOrigin));
2611
+ }
2612
+ const abort = new AbortController();
2613
+ let timer;
2614
+ const dispose = (notify) => {
2615
+ if (closed) return;
2616
+ closed = true;
2617
+ abort.abort();
2618
+ clearInterval(timer);
2619
+ dialog.remove();
2620
+ previousFocus?.focus();
2621
+ if (notify) options.onClose?.();
2622
+ };
2623
+ const render = () => {
2624
+ if (closed) return;
2625
+ const l = getMessages(locale);
2626
+ dialog.lang = resolveLocale(locale);
2627
+ dialog.dataset.variant = variant;
2628
+ dialog.dataset.mode = mode;
2629
+ dialog.dataset.hasQr = String(Boolean(image));
2630
+ dialog.setAttribute("aria-label", l[mode]);
2631
+ close.setAttribute("aria-label", l.close);
2632
+ const focused = content.contains(document.activeElement);
2633
+ const remaining = Math.max(0, Math.ceil((deadline - Date.now()) / 1e3));
2634
+ const snapshot = { status: remaining ? "pending" : "expired", code: null, secondsRemaining: remaining, codeSecondsRemaining: remaining, submitting: busy, error: error ?? null };
2635
+ content.replaceChildren(element(widgetView({
2636
+ mode,
2637
+ locale,
2638
+ variant,
2639
+ passcodeMode: true,
2640
+ snapshot,
2641
+ qr: image,
2642
+ showQr: Boolean(image),
2643
+ inputCode: code,
2644
+ setCode: (value) => {
2645
+ code = value;
2646
+ },
2647
+ submitCode: submit,
2648
+ retry: () => {
2649
+ error = void 0;
2650
+ render();
2651
+ },
2652
+ close: () => dispose(true)
2653
+ })));
2654
+ if (focused) content.querySelector("input")?.focus();
2655
+ };
2656
+ const submit = async (value) => {
2657
+ if (closed || busy) return;
2658
+ if (Date.now() >= deadline) {
2659
+ render();
2660
+ return;
2661
+ }
2662
+ if (!/^[0-9]{6}$/.test(value)) {
2663
+ error = new AuthLinkError("PASSCODE_INVALID");
2664
+ render();
2665
+ return;
2666
+ }
2667
+ code = value;
2668
+ busy = true;
2669
+ error = void 0;
2670
+ render();
2671
+ try {
2672
+ const result = validateOTPResult(await options.client.verify(value, abort.signal));
2673
+ if (closed || abort.signal.aborted || Date.now() >= deadline) return;
2674
+ try {
2675
+ await options.onVerified?.(result);
2676
+ } catch {
2677
+ options.onError?.(new AuthLinkError("CALLBACK_FAILED"));
2678
+ }
2679
+ dispose(false);
2680
+ } catch (cause) {
2681
+ if (!closed && !abort.signal.aborted) {
2682
+ error = cause instanceof Error ? cause : new AuthLinkError("NETWORK_ERROR");
2683
+ options.onError?.(error);
2684
+ }
2685
+ } finally {
2686
+ busy = false;
2687
+ render();
2688
+ }
2689
+ };
2690
+ close.addEventListener("click", () => dispose(true));
2691
+ dialog.addEventListener("cancel", (event) => {
2692
+ event.preventDefault();
2693
+ dispose(true);
2694
+ });
2695
+ document.body.append(dialog);
2696
+ render();
2697
+ dialog.showModal();
2698
+ content.querySelector("input")?.focus();
2699
+ timer = setInterval(() => {
2700
+ if (closed) return;
2701
+ if (Date.now() >= deadline) {
2702
+ render();
2703
+ clearInterval(timer);
2704
+ void Promise.resolve(options.onExpired?.()).catch(() => options.onError?.(new AuthLinkError("CALLBACK_FAILED")));
2705
+ }
2706
+ }, 1e3);
2707
+ return {
2708
+ close: () => dispose(true),
2709
+ destroy: () => dispose(false),
2710
+ setLocale: (value) => {
2711
+ locale = value;
2712
+ render();
2713
+ },
2714
+ setVariant: (value) => {
2715
+ variant = resolveVariant(value);
2716
+ render();
2717
+ },
2718
+ retry: () => {
2719
+ error = void 0;
2720
+ render();
2721
+ }
2722
+ };
2723
+ }
2724
+
2435
2725
  // src/vue.ts
2726
+ var AuthLinkPasscode = defineComponent({
2727
+ name: "AuthLinkPasscode",
2728
+ props: {
2729
+ client: { type: Object, required: true },
2730
+ expiresAt: { type: String, required: true },
2731
+ bindingQr: String,
2732
+ authLinkOrigin: String,
2733
+ locale: String,
2734
+ variant: String
2735
+ },
2736
+ emits: ["verified", "expired", "error", "close"],
2737
+ setup(props, { emit }) {
2738
+ let modal, mounted = false;
2739
+ const open = () => {
2740
+ if (!mounted) return;
2741
+ modal?.destroy();
2742
+ modal = openPasscode({
2743
+ ...props,
2744
+ onVerified: (value) => emit("verified", value),
2745
+ onExpired: () => emit("expired"),
2746
+ onError: (value) => emit("error", value),
2747
+ onClose: () => emit("close")
2748
+ });
2749
+ };
2750
+ onMounted(() => {
2751
+ mounted = true;
2752
+ open();
2753
+ });
2754
+ watch([() => props.client, () => props.expiresAt, () => props.bindingQr, () => props.authLinkOrigin], open);
2755
+ watch(() => props.locale, (value) => modal?.setLocale(value));
2756
+ watch(() => props.variant, (value) => modal?.setVariant(value));
2757
+ onBeforeUnmount(() => {
2758
+ mounted = false;
2759
+ modal?.destroy();
2760
+ });
2761
+ return () => null;
2762
+ }
2763
+ });
2436
2764
  function useAuthLink(getOptions) {
2437
2765
  const snapshot = shallowRef(initialSnapshot());
2766
+ let submit;
2438
2767
  const delivered = /* @__PURE__ */ new Set();
2439
2768
  let mounted = false, abort;
2440
2769
  const retry = () => {
@@ -2454,6 +2783,9 @@ function useAuthLink(getOptions) {
2454
2783
  intervalMs: options.intervalMs,
2455
2784
  expectedMode: options.mode,
2456
2785
  signal: abort.signal,
2786
+ onReady: (fn) => {
2787
+ submit = fn;
2788
+ },
2457
2789
  onUpdate: (value) => {
2458
2790
  snapshot.value = value;
2459
2791
  },
@@ -2477,7 +2809,7 @@ function useAuthLink(getOptions) {
2477
2809
  mounted = false;
2478
2810
  abort?.abort();
2479
2811
  });
2480
- return { snapshot, retry };
2812
+ return { snapshot, retry, submitCode: (code) => submit?.(code) ?? Promise.resolve() };
2481
2813
  }
2482
2814
  function widget(mode) {
2483
2815
  return defineComponent({
@@ -2545,6 +2877,7 @@ var AuthLinkConfirm = widget("confirm");
2545
2877
  export {
2546
2878
  AuthLinkBind,
2547
2879
  AuthLinkConfirm,
2880
+ AuthLinkPasscode,
2548
2881
  useAuthLink
2549
2882
  };
2550
2883
  //# sourceMappingURL=vue.js.map