@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.d.ts +376 -3
- package/dist/index.js +846 -601
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
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:
|
|
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/
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
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
|
-
|
|
2493
|
-
country_code: options?.countryCode,
|
|
2494
|
-
origin: options?.origin
|
|
2693
|
+
credential: claimsOf(credential)
|
|
2495
2694
|
},
|
|
2496
|
-
|
|
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/
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
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
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
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
|
-
|
|
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/
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
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/
|
|
2575
|
-
|
|
2576
|
-
const
|
|
2577
|
-
if (
|
|
2578
|
-
|
|
2579
|
-
|
|
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
|
-
|
|
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/
|
|
2810
|
+
//#region src/auth/validation/base.ts
|
|
2598
2811
|
/**
|
|
2599
|
-
*
|
|
2600
|
-
*
|
|
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
|
|
2815
|
+
const validateInput = (schema, data) => {
|
|
2605
2816
|
try {
|
|
2606
|
-
|
|
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
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
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
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
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
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
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
|
|
3178
|
-
let tokenRefreshFunction = null;
|
|
3248
|
+
//#region src/auth/api-url.ts
|
|
3179
3249
|
/**
|
|
3180
|
-
*
|
|
3181
|
-
* This should be called during initialization
|
|
3250
|
+
* Global API base URL store
|
|
3182
3251
|
*/
|
|
3183
|
-
const
|
|
3184
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
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")
|
|
3268
|
-
|
|
3269
|
-
|
|
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)
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|