@rixl/sdk 0.32.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -0
- package/dist/index.js +337 -282
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2576,6 +2576,7 @@ const videosV1VideoServiceGetVideo = (options) => (options.client ?? client).get
|
|
|
2576
2576
|
const GLOBAL_PREFIX = "__rixl_auth";
|
|
2577
2577
|
/** OAuth state storage key prefix */
|
|
2578
2578
|
const STATE_STORAGE_KEY_PREFIX = "__rixl_auth_state_";
|
|
2579
|
+
const PKCE_STORAGE_KEY_PREFIX = "__rixl_auth_pkce_";
|
|
2579
2580
|
/** Social connect storage key prefix */
|
|
2580
2581
|
const SOCIAL_CONNECT_KEY_PREFIX = "__rixl_auth_social_connect_";
|
|
2581
2582
|
/** HTTP Status codes - only codes actually used in the library */
|
|
@@ -2592,7 +2593,7 @@ const HTTP_STATUS = {
|
|
|
2592
2593
|
|
|
2593
2594
|
//#endregion
|
|
2594
2595
|
//#region src/auth/state.ts
|
|
2595
|
-
const storagePath = (provider) => STATE_STORAGE_KEY_PREFIX + provider;
|
|
2596
|
+
const storagePath$1 = (provider) => STATE_STORAGE_KEY_PREFIX + provider;
|
|
2596
2597
|
/**
|
|
2597
2598
|
* Retrieves and validates the OAuth state from session storage
|
|
2598
2599
|
* @param provider The provider identifier
|
|
@@ -2600,7 +2601,7 @@ const storagePath = (provider) => STATE_STORAGE_KEY_PREFIX + provider;
|
|
|
2600
2601
|
* @returns True if the state is valid, false otherwise
|
|
2601
2602
|
*/
|
|
2602
2603
|
function validateOAuthState(provider, state) {
|
|
2603
|
-
return sessionStorage.getItem(storagePath(provider)) === state;
|
|
2604
|
+
return sessionStorage.getItem(storagePath$1(provider)) === state;
|
|
2604
2605
|
}
|
|
2605
2606
|
/**
|
|
2606
2607
|
* Discards the stored state for a provider so the next login round-trip mints a
|
|
@@ -2609,7 +2610,7 @@ function validateOAuthState(provider, state) {
|
|
|
2609
2610
|
* @param provider The provider identifier
|
|
2610
2611
|
*/
|
|
2611
2612
|
function clearOauthState(provider) {
|
|
2612
|
-
sessionStorage.removeItem(storagePath(provider));
|
|
2613
|
+
sessionStorage.removeItem(storagePath$1(provider));
|
|
2613
2614
|
}
|
|
2614
2615
|
/**
|
|
2615
2616
|
* Gets or Generates a complete state parameter for OAuth requests
|
|
@@ -2617,11 +2618,11 @@ function clearOauthState(provider) {
|
|
|
2617
2618
|
* @returns A state string containing the provider identifier and random data
|
|
2618
2619
|
*/
|
|
2619
2620
|
function getOauthState(provider) {
|
|
2620
|
-
return sessionStorage.getItem(storagePath(provider)) ?? generateOauthState(provider);
|
|
2621
|
+
return sessionStorage.getItem(storagePath$1(provider)) ?? generateOauthState(provider);
|
|
2621
2622
|
}
|
|
2622
2623
|
function generateOauthState(provider) {
|
|
2623
2624
|
const state = `${provider}_${crypto.randomUUID()}`;
|
|
2624
|
-
sessionStorage.setItem(storagePath(provider), state);
|
|
2625
|
+
sessionStorage.setItem(storagePath$1(provider), state);
|
|
2625
2626
|
return state;
|
|
2626
2627
|
}
|
|
2627
2628
|
|
|
@@ -2736,10 +2737,49 @@ const appleConfig = appleProvider.config;
|
|
|
2736
2737
|
const appleAuthUrl = appleProvider.authUrl;
|
|
2737
2738
|
const updateAppleAuthUrl = appleProvider.updateAuthUrl;
|
|
2738
2739
|
|
|
2740
|
+
//#endregion
|
|
2741
|
+
//#region src/auth/pkce.ts
|
|
2742
|
+
const storagePath = (provider) => PKCE_STORAGE_KEY_PREFIX + provider;
|
|
2743
|
+
const base64Url = (bytes) => btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2744
|
+
/**
|
|
2745
|
+
* Gets or generates the PKCE code verifier for a provider. It lives in session
|
|
2746
|
+
* storage so the callback page can send it with the authorization code.
|
|
2747
|
+
*/
|
|
2748
|
+
function getPkceVerifier(provider) {
|
|
2749
|
+
const stored = sessionStorage.getItem(storagePath(provider));
|
|
2750
|
+
if (stored) return stored;
|
|
2751
|
+
const verifier = base64Url(crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(32)));
|
|
2752
|
+
sessionStorage.setItem(storagePath(provider), verifier);
|
|
2753
|
+
return verifier;
|
|
2754
|
+
}
|
|
2755
|
+
function clearPkceVerifier(provider) {
|
|
2756
|
+
sessionStorage.removeItem(storagePath(provider));
|
|
2757
|
+
}
|
|
2758
|
+
/** The S256 code challenge for a verifier. */
|
|
2759
|
+
async function pkceChallenge(verifier) {
|
|
2760
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
|
|
2761
|
+
return base64Url(new Uint8Array(digest));
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2739
2764
|
//#endregion
|
|
2740
2765
|
//#region src/auth/providers/telegram.ts
|
|
2766
|
+
const TELEGRAM_AUTH_URL = "https://oauth.telegram.org/auth";
|
|
2741
2767
|
const telegramConfig = shared("provider.telegram.config", () => atom(null));
|
|
2742
2768
|
const telegramAuthUrl = shared("provider.telegram.authUrl", () => atom(null));
|
|
2769
|
+
const telegramRedirectUri = (config) => config.redirectUri ?? window.location.origin;
|
|
2770
|
+
const legacyAuthUrl = (config) => `${TELEGRAM_AUTH_URL}?bot_id=${encodeURIComponent(config.botId)}&origin=${encodeURIComponent(window.location.origin)}&return_to=${encodeURIComponent(window.location.origin + location.pathname)}`;
|
|
2771
|
+
const oidcAuthUrl = async (config) => {
|
|
2772
|
+
const params = new URLSearchParams({
|
|
2773
|
+
client_id: config.botId,
|
|
2774
|
+
redirect_uri: telegramRedirectUri(config),
|
|
2775
|
+
response_type: "code",
|
|
2776
|
+
scope: "openid profile",
|
|
2777
|
+
state: getOauthState("telegram"),
|
|
2778
|
+
code_challenge: await pkceChallenge(getPkceVerifier("telegram")),
|
|
2779
|
+
code_challenge_method: "S256"
|
|
2780
|
+
});
|
|
2781
|
+
return `${TELEGRAM_AUTH_URL}?${params.toString()}`;
|
|
2782
|
+
};
|
|
2743
2783
|
/**
|
|
2744
2784
|
* Updates the Telegram authentication URL using the configured settings
|
|
2745
2785
|
*/
|
|
@@ -2750,9 +2790,22 @@ function updateTelegramAuthUrl() {
|
|
|
2750
2790
|
telegramAuthUrl.set(null);
|
|
2751
2791
|
return;
|
|
2752
2792
|
}
|
|
2753
|
-
|
|
2754
|
-
|
|
2793
|
+
if (!config.oidc) {
|
|
2794
|
+
telegramAuthUrl.set(legacyAuthUrl(config));
|
|
2795
|
+
return;
|
|
2796
|
+
}
|
|
2797
|
+
telegramAuthUrl.set(null);
|
|
2798
|
+
oidcAuthUrl(config).then((url) => telegramAuthUrl.set(url));
|
|
2755
2799
|
}
|
|
2800
|
+
/** The PKCE verifier and redirect URI the backend needs to redeem a Telegram authorization code. */
|
|
2801
|
+
const telegramCodeExchange = () => {
|
|
2802
|
+
const config = telegramConfig.get();
|
|
2803
|
+
if (!config) return void 0;
|
|
2804
|
+
return {
|
|
2805
|
+
codeVerifier: getPkceVerifier("telegram"),
|
|
2806
|
+
redirectUri: telegramRedirectUri(config)
|
|
2807
|
+
};
|
|
2808
|
+
};
|
|
2756
2809
|
|
|
2757
2810
|
//#endregion
|
|
2758
2811
|
//#region src/auth/url.ts
|
|
@@ -2783,10 +2836,10 @@ const OAUTH_PROVIDERS$1 = [
|
|
|
2783
2836
|
*/
|
|
2784
2837
|
function detectProvider() {
|
|
2785
2838
|
if (urlParams.has("tgWebAppData")) return "tgWebAppData";
|
|
2786
|
-
if (urlParams.has("tgAuthResult")) return "tgAuthResult";
|
|
2787
|
-
const id_token = urlParams.get("id_token");
|
|
2788
2839
|
const state = urlParams.get("state");
|
|
2789
|
-
if (
|
|
2840
|
+
if (urlParams.has("code") && state && validateOAuthState("telegram", state)) return "telegram";
|
|
2841
|
+
if (urlParams.has("tgAuthResult")) return "tgAuthResult";
|
|
2842
|
+
if (urlParams.get("id_token") && state) {
|
|
2790
2843
|
const providerFromState = extractProviderFromState(state);
|
|
2791
2844
|
return OAUTH_PROVIDERS$1.find((p) => providerFromState === p && validateOAuthState(p, state));
|
|
2792
2845
|
}
|
|
@@ -2798,6 +2851,7 @@ function detectProvider() {
|
|
|
2798
2851
|
*/
|
|
2799
2852
|
function getProviderToken(provider) {
|
|
2800
2853
|
if (provider === "tgWebAppData" || provider === "tgAuthResult") return urlParams.get(provider) || void 0;
|
|
2854
|
+
if (provider === "telegram") return urlParams.get("code") || void 0;
|
|
2801
2855
|
if (provider === "google" || provider === "apple" || provider === "microsoft") return urlParams.get("id_token") || void 0;
|
|
2802
2856
|
}
|
|
2803
2857
|
|
|
@@ -2833,7 +2887,8 @@ const hasProviderResponse = () => CREDENTIAL_PARAMS.some((key) => urlParams.has(
|
|
|
2833
2887
|
const AUTH_URL_UPDATERS = {
|
|
2834
2888
|
["google"]: updateGoogleAuthUrl,
|
|
2835
2889
|
["apple"]: updateAppleAuthUrl,
|
|
2836
|
-
["microsoft"]: updateMicrosoftAuthUrl
|
|
2890
|
+
["microsoft"]: updateMicrosoftAuthUrl,
|
|
2891
|
+
["telegram"]: updateTelegramAuthUrl
|
|
2837
2892
|
};
|
|
2838
2893
|
/** Returns undefined when the half holds no credential, meaning it is the app's own and must not be touched. */
|
|
2839
2894
|
const stripped = (query) => {
|
|
@@ -2869,6 +2924,7 @@ const completeOAuthCallback = () => {
|
|
|
2869
2924
|
const provider = detectProvider();
|
|
2870
2925
|
if (!provider) return;
|
|
2871
2926
|
clearOauthState(provider);
|
|
2927
|
+
clearPkceVerifier(provider);
|
|
2872
2928
|
AUTH_URL_UPDATERS[provider]?.();
|
|
2873
2929
|
window.history.replaceState(window.history.state, "", withoutOAuthResponse(window.location.href));
|
|
2874
2930
|
};
|
|
@@ -2981,30 +3037,31 @@ const logProviderExchangeFailure = (provider, credential, error) => {
|
|
|
2981
3037
|
};
|
|
2982
3038
|
|
|
2983
3039
|
//#endregion
|
|
2984
|
-
//#region src/auth/
|
|
2985
|
-
const socialStoragePath = (provider) => SOCIAL_CONNECT_KEY_PREFIX + provider;
|
|
2986
|
-
/**
|
|
2987
|
-
* Sets a flag indicating that a social provider connection is being attempted
|
|
2988
|
-
* @param provider The provider identifier
|
|
2989
|
-
*/
|
|
2990
|
-
function setSocialConnectAttempt(provider) {
|
|
2991
|
-
sessionStorage.setItem(socialStoragePath(provider), "true");
|
|
2992
|
-
}
|
|
2993
|
-
/**
|
|
2994
|
-
* Checks if there's a pending social provider connection attempt
|
|
2995
|
-
* @param provider The provider identifier
|
|
2996
|
-
* @returns True if there's a pending connection attempt, false otherwise
|
|
2997
|
-
*/
|
|
2998
|
-
function hasSocialConnectAttempt(provider) {
|
|
2999
|
-
return sessionStorage.getItem(socialStoragePath(provider)) === "true";
|
|
3000
|
-
}
|
|
3040
|
+
//#region src/auth/api/refresh-tokens.ts
|
|
3001
3041
|
/**
|
|
3002
|
-
*
|
|
3003
|
-
*
|
|
3042
|
+
* Exchange a provider credential for a Rixl session, or refresh an existing
|
|
3043
|
+
* Rixl session with a Bearer refresh token.
|
|
3044
|
+
*
|
|
3045
|
+
* Both go to `/auth/v1/token`, which needs no session: `token_type` is the
|
|
3046
|
+
* `AuthProvider` value and `refresh_token` carries the stored refresh token or
|
|
3047
|
+
* the provider's `id_token` / Telegram payload. `/auth/v1/providers/connect`
|
|
3048
|
+
* links a provider to an already signed-in user, so it cannot sign anyone in.
|
|
3004
3049
|
*/
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3050
|
+
const refreshTokens = async (provider, token, options) => {
|
|
3051
|
+
const body = {
|
|
3052
|
+
token_type: provider,
|
|
3053
|
+
refresh_token: token,
|
|
3054
|
+
country_code: options?.countryCode,
|
|
3055
|
+
origin: options?.origin,
|
|
3056
|
+
code_verifier: options?.codeVerifier,
|
|
3057
|
+
redirect_uri: options?.redirectUri
|
|
3058
|
+
};
|
|
3059
|
+
const { data } = await authV1TokenServiceRefreshToken({
|
|
3060
|
+
body,
|
|
3061
|
+
throwOnError: true
|
|
3062
|
+
});
|
|
3063
|
+
return data;
|
|
3064
|
+
};
|
|
3008
3065
|
|
|
3009
3066
|
//#endregion
|
|
3010
3067
|
//#region src/auth/initialization.ts
|
|
@@ -3035,254 +3092,6 @@ function createDeferred() {
|
|
|
3035
3092
|
*/
|
|
3036
3093
|
const initDeferred = shared("initDeferred", createDeferred);
|
|
3037
3094
|
|
|
3038
|
-
//#endregion
|
|
3039
|
-
//#region src/auth/api/error-handlers.ts
|
|
3040
|
-
/**
|
|
3041
|
-
* Helper to create error functions - reduces bundle size by reusing error creation logic
|
|
3042
|
-
*/
|
|
3043
|
-
const err = (message) => () => new Error(message);
|
|
3044
|
-
/** Reusable error handlers for common cases - reduces repetitive error messages */
|
|
3045
|
-
const commonErrors = {
|
|
3046
|
-
unauthorized: err("User is not authorized"),
|
|
3047
|
-
badRequest: err("Bad request"),
|
|
3048
|
-
notFound: err("Not found"),
|
|
3049
|
-
conflict: err("Resource already exists"),
|
|
3050
|
-
forbidden: err("Forbidden"),
|
|
3051
|
-
tooManyRequests: err("Too many requests")
|
|
3052
|
-
};
|
|
3053
|
-
/**
|
|
3054
|
-
* Standard error handler for API errors with custom status code handling
|
|
3055
|
-
*/
|
|
3056
|
-
const handleApiError = (error, statusHandlers) => {
|
|
3057
|
-
if (error instanceof ApiError) {
|
|
3058
|
-
const handler = statusHandlers[error.status];
|
|
3059
|
-
if (handler) throw new ApiError(handler().message, error.status, error.endpoint, error.data);
|
|
3060
|
-
throw error;
|
|
3061
|
-
}
|
|
3062
|
-
throw error;
|
|
3063
|
-
};
|
|
3064
|
-
|
|
3065
|
-
//#endregion
|
|
3066
|
-
//#region src/auth/api/utils.ts
|
|
3067
|
-
/**
|
|
3068
|
-
* Generic helper for API calls to handle initialization and error handling
|
|
3069
|
-
* @param fn The async function to execute
|
|
3070
|
-
* @param errorMap A map of status codes to error functions
|
|
3071
|
-
* @returns The result of the function execution
|
|
3072
|
-
*/
|
|
3073
|
-
const apiCall = async (fn, errorMap = {}) => {
|
|
3074
|
-
await initDeferred.promise;
|
|
3075
|
-
try {
|
|
3076
|
-
return await fn();
|
|
3077
|
-
} catch (error) {
|
|
3078
|
-
return handleApiError(error, errorMap);
|
|
3079
|
-
}
|
|
3080
|
-
};
|
|
3081
|
-
|
|
3082
|
-
//#endregion
|
|
3083
|
-
//#region src/auth/api/tokens.ts
|
|
3084
|
-
function persistTokens(data) {
|
|
3085
|
-
const tokens = data ?? {};
|
|
3086
|
-
if (tokens.access_token && tokens.refresh_token && tokens.expires_in) {
|
|
3087
|
-
setTokens(tokens.access_token, tokens.refresh_token, Number(tokens.expires_in));
|
|
3088
|
-
return true;
|
|
3089
|
-
}
|
|
3090
|
-
return false;
|
|
3091
|
-
}
|
|
3092
|
-
|
|
3093
|
-
//#endregion
|
|
3094
|
-
//#region src/auth/validation/base.ts
|
|
3095
|
-
/**
|
|
3096
|
-
* 🛡️ INPUT VALIDATION UTILITY
|
|
3097
|
-
* Validates data before API calls and throws user-friendly errors
|
|
3098
|
-
*/
|
|
3099
|
-
const validateInput = (schema, data) => {
|
|
3100
|
-
try {
|
|
3101
|
-
return v.parse(schema, data);
|
|
3102
|
-
} catch (error) {
|
|
3103
|
-
if (error instanceof v.ValiError) {
|
|
3104
|
-
const firstError = error.issues[0];
|
|
3105
|
-
throw new Error(firstError.message);
|
|
3106
|
-
}
|
|
3107
|
-
throw error;
|
|
3108
|
-
}
|
|
3109
|
-
};
|
|
3110
|
-
const EmailSchema = v.pipe(v.string("Email must be text"), v.email("Please enter a valid email address"), v.minLength(1, "Email is required"));
|
|
3111
|
-
const PasswordSchema = v.pipe(v.string("Password must be text"), v.minLength(8, "Password must be at least 8 characters long"), v.regex(/[A-Z]/, "Password must contain at least one uppercase letter"), v.regex(/[a-z]/, "Password must contain at least one lowercase letter"), v.regex(/[0-9]/, "Password must contain at least one number"));
|
|
3112
|
-
/**
|
|
3113
|
-
* Username validation schema
|
|
3114
|
-
* - Must be 4-24 characters
|
|
3115
|
-
* - Only letters, numbers, underscores, and periods
|
|
3116
|
-
*/
|
|
3117
|
-
const UsernameSchema = v.pipe(v.string("Username must be text"), v.minLength(4, "Username must be 4-24 characters long"), v.maxLength(24, "Username must be 4-24 characters long"), v.regex(/^[a-z0-9_.]+$/, "Username can only contain lowercase letters, numbers, dots and underscores"));
|
|
3118
|
-
/**
|
|
3119
|
-
* Name validation schema
|
|
3120
|
-
* - Must be 1-30 characters
|
|
3121
|
-
*/
|
|
3122
|
-
const NameSchema = v.pipe(v.string("Name must be text"), v.minLength(1, "Name must be 1-30 characters long"), v.maxLength(30, "Name must be 1-30 characters long"));
|
|
3123
|
-
/**
|
|
3124
|
-
* Domain validation schema
|
|
3125
|
-
* - Must be lowercase
|
|
3126
|
-
* - Must contain at least one dot
|
|
3127
|
-
* - Only alphanumeric characters, hyphens, and dots
|
|
3128
|
-
* - Cannot start or end with hyphen in any part
|
|
3129
|
-
*/
|
|
3130
|
-
const DomainSchema = v.pipe(v.string("Domain must be text"), v.trim(), v.toLowerCase(), v.minLength(1, "Domain is required"), v.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/, "Invalid domain format. Please enter a valid domain like company.com"));
|
|
3131
|
-
|
|
3132
|
-
//#endregion
|
|
3133
|
-
//#region src/auth/validation/auth.ts
|
|
3134
|
-
const EmailAuthRequestSchema = v.object({
|
|
3135
|
-
email: EmailSchema,
|
|
3136
|
-
password: PasswordSchema
|
|
3137
|
-
});
|
|
3138
|
-
const RegisterRequestSchema = v.object({
|
|
3139
|
-
email: EmailSchema,
|
|
3140
|
-
password: PasswordSchema,
|
|
3141
|
-
country_code: v.optional(v.string()),
|
|
3142
|
-
subscribe_to_blog: v.optional(v.boolean())
|
|
3143
|
-
});
|
|
3144
|
-
const ResetPasswordRequestSchema = v.object({
|
|
3145
|
-
token: v.string(),
|
|
3146
|
-
new_password: PasswordSchema
|
|
3147
|
-
});
|
|
3148
|
-
const LoginOTPVerifyRequestSchema = v.object({
|
|
3149
|
-
code: v.pipe(v.string("TOTP or backup code must be text"), v.minLength(1, "TOTP or backup code is required")),
|
|
3150
|
-
session_id: v.pipe(v.string("Session ID must be text"), v.minLength(1, "Session ID is required"))
|
|
3151
|
-
});
|
|
3152
|
-
const ResendEmailRequestSchema = v.object({ email: EmailSchema });
|
|
3153
|
-
const ChangeEmailRequestSchema = v.object({ new_email: EmailSchema });
|
|
3154
|
-
const verifyEmailChangeRequestSchema = v.object({
|
|
3155
|
-
code: v.pipe(v.string("OTP code must be text"), v.minLength(6, "OTP code must be at least 6 characters"), v.maxLength(8, "OTP code must be at most 8 characters"), v.regex(/^\d+$/, "OTP code must contain only numbers")),
|
|
3156
|
-
new_email: v.optional(EmailSchema),
|
|
3157
|
-
type: v.union([v.literal("verification"), v.literal("email_change")]),
|
|
3158
|
-
verification_id: v.string("Verification ID is required")
|
|
3159
|
-
});
|
|
3160
|
-
/**
|
|
3161
|
-
* Social provider schemas
|
|
3162
|
-
*/
|
|
3163
|
-
const ConnectProviderSchema = v.object({
|
|
3164
|
-
provider: v.pipe(v.string("Provider must be text"), v.minLength(1, "Provider is required")),
|
|
3165
|
-
token: v.pipe(v.string("Token must be text"), v.minLength(1, "Token is required"))
|
|
3166
|
-
});
|
|
3167
|
-
/**
|
|
3168
|
-
* OTP verification schema (for user OTP operations)
|
|
3169
|
-
*/
|
|
3170
|
-
const VerifyOTPCodeSchema = v.object({ code: v.pipe(v.string("OTP code must be text"), v.minLength(6, "OTP code must be at least 6 characters"), v.regex(/^\d+$/, "OTP code must contain only numbers")) });
|
|
3171
|
-
|
|
3172
|
-
//#endregion
|
|
3173
|
-
//#region src/auth/social/socialConnections.ts
|
|
3174
|
-
const PROVIDER_TO_PROTO = {
|
|
3175
|
-
google: "EXTERNAL_ACCOUNT_PROVIDER_GOOGLE",
|
|
3176
|
-
apple: "EXTERNAL_ACCOUNT_PROVIDER_APPLE",
|
|
3177
|
-
microsoft: "EXTERNAL_ACCOUNT_PROVIDER_MICROSOFT",
|
|
3178
|
-
facebook: "EXTERNAL_ACCOUNT_PROVIDER_FACEBOOK",
|
|
3179
|
-
telegram: "EXTERNAL_ACCOUNT_PROVIDER_TELEGRAM"
|
|
3180
|
-
};
|
|
3181
|
-
const PROVIDER_FROM_PROTO = {
|
|
3182
|
-
EXTERNAL_ACCOUNT_PROVIDER_GOOGLE: "google",
|
|
3183
|
-
EXTERNAL_ACCOUNT_PROVIDER_APPLE: "apple",
|
|
3184
|
-
EXTERNAL_ACCOUNT_PROVIDER_MICROSOFT: "microsoft",
|
|
3185
|
-
EXTERNAL_ACCOUNT_PROVIDER_FACEBOOK: "facebook",
|
|
3186
|
-
EXTERNAL_ACCOUNT_PROVIDER_TELEGRAM: "telegram"
|
|
3187
|
-
};
|
|
3188
|
-
const normalizeProviderType = (provider) => provider === "tgAuthResult" || provider === "tgWebAppData" ? "telegram" : provider;
|
|
3189
|
-
const toProtoProvider = (provider) => {
|
|
3190
|
-
const proto = PROVIDER_TO_PROTO[provider];
|
|
3191
|
-
if (!proto) throw new Error(`Unknown provider: ${provider}`);
|
|
3192
|
-
return proto;
|
|
3193
|
-
};
|
|
3194
|
-
const listSocials = async () => {
|
|
3195
|
-
return apiCall(async () => {
|
|
3196
|
-
const { data } = await authV1ProvidersServiceListProviders({ throwOnError: true });
|
|
3197
|
-
return (data.providers ?? []).flatMap((p) => {
|
|
3198
|
-
const provider = p.provider ? PROVIDER_FROM_PROTO[p.provider] : void 0;
|
|
3199
|
-
if (!provider) return [];
|
|
3200
|
-
return [{
|
|
3201
|
-
provider,
|
|
3202
|
-
username: p.username,
|
|
3203
|
-
first_name: p.first_name,
|
|
3204
|
-
last_name: p.last_name,
|
|
3205
|
-
email_address: p.email_address,
|
|
3206
|
-
image_url: p.image_url
|
|
3207
|
-
}];
|
|
3208
|
-
});
|
|
3209
|
-
}, { [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to list providers!") });
|
|
3210
|
-
};
|
|
3211
|
-
const connectSocialInternal = async (provider, token) => {
|
|
3212
|
-
return apiCall(async () => {
|
|
3213
|
-
const requestBody = validateInput(ConnectProviderSchema, {
|
|
3214
|
-
provider,
|
|
3215
|
-
token
|
|
3216
|
-
});
|
|
3217
|
-
const sessionToken = await getToken();
|
|
3218
|
-
const headers = sessionToken ? { Authorization: `Bearer ${sessionToken}` } : {};
|
|
3219
|
-
const { data } = await authV1ProvidersServiceConnectProvider({
|
|
3220
|
-
body: {
|
|
3221
|
-
provider: toProtoProvider(normalizeProviderType(requestBody.provider)),
|
|
3222
|
-
token: requestBody.token
|
|
3223
|
-
},
|
|
3224
|
-
headers,
|
|
3225
|
-
throwOnError: true
|
|
3226
|
-
});
|
|
3227
|
-
persistTokens(data);
|
|
3228
|
-
}, { [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to connect provider!") });
|
|
3229
|
-
};
|
|
3230
|
-
const disconnectSocial = async (provider) => {
|
|
3231
|
-
return apiCall(async () => {
|
|
3232
|
-
await authV1ProvidersServiceDisconnectProvider({
|
|
3233
|
-
path: { provider: toProtoProvider(provider) },
|
|
3234
|
-
throwOnError: true
|
|
3235
|
-
});
|
|
3236
|
-
}, {
|
|
3237
|
-
[HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to disconnect provider!"),
|
|
3238
|
-
[HTTP_STATUS.NOT_FOUND]: () => /* @__PURE__ */ new Error("Provider not found!"),
|
|
3239
|
-
[HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Cannot disconnect the last social provider!")
|
|
3240
|
-
});
|
|
3241
|
-
};
|
|
3242
|
-
const connectSocial = (provider) => {
|
|
3243
|
-
setSocialConnectAttempt(provider);
|
|
3244
|
-
login(provider);
|
|
3245
|
-
};
|
|
3246
|
-
|
|
3247
|
-
//#endregion
|
|
3248
|
-
//#region src/auth/api/refresh-tokens.ts
|
|
3249
|
-
/**
|
|
3250
|
-
* Exchange a provider credential for a Rixl session, or refresh an existing
|
|
3251
|
-
* Rixl session with a Bearer refresh token.
|
|
3252
|
-
*
|
|
3253
|
-
* - For `AuthProvider.BEARER`, the call hits `/auth/v1/token` with the stored
|
|
3254
|
-
* Rixl refresh token.
|
|
3255
|
-
* - For OAuth/Telegram providers, the call hits `/auth/v1/providers/connect`
|
|
3256
|
-
* with the provider's `id_token` or Telegram payload. The wire `provider`
|
|
3257
|
-
* value is the `auth.v1.ExternalAccountProvider` enum (e.g.
|
|
3258
|
-
* `EXTERNAL_ACCOUNT_PROVIDER_GOOGLE`), not the short SDK name.
|
|
3259
|
-
*/
|
|
3260
|
-
const refreshTokens = async (provider, token, options) => {
|
|
3261
|
-
if (provider === "Bearer") {
|
|
3262
|
-
const { data } = await authV1TokenServiceRefreshToken({
|
|
3263
|
-
body: {
|
|
3264
|
-
token_type: "Bearer",
|
|
3265
|
-
refresh_token: token,
|
|
3266
|
-
country_code: options?.countryCode,
|
|
3267
|
-
origin: options?.origin
|
|
3268
|
-
},
|
|
3269
|
-
throwOnError: true
|
|
3270
|
-
});
|
|
3271
|
-
return data;
|
|
3272
|
-
}
|
|
3273
|
-
const requestProvider = normalizeProviderType(provider);
|
|
3274
|
-
const { data } = await authV1ProvidersServiceConnectProvider({
|
|
3275
|
-
body: {
|
|
3276
|
-
provider: toProtoProvider(requestProvider),
|
|
3277
|
-
token,
|
|
3278
|
-
country_code: options?.countryCode,
|
|
3279
|
-
origin: options?.origin
|
|
3280
|
-
},
|
|
3281
|
-
throwOnError: true
|
|
3282
|
-
});
|
|
3283
|
-
return data;
|
|
3284
|
-
};
|
|
3285
|
-
|
|
3286
3095
|
//#endregion
|
|
3287
3096
|
//#region src/auth/cookie/util.ts
|
|
3288
3097
|
const splitOnFirstEquals = (pair) => {
|
|
@@ -3797,6 +3606,245 @@ function configureSdkClient() {
|
|
|
3797
3606
|
});
|
|
3798
3607
|
}
|
|
3799
3608
|
|
|
3609
|
+
//#endregion
|
|
3610
|
+
//#region src/auth/social/socialState.ts
|
|
3611
|
+
const socialStoragePath = (provider) => SOCIAL_CONNECT_KEY_PREFIX + provider;
|
|
3612
|
+
/**
|
|
3613
|
+
* Sets a flag indicating that a social provider connection is being attempted
|
|
3614
|
+
* @param provider The provider identifier
|
|
3615
|
+
*/
|
|
3616
|
+
function setSocialConnectAttempt(provider) {
|
|
3617
|
+
sessionStorage.setItem(socialStoragePath(provider), "true");
|
|
3618
|
+
}
|
|
3619
|
+
/**
|
|
3620
|
+
* Checks if there's a pending social provider connection attempt
|
|
3621
|
+
* @param provider The provider identifier
|
|
3622
|
+
* @returns True if there's a pending connection attempt, false otherwise
|
|
3623
|
+
*/
|
|
3624
|
+
function hasSocialConnectAttempt(provider) {
|
|
3625
|
+
return sessionStorage.getItem(socialStoragePath(provider)) === "true";
|
|
3626
|
+
}
|
|
3627
|
+
/**
|
|
3628
|
+
* Clears the social provider connection attempt flag
|
|
3629
|
+
* @param provider The provider identifier
|
|
3630
|
+
*/
|
|
3631
|
+
function clearSocialConnectAttempt(provider) {
|
|
3632
|
+
sessionStorage.removeItem(socialStoragePath(provider));
|
|
3633
|
+
}
|
|
3634
|
+
|
|
3635
|
+
//#endregion
|
|
3636
|
+
//#region src/auth/api/error-handlers.ts
|
|
3637
|
+
/**
|
|
3638
|
+
* Helper to create error functions - reduces bundle size by reusing error creation logic
|
|
3639
|
+
*/
|
|
3640
|
+
const err = (message) => () => new Error(message);
|
|
3641
|
+
/** Reusable error handlers for common cases - reduces repetitive error messages */
|
|
3642
|
+
const commonErrors = {
|
|
3643
|
+
unauthorized: err("User is not authorized"),
|
|
3644
|
+
badRequest: err("Bad request"),
|
|
3645
|
+
notFound: err("Not found"),
|
|
3646
|
+
conflict: err("Resource already exists"),
|
|
3647
|
+
forbidden: err("Forbidden"),
|
|
3648
|
+
tooManyRequests: err("Too many requests")
|
|
3649
|
+
};
|
|
3650
|
+
/**
|
|
3651
|
+
* Standard error handler for API errors with custom status code handling
|
|
3652
|
+
*/
|
|
3653
|
+
const handleApiError = (error, statusHandlers) => {
|
|
3654
|
+
if (error instanceof ApiError) {
|
|
3655
|
+
const handler = statusHandlers[error.status];
|
|
3656
|
+
if (handler) throw new ApiError(handler().message, error.status, error.endpoint, error.data);
|
|
3657
|
+
throw error;
|
|
3658
|
+
}
|
|
3659
|
+
throw error;
|
|
3660
|
+
};
|
|
3661
|
+
|
|
3662
|
+
//#endregion
|
|
3663
|
+
//#region src/auth/api/utils.ts
|
|
3664
|
+
/**
|
|
3665
|
+
* Generic helper for API calls to handle initialization and error handling
|
|
3666
|
+
* @param fn The async function to execute
|
|
3667
|
+
* @param errorMap A map of status codes to error functions
|
|
3668
|
+
* @returns The result of the function execution
|
|
3669
|
+
*/
|
|
3670
|
+
const apiCall = async (fn, errorMap = {}) => {
|
|
3671
|
+
await initDeferred.promise;
|
|
3672
|
+
try {
|
|
3673
|
+
return await fn();
|
|
3674
|
+
} catch (error) {
|
|
3675
|
+
return handleApiError(error, errorMap);
|
|
3676
|
+
}
|
|
3677
|
+
};
|
|
3678
|
+
|
|
3679
|
+
//#endregion
|
|
3680
|
+
//#region src/auth/api/tokens.ts
|
|
3681
|
+
function persistTokens(data) {
|
|
3682
|
+
const tokens = data ?? {};
|
|
3683
|
+
if (tokens.access_token && tokens.refresh_token && tokens.expires_in) {
|
|
3684
|
+
setTokens(tokens.access_token, tokens.refresh_token, Number(tokens.expires_in));
|
|
3685
|
+
return true;
|
|
3686
|
+
}
|
|
3687
|
+
return false;
|
|
3688
|
+
}
|
|
3689
|
+
|
|
3690
|
+
//#endregion
|
|
3691
|
+
//#region src/auth/validation/base.ts
|
|
3692
|
+
/**
|
|
3693
|
+
* 🛡️ INPUT VALIDATION UTILITY
|
|
3694
|
+
* Validates data before API calls and throws user-friendly errors
|
|
3695
|
+
*/
|
|
3696
|
+
const validateInput = (schema, data) => {
|
|
3697
|
+
try {
|
|
3698
|
+
return v.parse(schema, data);
|
|
3699
|
+
} catch (error) {
|
|
3700
|
+
if (error instanceof v.ValiError) {
|
|
3701
|
+
const firstError = error.issues[0];
|
|
3702
|
+
throw new Error(firstError.message);
|
|
3703
|
+
}
|
|
3704
|
+
throw error;
|
|
3705
|
+
}
|
|
3706
|
+
};
|
|
3707
|
+
const EmailSchema = v.pipe(v.string("Email must be text"), v.email("Please enter a valid email address"), v.minLength(1, "Email is required"));
|
|
3708
|
+
const PasswordSchema = v.pipe(v.string("Password must be text"), v.minLength(8, "Password must be at least 8 characters long"), v.regex(/[A-Z]/, "Password must contain at least one uppercase letter"), v.regex(/[a-z]/, "Password must contain at least one lowercase letter"), v.regex(/[0-9]/, "Password must contain at least one number"));
|
|
3709
|
+
/**
|
|
3710
|
+
* Username validation schema
|
|
3711
|
+
* - Must be 4-24 characters
|
|
3712
|
+
* - Only letters, numbers, underscores, and periods
|
|
3713
|
+
*/
|
|
3714
|
+
const UsernameSchema = v.pipe(v.string("Username must be text"), v.minLength(4, "Username must be 4-24 characters long"), v.maxLength(24, "Username must be 4-24 characters long"), v.regex(/^[a-z0-9_.]+$/, "Username can only contain lowercase letters, numbers, dots and underscores"));
|
|
3715
|
+
/**
|
|
3716
|
+
* Name validation schema
|
|
3717
|
+
* - Must be 1-30 characters
|
|
3718
|
+
*/
|
|
3719
|
+
const NameSchema = v.pipe(v.string("Name must be text"), v.minLength(1, "Name must be 1-30 characters long"), v.maxLength(30, "Name must be 1-30 characters long"));
|
|
3720
|
+
/**
|
|
3721
|
+
* Domain validation schema
|
|
3722
|
+
* - Must be lowercase
|
|
3723
|
+
* - Must contain at least one dot
|
|
3724
|
+
* - Only alphanumeric characters, hyphens, and dots
|
|
3725
|
+
* - Cannot start or end with hyphen in any part
|
|
3726
|
+
*/
|
|
3727
|
+
const DomainSchema = v.pipe(v.string("Domain must be text"), v.trim(), v.toLowerCase(), v.minLength(1, "Domain is required"), v.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/, "Invalid domain format. Please enter a valid domain like company.com"));
|
|
3728
|
+
|
|
3729
|
+
//#endregion
|
|
3730
|
+
//#region src/auth/validation/auth.ts
|
|
3731
|
+
const EmailAuthRequestSchema = v.object({
|
|
3732
|
+
email: EmailSchema,
|
|
3733
|
+
password: PasswordSchema
|
|
3734
|
+
});
|
|
3735
|
+
const RegisterRequestSchema = v.object({
|
|
3736
|
+
email: EmailSchema,
|
|
3737
|
+
password: PasswordSchema,
|
|
3738
|
+
country_code: v.optional(v.string()),
|
|
3739
|
+
subscribe_to_blog: v.optional(v.boolean())
|
|
3740
|
+
});
|
|
3741
|
+
const ResetPasswordRequestSchema = v.object({
|
|
3742
|
+
token: v.string(),
|
|
3743
|
+
new_password: PasswordSchema
|
|
3744
|
+
});
|
|
3745
|
+
const LoginOTPVerifyRequestSchema = v.object({
|
|
3746
|
+
code: v.pipe(v.string("TOTP or backup code must be text"), v.minLength(1, "TOTP or backup code is required")),
|
|
3747
|
+
session_id: v.pipe(v.string("Session ID must be text"), v.minLength(1, "Session ID is required"))
|
|
3748
|
+
});
|
|
3749
|
+
const ResendEmailRequestSchema = v.object({ email: EmailSchema });
|
|
3750
|
+
const ChangeEmailRequestSchema = v.object({ new_email: EmailSchema });
|
|
3751
|
+
const verifyEmailChangeRequestSchema = v.object({
|
|
3752
|
+
code: v.pipe(v.string("OTP code must be text"), v.minLength(6, "OTP code must be at least 6 characters"), v.maxLength(8, "OTP code must be at most 8 characters"), v.regex(/^\d+$/, "OTP code must contain only numbers")),
|
|
3753
|
+
new_email: v.optional(EmailSchema),
|
|
3754
|
+
type: v.union([v.literal("verification"), v.literal("email_change")]),
|
|
3755
|
+
verification_id: v.string("Verification ID is required")
|
|
3756
|
+
});
|
|
3757
|
+
/**
|
|
3758
|
+
* Social provider schemas
|
|
3759
|
+
*/
|
|
3760
|
+
const ConnectProviderSchema = v.object({
|
|
3761
|
+
provider: v.pipe(v.string("Provider must be text"), v.minLength(1, "Provider is required")),
|
|
3762
|
+
token: v.pipe(v.string("Token must be text"), v.minLength(1, "Token is required"))
|
|
3763
|
+
});
|
|
3764
|
+
/**
|
|
3765
|
+
* OTP verification schema (for user OTP operations)
|
|
3766
|
+
*/
|
|
3767
|
+
const VerifyOTPCodeSchema = v.object({ code: v.pipe(v.string("OTP code must be text"), v.minLength(6, "OTP code must be at least 6 characters"), v.regex(/^\d+$/, "OTP code must contain only numbers")) });
|
|
3768
|
+
|
|
3769
|
+
//#endregion
|
|
3770
|
+
//#region src/auth/social/socialConnections.ts
|
|
3771
|
+
const PROVIDER_TO_PROTO = {
|
|
3772
|
+
google: "EXTERNAL_ACCOUNT_PROVIDER_GOOGLE",
|
|
3773
|
+
apple: "EXTERNAL_ACCOUNT_PROVIDER_APPLE",
|
|
3774
|
+
microsoft: "EXTERNAL_ACCOUNT_PROVIDER_MICROSOFT",
|
|
3775
|
+
facebook: "EXTERNAL_ACCOUNT_PROVIDER_FACEBOOK",
|
|
3776
|
+
telegram: "EXTERNAL_ACCOUNT_PROVIDER_TELEGRAM"
|
|
3777
|
+
};
|
|
3778
|
+
const PROVIDER_FROM_PROTO = {
|
|
3779
|
+
EXTERNAL_ACCOUNT_PROVIDER_GOOGLE: "google",
|
|
3780
|
+
EXTERNAL_ACCOUNT_PROVIDER_APPLE: "apple",
|
|
3781
|
+
EXTERNAL_ACCOUNT_PROVIDER_MICROSOFT: "microsoft",
|
|
3782
|
+
EXTERNAL_ACCOUNT_PROVIDER_FACEBOOK: "facebook",
|
|
3783
|
+
EXTERNAL_ACCOUNT_PROVIDER_TELEGRAM: "telegram"
|
|
3784
|
+
};
|
|
3785
|
+
const normalizeProviderType = (provider) => provider === "tgAuthResult" || provider === "tgWebAppData" ? "telegram" : provider;
|
|
3786
|
+
const toProtoProvider = (provider) => {
|
|
3787
|
+
const proto = PROVIDER_TO_PROTO[provider];
|
|
3788
|
+
if (!proto) throw new Error(`Unknown provider: ${provider}`);
|
|
3789
|
+
return proto;
|
|
3790
|
+
};
|
|
3791
|
+
const listSocials = async () => {
|
|
3792
|
+
return apiCall(async () => {
|
|
3793
|
+
const { data } = await authV1ProvidersServiceListProviders({ throwOnError: true });
|
|
3794
|
+
return (data.providers ?? []).flatMap((p) => {
|
|
3795
|
+
const provider = p.provider ? PROVIDER_FROM_PROTO[p.provider] : void 0;
|
|
3796
|
+
if (!provider) return [];
|
|
3797
|
+
return [{
|
|
3798
|
+
provider,
|
|
3799
|
+
username: p.username,
|
|
3800
|
+
first_name: p.first_name,
|
|
3801
|
+
last_name: p.last_name,
|
|
3802
|
+
email_address: p.email_address,
|
|
3803
|
+
image_url: p.image_url
|
|
3804
|
+
}];
|
|
3805
|
+
});
|
|
3806
|
+
}, { [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to list providers!") });
|
|
3807
|
+
};
|
|
3808
|
+
const connectSocialInternal = async (provider, token) => {
|
|
3809
|
+
return apiCall(async () => {
|
|
3810
|
+
const requestBody = validateInput(ConnectProviderSchema, {
|
|
3811
|
+
provider,
|
|
3812
|
+
token
|
|
3813
|
+
});
|
|
3814
|
+
const sessionToken = await getToken();
|
|
3815
|
+
const headers = sessionToken ? { Authorization: `Bearer ${sessionToken}` } : {};
|
|
3816
|
+
const exchange = provider === "telegram" ? telegramCodeExchange() : void 0;
|
|
3817
|
+
const body = {
|
|
3818
|
+
provider: toProtoProvider(normalizeProviderType(requestBody.provider)),
|
|
3819
|
+
token: requestBody.token,
|
|
3820
|
+
code_verifier: exchange?.codeVerifier,
|
|
3821
|
+
redirect_uri: exchange?.redirectUri
|
|
3822
|
+
};
|
|
3823
|
+
const { data } = await authV1ProvidersServiceConnectProvider({
|
|
3824
|
+
body,
|
|
3825
|
+
headers,
|
|
3826
|
+
throwOnError: true
|
|
3827
|
+
});
|
|
3828
|
+
persistTokens(data);
|
|
3829
|
+
}, { [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to connect provider!") });
|
|
3830
|
+
};
|
|
3831
|
+
const disconnectSocial = async (provider) => {
|
|
3832
|
+
return apiCall(async () => {
|
|
3833
|
+
await authV1ProvidersServiceDisconnectProvider({
|
|
3834
|
+
path: { provider: toProtoProvider(provider) },
|
|
3835
|
+
throwOnError: true
|
|
3836
|
+
});
|
|
3837
|
+
}, {
|
|
3838
|
+
[HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to disconnect provider!"),
|
|
3839
|
+
[HTTP_STATUS.NOT_FOUND]: () => /* @__PURE__ */ new Error("Provider not found!"),
|
|
3840
|
+
[HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Cannot disconnect the last social provider!")
|
|
3841
|
+
});
|
|
3842
|
+
};
|
|
3843
|
+
const connectSocial = (provider) => {
|
|
3844
|
+
setSocialConnectAttempt(provider);
|
|
3845
|
+
login(provider);
|
|
3846
|
+
};
|
|
3847
|
+
|
|
3800
3848
|
//#endregion
|
|
3801
3849
|
//#region src/auth/authConfig.ts
|
|
3802
3850
|
const config = shared("authConfig", () => ({ loginRedirectUrl: void 0 }));
|
|
@@ -3887,7 +3935,8 @@ const handleInitPageApiError = (error) => {
|
|
|
3887
3935
|
setAuthErrorAndClear("provider_exchange_failed", info.error || info.description, info.email);
|
|
3888
3936
|
};
|
|
3889
3937
|
const exchangeProviderToken = async (provider, token) => {
|
|
3890
|
-
const
|
|
3938
|
+
const options = provider === "telegram" ? telegramCodeExchange() : void 0;
|
|
3939
|
+
const result = await refreshTokens(provider, token, options);
|
|
3891
3940
|
applyTokenExchangeResult(result);
|
|
3892
3941
|
};
|
|
3893
3942
|
const initPage = async () => {
|
|
@@ -3896,8 +3945,12 @@ const initPage = async () => {
|
|
|
3896
3945
|
if (hasProviderResponse()) logUnusableProviderResponse();
|
|
3897
3946
|
return;
|
|
3898
3947
|
}
|
|
3948
|
+
if (provider === "telegram" && hasSocialConnectAttempt(provider)) return void 0;
|
|
3899
3949
|
const token = getProviderToken(provider);
|
|
3900
3950
|
if (!token) return void 0;
|
|
3951
|
+
await loginWithProviderToken(provider, token);
|
|
3952
|
+
};
|
|
3953
|
+
const loginWithProviderToken = async (provider, token) => {
|
|
3901
3954
|
try {
|
|
3902
3955
|
await exchangeProviderToken(provider, token);
|
|
3903
3956
|
} catch (error) {
|
|
@@ -4619,8 +4672,10 @@ const initiateEmailChange = async (email) => {
|
|
|
4619
4672
|
const addEmail = async (email) => {
|
|
4620
4673
|
return apiCall(async () => {
|
|
4621
4674
|
const validatedInput = validateInput(ResendEmailRequestSchema, { email });
|
|
4675
|
+
const limitedToken = limitedAccessToken.get();
|
|
4622
4676
|
const { data } = await authV1EmailServiceAddEmail({
|
|
4623
4677
|
body: validatedInput,
|
|
4678
|
+
...limitedToken && { headers: { Authorization: `Bearer ${limitedToken}` } },
|
|
4624
4679
|
throwOnError: true
|
|
4625
4680
|
});
|
|
4626
4681
|
if (data.verification_id) return {
|