@orangecheck/auth-client 2.34.0 → 2.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -348,12 +348,24 @@ function normalizeRosterEntry(raw) {
348
348
  lastSeenAt: raw.last_seen_at ?? raw.lastSeenAt ?? null
349
349
  };
350
350
  }
351
+ var ME_TIMEOUT_MS = 1e4;
352
+ function timeoutSignal(ms) {
353
+ if (typeof AbortSignal.timeout === "function") return AbortSignal.timeout(ms);
354
+ const controller = new AbortController();
355
+ setTimeout(() => controller.abort(), ms);
356
+ return controller.signal;
357
+ }
358
+ function isTimeout(err) {
359
+ const name = err?.name;
360
+ return name === "TimeoutError" || name === "AbortError";
361
+ }
351
362
  async function fetchHostRoster(cfg) {
352
363
  try {
353
364
  const res = await fetch(`${cfg.authOrigin}${cfg.mePath}`, {
354
365
  method: "GET",
355
366
  credentials: "include",
356
- headers: { Accept: "application/json", ...tabSessionHeader() }
367
+ headers: { Accept: "application/json", ...tabSessionHeader() },
368
+ signal: timeoutSignal(ME_TIMEOUT_MS)
357
369
  });
358
370
  if (!res.ok) return [];
359
371
  const body = await res.json();
@@ -429,7 +441,8 @@ function OcSessionProvider({
429
441
  let res = await fetch(cfg.mePath, {
430
442
  method: "GET",
431
443
  credentials: "include",
432
- headers: { Accept: "application/json", ...tabSessionHeader() }
444
+ headers: { Accept: "application/json", ...tabSessionHeader() },
445
+ signal: timeoutSignal(ME_TIMEOUT_MS)
433
446
  });
434
447
  if (res.status === 401 && pin) {
435
448
  clearTabSession();
@@ -438,7 +451,8 @@ function OcSessionProvider({
438
451
  res = await fetch(cfg.mePath, {
439
452
  method: "GET",
440
453
  credentials: "include",
441
- headers: { Accept: "application/json" }
454
+ headers: { Accept: "application/json" },
455
+ signal: timeoutSignal(ME_TIMEOUT_MS)
442
456
  });
443
457
  }
444
458
  if (res.status === 401) {
@@ -473,7 +487,9 @@ function OcSessionProvider({
473
487
  }
474
488
  } catch (err) {
475
489
  setStatus("error");
476
- setError(err instanceof Error ? err : new Error(String(err)));
490
+ setError(
491
+ isTimeout(err) ? new Error(`me endpoint did not answer within ${ME_TIMEOUT_MS / 1e3}s`) : err instanceof Error ? err : new Error(String(err))
492
+ );
477
493
  }
478
494
  }, [cfg, pinThisTab]);
479
495
  React4__namespace.useEffect(() => {
@@ -2144,7 +2160,6 @@ var inputStyle = {
2144
2160
  fontFamily: SIGNIN_FONT,
2145
2161
  // 16px — never lower · suppresses iOS Safari focus auto-zoom.
2146
2162
  fontSize: 16,
2147
- outline: "none",
2148
2163
  boxSizing: "border-box"
2149
2164
  };
2150
2165
  function btnBase(disabled) {
@@ -2251,15 +2266,22 @@ var EMAIL_ERRORS = {
2251
2266
  var SUBMIT_ERRORS = {
2252
2267
  bad_request: "That signature couldn't be read. Copy it again, whole."
2253
2268
  };
2254
- var NETWORK_ERROR = "We couldn't reach the server. Check your connection and try again.";
2269
+ function networkError(authOrigin) {
2270
+ let host = authOrigin;
2271
+ try {
2272
+ host = new URL(authOrigin).host;
2273
+ } catch {
2274
+ }
2275
+ return `We couldn't reach the orangecheck sign-in service at ${host}. Check your connection, then try again.`;
2276
+ }
2255
2277
  function humanSigninError(reason, path, step = "challenge") {
2256
2278
  if (!/^[a-z0-9_]+$/.test(reason)) return reason;
2257
2279
  if (path === "wallet" && step === "submit" && SUBMIT_ERRORS[reason]) return SUBMIT_ERRORS[reason];
2258
2280
  if (path === "email" && EMAIL_ERRORS[reason]) return EMAIL_ERRORS[reason];
2259
2281
  return SIGNIN_ERRORS[reason] ?? (path === "email" ? "That didn't work. Try again, or send a new code." : "That didn't work. Try again.");
2260
2282
  }
2261
- function failureMessage(err, path, step) {
2262
- if (err instanceof TypeError || err instanceof SyntaxError) return NETWORK_ERROR;
2283
+ function failureMessage(err, path, step, authOrigin) {
2284
+ if (err instanceof TypeError || err instanceof SyntaxError) return networkError(authOrigin);
2263
2285
  return humanSigninError(err instanceof Error ? err.message : "failed", path, step);
2264
2286
  }
2265
2287
  var BECH32_ADDRESS = /^(bc1|tb1|bcrt1)[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{8,87}$/i;
@@ -2318,6 +2340,19 @@ function OcSignIn({
2318
2340
  const [path, setPath] = React4__namespace.useState(
2319
2341
  initialPath ?? (providersFirst ? "email" : "wallet")
2320
2342
  );
2343
+ const tabsId = React4__namespace.useId();
2344
+ const tabOrder = providersFirst ? ["email", "wallet"] : ["wallet", "email"];
2345
+ const tabRefs = React4__namespace.useRef({});
2346
+ const onTabKey = (e) => {
2347
+ const i = tabOrder.indexOf(path);
2348
+ const last = tabOrder.length - 1;
2349
+ const to = e.key === "ArrowRight" ? (i + 1) % tabOrder.length : e.key === "ArrowLeft" ? (i + last) % tabOrder.length : e.key === "Home" ? 0 : e.key === "End" ? last : -1;
2350
+ if (to < 0) return;
2351
+ e.preventDefault();
2352
+ const next = tabOrder[to];
2353
+ setPath(next);
2354
+ tabRefs.current[next]?.focus();
2355
+ };
2321
2356
  const [signedIn, setSignedIn] = React4__namespace.useState(null);
2322
2357
  const [linkAlso, setLinkAlso] = React4__namespace.useState(false);
2323
2358
  const [oauthError, setOauthError] = React4__namespace.useState(false);
@@ -2481,7 +2516,7 @@ function OcSignIn({
2481
2516
  "div",
2482
2517
  {
2483
2518
  role: "tablist",
2484
- "aria-label": "signin method",
2519
+ "aria-label": "Sign-in method",
2485
2520
  "data-oc-signin-tabs": "",
2486
2521
  style: {
2487
2522
  display: "flex",
@@ -2489,64 +2524,55 @@ function OcSignIn({
2489
2524
  marginBottom: 16,
2490
2525
  borderBottom: "1px solid var(--border, #27272a)"
2491
2526
  },
2492
- children: providersFirst ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2493
- /* @__PURE__ */ jsxRuntime.jsx(
2494
- SigninTab,
2495
- {
2496
- active: path === "email",
2497
- onClick: () => setPath("email"),
2498
- children: "Email"
2499
- }
2500
- ),
2501
- /* @__PURE__ */ jsxRuntime.jsx(
2502
- SigninTab,
2503
- {
2504
- active: path === "wallet",
2505
- onClick: () => setPath("wallet"),
2506
- children: "Bitcoin wallet"
2507
- }
2508
- )
2509
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2510
- /* @__PURE__ */ jsxRuntime.jsx(
2511
- SigninTab,
2527
+ children: tabOrder.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
2528
+ SigninTab,
2529
+ {
2530
+ id: `${tabsId}-${p}`,
2531
+ controls: `${tabsId}-panel`,
2532
+ active: path === p,
2533
+ onClick: () => setPath(p),
2534
+ onKeyDown: onTabKey,
2535
+ ref: (el) => {
2536
+ tabRefs.current[p] = el;
2537
+ },
2538
+ children: p === "email" ? "Email" : "Bitcoin wallet"
2539
+ },
2540
+ p
2541
+ ))
2542
+ }
2543
+ ),
2544
+ /* @__PURE__ */ jsxRuntime.jsxs(
2545
+ "div",
2546
+ {
2547
+ "data-oc-signin-panel": "",
2548
+ ...bothEnabled ? {
2549
+ id: `${tabsId}-panel`,
2550
+ role: "tabpanel",
2551
+ "aria-labelledby": `${tabsId}-${path}`
2552
+ } : {},
2553
+ children: [
2554
+ showWallet && /* @__PURE__ */ jsxRuntime.jsx(
2555
+ WalletFlow,
2512
2556
  {
2513
- active: path === "wallet",
2514
- onClick: () => setPath("wallet"),
2515
- children: "Bitcoin wallet"
2557
+ authOrigin,
2558
+ audience,
2559
+ add: addMode,
2560
+ credentials,
2561
+ onSuccess: (a, t) => void handleSuccess(a, t, "wallet")
2516
2562
  }
2517
2563
  ),
2518
- /* @__PURE__ */ jsxRuntime.jsx(
2519
- SigninTab,
2564
+ showEmail && /* @__PURE__ */ jsxRuntime.jsx(
2565
+ EmailFlow,
2520
2566
  {
2521
- active: path === "email",
2522
- onClick: () => setPath("email"),
2523
- children: "Email"
2567
+ authOrigin,
2568
+ add: addMode,
2569
+ credentials,
2570
+ onSuccess: (a, t) => void handleSuccess(a, t, "email")
2524
2571
  }
2525
2572
  )
2526
- ] })
2573
+ ]
2527
2574
  }
2528
2575
  ),
2529
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-oc-signin-panel": "", role: "tabpanel", children: [
2530
- showWallet && /* @__PURE__ */ jsxRuntime.jsx(
2531
- WalletFlow,
2532
- {
2533
- authOrigin,
2534
- audience,
2535
- add: addMode,
2536
- credentials,
2537
- onSuccess: (a, t) => void handleSuccess(a, t, "wallet")
2538
- }
2539
- ),
2540
- showEmail && /* @__PURE__ */ jsxRuntime.jsx(
2541
- EmailFlow,
2542
- {
2543
- authOrigin,
2544
- add: addMode,
2545
- credentials,
2546
- onSuccess: (a, t) => void handleSuccess(a, t, "email")
2547
- }
2548
- )
2549
- ] }),
2550
2576
  !providersFirst && /* @__PURE__ */ jsxRuntime.jsx(
2551
2577
  ProviderSignIn,
2552
2578
  {
@@ -2578,18 +2604,19 @@ function OcSignIn({
2578
2604
  ] })
2579
2605
  ] });
2580
2606
  }
2581
- function SigninTab({
2582
- active,
2583
- onClick,
2584
- children
2585
- }) {
2607
+ var SigninTab = React4__namespace.forwardRef(function SigninTab2({ id, controls, active, onClick, onKeyDown, children }, ref) {
2586
2608
  return /* @__PURE__ */ jsxRuntime.jsx(
2587
2609
  "button",
2588
2610
  {
2611
+ ref,
2589
2612
  type: "button",
2590
2613
  role: "tab",
2614
+ id,
2591
2615
  "aria-selected": active,
2616
+ "aria-controls": controls,
2617
+ tabIndex: active ? 0 : -1,
2592
2618
  onClick,
2619
+ onKeyDown,
2593
2620
  "data-oc-signin-tab": active ? "active" : "inactive",
2594
2621
  style: {
2595
2622
  minHeight: 44,
@@ -2608,7 +2635,7 @@ function SigninTab({
2608
2635
  children
2609
2636
  }
2610
2637
  );
2611
- }
2638
+ });
2612
2639
  function ProviderIcon({ id }) {
2613
2640
  const common = {
2614
2641
  width: 14,
@@ -2847,7 +2874,7 @@ function WalletFlow({
2847
2874
  step = "submit";
2848
2875
  await submitSignature(challenge.message, challenge.nonce, signature, "bip322");
2849
2876
  } catch (err) {
2850
- setError(failureMessage(err, "wallet", step));
2877
+ setError(failureMessage(err, "wallet", step, authOrigin));
2851
2878
  setSubmitting(false);
2852
2879
  }
2853
2880
  }
@@ -2864,7 +2891,7 @@ function WalletFlow({
2864
2891
  try {
2865
2892
  await submitSignature(manual.message, manual.nonce, sig, void 0);
2866
2893
  } catch (err) {
2867
- setError(failureMessage(err, "wallet", "submit"));
2894
+ setError(failureMessage(err, "wallet", "submit", authOrigin));
2868
2895
  setSubmitting(false);
2869
2896
  }
2870
2897
  }
@@ -3016,7 +3043,7 @@ function EmailFlow({ authOrigin, add, credentials, onSuccess }) {
3016
3043
  setToken(json.token);
3017
3044
  return null;
3018
3045
  } catch {
3019
- return NETWORK_ERROR;
3046
+ return networkError(authOrigin);
3020
3047
  }
3021
3048
  }
3022
3049
  async function start(e) {
@@ -3077,7 +3104,7 @@ function EmailFlow({ authOrigin, add, credentials, onSuccess }) {
3077
3104
  }
3078
3105
  onSuccess(json.account, json.token);
3079
3106
  } catch (err) {
3080
- setCodeError(failureMessage(err, "email", "submit"));
3107
+ setCodeError(failureMessage(err, "email", "submit", authOrigin));
3081
3108
  } finally {
3082
3109
  setSubmitting(false);
3083
3110
  }
@@ -3260,8 +3287,7 @@ var inputStyle2 = {
3260
3287
  // 16px — never below it. A sub-16px font-size makes iOS Safari
3261
3288
  // auto-zoom the viewport on focus; the family rule is >=16px on
3262
3289
  // every form field. Desktop reads fine at 16 too.
3263
- fontSize: 16,
3264
- outline: "none"
3290
+ fontSize: 16
3265
3291
  };
3266
3292
  var linkAlsoStyle = {
3267
3293
  display: "flex",