@ollaid/native-sso 2.7.0 → 2.7.2

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
@@ -289,17 +289,18 @@ function OTPInput({
289
289
  disabled = false,
290
290
  autoFocus = true
291
291
  }) {
292
+ const safeLength = Number.isFinite(length) ? Math.max(1, Math.min(12, Math.trunc(length))) : 6;
292
293
  const inputRefs = useRef([]);
293
294
  const [activeIndex, setActiveIndex] = useState(0);
294
295
  useEffect(() => {
295
- inputRefs.current = inputRefs.current.slice(0, length);
296
- }, [length]);
296
+ inputRefs.current = inputRefs.current.slice(0, safeLength);
297
+ }, [safeLength]);
297
298
  useEffect(() => {
298
299
  if (autoFocus && inputRefs.current[0]) inputRefs.current[0].focus();
299
300
  }, [autoFocus]);
300
301
  useEffect(() => {
301
- if (value.length === length && onComplete) onComplete(value);
302
- }, [value, length, onComplete]);
302
+ if (value.length === safeLength && onComplete) onComplete(value);
303
+ }, [value, safeLength, onComplete]);
303
304
  const handleChange = (index, char) => {
304
305
  var _a;
305
306
  if (disabled) return;
@@ -307,8 +308,8 @@ function OTPInput({
307
308
  if (!digit) return;
308
309
  const newValue = value.split("");
309
310
  newValue[index] = digit;
310
- onChange(newValue.join("").slice(0, length));
311
- if (index < length - 1) {
311
+ onChange(newValue.join("").slice(0, safeLength));
312
+ if (index < safeLength - 1) {
312
313
  (_a = inputRefs.current[index + 1]) == null ? void 0 : _a.focus();
313
314
  setActiveIndex(index + 1);
314
315
  }
@@ -331,7 +332,7 @@ function OTPInput({
331
332
  } else if (e.key === "ArrowLeft" && index > 0) {
332
333
  (_b = inputRefs.current[index - 1]) == null ? void 0 : _b.focus();
333
334
  setActiveIndex(index - 1);
334
- } else if (e.key === "ArrowRight" && index < length - 1) {
335
+ } else if (e.key === "ArrowRight" && index < safeLength - 1) {
335
336
  (_c = inputRefs.current[index + 1]) == null ? void 0 : _c.focus();
336
337
  setActiveIndex(index + 1);
337
338
  }
@@ -342,14 +343,14 @@ function OTPInput({
342
343
  e.preventDefault();
343
344
  const pasted = e.clipboardData.getData("text").replace(/[^0-9]/g, "");
344
345
  if (pasted) {
345
- const newValue = pasted.slice(0, length);
346
+ const newValue = pasted.slice(0, safeLength);
346
347
  onChange(newValue);
347
- const focusIndex = Math.min(newValue.length, length - 1);
348
+ const focusIndex = Math.min(newValue.length, safeLength - 1);
348
349
  (_a = inputRefs.current[focusIndex]) == null ? void 0 : _a.focus();
349
350
  setActiveIndex(focusIndex);
350
351
  }
351
352
  };
352
- return /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem" }, children: Array.from({ length }).map((_, index) => /* @__PURE__ */ jsx(
353
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem" }, children: Array.from({ length: safeLength }).map((_, index) => /* @__PURE__ */ jsx(
353
354
  "input",
354
355
  {
355
356
  ref: (el) => inputRefs.current[index] = el,
@@ -7555,8 +7556,12 @@ function getHeaders(token, includeConfigPrefix = false) {
7555
7556
  let credentials = null;
7556
7557
  let credentialsLoadedAt = 0;
7557
7558
  let credentialsTtl = 300;
7559
+ let refreshInFlight = null;
7560
+ let lastSuccessfulRefreshAt = 0;
7561
+ let lastSuccessfulRefreshResponse = null;
7558
7562
  const DEFAULT_TTL = 300;
7559
7563
  const REFRESH_MARGIN = 30;
7564
+ const REFRESH_COOLDOWN_MS = 60 * 1e3;
7560
7565
  const nativeAuthService = {
7561
7566
  hasCredentials() {
7562
7567
  return credentials !== null;
@@ -7855,6 +7860,16 @@ const nativeAuthService = {
7855
7860
  }
7856
7861
  },
7857
7862
  async refresh() {
7863
+ const now = Date.now();
7864
+ if (refreshInFlight) {
7865
+ return refreshInFlight;
7866
+ }
7867
+ if ((lastSuccessfulRefreshResponse == null ? void 0 : lastSuccessfulRefreshResponse.success) && lastSuccessfulRefreshAt && now - lastSuccessfulRefreshAt < REFRESH_COOLDOWN_MS) {
7868
+ if (isDebugMode()) {
7869
+ console.log("🔄 [SaaS] POST /native/refresh — cooldown actif, réponse réutilisée");
7870
+ }
7871
+ return lastSuccessfulRefreshResponse;
7872
+ }
7858
7873
  const cfg = getNativeAuthConfig();
7859
7874
  if (!cfg.saasApiUrl) {
7860
7875
  throw new ApiError("saasApiUrl non configurée", "unknown");
@@ -7867,51 +7882,62 @@ const nativeAuthService = {
7867
7882
  if (isDebugMode()) {
7868
7883
  console.log("📤 [SaaS] POST /native/refresh");
7869
7884
  }
7870
- let response;
7871
- try {
7872
- response = await fetchWithTimeout(
7873
- `${cfg.saasApiUrl}/native/refresh`,
7874
- {
7875
- method: "POST",
7876
- headers: getHeaders(void 0, true),
7877
- body: JSON.stringify({ refresh_token: refreshToken })
7878
- },
7879
- cfg.timeout || 3e4
7880
- );
7881
- } catch (err) {
7882
- if (err instanceof ApiError) {
7883
- if (err.statusCode === 401) {
7884
- return {
7885
- success: false,
7886
- error_type: err.errorType || "invalid_refresh",
7887
- message: err.message
7888
- };
7885
+ refreshInFlight = (async () => {
7886
+ try {
7887
+ let response;
7888
+ try {
7889
+ response = await fetchWithTimeout(
7890
+ `${cfg.saasApiUrl}/native/refresh`,
7891
+ {
7892
+ method: "POST",
7893
+ headers: getHeaders(void 0, true),
7894
+ body: JSON.stringify({ refresh_token: refreshToken })
7895
+ },
7896
+ cfg.timeout || 3e4
7897
+ );
7898
+ } catch (err) {
7899
+ if (err instanceof ApiError) {
7900
+ if (err.statusCode === 401) {
7901
+ response = {
7902
+ success: false,
7903
+ error_type: err.errorType || "invalid_refresh",
7904
+ message: err.message
7905
+ };
7906
+ } else if (err.statusCode === 404) {
7907
+ response = {
7908
+ success: false,
7909
+ error_type: "not_supported",
7910
+ message: "Endpoint refresh non disponible sur ce SaaS"
7911
+ };
7912
+ } else {
7913
+ throw err;
7914
+ }
7915
+ } else {
7916
+ throw err;
7917
+ }
7889
7918
  }
7890
- if (err.statusCode === 404) {
7891
- return {
7892
- success: false,
7893
- error_type: "not_supported",
7894
- message: "Endpoint refresh non disponible sur ce SaaS"
7895
- };
7919
+ if (response.success) {
7920
+ if (response.token) {
7921
+ setAuthToken(response.token);
7922
+ }
7923
+ const storage = getNativeStorage();
7924
+ if (response.expires_at) storage.setItem(STORAGE.TOKEN_EXPIRES_AT, response.expires_at);
7925
+ if (response.refresh_token) storage.setItem(STORAGE.REFRESH_TOKEN, response.refresh_token);
7926
+ if (response.refresh_expires_at) storage.setItem(STORAGE.REFRESH_EXPIRES_AT, response.refresh_expires_at);
7927
+ if (response.app_access_token_ref) storage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, response.app_access_token_ref);
7928
+ if (response.alias_reference) storage.setItem(STORAGE.ALIAS_REFERENCE, response.alias_reference);
7929
+ if (response.user) {
7930
+ setAuthUser(response.user);
7931
+ }
7932
+ lastSuccessfulRefreshAt = Date.now();
7933
+ lastSuccessfulRefreshResponse = response;
7896
7934
  }
7935
+ return response;
7936
+ } finally {
7937
+ refreshInFlight = null;
7897
7938
  }
7898
- throw err;
7899
- }
7900
- if (response.success) {
7901
- if (response.token) {
7902
- setAuthToken(response.token);
7903
- }
7904
- const storage = getNativeStorage();
7905
- if (response.expires_at) storage.setItem(STORAGE.TOKEN_EXPIRES_AT, response.expires_at);
7906
- if (response.refresh_token) storage.setItem(STORAGE.REFRESH_TOKEN, response.refresh_token);
7907
- if (response.refresh_expires_at) storage.setItem(STORAGE.REFRESH_EXPIRES_AT, response.refresh_expires_at);
7908
- if (response.app_access_token_ref) storage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, response.app_access_token_ref);
7909
- if (response.alias_reference) storage.setItem(STORAGE.ALIAS_REFERENCE, response.alias_reference);
7910
- if (response.user) {
7911
- setAuthUser(response.user);
7912
- }
7913
- }
7914
- return response;
7939
+ })();
7940
+ return refreshInFlight;
7915
7941
  },
7916
7942
  async logout(token) {
7917
7943
  const config2 = getNativeAuthConfig();
@@ -7960,11 +7986,17 @@ const nativeAuthService = {
7960
7986
  clearAuthToken();
7961
7987
  credentials = null;
7962
7988
  credentialsLoadedAt = 0;
7989
+ refreshInFlight = null;
7990
+ lastSuccessfulRefreshAt = 0;
7991
+ lastSuccessfulRefreshResponse = null;
7963
7992
  return { success: true };
7964
7993
  },
7965
7994
  clearCredentials() {
7966
7995
  credentials = null;
7967
7996
  credentialsLoadedAt = 0;
7997
+ refreshInFlight = null;
7998
+ lastSuccessfulRefreshAt = 0;
7999
+ lastSuccessfulRefreshResponse = null;
7968
8000
  },
7969
8001
  // ============================================
7970
8002
  // High-level methods
@@ -9583,6 +9615,8 @@ function LoginModal({
9583
9615
  const [loginSuccess, setLoginSuccess] = useState(false);
9584
9616
  const [loginData, setLoginData] = useState(null);
9585
9617
  const [showPasswordRecovery, setShowPasswordRecovery] = useState(false);
9618
+ const [passwordSubmitting, setPasswordSubmitting] = useState(false);
9619
+ const successCallbackTimerRef = useRef(null);
9586
9620
  const CCPHONE = "+221";
9587
9621
  const isSubmitting = authLoading || loading;
9588
9622
  const error = localError || authError;
@@ -9600,15 +9634,11 @@ function LoginModal({
9600
9634
  setResendCooldown(60);
9601
9635
  }
9602
9636
  }, [status, step]);
9603
- useEffect(() => {
9604
- if (loginSuccess && loginData) {
9605
- const timer = setTimeout(() => {
9606
- onLoginSuccess == null ? void 0 : onLoginSuccess(loginData.token, loginData.user);
9607
- }, 1e3);
9608
- return () => clearTimeout(timer);
9609
- }
9610
- }, [loginSuccess, loginData, onLoginSuccess]);
9611
9637
  const resetState = useCallback(() => {
9638
+ if (successCallbackTimerRef.current) {
9639
+ clearTimeout(successCallbackTimerRef.current);
9640
+ successCallbackTimerRef.current = null;
9641
+ }
9612
9642
  setStep("choice");
9613
9643
  setEmail("");
9614
9644
  setPassword("");
@@ -9622,6 +9652,7 @@ function LoginModal({
9622
9652
  setLoginSuccess(false);
9623
9653
  setLoginData(null);
9624
9654
  setResendCooldown(0);
9655
+ setPasswordSubmitting(false);
9625
9656
  resetAuth();
9626
9657
  }, [resetAuth]);
9627
9658
  useEffect(() => {
@@ -9634,12 +9665,34 @@ function LoginModal({
9634
9665
  }
9635
9666
  }, [open, initialPhone]);
9636
9667
  const finalizeLogin = (result) => {
9637
- if (result.success && result.user) {
9668
+ if (result.success) {
9638
9669
  const token = getAuthToken() || "";
9639
- setLoginData({ token, user: result.user });
9640
- setLoginSuccess(true);
9670
+ const resolvedUser = result.user || user;
9671
+ if (resolvedUser) {
9672
+ setLoginData({ token, user: resolvedUser });
9673
+ setLoginSuccess(true);
9674
+ }
9641
9675
  }
9642
9676
  };
9677
+ useEffect(() => {
9678
+ if (!loginSuccess || !loginData || !onLoginSuccess) return;
9679
+ if (successCallbackTimerRef.current) {
9680
+ clearTimeout(successCallbackTimerRef.current);
9681
+ }
9682
+ successCallbackTimerRef.current = setTimeout(() => {
9683
+ try {
9684
+ onLoginSuccess(loginData.token, loginData.user);
9685
+ } catch (callbackError) {
9686
+ console.error("Erreur dans onLoginSuccess", callbackError);
9687
+ }
9688
+ }, 900);
9689
+ return () => {
9690
+ if (successCallbackTimerRef.current) {
9691
+ clearTimeout(successCallbackTimerRef.current);
9692
+ successCallbackTimerRef.current = null;
9693
+ }
9694
+ };
9695
+ }, [loginSuccess, loginData, onLoginSuccess]);
9643
9696
  const handleEmailCheck = async () => {
9644
9697
  setLocalError(null);
9645
9698
  clearError();
@@ -9656,18 +9709,24 @@ function LoginModal({
9656
9709
  };
9657
9710
  const handleEmailPasswordSubmit = async (e) => {
9658
9711
  e.preventDefault();
9712
+ if (passwordSubmitting || isSubmitting) return;
9713
+ setPasswordSubmitting(true);
9659
9714
  setLocalError(null);
9660
9715
  clearError();
9661
- if (!password) {
9662
- setLocalError("Le mot de passe est requis");
9663
- return;
9664
- }
9665
- if (password.length < 8) {
9666
- setLocalError("Le mot de passe doit contenir au moins 8 caractères");
9667
- return;
9716
+ try {
9717
+ if (!password) {
9718
+ setLocalError("Le mot de passe est requis");
9719
+ return;
9720
+ }
9721
+ if (password.length < 8) {
9722
+ setLocalError("Le mot de passe doit contenir au moins 8 caractères");
9723
+ return;
9724
+ }
9725
+ const result = await submitPassword(password);
9726
+ finalizeLogin(result);
9727
+ } finally {
9728
+ setPasswordSubmitting(false);
9668
9729
  }
9669
- const result = await submitPassword(password);
9670
- finalizeLogin(result);
9671
9730
  };
9672
9731
  const handleEmailOtpVerify = async () => {
9673
9732
  setLocalError(null);
@@ -9931,7 +9990,7 @@ function LoginModal({
9931
9990
  placeholder: "••••••••",
9932
9991
  value: password,
9933
9992
  onChange: (e) => setPassword(e.target.value),
9934
- disabled: isSubmitting,
9993
+ disabled: isSubmitting || passwordSubmitting,
9935
9994
  style: { paddingRight: "2.5rem" }
9936
9995
  }
9937
9996
  ),
@@ -9947,7 +10006,7 @@ function LoginModal({
9947
10006
  ] })
9948
10007
  ] })
9949
10008
  ] }) }),
9950
- /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSubmitting || !password, style: { width: "100%" }, children: isSubmitting ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
10009
+ /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSubmitting || passwordSubmitting || !password, style: { width: "100%" }, children: isSubmitting ? /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
9951
10010
  /* @__PURE__ */ jsx(IconLoader2, { style: { width: "1rem", height: "1rem" } }),
9952
10011
  "Connexion..."
9953
10012
  ] }) : "Se connecter" }) })
@@ -13203,6 +13262,8 @@ function NativeSSOPage({
13203
13262
  const [showOnboarding, setShowOnboarding] = useState(false);
13204
13263
  const [pendingSession, setPendingSession] = useState(null);
13205
13264
  const [debugOnboardingState, setDebugOnboardingState] = useState(null);
13265
+ const [redirectingTarget, setRedirectingTarget] = useState(null);
13266
+ const [redirectingReason, setRedirectingReason] = useState(null);
13206
13267
  const [session, setSession] = useState(() => {
13207
13268
  try {
13208
13269
  const storage2 = getNativeStorage();
@@ -13225,6 +13286,17 @@ function NativeSSOPage({
13225
13286
  useEffect(() => {
13226
13287
  sessionRef.current = session;
13227
13288
  }, [session]);
13289
+ useEffect(() => {
13290
+ if (!redirectingTarget) return;
13291
+ const timer = window.setTimeout(() => {
13292
+ const redirected = safeRedirect(redirectingTarget);
13293
+ if (!redirected) {
13294
+ setRedirectingTarget(null);
13295
+ setRedirectingReason(null);
13296
+ }
13297
+ }, 200);
13298
+ return () => window.clearTimeout(timer);
13299
+ }, [redirectingTarget]);
13228
13300
  const clearOnboardingTimers = useCallback(() => {
13229
13301
  if (onboardingPromptTimerRef.current) {
13230
13302
  clearTimeout(onboardingPromptTimerRef.current);
@@ -13392,6 +13464,12 @@ function NativeSSOPage({
13392
13464
  setLoginInitialPhone(phone);
13393
13465
  setTimeout(() => setModal("login"), 150);
13394
13466
  }, []);
13467
+ const beginRedirect = useCallback((target, reason = "login") => {
13468
+ if (!target) return false;
13469
+ setRedirectingReason(reason);
13470
+ setRedirectingTarget(target);
13471
+ return true;
13472
+ }, []);
13395
13473
  const handleLoginSuccess = useCallback((token, user) => {
13396
13474
  const userObj = {
13397
13475
  reference: "",
@@ -13408,10 +13486,14 @@ function NativeSSOPage({
13408
13486
  void refreshSessionProfile(true);
13409
13487
  if (!needsOnboarding(userObj)) {
13410
13488
  markProfilePromptComplete();
13411
- onLoginSuccess == null ? void 0 : onLoginSuccess(token, user);
13412
- safeRedirect(redirectAfterLogin);
13489
+ try {
13490
+ onLoginSuccess == null ? void 0 : onLoginSuccess(token, user);
13491
+ } catch (callbackError) {
13492
+ console.error("Erreur dans le callback onLoginSuccess du wrapper SSO", callbackError);
13493
+ }
13494
+ beginRedirect(redirectAfterLogin, "login");
13413
13495
  }
13414
- }, [onLoginSuccess, redirectAfterLogin, persistSessionUser, syncProfilePrompt, refreshSessionProfile, accountType]);
13496
+ }, [onLoginSuccess, redirectAfterLogin, persistSessionUser, syncProfilePrompt, refreshSessionProfile, accountType, beginRedirect]);
13415
13497
  const handleOnboardingComplete = useCallback((data) => {
13416
13498
  const activeSession = debugOnboardingState || pendingSession;
13417
13499
  if (!activeSession) return;
@@ -13455,11 +13537,15 @@ function NativeSSOPage({
13455
13537
  if (!debugOnboardingState) {
13456
13538
  persistSessionUser(activeSession.token, activeSession.user);
13457
13539
  snoozeProfilePrompt(PROFILE_PROMPT_SNOOZE_MS / (60 * 60 * 1e3));
13458
- onLoginSuccess == null ? void 0 : onLoginSuccess(activeSession.token, activeSession.user);
13459
- safeRedirect(redirectAfterLogin);
13540
+ try {
13541
+ onLoginSuccess == null ? void 0 : onLoginSuccess(activeSession.token, activeSession.user);
13542
+ } catch (callbackError) {
13543
+ console.error("Erreur dans le callback onLoginSuccess du wrapper SSO", callbackError);
13544
+ }
13545
+ beginRedirect(redirectAfterLogin, "login");
13460
13546
  return;
13461
13547
  }
13462
- }, [pendingSession, debugOnboardingState, onLoginSuccess, redirectAfterLogin, persistSessionUser]);
13548
+ }, [pendingSession, debugOnboardingState, onLoginSuccess, redirectAfterLogin, persistSessionUser, beginRedirect]);
13463
13549
  const handleOnboardingDismiss = useCallback(() => {
13464
13550
  setShowOnboarding(false);
13465
13551
  setPendingSession(null);
@@ -13472,8 +13558,8 @@ function NativeSSOPage({
13472
13558
  setDebugOnboardingState(null);
13473
13559
  clearOnboardingTimers();
13474
13560
  onLogout == null ? void 0 : onLogout();
13475
- safeRedirect(redirectAfterLogout);
13476
- }, [onLogout, redirectAfterLogout, clearOnboardingTimers]);
13561
+ beginRedirect(redirectAfterLogout, "logout");
13562
+ }, [onLogout, redirectAfterLogout, clearOnboardingTimers, beginRedirect]);
13477
13563
  const openDebugLogin = useCallback(() => {
13478
13564
  clearOnboardingTimers();
13479
13565
  setShowOnboarding(false);
@@ -13488,6 +13574,10 @@ function NativeSSOPage({
13488
13574
  setDebugOnboardingState(null);
13489
13575
  setModal("signup");
13490
13576
  }, [clearOnboardingTimers]);
13577
+ useEffect(() => {
13578
+ if (!(session == null ? void 0 : session.token) || !redirectAfterLogin || redirectingTarget) return;
13579
+ beginRedirect(redirectAfterLogin, "already-authenticated");
13580
+ }, [session == null ? void 0 : session.token, redirectAfterLogin, redirectingTarget, beginRedirect]);
13491
13581
  const openDebugOnboarding = useCallback((preset = "current") => {
13492
13582
  if (!session) return;
13493
13583
  clearOnboardingTimers();
@@ -13610,14 +13700,18 @@ function NativeSSOPage({
13610
13700
  overflow: "hidden"
13611
13701
  }, children: /* @__PURE__ */ jsx(AppsLogoSlider, { iamApiUrl, speed: "normal" }) }) })
13612
13702
  ] }) });
13703
+ if (redirectingTarget) {
13704
+ return /* @__PURE__ */ jsxs("div", { style: containerStyle, children: [
13705
+ /* @__PURE__ */ jsx(TopBranding, { subtitle: title }),
13706
+ /* @__PURE__ */ jsx(SliderBadge, {}),
13707
+ /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { padding: "2rem 1.5rem 1.5rem", textAlign: "center" }, children: [
13708
+ /* @__PURE__ */ jsx("h2", { style: { fontSize: "1.25rem", fontWeight: 600, color: COLORS.cardForeground }, children: redirectingReason === "logout" ? "Déconnexion réussie" : redirectingReason === "already-authenticated" ? "Session déjà valide" : "Connexion réussie" }),
13709
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", color: COLORS.muted, marginTop: "0.5rem" }, children: "Redirection en cours..." })
13710
+ ] }) }),
13711
+ /* @__PURE__ */ jsx(Footer, { hideFooter })
13712
+ ] });
13713
+ }
13613
13714
  if (session) {
13614
- if (redirectAfterLogin) {
13615
- safeRedirect(redirectAfterLogin);
13616
- return /* @__PURE__ */ jsxs("div", { style: containerStyle, children: [
13617
- /* @__PURE__ */ jsx(TopBranding, { subtitle: title }),
13618
- /* @__PURE__ */ jsx("p", { style: { color: "rgba(255,255,255,0.7)", fontSize: "0.875rem" }, children: "Redirection en cours..." })
13619
- ] });
13620
- }
13621
13715
  return /* @__PURE__ */ jsxs("div", { style: containerStyle, children: [
13622
13716
  /* @__PURE__ */ jsx(TopBranding, { subtitle: title }),
13623
13717
  /* @__PURE__ */ jsx(SliderBadge, {}),