@rixl/sdk 0.8.3 → 0.9.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
@@ -1,7 +1,6 @@
1
1
  import { atom } from "nanostores";
2
2
  import { decodeJwt } from "jose";
3
3
  import * as v from "valibot";
4
- import "ky";
5
4
 
6
5
  //#region src/generated/core/bodySerializer.gen.ts
7
6
  const jsonBodySerializer = { bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value) };
@@ -352,9 +351,7 @@ const setAuthParams = async ({ security, ...options }) => {
352
351
  case "cookie":
353
352
  options.headers.append("Cookie", `${name}=${token}`);
354
353
  break;
355
- default:
356
- options.headers.set(name, token);
357
- break;
354
+ default: options.headers.set(name, token);
358
355
  }
359
356
  }
360
357
  };
@@ -515,9 +512,7 @@ const createClient = (config = {}) => {
515
512
  case "stream":
516
513
  emptyData = response.body;
517
514
  break;
518
- default:
519
- emptyData = {};
520
- break;
515
+ default: emptyData = {};
521
516
  }
522
517
  return opts.responseStyle === "data" ? emptyData : {
523
518
  data: emptyData,
@@ -746,6 +741,35 @@ const analyticsV1DashboardServiceGetDashboardStats = (options) => (options.clien
746
741
  ...options
747
742
  });
748
743
  /**
744
+ * QueryChart
745
+ */
746
+ const analyticsV1DashboardServiceQueryChart = (options) => (options.client ?? client).post({
747
+ url: "/analytics/v1/dashboard/chart-query",
748
+ ...options,
749
+ headers: {
750
+ "Content-Type": "application/json",
751
+ ...options.headers
752
+ }
753
+ });
754
+ /**
755
+ * ListDatasets
756
+ */
757
+ const analyticsV1DashboardServiceListDatasets = (options) => (options?.client ?? client).get({
758
+ url: "/analytics/v1/dashboard/datasets",
759
+ ...options
760
+ });
761
+ /**
762
+ * GetFilterOptions
763
+ */
764
+ const analyticsV1DashboardServiceGetFilterOptions = (options) => (options.client ?? client).post({
765
+ url: "/analytics/v1/dashboard/filter-options",
766
+ ...options,
767
+ headers: {
768
+ "Content-Type": "application/json",
769
+ ...options.headers
770
+ }
771
+ });
772
+ /**
749
773
  * TrackEvents
750
774
  */
751
775
  const analyticsV1EventsServiceTrackEvents = (options) => (options.client ?? client).post({
@@ -2295,6 +2319,15 @@ function validateOAuthState(provider, state) {
2295
2319
  return sessionStorage.getItem(storagePath(provider)) === state;
2296
2320
  }
2297
2321
  /**
2322
+ * Discards the stored state for a provider so the next login round-trip mints a
2323
+ * fresh one. The state doubles as the OAuth `nonce`, so reusing it across logins
2324
+ * would replay a nonce the provider has already issued a token for.
2325
+ * @param provider The provider identifier
2326
+ */
2327
+ function clearOauthState(provider) {
2328
+ sessionStorage.removeItem(storagePath(provider));
2329
+ }
2330
+ /**
2298
2331
  * Gets or Generates a complete state parameter for OAuth requests
2299
2332
  * @param provider The identifier for the provider (e.g., 'google', 'apple')
2300
2333
  * @returns A state string containing the provider identifier and random data
@@ -2318,9 +2351,10 @@ function generateOauthState(provider) {
2318
2351
  * Builds an OAuth URL from configuration and metadata
2319
2352
  */
2320
2353
  const buildOAuthUrl = (config, metadata, state) => {
2354
+ const redirectUri = config.redirectUri ?? window.location.origin;
2321
2355
  const params = new URLSearchParams({
2322
2356
  client_id: config.clientId,
2323
- redirect_uri: window.location.origin,
2357
+ redirect_uri: redirectUri,
2324
2358
  response_type: metadata.responseType,
2325
2359
  scope: [...metadata.defaultScopes, ...config.scope ? [config.scope] : []].join(" "),
2326
2360
  state
@@ -2343,8 +2377,8 @@ const warnProviderNotConfigured = (providerName) => {
2343
2377
  * This factory reduces code duplication across OAuth providers
2344
2378
  */
2345
2379
  const createOAuthProvider = ({ provider, metadata }) => {
2346
- const config = atom(null);
2347
- const authUrl = atom(null);
2380
+ const config = shared(`provider.${provider}.config`, () => atom(null));
2381
+ const authUrl = shared(`provider.${provider}.authUrl`, () => atom(null));
2348
2382
  const updateAuthUrl = () => {
2349
2383
  const currentConfig = config.get();
2350
2384
  if (!currentConfig) {
@@ -2420,8 +2454,8 @@ const updateAppleAuthUrl = appleProvider.updateAuthUrl;
2420
2454
 
2421
2455
  //#endregion
2422
2456
  //#region src/auth/providers/telegram.ts
2423
- const telegramConfig = atom(null);
2424
- const telegramAuthUrl = atom(null);
2457
+ const telegramConfig = shared("provider.telegram.config", () => atom(null));
2458
+ const telegramAuthUrl = shared("provider.telegram.authUrl", () => atom(null));
2425
2459
  /**
2426
2460
  * Updates the Telegram authentication URL using the configured settings
2427
2461
  */
@@ -2454,7 +2488,7 @@ function extractProviderFromState(state) {
2454
2488
  const parts = state.split("_");
2455
2489
  if (parts.length >= 1) return parts[0];
2456
2490
  }
2457
- const OAUTH_PROVIDERS = [
2491
+ const OAUTH_PROVIDERS$1 = [
2458
2492
  "google",
2459
2493
  "apple",
2460
2494
  "microsoft"
@@ -2470,7 +2504,7 @@ function detectProvider() {
2470
2504
  const state = urlParams.get("state");
2471
2505
  if (id_token && state) {
2472
2506
  const providerFromState = extractProviderFromState(state);
2473
- return OAUTH_PROVIDERS.find((p) => providerFromState === p && validateOAuthState(p, state));
2507
+ return OAUTH_PROVIDERS$1.find((p) => providerFromState === p && validateOAuthState(p, state));
2474
2508
  }
2475
2509
  }
2476
2510
  /**
@@ -2484,20 +2518,210 @@ function getProviderToken(provider) {
2484
2518
  }
2485
2519
 
2486
2520
  //#endregion
2487
- //#region src/auth/api/refresh-tokens.ts
2488
- const refreshTokens = async (provider, token, options) => {
2489
- const { data } = await authV1TokenServiceRefreshToken({
2490
- body: {
2521
+ //#region src/auth/providers/callback.ts
2522
+ /** Params that carry the credential itself their presence marks a callback response. */
2523
+ const CREDENTIAL_PARAMS = [
2524
+ "id_token",
2525
+ "code",
2526
+ "access_token",
2527
+ "tgAuthResult",
2528
+ "tgWebAppData"
2529
+ ];
2530
+ /** Everything the providers append to the redirect URL, credential and bookkeeping alike. */
2531
+ const OAUTH_RESPONSE_PARAMS = [
2532
+ ...CREDENTIAL_PARAMS,
2533
+ "state",
2534
+ "token_type",
2535
+ "expires_in",
2536
+ "scope",
2537
+ "session_state",
2538
+ "authuser",
2539
+ "prompt",
2540
+ "hd"
2541
+ ];
2542
+ /**
2543
+ * Whether the URL this page loaded with carries a provider response at all —
2544
+ * unlike `detectProvider()`, this does not require the state to validate. The
2545
+ * gap between the two is the case where a login round-trip came back but cannot
2546
+ * be used, which otherwise ends the flow in silence.
2547
+ */
2548
+ const hasProviderResponse = () => CREDENTIAL_PARAMS.some((key) => urlParams.has(key));
2549
+ const AUTH_URL_UPDATERS = {
2550
+ ["google"]: updateGoogleAuthUrl,
2551
+ ["apple"]: updateAppleAuthUrl,
2552
+ ["microsoft"]: updateMicrosoftAuthUrl
2553
+ };
2554
+ /** Returns undefined when the half holds no credential, meaning it is the app's own and must not be touched. */
2555
+ const stripped = (query) => {
2556
+ const params = new URLSearchParams(query);
2557
+ if (!CREDENTIAL_PARAMS.some((key) => params.has(key))) return void 0;
2558
+ OAUTH_RESPONSE_PARAMS.forEach((key) => params.delete(key));
2559
+ return params.toString();
2560
+ };
2561
+ /**
2562
+ * Providers put their response in the query string or the fragment depending on
2563
+ * `response_mode`, and either half may also hold params the app itself put
2564
+ * there. Only the half actually carrying the credential is rewritten.
2565
+ */
2566
+ const withoutOAuthResponse = (href) => {
2567
+ const url = new URL(href);
2568
+ url.search = stripped(url.search) ?? url.search;
2569
+ url.hash = stripped(url.hash.slice(1)) ?? url.hash;
2570
+ return url.toString();
2571
+ };
2572
+ /**
2573
+ * Retires the provider response after `initClient` is done with it.
2574
+ *
2575
+ * Left in place, the credential stays in the address bar and every reload — or
2576
+ * Vite's HMR full reload — replays an already-consumed `id_token`, which the
2577
+ * gateway rejects. Clearing the stored state on the way out also stops the next
2578
+ * login from reusing this round-trip's `nonce`.
2579
+ *
2580
+ * The `urlParams` snapshot is taken at import time and is intentionally left
2581
+ * untouched, so callers that already read the credential out of it keep working
2582
+ * for the rest of this page load.
2583
+ */
2584
+ const completeOAuthCallback = () => {
2585
+ const provider = detectProvider();
2586
+ if (!provider) return;
2587
+ clearOauthState(provider);
2588
+ AUTH_URL_UPDATERS[provider]?.();
2589
+ window.history.replaceState(window.history.state, "", withoutOAuthResponse(window.location.href));
2590
+ };
2591
+
2592
+ //#endregion
2593
+ //#region src/auth/api/types.ts
2594
+ /**
2595
+ * Generic API error class - wraps ky's HTTPError for consistency
2596
+ */
2597
+ var ApiError = class extends Error {
2598
+ status;
2599
+ endpoint;
2600
+ data;
2601
+ constructor(message, ...rest) {
2602
+ super(message);
2603
+ this.name = "ApiError";
2604
+ const firstArg = rest[0];
2605
+ if (typeof firstArg === "number") {
2606
+ this.status = firstArg;
2607
+ this.endpoint = rest[1] ?? "";
2608
+ this.data = rest[2];
2609
+ return;
2610
+ }
2611
+ this.status = firstArg.status;
2612
+ this.endpoint = firstArg.endpoint;
2613
+ this.data = firstArg.data;
2614
+ }
2615
+ };
2616
+
2617
+ //#endregion
2618
+ //#region src/auth/providers/diagnostics.ts
2619
+ const claimsOf = (token) => {
2620
+ try {
2621
+ const { iss, aud, exp, nonce, email } = decodeJwt(token);
2622
+ return {
2623
+ iss: String(iss ?? ""),
2624
+ aud: String(aud ?? ""),
2625
+ exp: exp ? (/* @__PURE__ */ new Date(Number(exp) * 1e3)).toISOString() : void 0,
2626
+ expired: typeof exp === "number" && Date.now() >= exp * 1e3,
2627
+ nonce: String(nonce ?? ""),
2628
+ email: String(email ?? "")
2629
+ };
2630
+ } catch {
2631
+ return { note: "not a JWT — expected for Telegram, unexpected for Google/Apple/Microsoft" };
2632
+ }
2633
+ };
2634
+ const verdictFor = (error) => {
2635
+ if ((typeof error.data === "object" && error.data !== null ? error.data : void 0)?.error === "invalid token type") return "CLIENT: the gateway does not accept this token_type. Expected one of Bearer, google, apple, microsoft, tgAuthResult, tgWebAppData.";
2636
+ if (error.status === HTTP_STATUS.UNAUTHORIZED) return "BACKEND or CONFIG: the gateway could not verify the credential. Compare `aud` above with the client ID the gateway is configured with, and check `expired`.";
2637
+ if (error.status === HTTP_STATUS.CONFLICT) return "EXPECTED: this email already belongs to an account created with a different provider.";
2638
+ if (error.status === HTTP_STATUS.BAD_REQUEST) return "BACKEND: the gateway rejected the request body. Read `response.body` for its reason.";
2639
+ return "UNKNOWN: see `response` below.";
2640
+ };
2641
+ const describe = (error) => {
2642
+ if (!(error instanceof ApiError)) return {
2643
+ response: {
2644
+ status: "none — the request never completed",
2645
+ detail: String(error)
2646
+ },
2647
+ verdict: "NETWORK or CORS: the browser never got a response. Check the gateway is reachable and its CORS headers allow this origin."
2648
+ };
2649
+ return {
2650
+ response: {
2651
+ status: error.status,
2652
+ body: error.data,
2653
+ message: error.message
2654
+ },
2655
+ verdict: verdictFor(error)
2656
+ };
2657
+ };
2658
+ const OAUTH_PROVIDERS = [
2659
+ "google",
2660
+ "apple",
2661
+ "microsoft"
2662
+ ];
2663
+ const storedStates = () => Object.fromEntries(OAUTH_PROVIDERS.map((p) => [p, sessionStorage.getItem("__rixl_auth_state_" + p) ?? "(none)"]));
2664
+ /**
2665
+ * Reports a provider response that arrived but could not be used, which ends the
2666
+ * login without a request ever being sent — the case that otherwise looks like
2667
+ * "it just went back to the login page".
2668
+ *
2669
+ * `detectProvider()` requires the `state` in the URL to equal the one stored when
2670
+ * the login started, so the two states below are the thing to compare.
2671
+ */
2672
+ const logUnusableProviderResponse = () => {
2673
+ const state = urlParams.get("state") ?? "(none)";
2674
+ console.error("[@rixl/sdk] a provider response is in the URL but no login was attempted", {
2675
+ urlState: state,
2676
+ storedStates: storedStates(),
2677
+ credentialParams: [
2678
+ "id_token",
2679
+ "code",
2680
+ "access_token"
2681
+ ].filter((key) => urlParams.has(key)),
2682
+ verdict: state === "(none)" ? "CLIENT: the provider returned no `state`, so the response cannot be matched to a login attempt." : "CLIENT: `urlState` does not match the stored state for its provider. sessionStorage was cleared, the login started in a different tab, or the response was replayed after the state had already been retired."
2683
+ });
2684
+ };
2685
+ /**
2686
+ * Reports a failed provider token exchange. `provider` doubles as the `token_type`
2687
+ * sent on the wire, so it is printed as-is.
2688
+ */
2689
+ const logProviderExchangeFailure = (provider, credential, error) => {
2690
+ console.error("[@rixl/sdk] provider login failed at POST /auth/v1/token", {
2691
+ request: {
2491
2692
  token_type: provider,
2492
- refresh_token: token,
2493
- country_code: options?.countryCode,
2494
- origin: options?.origin
2693
+ credential: claimsOf(credential)
2495
2694
  },
2496
- throwOnError: true
2695
+ ...describe(error)
2497
2696
  });
2498
- return data;
2499
2697
  };
2500
2698
 
2699
+ //#endregion
2700
+ //#region src/auth/social/socialState.ts
2701
+ const socialStoragePath = (provider) => SOCIAL_CONNECT_KEY_PREFIX + provider;
2702
+ /**
2703
+ * Sets a flag indicating that a social provider connection is being attempted
2704
+ * @param provider The provider identifier
2705
+ */
2706
+ function setSocialConnectAttempt(provider) {
2707
+ sessionStorage.setItem(socialStoragePath(provider), "true");
2708
+ }
2709
+ /**
2710
+ * Checks if there's a pending social provider connection attempt
2711
+ * @param provider The provider identifier
2712
+ * @returns True if there's a pending connection attempt, false otherwise
2713
+ */
2714
+ function hasSocialConnectAttempt(provider) {
2715
+ return sessionStorage.getItem(socialStoragePath(provider)) === "true";
2716
+ }
2717
+ /**
2718
+ * Clears the social provider connection attempt flag
2719
+ * @param provider The provider identifier
2720
+ */
2721
+ function clearSocialConnectAttempt(provider) {
2722
+ sessionStorage.removeItem(socialStoragePath(provider));
2723
+ }
2724
+
2501
2725
  //#endregion
2502
2726
  //#region src/auth/initialization.ts
2503
2727
  /**
@@ -2517,520 +2741,80 @@ function createDeferred() {
2517
2741
  };
2518
2742
  }
2519
2743
  /**
2520
- * Global deferred promise that tracks the initialization status of the auth library
2521
- * This is resolved when initClient is called
2744
+ * Global deferred promise that tracks the initialization status of the auth library.
2745
+ * This is resolved when initClient is called.
2746
+ *
2747
+ * Shared across copies of this package. `connect()` runs in exactly one copy, so
2748
+ * a per-copy deferred leaves every other copy awaiting a promise nothing will
2749
+ * ever resolve — and because getToken() and the request interceptor both await
2750
+ * it, that is not a slow path but a permanent hang.
2522
2751
  */
2523
- const initDeferred = createDeferred();
2752
+ const initDeferred = shared("initDeferred", createDeferred);
2524
2753
 
2525
2754
  //#endregion
2526
- //#region src/auth/cookie/util.ts
2527
- const getAllCookiesStartWith = (startWithKey) => {
2528
- if (typeof document === "undefined") return {};
2529
- return document.cookie.split(";").map((cv) => cv.split("=").map((v) => v.trim())).filter(([key]) => key && key !== startWithKey && key.startsWith(startWithKey)).reduce((ac, [key, value]) => Object.assign(ac, { [key.slice(startWithKey.length + 1)]: value }), {});
2755
+ //#region src/auth/api/error-handlers.ts
2756
+ /**
2757
+ * Helper to create error functions - reduces bundle size by reusing error creation logic
2758
+ */
2759
+ const err = (message) => () => new Error(message);
2760
+ /** Reusable error handlers for common cases - reduces repetitive error messages */
2761
+ const commonErrors = {
2762
+ unauthorized: err("User is not authorized"),
2763
+ badRequest: err("Bad request"),
2764
+ notFound: err("Not found"),
2765
+ conflict: err("Resource already exists"),
2766
+ forbidden: err("Forbidden"),
2767
+ tooManyRequests: err("Too many requests")
2530
2768
  };
2531
- function setCookie(name, value, options) {
2532
- if (typeof document === "undefined") return;
2533
- let cookieString = `${encodeName(name)}=${encodeValue(value)}`;
2534
- if (options) {
2535
- if (options.expires) if (typeof options.expires === "number") {
2536
- const date = /* @__PURE__ */ new Date();
2537
- date.setTime(date.getTime() + options.expires * 24 * 60 * 60 * 1e3);
2538
- cookieString += `; expires=${date.toUTCString()}`;
2539
- } else cookieString += `; expires=${options.expires.toUTCString()}`;
2540
- if (options.path) cookieString += `; path=${options.path}`;
2541
- if (options.domain) cookieString += `; domain=${options.domain}`;
2542
- if (options.secure) cookieString += `; secure`;
2543
- if (options.sameSite) cookieString += `; samesite=${options.sameSite}`;
2769
+ /**
2770
+ * Standard error handler for API errors with custom status code handling
2771
+ */
2772
+ const handleApiError = (error, statusHandlers) => {
2773
+ if (error instanceof ApiError) {
2774
+ const handler = statusHandlers[error.status];
2775
+ if (handler) throw new ApiError(handler().message, error.status, error.endpoint, error.data);
2776
+ throw error;
2544
2777
  }
2545
- document.cookie = cookieString;
2546
- }
2547
- function deleteCookie(name) {
2548
- if (typeof document === "undefined") return;
2549
- document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
2550
- }
2551
- const encodeName = (name) => encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent);
2552
- const encodeValue = (value) => encodeURIComponent(value).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, decodeURIComponent);
2778
+ throw error;
2779
+ };
2553
2780
 
2554
2781
  //#endregion
2555
- //#region src/auth/cookie/index.ts
2556
- const initVals = getAllCookiesStartWith(GLOBAL_PREFIX);
2557
- const setStoreCookie = (key, value) => {
2558
- const expires = /* @__PURE__ */ new Date();
2559
- expires.setTime(expires.getTime() + 30 * 24 * 60 * 60 * 1e3);
2560
- const cookieKey = `${GLOBAL_PREFIX}_${key}`;
2561
- if (!value || value === "") {
2562
- deleteCookie(cookieKey);
2563
- return;
2782
+ //#region src/auth/api/utils.ts
2783
+ /**
2784
+ * Generic helper for API calls to handle initialization and error handling
2785
+ * @param fn The async function to execute
2786
+ * @param errorMap A map of status codes to error functions
2787
+ * @returns The result of the function execution
2788
+ */
2789
+ const apiCall = async (fn, errorMap = {}) => {
2790
+ await initDeferred.promise;
2791
+ try {
2792
+ return await fn();
2793
+ } catch (error) {
2794
+ return handleApiError(error, errorMap);
2564
2795
  }
2565
- const stringValue = typeof value === "string" ? value : JSON.stringify(value);
2566
- setCookie(`${GLOBAL_PREFIX}_${key}`, stringValue, {
2567
- expires,
2568
- path: "/",
2569
- sameSite: "Lax"
2570
- });
2571
2796
  };
2572
2797
 
2573
2798
  //#endregion
2574
- //#region src/auth/userStore.ts
2575
- const userPath = GLOBAL_PREFIX + "_user";
2576
- const parseUser = () => {
2577
- if (typeof localStorage === "undefined" || !localStorage || typeof localStorage.getItem !== "function") return;
2578
- const value = localStorage.getItem(userPath);
2579
- if (value && value != "undefined") try {
2580
- return JSON.parse(value);
2581
- } catch (err) {
2582
- console.warn("Can't parse user data, error: ", err);
2583
- return;
2799
+ //#region src/auth/api/tokens.ts
2800
+ function persistTokens(data) {
2801
+ const tokens = data ?? {};
2802
+ if (tokens.access_token && tokens.refresh_token && tokens.expires_in) {
2803
+ setTokens(tokens.access_token, tokens.refresh_token, Number(tokens.expires_in));
2804
+ return true;
2584
2805
  }
2585
- };
2586
- const user = shared("user", () => {
2587
- const store = atom(parseUser());
2588
- store.subscribe((value) => {
2589
- if (typeof localStorage === "undefined" || !localStorage || typeof localStorage.setItem !== "function") return;
2590
- if (value) localStorage.setItem(userPath, JSON.stringify(value));
2591
- else localStorage.removeItem(userPath);
2592
- });
2593
- return store;
2594
- });
2806
+ return false;
2807
+ }
2595
2808
 
2596
2809
  //#endregion
2597
- //#region src/auth/utils/jwt.ts
2810
+ //#region src/auth/validation/base.ts
2598
2811
  /**
2599
- * Decodes a JWT token and extracts user information
2600
- * Uses jose library for modern, secure JWT handling
2601
- * @param token The JWT token to decode
2602
- * @returns The decoded user data or undefined if decoding fails
2812
+ * 🛡️ INPUT VALIDATION UTILITY
2813
+ * Validates data before API calls and throws user-friendly errors
2603
2814
  */
2604
- const decodeToken = (token) => {
2815
+ const validateInput = (schema, data) => {
2605
2816
  try {
2606
- const decodedUser = decodeJwt(token);
2607
- return {
2608
- id: decodedUser.id,
2609
- email: decodedUser.email,
2610
- first_name: decodedUser.first_name,
2611
- last_name: decodedUser.last_name,
2612
- username: decodedUser.username,
2613
- image_url: decodedUser.image_url,
2614
- language_code: decodedUser.language_code,
2615
- org_id: decodedUser.org_id
2616
- };
2617
- } catch (error) {
2618
- console.warn("Failed to decode JWT token. Error: ", error);
2619
- return;
2620
- }
2621
- };
2622
- /**
2623
- * Decodes a JWT token and sets the user in the store
2624
- * @param token The JWT token to decode
2625
- * @returns True if user was successfully decoded and set, false otherwise
2626
- */
2627
- const decodeAndSetUser = (token) => {
2628
- const userData = decodeToken(token);
2629
- if (userData) {
2630
- user.set(userData);
2631
- return true;
2632
- }
2633
- return false;
2634
- };
2635
- /**
2636
- * Checks if a token is expired based on the expiration timestamp
2637
- * @param expireAt The expiration timestamp in milliseconds
2638
- * @returns True if the token is expired, false otherwise
2639
- */
2640
- const isTokenExpired = (expireAt) => {
2641
- if (!expireAt) return true;
2642
- return Date.now() >= expireAt;
2643
- };
2644
-
2645
- //#endregion
2646
- //#region src/auth/authStore.ts
2647
- const isLogged = shared("isLogged", () => atom(initVals["isLogged"] === "true" || detectProvider() !== void 0));
2648
- const accessToken = shared("accessToken", () => atom(initVals["accessToken"]));
2649
- const refreshToken = shared("refreshToken", () => atom(initVals["refreshToken"]));
2650
- const expireAt = shared("expireAt", () => atom(Number(initVals["expireAt"])));
2651
- const authError = shared("authError", () => atom(null));
2652
- const requiresAction = shared("requiresAction", () => atom(initVals["requiresAction"] || null));
2653
- const limitedAccessToken = shared("limitedAccessToken", () => atom(initVals["limitedAccessToken"] || null));
2654
- let currentTokenPromise = null;
2655
- const PROVIDER_URL_MAP = {
2656
- google: googleAuthUrl,
2657
- apple: appleAuthUrl,
2658
- microsoft: microsoftAuthUrl,
2659
- telegram: telegramAuthUrl
2660
- };
2661
- const login = async (provider) => {
2662
- await initDeferred.promise;
2663
- const authUrlAtom = PROVIDER_URL_MAP[provider];
2664
- if (!authUrlAtom) throw new Error(`Unsupported provider: ${provider}`);
2665
- const authUrl = authUrlAtom.get();
2666
- if (authUrl) window.location.href = authUrl;
2667
- else throw new Error(`${provider} provider is not configured. Please check your initClient configuration.`);
2668
- };
2669
- const refreshAccessToken = async (refresh) => {
2670
- const result = await refreshTokens("Bearer", refresh);
2671
- if (!("requires_action" in result)) setTokens(result.access_token, result.refresh_token, result.expires_in);
2672
- };
2673
- const ensureValidAccessToken = async (refresh) => {
2674
- if (accessToken.get() && !isTokenExpired(expireAt.get())) return;
2675
- try {
2676
- await refreshAccessToken(refresh);
2677
- } catch (refreshError) {
2678
- console.error("Token refresh failed in getToken:", refreshError);
2679
- removeTokens();
2680
- throw refreshError;
2681
- }
2682
- };
2683
- const getToken = async () => {
2684
- if (currentTokenPromise) return currentTokenPromise;
2685
- currentTokenPromise = (async () => {
2686
- try {
2687
- await initDeferred.promise;
2688
- if (requiresAction.get()) return void 0;
2689
- const currentRefreshToken = refreshToken.get();
2690
- if (!currentRefreshToken) return void 0;
2691
- await ensureValidAccessToken(currentRefreshToken);
2692
- const token = accessToken.get();
2693
- if (token) decodeAndSetUser(token);
2694
- return token;
2695
- } catch (error) {
2696
- console.warn("Failed to getToken(). Error: ", error);
2697
- throw error;
2698
- } finally {
2699
- currentTokenPromise = null;
2700
- }
2701
- })();
2702
- return currentTokenPromise;
2703
- };
2704
- /**
2705
- * Sets authentication tokens in the store
2706
- * @param access The access token
2707
- * @param refresh The refresh token
2708
- * @param expiresIn The token expiration time in seconds
2709
- */
2710
- const setTokens = (access, refresh, expiresIn) => {
2711
- accessToken.set(access);
2712
- refreshToken.set(refresh);
2713
- expireAt.set(Date.now() + expiresIn * 1e3);
2714
- isLogged.set(true);
2715
- limitedAccessToken.set(null);
2716
- requiresAction.set(null);
2717
- authError.set(null);
2718
- decodeAndSetUser(access);
2719
- };
2720
- /**
2721
- * Removes authentication tokens from the store
2722
- */
2723
- const removeTokens = () => {
2724
- accessToken.set("");
2725
- refreshToken.set("");
2726
- expireAt.set(0);
2727
- isLogged.set(false);
2728
- user.set(void 0);
2729
- limitedAccessToken.set(null);
2730
- requiresAction.set(null);
2731
- authError.set(null);
2732
- };
2733
- /**
2734
- * Clears the auth error from the store
2735
- */
2736
- const clearAuthError = () => {
2737
- authError.set(null);
2738
- };
2739
- /**
2740
- * Sets limited access state for users requiring additional action (e.g., Telegram users without email)
2741
- * @param token The limited scope access token
2742
- * @param action The required action (e.g., "add_email")
2743
- */
2744
- const setLimitedAccessState = (token, action) => {
2745
- limitedAccessToken.set(token);
2746
- requiresAction.set(action);
2747
- authError.set(null);
2748
- isLogged.set(true);
2749
- };
2750
- /**
2751
- * Clears the limited access state (after email verification completes or user logs out)
2752
- */
2753
- const clearLimitedAccessState = () => {
2754
- limitedAccessToken.set(null);
2755
- requiresAction.set(null);
2756
- if (!(!!accessToken.get() && !!refreshToken.get())) isLogged.set(false);
2757
- };
2758
- isLogged.subscribe((value) => setStoreCookie("isLogged", value));
2759
- accessToken.subscribe((value) => setStoreCookie("accessToken", value));
2760
- refreshToken.subscribe((value) => setStoreCookie("refreshToken", value));
2761
- expireAt.subscribe((value) => setStoreCookie("expireAt", value));
2762
- requiresAction.subscribe((value) => setStoreCookie("requiresAction", value));
2763
- limitedAccessToken.subscribe((value) => setStoreCookie("limitedAccessToken", value));
2764
-
2765
- //#endregion
2766
- //#region src/auth/api/types.ts
2767
- /**
2768
- * Generic API error class - wraps ky's HTTPError for consistency
2769
- */
2770
- var ApiError = class extends Error {
2771
- status;
2772
- endpoint;
2773
- data;
2774
- constructor(message, ...rest) {
2775
- super(message);
2776
- this.name = "ApiError";
2777
- const firstArg = rest[0];
2778
- if (typeof firstArg === "number") {
2779
- this.status = firstArg;
2780
- this.endpoint = rest[1] ?? "";
2781
- this.data = rest[2];
2782
- return;
2783
- }
2784
- this.status = firstArg.status;
2785
- this.endpoint = firstArg.endpoint;
2786
- this.data = firstArg.data;
2787
- }
2788
- };
2789
-
2790
- //#endregion
2791
- //#region src/auth/api-url.ts
2792
- /**
2793
- * Global API base URL store
2794
- */
2795
- const apiURL = shared("apiURL", () => atom(""));
2796
-
2797
- //#endregion
2798
- //#region src/auth/api/sdk-client.ts
2799
- function isWireErrorBody(error) {
2800
- return typeof error === "object" && error !== null;
2801
- }
2802
- const state = shared("sdkClientState", () => ({
2803
- configured: false,
2804
- tokenResolver: getToken
2805
- }));
2806
- function setTokenResolver(resolver) {
2807
- state.tokenResolver = resolver;
2808
- }
2809
- /**
2810
- * Routes that do not require a Bearer token at the gateway edge. These
2811
- * authenticate via credentials in the request body (or are webhooks verified by
2812
- * signature), so attaching an Authorization header here would make the gateway
2813
- * attempt to validate a stale/absent token and reject the request with 401.
2814
- * Mirrors `publicRoutes` in backend/gateway/internal/routes/routes.go.
2815
- */
2816
- const publicRoutes = [
2817
- {
2818
- method: "POST",
2819
- path: "/auth/v1/token"
2820
- },
2821
- {
2822
- method: "POST",
2823
- path: "/auth/v1/register"
2824
- },
2825
- {
2826
- method: "POST",
2827
- path: "/auth/v1/login"
2828
- },
2829
- {
2830
- method: "POST",
2831
- path: "/auth/v1/email/verify"
2832
- },
2833
- {
2834
- method: "POST",
2835
- path: "/auth/v1/email/verify/resend"
2836
- },
2837
- {
2838
- method: "POST",
2839
- path: "/auth/v1/password/reset"
2840
- },
2841
- {
2842
- method: "POST",
2843
- path: "/auth/v1/password/reset/confirm"
2844
- },
2845
- {
2846
- method: "POST",
2847
- path: "/auth/v1/verify-totp"
2848
- },
2849
- {
2850
- method: "POST",
2851
- path: "/auth/v1/verify-passkey"
2852
- },
2853
- {
2854
- method: "POST",
2855
- path: "/auth/v1/invitations/",
2856
- prefix: true
2857
- },
2858
- {
2859
- method: "POST",
2860
- path: "/auth/v1/passkey/login/begin"
2861
- },
2862
- {
2863
- method: "POST",
2864
- path: "/auth/v1/passkey/login/finish"
2865
- },
2866
- {
2867
- method: "POST",
2868
- path: "/auth/v1/logout"
2869
- },
2870
- {
2871
- method: "POST",
2872
- path: "/auth/v1/blog/unsubscribe/email"
2873
- },
2874
- {
2875
- method: "POST",
2876
- path: "/auth/v1/blog/broadcast"
2877
- },
2878
- {
2879
- method: "GET",
2880
- path: "/media/v1/videos/",
2881
- prefix: true
2882
- },
2883
- {
2884
- method: "GET",
2885
- path: "/media/v1/images/",
2886
- prefix: true
2887
- },
2888
- {
2889
- method: "GET",
2890
- path: "/media/v1/languages"
2891
- },
2892
- {
2893
- method: "GET",
2894
- path: "/posts/v1/feeds/",
2895
- prefix: true
2896
- },
2897
- {
2898
- method: "POST",
2899
- path: "/billing/webhooks/stripe"
2900
- },
2901
- {
2902
- method: "POST",
2903
- path: "/webhooks/storage"
2904
- },
2905
- {
2906
- method: "POST",
2907
- path: "/platform/auth/v1/token"
2908
- },
2909
- {
2910
- method: "POST",
2911
- path: "/platform/auth/v1/refresh"
2912
- }
2913
- ];
2914
- function isPublicRoute(method, pathname) {
2915
- const match = method.toUpperCase();
2916
- return publicRoutes.some(({ method: m, path, prefix }) => match === m && (prefix ? pathname.startsWith(path) : pathname === path));
2917
- }
2918
- function configureSdkClient() {
2919
- if (state.configured) return;
2920
- state.configured = true;
2921
- configureAllClients(apiURL.get());
2922
- apiURL.subscribe((url) => {
2923
- configureAllClients(url);
2924
- });
2925
- addClientInitializer((client) => {
2926
- client.interceptors.request.use(async (request) => {
2927
- if (request.headers.has("Authorization")) return request;
2928
- const { pathname } = new URL(request.url);
2929
- if (isPublicRoute(request.method, pathname)) return request;
2930
- const token = await state.tokenResolver();
2931
- if (!token) throw new ApiError("No access token available for an authenticated request", HTTP_STATUS.UNAUTHORIZED, pathname);
2932
- request.headers.set("Authorization", `Bearer ${token}`);
2933
- return request;
2934
- });
2935
- client.interceptors.error.use((error, response, request) => {
2936
- if (error instanceof Error) return error;
2937
- const body = isWireErrorBody(error) ? error : void 0;
2938
- const status = response?.status ?? body?.code ?? 0;
2939
- return new ApiError(body?.error || body?.details || (typeof error === "string" ? error : "Request failed"), status, request ? new URL(request.url).pathname : "", error);
2940
- });
2941
- });
2942
- }
2943
-
2944
- //#endregion
2945
- //#region src/auth/social/socialState.ts
2946
- const socialStoragePath = (provider) => SOCIAL_CONNECT_KEY_PREFIX + provider;
2947
- /**
2948
- * Sets a flag indicating that a social provider connection is being attempted
2949
- * @param provider The provider identifier
2950
- */
2951
- function setSocialConnectAttempt(provider) {
2952
- sessionStorage.setItem(socialStoragePath(provider), "true");
2953
- }
2954
- /**
2955
- * Checks if there's a pending social provider connection attempt
2956
- * @param provider The provider identifier
2957
- * @returns True if there's a pending connection attempt, false otherwise
2958
- */
2959
- function hasSocialConnectAttempt(provider) {
2960
- return sessionStorage.getItem(socialStoragePath(provider)) === "true";
2961
- }
2962
- /**
2963
- * Clears the social provider connection attempt flag
2964
- * @param provider The provider identifier
2965
- */
2966
- function clearSocialConnectAttempt(provider) {
2967
- sessionStorage.removeItem(socialStoragePath(provider));
2968
- }
2969
-
2970
- //#endregion
2971
- //#region src/auth/api/error-handlers.ts
2972
- /**
2973
- * Helper to create error functions - reduces bundle size by reusing error creation logic
2974
- */
2975
- const err = (message) => () => new Error(message);
2976
- /** Reusable error handlers for common cases - reduces repetitive error messages */
2977
- const commonErrors = {
2978
- unauthorized: err("User is not authorized"),
2979
- badRequest: err("Bad request"),
2980
- notFound: err("Not found"),
2981
- conflict: err("Resource already exists"),
2982
- forbidden: err("Forbidden"),
2983
- tooManyRequests: err("Too many requests")
2984
- };
2985
- /**
2986
- * Standard error handler for API errors with custom status code handling
2987
- */
2988
- const handleApiError = (error, statusHandlers) => {
2989
- if (error instanceof ApiError) {
2990
- const handler = statusHandlers[error.status];
2991
- if (handler) throw new ApiError(handler().message, error.status, error.endpoint, error.data);
2992
- throw error;
2993
- }
2994
- throw error;
2995
- };
2996
-
2997
- //#endregion
2998
- //#region src/auth/api/utils.ts
2999
- /**
3000
- * Generic helper for API calls to handle initialization and error handling
3001
- * @param fn The async function to execute
3002
- * @param errorMap A map of status codes to error functions
3003
- * @returns The result of the function execution
3004
- */
3005
- const apiCall = async (fn, errorMap = {}) => {
3006
- await initDeferred.promise;
3007
- try {
3008
- return await fn();
3009
- } catch (error) {
3010
- return handleApiError(error, errorMap);
3011
- }
3012
- };
3013
-
3014
- //#endregion
3015
- //#region src/auth/api/tokens.ts
3016
- function persistTokens(data) {
3017
- const tokens = data ?? {};
3018
- if (tokens.access_token && tokens.refresh_token && tokens.expires_in) {
3019
- setTokens(tokens.access_token, tokens.refresh_token, Number(tokens.expires_in));
3020
- return true;
3021
- }
3022
- return false;
3023
- }
3024
-
3025
- //#endregion
3026
- //#region src/auth/validation/base.ts
3027
- /**
3028
- * 🛡️ INPUT VALIDATION UTILITY
3029
- * Validates data before API calls and throws user-friendly errors
3030
- */
3031
- const validateInput = (schema, data) => {
3032
- try {
3033
- return v.parse(schema, data);
2817
+ return v.parse(schema, data);
3034
2818
  } catch (error) {
3035
2819
  if (error instanceof v.ValiError) {
3036
2820
  const firstError = error.issues[0];
@@ -3140,55 +2924,491 @@ const listSocials = async () => {
3140
2924
  });
3141
2925
  }, { [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to list providers!") });
3142
2926
  };
3143
- const connectSocialInternal = async (provider, token) => {
3144
- return apiCall(async () => {
3145
- const requestBody = validateInput(ConnectProviderSchema, {
3146
- provider,
3147
- token
3148
- });
3149
- const { data } = await authV1ProvidersServiceConnectProvider({
3150
- body: {
3151
- provider: toProtoProvider(normalizeProviderType(requestBody.provider)),
3152
- token: requestBody.token
3153
- },
3154
- throwOnError: true
3155
- });
3156
- persistTokens(data);
3157
- }, { [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to connect provider!") });
2927
+ const connectSocialInternal = async (provider, token) => {
2928
+ return apiCall(async () => {
2929
+ const requestBody = validateInput(ConnectProviderSchema, {
2930
+ provider,
2931
+ token
2932
+ });
2933
+ const sessionToken = await getToken();
2934
+ const headers = sessionToken ? { Authorization: `Bearer ${sessionToken}` } : {};
2935
+ const { data } = await authV1ProvidersServiceConnectProvider({
2936
+ body: {
2937
+ provider: toProtoProvider(normalizeProviderType(requestBody.provider)),
2938
+ token: requestBody.token
2939
+ },
2940
+ headers,
2941
+ throwOnError: true
2942
+ });
2943
+ persistTokens(data);
2944
+ }, { [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to connect provider!") });
2945
+ };
2946
+ const disconnectSocial = async (provider) => {
2947
+ return apiCall(async () => {
2948
+ await authV1ProvidersServiceDisconnectProvider({
2949
+ path: { provider: toProtoProvider(provider) },
2950
+ throwOnError: true
2951
+ });
2952
+ }, {
2953
+ [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to disconnect provider!"),
2954
+ [HTTP_STATUS.NOT_FOUND]: () => /* @__PURE__ */ new Error("Provider not found!"),
2955
+ [HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Cannot disconnect the last social provider!")
2956
+ });
2957
+ };
2958
+ const connectSocial = (provider) => {
2959
+ setSocialConnectAttempt(provider);
2960
+ login(provider);
2961
+ };
2962
+
2963
+ //#endregion
2964
+ //#region src/auth/api/refresh-tokens.ts
2965
+ /**
2966
+ * Exchange a provider credential for a Rixl session, or refresh an existing
2967
+ * Rixl session with a Bearer refresh token.
2968
+ *
2969
+ * - For `AuthProvider.BEARER`, the call hits `/auth/v1/token` with the stored
2970
+ * Rixl refresh token.
2971
+ * - For OAuth/Telegram providers, the call hits `/auth/v1/providers/connect`
2972
+ * with the provider's `id_token` or Telegram payload. The wire `provider`
2973
+ * value is the `auth.v1.ExternalAccountProvider` enum (e.g.
2974
+ * `EXTERNAL_ACCOUNT_PROVIDER_GOOGLE`), not the short SDK name.
2975
+ */
2976
+ const refreshTokens = async (provider, token, options) => {
2977
+ if (provider === "Bearer") {
2978
+ const { data } = await authV1TokenServiceRefreshToken({
2979
+ body: {
2980
+ token_type: "Bearer",
2981
+ refresh_token: token,
2982
+ country_code: options?.countryCode,
2983
+ origin: options?.origin
2984
+ },
2985
+ throwOnError: true
2986
+ });
2987
+ return data;
2988
+ }
2989
+ const requestProvider = normalizeProviderType(provider);
2990
+ const { data } = await authV1ProvidersServiceConnectProvider({
2991
+ body: {
2992
+ provider: toProtoProvider(requestProvider),
2993
+ token,
2994
+ country_code: options?.countryCode,
2995
+ origin: options?.origin
2996
+ },
2997
+ throwOnError: true
2998
+ });
2999
+ return data;
3000
+ };
3001
+
3002
+ //#endregion
3003
+ //#region src/auth/cookie/util.ts
3004
+ const splitOnFirstEquals = (pair) => {
3005
+ const trimmed = pair.trim();
3006
+ const separator = trimmed.indexOf("=");
3007
+ return separator === -1 ? [trimmed, ""] : [trimmed.slice(0, separator), trimmed.slice(separator + 1).trim()];
3008
+ };
3009
+ const getAllCookiesStartWith = (startWithKey) => {
3010
+ if (typeof document === "undefined") return {};
3011
+ return document.cookie.split(";").map(splitOnFirstEquals).filter(([key]) => key && key !== startWithKey && key.startsWith(startWithKey)).reduce((ac, [key, value]) => Object.assign(ac, { [key.slice(startWithKey.length + 1)]: value }), {});
3012
+ };
3013
+ function setCookie(name, value, options) {
3014
+ if (typeof document === "undefined") return;
3015
+ let cookieString = `${encodeName(name)}=${encodeValue(value)}`;
3016
+ if (options) {
3017
+ if (options.expires) if (typeof options.expires === "number") {
3018
+ const date = /* @__PURE__ */ new Date();
3019
+ date.setTime(date.getTime() + options.expires * 24 * 60 * 60 * 1e3);
3020
+ cookieString += `; expires=${date.toUTCString()}`;
3021
+ } else cookieString += `; expires=${options.expires.toUTCString()}`;
3022
+ if (options.path) cookieString += `; path=${options.path}`;
3023
+ if (options.domain) cookieString += `; domain=${options.domain}`;
3024
+ if (options.secure) cookieString += `; secure`;
3025
+ if (options.sameSite) cookieString += `; samesite=${options.sameSite}`;
3026
+ }
3027
+ document.cookie = cookieString;
3028
+ }
3029
+ function deleteCookie(name) {
3030
+ if (typeof document === "undefined") return;
3031
+ document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
3032
+ }
3033
+ const encodeName = (name) => encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent);
3034
+ const encodeValue = (value) => encodeURIComponent(value).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, decodeURIComponent);
3035
+
3036
+ //#endregion
3037
+ //#region src/auth/cookie/index.ts
3038
+ const initVals = getAllCookiesStartWith(GLOBAL_PREFIX);
3039
+ const setStoreCookie = (key, value) => {
3040
+ const expires = /* @__PURE__ */ new Date();
3041
+ expires.setTime(expires.getTime() + 30 * 24 * 60 * 60 * 1e3);
3042
+ const cookieKey = `${GLOBAL_PREFIX}_${key}`;
3043
+ if (!value || value === "") {
3044
+ deleteCookie(cookieKey);
3045
+ return;
3046
+ }
3047
+ const stringValue = typeof value === "string" ? value : JSON.stringify(value);
3048
+ setCookie(`${GLOBAL_PREFIX}_${key}`, stringValue, {
3049
+ expires,
3050
+ path: "/",
3051
+ sameSite: "Lax"
3052
+ });
3053
+ };
3054
+
3055
+ //#endregion
3056
+ //#region src/auth/userStore.ts
3057
+ const userPath = GLOBAL_PREFIX + "_user";
3058
+ const parseUser = () => {
3059
+ if (typeof localStorage === "undefined" || !localStorage || typeof localStorage.getItem !== "function") return;
3060
+ const value = localStorage.getItem(userPath);
3061
+ if (value && value != "undefined") try {
3062
+ return JSON.parse(value);
3063
+ } catch (err) {
3064
+ console.warn("Can't parse user data, error: ", err);
3065
+ return;
3066
+ }
3067
+ };
3068
+ const user = shared("user", () => {
3069
+ const store = atom(parseUser());
3070
+ store.subscribe((value) => {
3071
+ if (typeof localStorage === "undefined" || !localStorage || typeof localStorage.setItem !== "function") return;
3072
+ if (value) localStorage.setItem(userPath, JSON.stringify(value));
3073
+ else localStorage.removeItem(userPath);
3074
+ });
3075
+ return store;
3076
+ });
3077
+
3078
+ //#endregion
3079
+ //#region src/auth/utils/jwt.ts
3080
+ /**
3081
+ * Decodes a JWT token and extracts user information
3082
+ * Uses jose library for modern, secure JWT handling
3083
+ * @param token The JWT token to decode
3084
+ * @returns The decoded user data or undefined if decoding fails
3085
+ */
3086
+ const decodeToken = (token) => {
3087
+ try {
3088
+ const decodedUser = decodeJwt(token);
3089
+ return {
3090
+ id: decodedUser.id,
3091
+ email: decodedUser.email,
3092
+ first_name: decodedUser.first_name,
3093
+ last_name: decodedUser.last_name,
3094
+ username: decodedUser.username,
3095
+ image_url: decodedUser.image_url,
3096
+ language_code: decodedUser.language_code,
3097
+ org_id: decodedUser.org_id
3098
+ };
3099
+ } catch (error) {
3100
+ console.warn("Failed to decode JWT token. Error: ", error);
3101
+ return;
3102
+ }
3103
+ };
3104
+ /**
3105
+ * Decodes a JWT token and sets the user in the store
3106
+ * @param token The JWT token to decode
3107
+ * @returns True if user was successfully decoded and set, false otherwise
3108
+ */
3109
+ const decodeAndSetUser = (token) => {
3110
+ const userData = decodeToken(token);
3111
+ if (userData) {
3112
+ user.set(userData);
3113
+ return true;
3114
+ }
3115
+ return false;
3116
+ };
3117
+ /**
3118
+ * Checks if a token is expired based on the expiration timestamp
3119
+ * @param expireAt The expiration timestamp in milliseconds
3120
+ * @returns True if the token is expired, false otherwise
3121
+ */
3122
+ const isTokenExpired = (expireAt) => {
3123
+ if (!expireAt) return true;
3124
+ return Date.now() >= expireAt;
3125
+ };
3126
+
3127
+ //#endregion
3128
+ //#region src/auth/authStore.ts
3129
+ const isLogged = shared("isLogged", () => atom(initVals["isLogged"] === "true"));
3130
+ const accessToken = shared("accessToken", () => atom(initVals["accessToken"]));
3131
+ const refreshToken = shared("refreshToken", () => atom(initVals["refreshToken"]));
3132
+ const expireAt = shared("expireAt", () => atom(Number(initVals["expireAt"])));
3133
+ const authError = shared("authError", () => atom(null));
3134
+ const requiresAction = shared("requiresAction", () => atom(initVals["requiresAction"] || null));
3135
+ const limitedAccessToken = shared("limitedAccessToken", () => atom(initVals["limitedAccessToken"] || null));
3136
+ const inFlight = shared("getTokenPromise", () => ({ promise: null }));
3137
+ const PROVIDER_URL_MAP = {
3138
+ google: googleAuthUrl,
3139
+ apple: appleAuthUrl,
3140
+ microsoft: microsoftAuthUrl,
3141
+ telegram: telegramAuthUrl
3142
+ };
3143
+ const login = async (provider) => {
3144
+ await initDeferred.promise;
3145
+ const authUrlAtom = PROVIDER_URL_MAP[provider];
3146
+ if (!authUrlAtom) throw new Error(`Unsupported provider: ${provider}`);
3147
+ const authUrl = authUrlAtom.get();
3148
+ if (authUrl) window.location.href = authUrl;
3149
+ else throw new Error(`${provider} provider is not configured. Please check your initClient configuration.`);
3150
+ };
3151
+ const refreshAccessToken = async (refresh) => {
3152
+ const result = await refreshTokens("Bearer", refresh);
3153
+ if (!("requires_action" in result)) setTokens(result.access_token, result.refresh_token, result.expires_in);
3154
+ };
3155
+ const ensureValidAccessToken = async (refresh) => {
3156
+ if (accessToken.get() && !isTokenExpired(expireAt.get())) return;
3157
+ try {
3158
+ await refreshAccessToken(refresh);
3159
+ } catch (refreshError) {
3160
+ console.error("Token refresh failed in getToken:", refreshError);
3161
+ removeTokens();
3162
+ throw refreshError;
3163
+ }
3164
+ };
3165
+ const getToken = async () => {
3166
+ if (inFlight.promise) return inFlight.promise;
3167
+ inFlight.promise = (async () => {
3168
+ try {
3169
+ await initDeferred.promise;
3170
+ if (requiresAction.get()) return void 0;
3171
+ const currentRefreshToken = refreshToken.get();
3172
+ if (!currentRefreshToken) return void 0;
3173
+ await ensureValidAccessToken(currentRefreshToken);
3174
+ const token = accessToken.get();
3175
+ if (token) decodeAndSetUser(token);
3176
+ return token;
3177
+ } catch (error) {
3178
+ console.warn("Failed to getToken(). Error: ", error);
3179
+ throw error;
3180
+ } finally {
3181
+ inFlight.promise = null;
3182
+ }
3183
+ })();
3184
+ return inFlight.promise;
3185
+ };
3186
+ /**
3187
+ * Sets authentication tokens in the store
3188
+ * @param access The access token
3189
+ * @param refresh The refresh token
3190
+ * @param expiresIn The token expiration time in seconds
3191
+ */
3192
+ const setTokens = (access, refresh, expiresIn) => {
3193
+ accessToken.set(access);
3194
+ refreshToken.set(refresh);
3195
+ expireAt.set(Date.now() + expiresIn * 1e3);
3196
+ isLogged.set(true);
3197
+ limitedAccessToken.set(null);
3198
+ requiresAction.set(null);
3199
+ authError.set(null);
3200
+ decodeAndSetUser(access);
3201
+ };
3202
+ /**
3203
+ * Removes authentication tokens from the store
3204
+ */
3205
+ const removeTokens = () => {
3206
+ accessToken.set("");
3207
+ refreshToken.set("");
3208
+ expireAt.set(0);
3209
+ isLogged.set(false);
3210
+ user.set(void 0);
3211
+ limitedAccessToken.set(null);
3212
+ requiresAction.set(null);
3213
+ authError.set(null);
3158
3214
  };
3159
- const disconnectSocial = async (provider) => {
3160
- return apiCall(async () => {
3161
- await authV1ProvidersServiceDisconnectProvider({
3162
- path: { provider: toProtoProvider(provider) },
3163
- throwOnError: true
3164
- });
3165
- }, {
3166
- [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to disconnect provider!"),
3167
- [HTTP_STATUS.NOT_FOUND]: () => /* @__PURE__ */ new Error("Provider not found!"),
3168
- [HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Cannot disconnect the last social provider!")
3169
- });
3215
+ /**
3216
+ * Clears the auth error from the store
3217
+ */
3218
+ const clearAuthError = () => {
3219
+ authError.set(null);
3170
3220
  };
3171
- const connectSocial = (provider) => {
3172
- setSocialConnectAttempt(provider);
3173
- login(provider);
3221
+ /**
3222
+ * Sets limited access state for users requiring additional action (e.g., Telegram users without email)
3223
+ * @param token The limited scope access token
3224
+ * @param action The required action (e.g., "add_email")
3225
+ */
3226
+ const setLimitedAccessState = (token, action) => {
3227
+ limitedAccessToken.set(token);
3228
+ requiresAction.set(action);
3229
+ authError.set(null);
3230
+ isLogged.set(true);
3174
3231
  };
3232
+ /**
3233
+ * Clears the limited access state (after email verification completes or user logs out)
3234
+ */
3235
+ const clearLimitedAccessState = () => {
3236
+ limitedAccessToken.set(null);
3237
+ requiresAction.set(null);
3238
+ if (!(!!accessToken.get() && !!refreshToken.get())) isLogged.set(false);
3239
+ };
3240
+ isLogged.subscribe((value) => setStoreCookie("isLogged", value));
3241
+ accessToken.subscribe((value) => setStoreCookie("accessToken", value));
3242
+ refreshToken.subscribe((value) => setStoreCookie("refreshToken", value));
3243
+ expireAt.subscribe((value) => setStoreCookie("expireAt", value));
3244
+ requiresAction.subscribe((value) => setStoreCookie("requiresAction", value));
3245
+ limitedAccessToken.subscribe((value) => setStoreCookie("limitedAccessToken", value));
3175
3246
 
3176
3247
  //#endregion
3177
- //#region src/auth/api/client-core.ts
3178
- let tokenRefreshFunction = null;
3248
+ //#region src/auth/api-url.ts
3179
3249
  /**
3180
- * Sets the token refresh function used by the API client
3181
- * This should be called during initialization
3250
+ * Global API base URL store
3182
3251
  */
3183
- const setTokenRefreshFunction = (fn) => {
3184
- tokenRefreshFunction = fn ?? null;
3185
- };
3252
+ const apiURL = shared("apiURL", () => atom(""));
3253
+
3254
+ //#endregion
3255
+ //#region src/auth/api/sdk-client.ts
3256
+ function isWireErrorBody(error) {
3257
+ return typeof error === "object" && error !== null;
3258
+ }
3259
+ const state = shared("sdkClientState", () => ({
3260
+ configured: false,
3261
+ tokenResolver: getToken
3262
+ }));
3263
+ function setTokenResolver(resolver) {
3264
+ state.tokenResolver = resolver;
3265
+ }
3266
+ /**
3267
+ * Routes that do not require a Bearer token at the gateway edge. These
3268
+ * authenticate via credentials in the request body (or are webhooks verified by
3269
+ * signature), so attaching an Authorization header here would make the gateway
3270
+ * attempt to validate a stale/absent token and reject the request with 401.
3271
+ * Mirrors `publicRoutes` in backend/gateway/internal/routes/routes.go.
3272
+ */
3273
+ const publicRoutes = [
3274
+ {
3275
+ method: "POST",
3276
+ path: "/auth/v1/token"
3277
+ },
3278
+ {
3279
+ method: "POST",
3280
+ path: "/auth/v1/register"
3281
+ },
3282
+ {
3283
+ method: "POST",
3284
+ path: "/auth/v1/login"
3285
+ },
3286
+ {
3287
+ method: "POST",
3288
+ path: "/auth/v1/email/verify"
3289
+ },
3290
+ {
3291
+ method: "POST",
3292
+ path: "/auth/v1/email/verify/resend"
3293
+ },
3294
+ {
3295
+ method: "POST",
3296
+ path: "/auth/v1/password/reset"
3297
+ },
3298
+ {
3299
+ method: "POST",
3300
+ path: "/auth/v1/password/reset/confirm"
3301
+ },
3302
+ {
3303
+ method: "POST",
3304
+ path: "/auth/v1/verify-totp"
3305
+ },
3306
+ {
3307
+ method: "POST",
3308
+ path: "/auth/v1/verify-passkey"
3309
+ },
3310
+ {
3311
+ method: "POST",
3312
+ path: "/auth/v1/invitations/",
3313
+ prefix: true
3314
+ },
3315
+ {
3316
+ method: "POST",
3317
+ path: "/auth/v1/passkey/login/begin"
3318
+ },
3319
+ {
3320
+ method: "POST",
3321
+ path: "/auth/v1/passkey/login/finish"
3322
+ },
3323
+ {
3324
+ method: "POST",
3325
+ path: "/auth/v1/logout"
3326
+ },
3327
+ {
3328
+ method: "POST",
3329
+ path: "/auth/v1/providers/connect"
3330
+ },
3331
+ {
3332
+ method: "POST",
3333
+ path: "/auth/v1/blog/unsubscribe/email"
3334
+ },
3335
+ {
3336
+ method: "POST",
3337
+ path: "/auth/v1/blog/broadcast"
3338
+ },
3339
+ {
3340
+ method: "GET",
3341
+ path: "/media/v1/videos/",
3342
+ prefix: true
3343
+ },
3344
+ {
3345
+ method: "GET",
3346
+ path: "/media/v1/images/",
3347
+ prefix: true
3348
+ },
3349
+ {
3350
+ method: "GET",
3351
+ path: "/media/v1/languages"
3352
+ },
3353
+ {
3354
+ method: "GET",
3355
+ path: "/posts/v1/feeds/",
3356
+ prefix: true
3357
+ },
3358
+ {
3359
+ method: "POST",
3360
+ path: "/billing/webhooks/stripe"
3361
+ },
3362
+ {
3363
+ method: "POST",
3364
+ path: "/webhooks/storage"
3365
+ },
3366
+ {
3367
+ method: "POST",
3368
+ path: "/platform/auth/v1/token"
3369
+ },
3370
+ {
3371
+ method: "POST",
3372
+ path: "/platform/auth/v1/refresh"
3373
+ }
3374
+ ];
3375
+ function isPublicRoute(method, pathname) {
3376
+ const match = method.toUpperCase();
3377
+ return publicRoutes.some(({ method: m, path, prefix }) => match === m && (prefix ? pathname.startsWith(path) : pathname === path));
3378
+ }
3379
+ function configureSdkClient() {
3380
+ if (state.configured) return;
3381
+ state.configured = true;
3382
+ configureAllClients(apiURL.get());
3383
+ apiURL.subscribe((url) => {
3384
+ configureAllClients(url);
3385
+ });
3386
+ addClientInitializer((client) => {
3387
+ client.interceptors.request.use(async (request) => {
3388
+ if (request.headers.has("Authorization")) return request;
3389
+ const { pathname } = new URL(request.url);
3390
+ if (isPublicRoute(request.method, pathname)) return request;
3391
+ const token = await state.tokenResolver();
3392
+ if (!token) throw new ApiError("No access token available for an authenticated request", HTTP_STATUS.UNAUTHORIZED, pathname);
3393
+ request.headers.set("Authorization", `Bearer ${token}`);
3394
+ return request;
3395
+ });
3396
+ client.interceptors.error.use((error, response, request) => {
3397
+ if (error instanceof Error) return error;
3398
+ const body = isWireErrorBody(error) ? error : void 0;
3399
+ const status = response?.status ?? body?.code ?? 0;
3400
+ const message = body?.error || body?.details || (typeof error === "string" ? error : "Request failed");
3401
+ const endpoint = request ? new URL(request.url).pathname : "";
3402
+ return new ApiError(message, status, endpoint, error);
3403
+ });
3404
+ });
3405
+ }
3186
3406
 
3187
3407
  //#endregion
3188
3408
  //#region src/auth/authConfig.ts
3189
- let loginRedirectUrl;
3409
+ const config = shared("authConfig", () => ({ loginRedirectUrl: void 0 }));
3190
3410
  const setLoginRedirectUrl = (url) => {
3191
- loginRedirectUrl = url;
3411
+ config.loginRedirectUrl = url;
3192
3412
  };
3193
3413
 
3194
3414
  //#endregion
@@ -3199,24 +3419,26 @@ const setLoginRedirectUrl = (url) => {
3199
3419
  * @returns A promise that resolves to the current access token (if available)
3200
3420
  */
3201
3421
  const initClient = async (config) => {
3202
- await initConfig(config);
3203
- await initPage();
3204
- initDeferred.resolve();
3205
- await initSocials();
3422
+ try {
3423
+ await runInitSequence(config);
3424
+ } finally {
3425
+ completeOAuthCallback();
3426
+ }
3206
3427
  return getToken();
3207
3428
  };
3429
+ const runInitSequence = async (config) => {
3430
+ try {
3431
+ await initConfig(config);
3432
+ await initPage();
3433
+ } finally {
3434
+ initDeferred.resolve();
3435
+ }
3436
+ await initSocials();
3437
+ };
3208
3438
  const initConfig = async (config) => {
3209
3439
  apiURL.set(config.apiUrl);
3210
3440
  configureSdkClient();
3211
3441
  setLoginRedirectUrl(config.loginRedirectUrl);
3212
- setTokenRefreshFunction(async () => {
3213
- const currentRefreshToken = refreshToken.get();
3214
- if (currentRefreshToken) {
3215
- const result = await refreshTokens("Bearer", currentRefreshToken);
3216
- if (result && !("requires_action" in result)) setTokens(result.access_token, result.refresh_token, result.expires_in);
3217
- return getToken();
3218
- }
3219
- });
3220
3442
  if (config.googleProvider) {
3221
3443
  googleConfig.set(config.googleProvider);
3222
3444
  updateGoogleAuthUrl();
@@ -3264,9 +3486,15 @@ const extractAuthErrorInfo = (error) => {
3264
3486
  };
3265
3487
  const handleInitPageApiError = (error) => {
3266
3488
  const info = extractAuthErrorInfo(error);
3267
- if (error.status === HTTP_STATUS.BAD_REQUEST && info.error === "invalid_grant") return setAuthErrorAndClear("email_not_verified", info.description, info.email);
3268
- if (error.status === HTTP_STATUS.CONFLICT) return setAuthErrorAndClear("provider_conflict", info.description, info.email);
3269
- return false;
3489
+ if (error.status === HTTP_STATUS.BAD_REQUEST && info.error === "invalid_grant") {
3490
+ setAuthErrorAndClear("email_not_verified", info.description, info.email);
3491
+ return;
3492
+ }
3493
+ if (error.status === HTTP_STATUS.CONFLICT) {
3494
+ setAuthErrorAndClear("provider_conflict", info.description, info.email);
3495
+ return;
3496
+ }
3497
+ setAuthErrorAndClear("provider_exchange_failed", info.error || info.description, info.email);
3270
3498
  };
3271
3499
  const exchangeProviderToken = async (provider, token) => {
3272
3500
  const result = await refreshTokens(provider, token);
@@ -3274,14 +3502,18 @@ const exchangeProviderToken = async (provider, token) => {
3274
3502
  };
3275
3503
  const initPage = async () => {
3276
3504
  const provider = detectProvider();
3277
- if (!provider) return void 0;
3505
+ if (!provider) {
3506
+ if (hasProviderResponse()) logUnusableProviderResponse();
3507
+ return;
3508
+ }
3278
3509
  const token = getProviderToken(provider);
3279
3510
  if (!token) return void 0;
3280
3511
  try {
3281
3512
  await exchangeProviderToken(provider, token);
3282
3513
  } catch (error) {
3283
- if (error instanceof ApiError && handleInitPageApiError(error)) return;
3284
- throw error;
3514
+ logProviderExchangeFailure(provider, token, error);
3515
+ if (!(error instanceof ApiError)) throw error;
3516
+ handleInitPageApiError(error);
3285
3517
  }
3286
3518
  };
3287
3519
  const initSocials = async () => {
@@ -3705,8 +3937,9 @@ const getUserInfo = async (userId) => {
3705
3937
  };
3706
3938
  const updateFullName = async (fullName) => {
3707
3939
  return apiCall(async () => {
3940
+ const validatedInput = validateInput(UpdateNameSchema, { full_name: fullName });
3708
3941
  await authV1UserServiceUpdateName({
3709
- body: validateInput(UpdateNameSchema, { full_name: fullName }),
3942
+ body: validatedInput,
3710
3943
  throwOnError: true
3711
3944
  });
3712
3945
  }, {
@@ -3717,8 +3950,9 @@ const updateFullName = async (fullName) => {
3717
3950
  };
3718
3951
  const updateUsername = async (username) => {
3719
3952
  return apiCall(async () => {
3953
+ const validatedInput = validateInput(UpdateUsernameSchema, { username });
3720
3954
  await authV1UserServiceUpdateUsername({
3721
- body: validateInput(UpdateUsernameSchema, { username }),
3955
+ body: validatedInput,
3722
3956
  throwOnError: true
3723
3957
  });
3724
3958
  }, {
@@ -3748,8 +3982,9 @@ const setupUserOTP = async () => {
3748
3982
  };
3749
3983
  const verifyUserOTP = async (code) => {
3750
3984
  return apiCall(async () => {
3985
+ const validatedBody = validateInput(VerifyOTPCodeSchema, { code });
3751
3986
  const { data } = await authV1OtpServiceVerifyOtp({
3752
- body: validateInput(VerifyOTPCodeSchema, { code }),
3987
+ body: validatedBody,
3753
3988
  throwOnError: true
3754
3989
  });
3755
3990
  persistTokens(data);
@@ -3832,11 +4067,12 @@ const loginWithEmail = async (email, password) => {
3832
4067
  };
3833
4068
  const verifyTOTPForLogin = async (code, session_id) => {
3834
4069
  return apiCall(async () => {
4070
+ const validatedInput = validateInput(LoginOTPVerifyRequestSchema, {
4071
+ code,
4072
+ session_id
4073
+ });
3835
4074
  const { data } = await authV1OtpServiceVerifyTotpForLogin({
3836
- body: validateInput(LoginOTPVerifyRequestSchema, {
3837
- code,
3838
- session_id
3839
- }),
4075
+ body: validatedInput,
3840
4076
  throwOnError: true
3841
4077
  });
3842
4078
  persistTokens(data);
@@ -3887,13 +4123,14 @@ function isApiErrorBody(error) {
3887
4123
  //#region src/auth/auth/register.ts
3888
4124
  const registerWithEmail = async (email, password, subscribeToBlog, countryCode) => {
3889
4125
  return apiCall(async () => {
4126
+ const validatedInput = validateInput(RegisterRequestSchema, {
4127
+ email,
4128
+ password,
4129
+ country_code: countryCode,
4130
+ subscribe_to_blog: subscribeToBlog
4131
+ });
3890
4132
  const { data } = await authV1EmailServiceRegister({
3891
- body: validateInput(RegisterRequestSchema, {
3892
- email,
3893
- password,
3894
- country_code: countryCode,
3895
- subscribe_to_blog: subscribeToBlog
3896
- }),
4133
+ body: validatedInput,
3897
4134
  throwOnError: true
3898
4135
  });
3899
4136
  if (data.verification_id) return {
@@ -3906,8 +4143,9 @@ const registerWithEmail = async (email, password, subscribeToBlog, countryCode)
3906
4143
  };
3907
4144
  const resendEmailVerificationCode = async (email) => {
3908
4145
  return apiCall(async () => {
4146
+ const validatedInput = validateInput(ResendEmailRequestSchema, { email });
3909
4147
  const { data } = await authV1EmailServiceResendVerification({
3910
- body: validateInput(ResendEmailRequestSchema, { email }),
4148
+ body: validatedInput,
3911
4149
  throwOnError: true
3912
4150
  });
3913
4151
  if (data.verification_id) return {
@@ -3925,19 +4163,21 @@ const resendEmailVerificationCode = async (email) => {
3925
4163
  //#region src/auth/auth/password.ts
3926
4164
  const sendPasswordResetEmail = async (email) => {
3927
4165
  return apiCall(async () => {
4166
+ const validatedInput = validateInput(ResendEmailRequestSchema, { email });
3928
4167
  await authV1EmailServiceSendPasswordReset({
3929
- body: validateInput(ResendEmailRequestSchema, { email }),
4168
+ body: validatedInput,
3930
4169
  throwOnError: true
3931
4170
  });
3932
4171
  }, { [HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Bad request - invalid email or validation error") });
3933
4172
  };
3934
4173
  const confirmPasswordReset = async (token, password) => {
3935
4174
  return apiCall(async () => {
4175
+ const validatedInput = validateInput(ResetPasswordRequestSchema, {
4176
+ token,
4177
+ new_password: password
4178
+ });
3936
4179
  await authV1EmailServiceResetPassword({
3937
- body: validateInput(ResetPasswordRequestSchema, {
3938
- token,
3939
- new_password: password
3940
- }),
4180
+ body: validatedInput,
3941
4181
  throwOnError: true
3942
4182
  });
3943
4183
  }, { [HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Bad request - invalid token or password") });
@@ -3947,8 +4187,9 @@ const confirmPasswordReset = async (token, password) => {
3947
4187
  //#region src/auth/auth/email.ts
3948
4188
  const initiateEmailChange = async (email) => {
3949
4189
  return apiCall(async () => {
4190
+ const validatedInput = validateInput(ChangeEmailRequestSchema, { new_email: email });
3950
4191
  const { data } = await authV1EmailServiceInitiateEmailChange({
3951
- body: validateInput(ChangeEmailRequestSchema, { new_email: email }),
4192
+ body: validatedInput,
3952
4193
  throwOnError: true
3953
4194
  });
3954
4195
  if (data.verification_id) return {
@@ -3965,8 +4206,9 @@ const initiateEmailChange = async (email) => {
3965
4206
  };
3966
4207
  const addEmail = async (email) => {
3967
4208
  return apiCall(async () => {
4209
+ const validatedInput = validateInput(ResendEmailRequestSchema, { email });
3968
4210
  const { data } = await authV1EmailServiceAddEmail({
3969
- body: validateInput(ResendEmailRequestSchema, { email }),
4211
+ body: validatedInput,
3970
4212
  throwOnError: true
3971
4213
  });
3972
4214
  if (data.verification_id) return {
@@ -4260,10 +4502,11 @@ function serializeRegistrationCredential(cred) {
4260
4502
  }
4261
4503
  const finishPasskeyLogin = async (session_id, credential) => {
4262
4504
  return apiCall(async () => {
4505
+ const serialized = serializeLoginCredential(credential);
4263
4506
  const { data } = await authV1PasskeyServicePasskeyLoginFinish({
4264
4507
  body: {
4265
4508
  session_id,
4266
- credential: serializeLoginCredential(credential)
4509
+ credential: serialized
4267
4510
  },
4268
4511
  throwOnError: true
4269
4512
  });
@@ -4303,11 +4546,12 @@ const beginPasskeyRegistration = async () => {
4303
4546
  };
4304
4547
  const finishPasskeyRegistration = async (session_id, name, credential) => {
4305
4548
  return apiCall(async () => {
4549
+ const serialized = serializeRegistrationCredential(credential);
4306
4550
  const { data } = await authV1PasskeyServicePasskeyRegisterFinish({
4307
4551
  body: {
4308
4552
  session_id,
4309
4553
  name,
4310
- credential: serializeRegistrationCredential(credential)
4554
+ credential: serialized
4311
4555
  },
4312
4556
  throwOnError: true
4313
4557
  });
@@ -4354,10 +4598,11 @@ const listPasskeys = async () => {
4354
4598
  };
4355
4599
  const verifyPasskeyForLogin = async (session_id, credential) => {
4356
4600
  return apiCall(async () => {
4601
+ const serialized = serializeLoginCredential(credential);
4357
4602
  const { data } = await authV1PasskeyServiceVerifyPasskeyForLogin({
4358
4603
  body: {
4359
4604
  session_id,
4360
- credential: serializeLoginCredential(credential)
4605
+ credential: serialized
4361
4606
  },
4362
4607
  throwOnError: true
4363
4608
  });
@@ -4370,5 +4615,5 @@ const verifyPasskeyForLogin = async (session_id, credential) => {
4370
4615
  };
4371
4616
 
4372
4617
  //#endregion
4373
- export { DomainStatus, MembershipRole, MembershipState, PasskeyUnavailableError, addEmail, analyticsV1DashboardServiceGetDashboardStats, analyticsV1EventsServiceTrackEvents, analyticsV1FeedsServiceGetFeedStats, analyticsV1FeedsServiceGetTopFeeds, analyticsV1FunnelsServiceGetFunnelAnalytics, analyticsV1FunnelsServiceGetRetentionAnalytics, analyticsV1HeatmapServiceGetHotSegments, analyticsV1HeatmapServiceGetVideoHeatmap, analyticsV1PostsServiceGetPostStats, analyticsV1PostsServiceGetTopPosts, analyticsV1RealtimeServiceGetRealtimeStats, analyticsV1VideosServiceGetTopVideos, analyticsV1VideosServiceGetVideoStats, apikeysV1ApiKeyServiceCreateApiKey, apikeysV1ApiKeyServiceDeleteApiKey, apikeysV1ApiKeyServiceListApiKeys, apikeysV1ApiKeyServiceRotateApiKey, authError, authV1BlogServiceGetBlogSubscription, authV1BlogServiceSendBlogBroadcast, authV1BlogServiceSubscribeBlog, authV1BlogServiceUnsubscribeBlog, authV1BlogServiceUnsubscribeBlogByEmail, authV1DomainServiceCheckDomainVerification, authV1DomainServiceCreateDomainVerification, authV1DomainServiceGetDomainAutoJoin, authV1DomainServiceGetDomainStatus, authV1DomainServiceRemoveDomain, authV1DomainServiceSetDomainAutoJoin, authV1EmailServiceAddEmail, authV1EmailServiceGetUserEmailStatus, authV1EmailServiceInitiateEmailChange, authV1EmailServiceLogin, authV1EmailServiceRegister, authV1EmailServiceResendVerification, authV1EmailServiceResetPassword, authV1EmailServiceSendPasswordReset, authV1EmailServiceVerifyEmail, authV1MembershipServiceAcceptInvitation, authV1MembershipServiceCancelInvitation, authV1MembershipServiceCheckMembership, authV1MembershipServiceDeclineInvitation, authV1MembershipServiceGetInternalMembershipInfo, authV1MembershipServiceInviteMember, authV1MembershipServiceLeaveOrganization, authV1MembershipServiceListMembershipApplications, authV1MembershipServiceListMemberships, authV1MembershipServiceListOrganizationMembers, authV1MembershipServiceReactivateMember, authV1MembershipServiceRemoveMember, authV1MembershipServiceResendInvitation, authV1MembershipServiceSuspendMember, authV1MembershipServiceUpdateActiveMembership, authV1MembershipServiceUpdateMemberRole, authV1MembershipServiceUpdateMembershipState, authV1MembershipServiceUpdateOrgName, authV1MembershipServiceUpdateOrgUsername, authV1OtpServiceDeleteOtp, authV1OtpServiceGetOtpStatus, authV1OtpServiceSetupOtp, authV1OtpServiceVerifyOtp, authV1OtpServiceVerifyTotpForLogin, authV1PasskeyServiceDeletePasskey, authV1PasskeyServiceListPasskeys, authV1PasskeyServicePasskeyLoginBegin, authV1PasskeyServicePasskeyLoginFinish, authV1PasskeyServicePasskeyRegisterBegin, authV1PasskeyServicePasskeyRegisterFinish, authV1PasskeyServiceRenamePasskey, authV1PasskeyServiceVerifyPasskeyForLogin, authV1PolicyServiceAttachPolicy, authV1PolicyServiceCreatePolicy, authV1PolicyServiceDeletePolicy, authV1PolicyServiceDetachPolicy, authV1PolicyServiceGetPolicy, authV1PolicyServiceListPermissionRegistry, authV1PolicyServiceListPolicies, authV1PolicyServiceListPolicyAttachments, authV1PolicyServiceListUserPolicies, authV1PolicyServiceUpdatePolicy, authV1ProvidersServiceConnectProvider, authV1ProvidersServiceDisconnectProvider, authV1ProvidersServiceListProviders, authV1TokenServiceLogout, authV1TokenServiceRefreshToken, authV1UserServiceGetUser, authV1UserServiceGetUserInfo, authV1UserServiceUpdateName, authV1UserServiceUpdateUsername, beginPasskeyLogin, beginPasskeyRegistration, billingV1InvoiceServiceListInvoices, billingV1InvoiceServiceUpdateInvoiceStatus, billingV1PaymentServiceCalculateGenericTax, billingV1PaymentServiceCalculateTax, billingV1PaymentServiceCreateCheckoutSession, billingV1PaymentServiceCreateSetupIntent, billingV1PaymentServiceDeletePaymentMethod, billingV1PaymentServiceGetBillingAddress, billingV1PaymentServiceGetPaymentMethodFromPaymentIntent, billingV1PaymentServiceGetPaymentMethodFromSetupIntent, billingV1PaymentServiceListPaymentMethods, billingV1PaymentServiceUpgradeSubscription, billingV1PaymentServiceUpsertBillingAddress, billingV1PaymentServiceUpsertPaymentMethod, billingV1PlanServiceGetPlan, billingV1PlanServiceListPlans, billingV1SalesServiceContactSales, billingV1SubscriptionServiceCancelSubscription, billingV1SubscriptionServiceCreateSubscription, billingV1SubscriptionServiceGetSubscription, billingV1SubscriptionServiceGetSubscriptionHistory, billingV1SubscriptionServiceReactivateSubscription, billingV1UsageServiceGetBandwidthUsage, billingV1UsageServiceGetBandwidthUsageHistory, billingV1UsageServiceGetStorageUsage, billingV1UsageServiceGetStorageUsageHistory, billingV1UsageServiceRefreshBandwidthUsage, billingV1UsageServiceRefreshStorageUsage, checkDomainVerification, clearAuthError, clearLimitedAccessState, client, clientauthV1ClientCredentialServiceCreateClientCredential, clientauthV1ClientCredentialServiceListClientCredentials, clientauthV1ClientCredentialServiceMintClientToken, clientauthV1ClientCredentialServiceRevokeClientCredential, confirmPasswordReset, connect, connectSocial, createClient, decodeRequestOptions, deleteMember, deletePasskey, deleteUserOTP, disconnectSocial, feedsV1FeedServiceCreateFeed, feedsV1FeedServiceDeleteFeed, feedsV1FeedServiceGetFeed, feedsV1FeedServiceListFeeds, feedsV1FeedServiceUpdateFeed, finishPasskeyLogin, finishPasskeyRegistration, getBlogSubscriptionStatus, getDomainStatus, getEmailVerificationStatus, getOTPStatus, getToken, getUserInfo, imagesV1ImageConversionServiceMarkImageFailed, imagesV1ImageConversionServiceMarkImageProcessed, imagesV1ImageConversionServiceTakeUnprocessedImage, imagesV1ImageServiceCreateImageUpload, imagesV1ImageServiceDeleteImage, imagesV1ImageServiceGetImage, imagesV1ImageServiceListImages, imagesV1ImageServiceUpdateImageVisibility, initClient, initiateDomainVerification, initiateEmailChange, inviteMember, isLogged, leaveOrganization, limitedAccessToken, listActiveMemberships, listOrganizationMembers, listPasskeys, listPendingMemberships, listSocials, login, loginWithEmail, logout, platformauthV1PlatformAuthServiceExchangeApiKey, platformauthV1PlatformAuthServiceRefreshPlatformToken, postsV1PostServiceCreatePost, postsV1PostServiceCreatePostUpload, postsV1PostServiceDeletePost, postsV1PostServiceDeletePost2, postsV1PostServiceGetPost, postsV1PostServiceGetPost2, postsV1PostServiceGetPost3, postsV1PostServiceListPosts, postsV1PostServiceListPosts2, postsV1PostServiceListPosts3, postsV1PostServiceListPosts4, projectV1ProjectServiceCreateProject, projectV1ProjectServiceDeleteProject, projectV1ProjectServiceGetProject, projectV1ProjectServiceListProjects, projectV1ProjectServiceMoveProject, projectV1ProjectServiceRemoveCustomDomain, projectV1ProjectServiceSetCustomDomain, projectV1ProjectServiceUpdateProjectName, projectV1ProjectServiceUpdateVideoQuality, publicRespondToInvitation, registerWithEmail, removeDomain, renamePasskey, requiresAction, resendEmailVerificationCode, resendMemberInvite, respondToInvitation, sendPasswordResetEmail, setLimitedAccessState, setupUserOTP, subscribeToBlog, unsubscribeFromBlog, updateActiveMembership, updateAutoJoin, updateFullName, updateMemberRole, updateOrgName, updateOrgUsername, updateUsername, user, verifyEmailWithCode, verifyPasskeyForLogin, verifyTOTPForLogin, verifyUserOTP, videosV1AudioTrackServiceCreateAudioTrackUpload, videosV1AudioTrackServiceDeleteAllAudioTracks, videosV1AudioTrackServiceDeleteAudioTrack, videosV1AudioTrackServiceDeleteAudioTracksByLanguage, videosV1AudioTrackServiceListAudioTracks, videosV1ChapterServiceDeleteVideoChapter, videosV1ChapterServiceGetVideoChapters, videosV1ChapterServiceUpdateVideoChapters, videosV1LanguageServiceListLanguages, videosV1SubtitleServiceCreateSubtitleUpload, videosV1SubtitleServiceDeleteAllSubtitles, videosV1SubtitleServiceDeleteSubtitle, videosV1SubtitleServiceDeleteSubtitlesByLanguage, videosV1SubtitleServiceListSubtitles, videosV1VideoConversionServiceMarkVideoFailed, videosV1VideoConversionServiceMarkVideoProcessed, videosV1VideoServiceCreateVideoUpload, videosV1VideoServiceDeleteVideo, videosV1VideoServiceGetVideo, videosV1VideoServiceListVideos, videosV1VideoServiceUpdateVideoVisibility };
4618
+ export { DomainStatus, MembershipRole, MembershipState, PasskeyUnavailableError, addEmail, analyticsV1DashboardServiceGetDashboardStats, analyticsV1DashboardServiceGetFilterOptions, analyticsV1DashboardServiceListDatasets, analyticsV1DashboardServiceQueryChart, analyticsV1EventsServiceTrackEvents, analyticsV1FeedsServiceGetFeedStats, analyticsV1FeedsServiceGetTopFeeds, analyticsV1FunnelsServiceGetFunnelAnalytics, analyticsV1FunnelsServiceGetRetentionAnalytics, analyticsV1HeatmapServiceGetHotSegments, analyticsV1HeatmapServiceGetVideoHeatmap, analyticsV1PostsServiceGetPostStats, analyticsV1PostsServiceGetTopPosts, analyticsV1RealtimeServiceGetRealtimeStats, analyticsV1VideosServiceGetTopVideos, analyticsV1VideosServiceGetVideoStats, apikeysV1ApiKeyServiceCreateApiKey, apikeysV1ApiKeyServiceDeleteApiKey, apikeysV1ApiKeyServiceListApiKeys, apikeysV1ApiKeyServiceRotateApiKey, authError, authV1BlogServiceGetBlogSubscription, authV1BlogServiceSendBlogBroadcast, authV1BlogServiceSubscribeBlog, authV1BlogServiceUnsubscribeBlog, authV1BlogServiceUnsubscribeBlogByEmail, authV1DomainServiceCheckDomainVerification, authV1DomainServiceCreateDomainVerification, authV1DomainServiceGetDomainAutoJoin, authV1DomainServiceGetDomainStatus, authV1DomainServiceRemoveDomain, authV1DomainServiceSetDomainAutoJoin, authV1EmailServiceAddEmail, authV1EmailServiceGetUserEmailStatus, authV1EmailServiceInitiateEmailChange, authV1EmailServiceLogin, authV1EmailServiceRegister, authV1EmailServiceResendVerification, authV1EmailServiceResetPassword, authV1EmailServiceSendPasswordReset, authV1EmailServiceVerifyEmail, authV1MembershipServiceAcceptInvitation, authV1MembershipServiceCancelInvitation, authV1MembershipServiceCheckMembership, authV1MembershipServiceDeclineInvitation, authV1MembershipServiceGetInternalMembershipInfo, authV1MembershipServiceInviteMember, authV1MembershipServiceLeaveOrganization, authV1MembershipServiceListMembershipApplications, authV1MembershipServiceListMemberships, authV1MembershipServiceListOrganizationMembers, authV1MembershipServiceReactivateMember, authV1MembershipServiceRemoveMember, authV1MembershipServiceResendInvitation, authV1MembershipServiceSuspendMember, authV1MembershipServiceUpdateActiveMembership, authV1MembershipServiceUpdateMemberRole, authV1MembershipServiceUpdateMembershipState, authV1MembershipServiceUpdateOrgName, authV1MembershipServiceUpdateOrgUsername, authV1OtpServiceDeleteOtp, authV1OtpServiceGetOtpStatus, authV1OtpServiceSetupOtp, authV1OtpServiceVerifyOtp, authV1OtpServiceVerifyTotpForLogin, authV1PasskeyServiceDeletePasskey, authV1PasskeyServiceListPasskeys, authV1PasskeyServicePasskeyLoginBegin, authV1PasskeyServicePasskeyLoginFinish, authV1PasskeyServicePasskeyRegisterBegin, authV1PasskeyServicePasskeyRegisterFinish, authV1PasskeyServiceRenamePasskey, authV1PasskeyServiceVerifyPasskeyForLogin, authV1PolicyServiceAttachPolicy, authV1PolicyServiceCreatePolicy, authV1PolicyServiceDeletePolicy, authV1PolicyServiceDetachPolicy, authV1PolicyServiceGetPolicy, authV1PolicyServiceListPermissionRegistry, authV1PolicyServiceListPolicies, authV1PolicyServiceListPolicyAttachments, authV1PolicyServiceListUserPolicies, authV1PolicyServiceUpdatePolicy, authV1ProvidersServiceConnectProvider, authV1ProvidersServiceDisconnectProvider, authV1ProvidersServiceListProviders, authV1TokenServiceLogout, authV1TokenServiceRefreshToken, authV1UserServiceGetUser, authV1UserServiceGetUserInfo, authV1UserServiceUpdateName, authV1UserServiceUpdateUsername, beginPasskeyLogin, beginPasskeyRegistration, billingV1InvoiceServiceListInvoices, billingV1InvoiceServiceUpdateInvoiceStatus, billingV1PaymentServiceCalculateGenericTax, billingV1PaymentServiceCalculateTax, billingV1PaymentServiceCreateCheckoutSession, billingV1PaymentServiceCreateSetupIntent, billingV1PaymentServiceDeletePaymentMethod, billingV1PaymentServiceGetBillingAddress, billingV1PaymentServiceGetPaymentMethodFromPaymentIntent, billingV1PaymentServiceGetPaymentMethodFromSetupIntent, billingV1PaymentServiceListPaymentMethods, billingV1PaymentServiceUpgradeSubscription, billingV1PaymentServiceUpsertBillingAddress, billingV1PaymentServiceUpsertPaymentMethod, billingV1PlanServiceGetPlan, billingV1PlanServiceListPlans, billingV1SalesServiceContactSales, billingV1SubscriptionServiceCancelSubscription, billingV1SubscriptionServiceCreateSubscription, billingV1SubscriptionServiceGetSubscription, billingV1SubscriptionServiceGetSubscriptionHistory, billingV1SubscriptionServiceReactivateSubscription, billingV1UsageServiceGetBandwidthUsage, billingV1UsageServiceGetBandwidthUsageHistory, billingV1UsageServiceGetStorageUsage, billingV1UsageServiceGetStorageUsageHistory, billingV1UsageServiceRefreshBandwidthUsage, billingV1UsageServiceRefreshStorageUsage, checkDomainVerification, clearAuthError, clearLimitedAccessState, client, clientauthV1ClientCredentialServiceCreateClientCredential, clientauthV1ClientCredentialServiceListClientCredentials, clientauthV1ClientCredentialServiceMintClientToken, clientauthV1ClientCredentialServiceRevokeClientCredential, confirmPasswordReset, connect, connectSocial, createClient, decodeRequestOptions, deleteMember, deletePasskey, deleteUserOTP, disconnectSocial, feedsV1FeedServiceCreateFeed, feedsV1FeedServiceDeleteFeed, feedsV1FeedServiceGetFeed, feedsV1FeedServiceListFeeds, feedsV1FeedServiceUpdateFeed, finishPasskeyLogin, finishPasskeyRegistration, getBlogSubscriptionStatus, getDomainStatus, getEmailVerificationStatus, getOTPStatus, getToken, getUserInfo, imagesV1ImageConversionServiceMarkImageFailed, imagesV1ImageConversionServiceMarkImageProcessed, imagesV1ImageConversionServiceTakeUnprocessedImage, imagesV1ImageServiceCreateImageUpload, imagesV1ImageServiceDeleteImage, imagesV1ImageServiceGetImage, imagesV1ImageServiceListImages, imagesV1ImageServiceUpdateImageVisibility, initClient, initiateDomainVerification, initiateEmailChange, inviteMember, isLogged, leaveOrganization, limitedAccessToken, listActiveMemberships, listOrganizationMembers, listPasskeys, listPendingMemberships, listSocials, login, loginWithEmail, logout, platformauthV1PlatformAuthServiceExchangeApiKey, platformauthV1PlatformAuthServiceRefreshPlatformToken, postsV1PostServiceCreatePost, postsV1PostServiceCreatePostUpload, postsV1PostServiceDeletePost, postsV1PostServiceDeletePost2, postsV1PostServiceGetPost, postsV1PostServiceGetPost2, postsV1PostServiceGetPost3, postsV1PostServiceListPosts, postsV1PostServiceListPosts2, postsV1PostServiceListPosts3, postsV1PostServiceListPosts4, projectV1ProjectServiceCreateProject, projectV1ProjectServiceDeleteProject, projectV1ProjectServiceGetProject, projectV1ProjectServiceListProjects, projectV1ProjectServiceMoveProject, projectV1ProjectServiceRemoveCustomDomain, projectV1ProjectServiceSetCustomDomain, projectV1ProjectServiceUpdateProjectName, projectV1ProjectServiceUpdateVideoQuality, publicRespondToInvitation, registerWithEmail, removeDomain, renamePasskey, requiresAction, resendEmailVerificationCode, resendMemberInvite, respondToInvitation, sendPasswordResetEmail, setLimitedAccessState, setupUserOTP, subscribeToBlog, unsubscribeFromBlog, updateActiveMembership, updateAutoJoin, updateFullName, updateMemberRole, updateOrgName, updateOrgUsername, updateUsername, user, verifyEmailWithCode, verifyPasskeyForLogin, verifyTOTPForLogin, verifyUserOTP, videosV1AudioTrackServiceCreateAudioTrackUpload, videosV1AudioTrackServiceDeleteAllAudioTracks, videosV1AudioTrackServiceDeleteAudioTrack, videosV1AudioTrackServiceDeleteAudioTracksByLanguage, videosV1AudioTrackServiceListAudioTracks, videosV1ChapterServiceDeleteVideoChapter, videosV1ChapterServiceGetVideoChapters, videosV1ChapterServiceUpdateVideoChapters, videosV1LanguageServiceListLanguages, videosV1SubtitleServiceCreateSubtitleUpload, videosV1SubtitleServiceDeleteAllSubtitles, videosV1SubtitleServiceDeleteSubtitle, videosV1SubtitleServiceDeleteSubtitlesByLanguage, videosV1SubtitleServiceListSubtitles, videosV1VideoConversionServiceMarkVideoFailed, videosV1VideoConversionServiceMarkVideoProcessed, videosV1VideoServiceCreateVideoUpload, videosV1VideoServiceDeleteVideo, videosV1VideoServiceGetVideo, videosV1VideoServiceListVideos, videosV1VideoServiceUpdateVideoVisibility };
4374
4619
  //# sourceMappingURL=index.js.map