@rixl/sdk 0.9.0 → 0.10.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 +1246 -114
- package/dist/index.js +933 -582
- 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,
|
|
@@ -757,6 +752,17 @@ const analyticsV1DashboardServiceQueryChart = (options) => (options.client ?? cl
|
|
|
757
752
|
}
|
|
758
753
|
});
|
|
759
754
|
/**
|
|
755
|
+
* BatchQueryChart
|
|
756
|
+
*/
|
|
757
|
+
const analyticsV1DashboardServiceBatchQueryChart = (options) => (options.client ?? client).post({
|
|
758
|
+
url: "/analytics/v1/dashboard/chart-query/batch",
|
|
759
|
+
...options,
|
|
760
|
+
headers: {
|
|
761
|
+
"Content-Type": "application/json",
|
|
762
|
+
...options.headers
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
/**
|
|
760
766
|
* ListDatasets
|
|
761
767
|
*/
|
|
762
768
|
const analyticsV1DashboardServiceListDatasets = (options) => (options?.client ?? client).get({
|
|
@@ -775,6 +781,107 @@ const analyticsV1DashboardServiceGetFilterOptions = (options) => (options.client
|
|
|
775
781
|
}
|
|
776
782
|
});
|
|
777
783
|
/**
|
|
784
|
+
* GetScopeTree
|
|
785
|
+
*/
|
|
786
|
+
const analyticsV1DashboardServiceGetScopeTree = (options) => (options.client ?? client).post({
|
|
787
|
+
url: "/analytics/v1/dashboard/scope-tree",
|
|
788
|
+
...options,
|
|
789
|
+
headers: {
|
|
790
|
+
"Content-Type": "application/json",
|
|
791
|
+
...options.headers
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
/**
|
|
795
|
+
* ListDashboards
|
|
796
|
+
*/
|
|
797
|
+
const analyticsV1DashboardServiceListDashboards = (options) => (options?.client ?? client).get({
|
|
798
|
+
url: "/analytics/v1/dashboards",
|
|
799
|
+
...options
|
|
800
|
+
});
|
|
801
|
+
/**
|
|
802
|
+
* CreateDashboard
|
|
803
|
+
*/
|
|
804
|
+
const analyticsV1DashboardServiceCreateDashboard = (options) => (options.client ?? client).post({
|
|
805
|
+
url: "/analytics/v1/dashboards",
|
|
806
|
+
...options,
|
|
807
|
+
headers: {
|
|
808
|
+
"Content-Type": "application/json",
|
|
809
|
+
...options.headers
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
/**
|
|
813
|
+
* DeleteWidget
|
|
814
|
+
*/
|
|
815
|
+
const analyticsV1DashboardServiceDeleteWidget = (options) => (options.client ?? client).delete({
|
|
816
|
+
url: "/analytics/v1/dashboards/widgets/{id}",
|
|
817
|
+
...options
|
|
818
|
+
});
|
|
819
|
+
/**
|
|
820
|
+
* UpdateWidget
|
|
821
|
+
*/
|
|
822
|
+
const analyticsV1DashboardServiceUpdateWidget = (options) => (options.client ?? client).patch({
|
|
823
|
+
url: "/analytics/v1/dashboards/widgets/{id}",
|
|
824
|
+
...options,
|
|
825
|
+
headers: {
|
|
826
|
+
"Content-Type": "application/json",
|
|
827
|
+
...options.headers
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
/**
|
|
831
|
+
* UpdateDashboardLayout
|
|
832
|
+
*/
|
|
833
|
+
const analyticsV1DashboardServiceUpdateDashboardLayout = (options) => (options.client ?? client).post({
|
|
834
|
+
url: "/analytics/v1/dashboards/{dashboard_id}/layout",
|
|
835
|
+
...options,
|
|
836
|
+
headers: {
|
|
837
|
+
"Content-Type": "application/json",
|
|
838
|
+
...options.headers
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
/**
|
|
842
|
+
* CreateWidget
|
|
843
|
+
*/
|
|
844
|
+
const analyticsV1DashboardServiceCreateWidget = (options) => (options.client ?? client).post({
|
|
845
|
+
url: "/analytics/v1/dashboards/{dashboard_id}/widgets",
|
|
846
|
+
...options,
|
|
847
|
+
headers: {
|
|
848
|
+
"Content-Type": "application/json",
|
|
849
|
+
...options.headers
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
/**
|
|
853
|
+
* DeleteDashboard
|
|
854
|
+
*/
|
|
855
|
+
const analyticsV1DashboardServiceDeleteDashboard = (options) => (options.client ?? client).delete({
|
|
856
|
+
url: "/analytics/v1/dashboards/{id}",
|
|
857
|
+
...options
|
|
858
|
+
});
|
|
859
|
+
/**
|
|
860
|
+
* GetDashboard
|
|
861
|
+
*/
|
|
862
|
+
const analyticsV1DashboardServiceGetDashboard = (options) => (options.client ?? client).get({
|
|
863
|
+
url: "/analytics/v1/dashboards/{id}",
|
|
864
|
+
...options
|
|
865
|
+
});
|
|
866
|
+
/**
|
|
867
|
+
* UpdateDashboard
|
|
868
|
+
*/
|
|
869
|
+
const analyticsV1DashboardServiceUpdateDashboard = (options) => (options.client ?? client).patch({
|
|
870
|
+
url: "/analytics/v1/dashboards/{id}",
|
|
871
|
+
...options,
|
|
872
|
+
headers: {
|
|
873
|
+
"Content-Type": "application/json",
|
|
874
|
+
...options.headers
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
/**
|
|
878
|
+
* SetDefaultDashboard
|
|
879
|
+
*/
|
|
880
|
+
const analyticsV1DashboardServiceSetDefaultDashboard = (options) => (options.client ?? client).post({
|
|
881
|
+
url: "/analytics/v1/dashboards/{id}/default",
|
|
882
|
+
...options
|
|
883
|
+
});
|
|
884
|
+
/**
|
|
778
885
|
* TrackEvents
|
|
779
886
|
*/
|
|
780
887
|
const analyticsV1EventsServiceTrackEvents = (options) => (options.client ?? client).post({
|
|
@@ -836,6 +943,20 @@ const analyticsV1HeatmapServiceGetHotSegments = (options) => (options.client ??
|
|
|
836
943
|
...options
|
|
837
944
|
});
|
|
838
945
|
/**
|
|
946
|
+
* GetImageStats
|
|
947
|
+
*/
|
|
948
|
+
const analyticsV1ImagesServiceGetImageStats = (options) => (options.client ?? client).get({
|
|
949
|
+
url: "/analytics/v1/images/{image_id}/stats",
|
|
950
|
+
...options
|
|
951
|
+
});
|
|
952
|
+
/**
|
|
953
|
+
* GetTopImages
|
|
954
|
+
*/
|
|
955
|
+
const analyticsV1ImagesServiceGetTopImages = (options) => (options?.client ?? client).get({
|
|
956
|
+
url: "/analytics/v1/top/images",
|
|
957
|
+
...options
|
|
958
|
+
});
|
|
959
|
+
/**
|
|
839
960
|
* GetPostStats
|
|
840
961
|
*/
|
|
841
962
|
const analyticsV1PostsServiceGetPostStats = (options) => (options.client ?? client).get({
|
|
@@ -1157,6 +1278,13 @@ const authV1MembershipServiceUpdateOrgUsername = (options) => (options.client ??
|
|
|
1157
1278
|
}
|
|
1158
1279
|
});
|
|
1159
1280
|
/**
|
|
1281
|
+
* RegenerateBackupCodes
|
|
1282
|
+
*/
|
|
1283
|
+
const authV1OtpServiceRegenerateBackupCodes = (options) => (options?.client ?? client).post({
|
|
1284
|
+
url: "/auth/v1/users/current/totp/backup-codes/regenerate",
|
|
1285
|
+
...options
|
|
1286
|
+
});
|
|
1287
|
+
/**
|
|
1160
1288
|
* DeleteOTP
|
|
1161
1289
|
*/
|
|
1162
1290
|
const authV1OtpServiceDeleteOtp = (options) => (options?.client ?? client).delete({
|
|
@@ -1312,6 +1440,13 @@ const authV1PolicyServiceDetachPolicy = (options) => (options.client ?? client).
|
|
|
1312
1440
|
...options
|
|
1313
1441
|
});
|
|
1314
1442
|
/**
|
|
1443
|
+
* ListPermissionRegistry
|
|
1444
|
+
*/
|
|
1445
|
+
const authV1PolicyServiceListPermissionRegistry = (options) => (options.client ?? client).get({
|
|
1446
|
+
url: "/auth/v1/memberships/{user.org_id}/policies/permissions",
|
|
1447
|
+
...options
|
|
1448
|
+
});
|
|
1449
|
+
/**
|
|
1315
1450
|
* DeletePolicy
|
|
1316
1451
|
*/
|
|
1317
1452
|
const authV1PolicyServiceDeletePolicy = (options) => (options.client ?? client).delete({
|
|
@@ -1355,13 +1490,6 @@ const authV1PolicyServiceAttachPolicy = (options) => (options.client ?? client).
|
|
|
1355
1490
|
}
|
|
1356
1491
|
});
|
|
1357
1492
|
/**
|
|
1358
|
-
* ListPermissionRegistry
|
|
1359
|
-
*/
|
|
1360
|
-
const authV1PolicyServiceListPermissionRegistry = (options) => (options?.client ?? client).get({
|
|
1361
|
-
url: "/auth/v1/policies/permissions",
|
|
1362
|
-
...options
|
|
1363
|
-
});
|
|
1364
|
-
/**
|
|
1365
1493
|
* ListProviders
|
|
1366
1494
|
*/
|
|
1367
1495
|
const authV1ProvidersServiceListProviders = (options) => (options?.client ?? client).get({
|
|
@@ -2324,6 +2452,15 @@ function validateOAuthState(provider, state) {
|
|
|
2324
2452
|
return sessionStorage.getItem(storagePath(provider)) === state;
|
|
2325
2453
|
}
|
|
2326
2454
|
/**
|
|
2455
|
+
* Discards the stored state for a provider so the next login round-trip mints a
|
|
2456
|
+
* fresh one. The state doubles as the OAuth `nonce`, so reusing it across logins
|
|
2457
|
+
* would replay a nonce the provider has already issued a token for.
|
|
2458
|
+
* @param provider The provider identifier
|
|
2459
|
+
*/
|
|
2460
|
+
function clearOauthState(provider) {
|
|
2461
|
+
sessionStorage.removeItem(storagePath(provider));
|
|
2462
|
+
}
|
|
2463
|
+
/**
|
|
2327
2464
|
* Gets or Generates a complete state parameter for OAuth requests
|
|
2328
2465
|
* @param provider The identifier for the provider (e.g., 'google', 'apple')
|
|
2329
2466
|
* @returns A state string containing the provider identifier and random data
|
|
@@ -2347,9 +2484,10 @@ function generateOauthState(provider) {
|
|
|
2347
2484
|
* Builds an OAuth URL from configuration and metadata
|
|
2348
2485
|
*/
|
|
2349
2486
|
const buildOAuthUrl = (config, metadata, state) => {
|
|
2487
|
+
const redirectUri = config.redirectUri ?? window.location.origin;
|
|
2350
2488
|
const params = new URLSearchParams({
|
|
2351
2489
|
client_id: config.clientId,
|
|
2352
|
-
redirect_uri:
|
|
2490
|
+
redirect_uri: redirectUri,
|
|
2353
2491
|
response_type: metadata.responseType,
|
|
2354
2492
|
scope: [...metadata.defaultScopes, ...config.scope ? [config.scope] : []].join(" "),
|
|
2355
2493
|
state
|
|
@@ -2372,8 +2510,8 @@ const warnProviderNotConfigured = (providerName) => {
|
|
|
2372
2510
|
* This factory reduces code duplication across OAuth providers
|
|
2373
2511
|
*/
|
|
2374
2512
|
const createOAuthProvider = ({ provider, metadata }) => {
|
|
2375
|
-
const config = atom(null);
|
|
2376
|
-
const authUrl = atom(null);
|
|
2513
|
+
const config = shared(`provider.${provider}.config`, () => atom(null));
|
|
2514
|
+
const authUrl = shared(`provider.${provider}.authUrl`, () => atom(null));
|
|
2377
2515
|
const updateAuthUrl = () => {
|
|
2378
2516
|
const currentConfig = config.get();
|
|
2379
2517
|
if (!currentConfig) {
|
|
@@ -2449,8 +2587,8 @@ const updateAppleAuthUrl = appleProvider.updateAuthUrl;
|
|
|
2449
2587
|
|
|
2450
2588
|
//#endregion
|
|
2451
2589
|
//#region src/auth/providers/telegram.ts
|
|
2452
|
-
const telegramConfig = atom(null);
|
|
2453
|
-
const telegramAuthUrl = atom(null);
|
|
2590
|
+
const telegramConfig = shared("provider.telegram.config", () => atom(null));
|
|
2591
|
+
const telegramAuthUrl = shared("provider.telegram.authUrl", () => atom(null));
|
|
2454
2592
|
/**
|
|
2455
2593
|
* Updates the Telegram authentication URL using the configured settings
|
|
2456
2594
|
*/
|
|
@@ -2483,7 +2621,7 @@ function extractProviderFromState(state) {
|
|
|
2483
2621
|
const parts = state.split("_");
|
|
2484
2622
|
if (parts.length >= 1) return parts[0];
|
|
2485
2623
|
}
|
|
2486
|
-
const OAUTH_PROVIDERS = [
|
|
2624
|
+
const OAUTH_PROVIDERS$1 = [
|
|
2487
2625
|
"google",
|
|
2488
2626
|
"apple",
|
|
2489
2627
|
"microsoft"
|
|
@@ -2499,7 +2637,7 @@ function detectProvider() {
|
|
|
2499
2637
|
const state = urlParams.get("state");
|
|
2500
2638
|
if (id_token && state) {
|
|
2501
2639
|
const providerFromState = extractProviderFromState(state);
|
|
2502
|
-
return OAUTH_PROVIDERS.find((p) => providerFromState === p && validateOAuthState(p, state));
|
|
2640
|
+
return OAUTH_PROVIDERS$1.find((p) => providerFromState === p && validateOAuthState(p, state));
|
|
2503
2641
|
}
|
|
2504
2642
|
}
|
|
2505
2643
|
/**
|
|
@@ -2513,20 +2651,210 @@ function getProviderToken(provider) {
|
|
|
2513
2651
|
}
|
|
2514
2652
|
|
|
2515
2653
|
//#endregion
|
|
2516
|
-
//#region src/auth/
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2654
|
+
//#region src/auth/providers/callback.ts
|
|
2655
|
+
/** Params that carry the credential itself — their presence marks a callback response. */
|
|
2656
|
+
const CREDENTIAL_PARAMS = [
|
|
2657
|
+
"id_token",
|
|
2658
|
+
"code",
|
|
2659
|
+
"access_token",
|
|
2660
|
+
"tgAuthResult",
|
|
2661
|
+
"tgWebAppData"
|
|
2662
|
+
];
|
|
2663
|
+
/** Everything the providers append to the redirect URL, credential and bookkeeping alike. */
|
|
2664
|
+
const OAUTH_RESPONSE_PARAMS = [
|
|
2665
|
+
...CREDENTIAL_PARAMS,
|
|
2666
|
+
"state",
|
|
2667
|
+
"token_type",
|
|
2668
|
+
"expires_in",
|
|
2669
|
+
"scope",
|
|
2670
|
+
"session_state",
|
|
2671
|
+
"authuser",
|
|
2672
|
+
"prompt",
|
|
2673
|
+
"hd"
|
|
2674
|
+
];
|
|
2675
|
+
/**
|
|
2676
|
+
* Whether the URL this page loaded with carries a provider response at all —
|
|
2677
|
+
* unlike `detectProvider()`, this does not require the state to validate. The
|
|
2678
|
+
* gap between the two is the case where a login round-trip came back but cannot
|
|
2679
|
+
* be used, which otherwise ends the flow in silence.
|
|
2680
|
+
*/
|
|
2681
|
+
const hasProviderResponse = () => CREDENTIAL_PARAMS.some((key) => urlParams.has(key));
|
|
2682
|
+
const AUTH_URL_UPDATERS = {
|
|
2683
|
+
["google"]: updateGoogleAuthUrl,
|
|
2684
|
+
["apple"]: updateAppleAuthUrl,
|
|
2685
|
+
["microsoft"]: updateMicrosoftAuthUrl
|
|
2686
|
+
};
|
|
2687
|
+
/** Returns undefined when the half holds no credential, meaning it is the app's own and must not be touched. */
|
|
2688
|
+
const stripped = (query) => {
|
|
2689
|
+
const params = new URLSearchParams(query);
|
|
2690
|
+
if (!CREDENTIAL_PARAMS.some((key) => params.has(key))) return void 0;
|
|
2691
|
+
OAUTH_RESPONSE_PARAMS.forEach((key) => params.delete(key));
|
|
2692
|
+
return params.toString();
|
|
2693
|
+
};
|
|
2694
|
+
/**
|
|
2695
|
+
* Providers put their response in the query string or the fragment depending on
|
|
2696
|
+
* `response_mode`, and either half may also hold params the app itself put
|
|
2697
|
+
* there. Only the half actually carrying the credential is rewritten.
|
|
2698
|
+
*/
|
|
2699
|
+
const withoutOAuthResponse = (href) => {
|
|
2700
|
+
const url = new URL(href);
|
|
2701
|
+
url.search = stripped(url.search) ?? url.search;
|
|
2702
|
+
url.hash = stripped(url.hash.slice(1)) ?? url.hash;
|
|
2703
|
+
return url.toString();
|
|
2704
|
+
};
|
|
2705
|
+
/**
|
|
2706
|
+
* Retires the provider response after `initClient` is done with it.
|
|
2707
|
+
*
|
|
2708
|
+
* Left in place, the credential stays in the address bar and every reload — or
|
|
2709
|
+
* Vite's HMR full reload — replays an already-consumed `id_token`, which the
|
|
2710
|
+
* gateway rejects. Clearing the stored state on the way out also stops the next
|
|
2711
|
+
* login from reusing this round-trip's `nonce`.
|
|
2712
|
+
*
|
|
2713
|
+
* The `urlParams` snapshot is taken at import time and is intentionally left
|
|
2714
|
+
* untouched, so callers that already read the credential out of it keep working
|
|
2715
|
+
* for the rest of this page load.
|
|
2716
|
+
*/
|
|
2717
|
+
const completeOAuthCallback = () => {
|
|
2718
|
+
const provider = detectProvider();
|
|
2719
|
+
if (!provider) return;
|
|
2720
|
+
clearOauthState(provider);
|
|
2721
|
+
AUTH_URL_UPDATERS[provider]?.();
|
|
2722
|
+
window.history.replaceState(window.history.state, "", withoutOAuthResponse(window.location.href));
|
|
2723
|
+
};
|
|
2724
|
+
|
|
2725
|
+
//#endregion
|
|
2726
|
+
//#region src/auth/api/types.ts
|
|
2727
|
+
/**
|
|
2728
|
+
* Generic API error class - wraps ky's HTTPError for consistency
|
|
2729
|
+
*/
|
|
2730
|
+
var ApiError = class extends Error {
|
|
2731
|
+
status;
|
|
2732
|
+
endpoint;
|
|
2733
|
+
data;
|
|
2734
|
+
constructor(message, ...rest) {
|
|
2735
|
+
super(message);
|
|
2736
|
+
this.name = "ApiError";
|
|
2737
|
+
const firstArg = rest[0];
|
|
2738
|
+
if (typeof firstArg === "number") {
|
|
2739
|
+
this.status = firstArg;
|
|
2740
|
+
this.endpoint = rest[1] ?? "";
|
|
2741
|
+
this.data = rest[2];
|
|
2742
|
+
return;
|
|
2743
|
+
}
|
|
2744
|
+
this.status = firstArg.status;
|
|
2745
|
+
this.endpoint = firstArg.endpoint;
|
|
2746
|
+
this.data = firstArg.data;
|
|
2747
|
+
}
|
|
2748
|
+
};
|
|
2749
|
+
|
|
2750
|
+
//#endregion
|
|
2751
|
+
//#region src/auth/providers/diagnostics.ts
|
|
2752
|
+
const claimsOf = (token) => {
|
|
2753
|
+
try {
|
|
2754
|
+
const { iss, aud, exp, nonce, email } = decodeJwt(token);
|
|
2755
|
+
return {
|
|
2756
|
+
iss: String(iss ?? ""),
|
|
2757
|
+
aud: String(aud ?? ""),
|
|
2758
|
+
exp: exp ? (/* @__PURE__ */ new Date(Number(exp) * 1e3)).toISOString() : void 0,
|
|
2759
|
+
expired: typeof exp === "number" && Date.now() >= exp * 1e3,
|
|
2760
|
+
nonce: String(nonce ?? ""),
|
|
2761
|
+
email: String(email ?? "")
|
|
2762
|
+
};
|
|
2763
|
+
} catch {
|
|
2764
|
+
return { note: "not a JWT — expected for Telegram, unexpected for Google/Apple/Microsoft" };
|
|
2765
|
+
}
|
|
2766
|
+
};
|
|
2767
|
+
const verdictFor = (error) => {
|
|
2768
|
+
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.";
|
|
2769
|
+
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`.";
|
|
2770
|
+
if (error.status === HTTP_STATUS.CONFLICT) return "EXPECTED: this email already belongs to an account created with a different provider.";
|
|
2771
|
+
if (error.status === HTTP_STATUS.BAD_REQUEST) return "BACKEND: the gateway rejected the request body. Read `response.body` for its reason.";
|
|
2772
|
+
return "UNKNOWN: see `response` below.";
|
|
2773
|
+
};
|
|
2774
|
+
const describe = (error) => {
|
|
2775
|
+
if (!(error instanceof ApiError)) return {
|
|
2776
|
+
response: {
|
|
2777
|
+
status: "none — the request never completed",
|
|
2778
|
+
detail: String(error)
|
|
2779
|
+
},
|
|
2780
|
+
verdict: "NETWORK or CORS: the browser never got a response. Check the gateway is reachable and its CORS headers allow this origin."
|
|
2781
|
+
};
|
|
2782
|
+
return {
|
|
2783
|
+
response: {
|
|
2784
|
+
status: error.status,
|
|
2785
|
+
body: error.data,
|
|
2786
|
+
message: error.message
|
|
2787
|
+
},
|
|
2788
|
+
verdict: verdictFor(error)
|
|
2789
|
+
};
|
|
2790
|
+
};
|
|
2791
|
+
const OAUTH_PROVIDERS = [
|
|
2792
|
+
"google",
|
|
2793
|
+
"apple",
|
|
2794
|
+
"microsoft"
|
|
2795
|
+
];
|
|
2796
|
+
const storedStates = () => Object.fromEntries(OAUTH_PROVIDERS.map((p) => [p, sessionStorage.getItem("__rixl_auth_state_" + p) ?? "(none)"]));
|
|
2797
|
+
/**
|
|
2798
|
+
* Reports a provider response that arrived but could not be used, which ends the
|
|
2799
|
+
* login without a request ever being sent — the case that otherwise looks like
|
|
2800
|
+
* "it just went back to the login page".
|
|
2801
|
+
*
|
|
2802
|
+
* `detectProvider()` requires the `state` in the URL to equal the one stored when
|
|
2803
|
+
* the login started, so the two states below are the thing to compare.
|
|
2804
|
+
*/
|
|
2805
|
+
const logUnusableProviderResponse = () => {
|
|
2806
|
+
const state = urlParams.get("state") ?? "(none)";
|
|
2807
|
+
console.error("[@rixl/sdk] a provider response is in the URL but no login was attempted", {
|
|
2808
|
+
urlState: state,
|
|
2809
|
+
storedStates: storedStates(),
|
|
2810
|
+
credentialParams: [
|
|
2811
|
+
"id_token",
|
|
2812
|
+
"code",
|
|
2813
|
+
"access_token"
|
|
2814
|
+
].filter((key) => urlParams.has(key)),
|
|
2815
|
+
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."
|
|
2816
|
+
});
|
|
2817
|
+
};
|
|
2818
|
+
/**
|
|
2819
|
+
* Reports a failed provider token exchange. `provider` doubles as the `token_type`
|
|
2820
|
+
* sent on the wire, so it is printed as-is.
|
|
2821
|
+
*/
|
|
2822
|
+
const logProviderExchangeFailure = (provider, credential, error) => {
|
|
2823
|
+
console.error("[@rixl/sdk] provider login failed at POST /auth/v1/token", {
|
|
2824
|
+
request: {
|
|
2520
2825
|
token_type: provider,
|
|
2521
|
-
|
|
2522
|
-
country_code: options?.countryCode,
|
|
2523
|
-
origin: options?.origin
|
|
2826
|
+
credential: claimsOf(credential)
|
|
2524
2827
|
},
|
|
2525
|
-
|
|
2828
|
+
...describe(error)
|
|
2526
2829
|
});
|
|
2527
|
-
return data;
|
|
2528
2830
|
};
|
|
2529
2831
|
|
|
2832
|
+
//#endregion
|
|
2833
|
+
//#region src/auth/social/socialState.ts
|
|
2834
|
+
const socialStoragePath = (provider) => SOCIAL_CONNECT_KEY_PREFIX + provider;
|
|
2835
|
+
/**
|
|
2836
|
+
* Sets a flag indicating that a social provider connection is being attempted
|
|
2837
|
+
* @param provider The provider identifier
|
|
2838
|
+
*/
|
|
2839
|
+
function setSocialConnectAttempt(provider) {
|
|
2840
|
+
sessionStorage.setItem(socialStoragePath(provider), "true");
|
|
2841
|
+
}
|
|
2842
|
+
/**
|
|
2843
|
+
* Checks if there's a pending social provider connection attempt
|
|
2844
|
+
* @param provider The provider identifier
|
|
2845
|
+
* @returns True if there's a pending connection attempt, false otherwise
|
|
2846
|
+
*/
|
|
2847
|
+
function hasSocialConnectAttempt(provider) {
|
|
2848
|
+
return sessionStorage.getItem(socialStoragePath(provider)) === "true";
|
|
2849
|
+
}
|
|
2850
|
+
/**
|
|
2851
|
+
* Clears the social provider connection attempt flag
|
|
2852
|
+
* @param provider The provider identifier
|
|
2853
|
+
*/
|
|
2854
|
+
function clearSocialConnectAttempt(provider) {
|
|
2855
|
+
sessionStorage.removeItem(socialStoragePath(provider));
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2530
2858
|
//#endregion
|
|
2531
2859
|
//#region src/auth/initialization.ts
|
|
2532
2860
|
/**
|
|
@@ -2546,482 +2874,42 @@ function createDeferred() {
|
|
|
2546
2874
|
};
|
|
2547
2875
|
}
|
|
2548
2876
|
/**
|
|
2549
|
-
* Global deferred promise that tracks the initialization status of the auth library
|
|
2550
|
-
* This is resolved when initClient is called
|
|
2877
|
+
* Global deferred promise that tracks the initialization status of the auth library.
|
|
2878
|
+
* This is resolved when initClient is called.
|
|
2879
|
+
*
|
|
2880
|
+
* Shared across copies of this package. `connect()` runs in exactly one copy, so
|
|
2881
|
+
* a per-copy deferred leaves every other copy awaiting a promise nothing will
|
|
2882
|
+
* ever resolve — and because getToken() and the request interceptor both await
|
|
2883
|
+
* it, that is not a slow path but a permanent hang.
|
|
2551
2884
|
*/
|
|
2552
|
-
const initDeferred = createDeferred
|
|
2885
|
+
const initDeferred = shared("initDeferred", createDeferred);
|
|
2553
2886
|
|
|
2554
2887
|
//#endregion
|
|
2555
|
-
//#region src/auth/
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2888
|
+
//#region src/auth/api/error-handlers.ts
|
|
2889
|
+
/**
|
|
2890
|
+
* Helper to create error functions - reduces bundle size by reusing error creation logic
|
|
2891
|
+
*/
|
|
2892
|
+
const err = (message) => () => new Error(message);
|
|
2893
|
+
/** Reusable error handlers for common cases - reduces repetitive error messages */
|
|
2894
|
+
const commonErrors = {
|
|
2895
|
+
unauthorized: err("User is not authorized"),
|
|
2896
|
+
badRequest: err("Bad request"),
|
|
2897
|
+
notFound: err("Not found"),
|
|
2898
|
+
conflict: err("Resource already exists"),
|
|
2899
|
+
forbidden: err("Forbidden"),
|
|
2900
|
+
tooManyRequests: err("Too many requests")
|
|
2559
2901
|
};
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
} else cookieString += `; expires=${options.expires.toUTCString()}`;
|
|
2569
|
-
if (options.path) cookieString += `; path=${options.path}`;
|
|
2570
|
-
if (options.domain) cookieString += `; domain=${options.domain}`;
|
|
2571
|
-
if (options.secure) cookieString += `; secure`;
|
|
2572
|
-
if (options.sameSite) cookieString += `; samesite=${options.sameSite}`;
|
|
2902
|
+
/**
|
|
2903
|
+
* Standard error handler for API errors with custom status code handling
|
|
2904
|
+
*/
|
|
2905
|
+
const handleApiError = (error, statusHandlers) => {
|
|
2906
|
+
if (error instanceof ApiError) {
|
|
2907
|
+
const handler = statusHandlers[error.status];
|
|
2908
|
+
if (handler) throw new ApiError(handler().message, error.status, error.endpoint, error.data);
|
|
2909
|
+
throw error;
|
|
2573
2910
|
}
|
|
2574
|
-
|
|
2575
|
-
}
|
|
2576
|
-
function deleteCookie(name) {
|
|
2577
|
-
if (typeof document === "undefined") return;
|
|
2578
|
-
document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
|
2579
|
-
}
|
|
2580
|
-
const encodeName = (name) => encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent);
|
|
2581
|
-
const encodeValue = (value) => encodeURIComponent(value).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, decodeURIComponent);
|
|
2582
|
-
|
|
2583
|
-
//#endregion
|
|
2584
|
-
//#region src/auth/cookie/index.ts
|
|
2585
|
-
const initVals = getAllCookiesStartWith(GLOBAL_PREFIX);
|
|
2586
|
-
const setStoreCookie = (key, value) => {
|
|
2587
|
-
const expires = /* @__PURE__ */ new Date();
|
|
2588
|
-
expires.setTime(expires.getTime() + 30 * 24 * 60 * 60 * 1e3);
|
|
2589
|
-
const cookieKey = `${GLOBAL_PREFIX}_${key}`;
|
|
2590
|
-
if (!value || value === "") {
|
|
2591
|
-
deleteCookie(cookieKey);
|
|
2592
|
-
return;
|
|
2593
|
-
}
|
|
2594
|
-
const stringValue = typeof value === "string" ? value : JSON.stringify(value);
|
|
2595
|
-
setCookie(`${GLOBAL_PREFIX}_${key}`, stringValue, {
|
|
2596
|
-
expires,
|
|
2597
|
-
path: "/",
|
|
2598
|
-
sameSite: "Lax"
|
|
2599
|
-
});
|
|
2600
|
-
};
|
|
2601
|
-
|
|
2602
|
-
//#endregion
|
|
2603
|
-
//#region src/auth/userStore.ts
|
|
2604
|
-
const userPath = GLOBAL_PREFIX + "_user";
|
|
2605
|
-
const parseUser = () => {
|
|
2606
|
-
if (typeof localStorage === "undefined" || !localStorage || typeof localStorage.getItem !== "function") return;
|
|
2607
|
-
const value = localStorage.getItem(userPath);
|
|
2608
|
-
if (value && value != "undefined") try {
|
|
2609
|
-
return JSON.parse(value);
|
|
2610
|
-
} catch (err) {
|
|
2611
|
-
console.warn("Can't parse user data, error: ", err);
|
|
2612
|
-
return;
|
|
2613
|
-
}
|
|
2614
|
-
};
|
|
2615
|
-
const user = shared("user", () => {
|
|
2616
|
-
const store = atom(parseUser());
|
|
2617
|
-
store.subscribe((value) => {
|
|
2618
|
-
if (typeof localStorage === "undefined" || !localStorage || typeof localStorage.setItem !== "function") return;
|
|
2619
|
-
if (value) localStorage.setItem(userPath, JSON.stringify(value));
|
|
2620
|
-
else localStorage.removeItem(userPath);
|
|
2621
|
-
});
|
|
2622
|
-
return store;
|
|
2623
|
-
});
|
|
2624
|
-
|
|
2625
|
-
//#endregion
|
|
2626
|
-
//#region src/auth/utils/jwt.ts
|
|
2627
|
-
/**
|
|
2628
|
-
* Decodes a JWT token and extracts user information
|
|
2629
|
-
* Uses jose library for modern, secure JWT handling
|
|
2630
|
-
* @param token The JWT token to decode
|
|
2631
|
-
* @returns The decoded user data or undefined if decoding fails
|
|
2632
|
-
*/
|
|
2633
|
-
const decodeToken = (token) => {
|
|
2634
|
-
try {
|
|
2635
|
-
const decodedUser = decodeJwt(token);
|
|
2636
|
-
return {
|
|
2637
|
-
id: decodedUser.id,
|
|
2638
|
-
email: decodedUser.email,
|
|
2639
|
-
first_name: decodedUser.first_name,
|
|
2640
|
-
last_name: decodedUser.last_name,
|
|
2641
|
-
username: decodedUser.username,
|
|
2642
|
-
image_url: decodedUser.image_url,
|
|
2643
|
-
language_code: decodedUser.language_code,
|
|
2644
|
-
org_id: decodedUser.org_id
|
|
2645
|
-
};
|
|
2646
|
-
} catch (error) {
|
|
2647
|
-
console.warn("Failed to decode JWT token. Error: ", error);
|
|
2648
|
-
return;
|
|
2649
|
-
}
|
|
2650
|
-
};
|
|
2651
|
-
/**
|
|
2652
|
-
* Decodes a JWT token and sets the user in the store
|
|
2653
|
-
* @param token The JWT token to decode
|
|
2654
|
-
* @returns True if user was successfully decoded and set, false otherwise
|
|
2655
|
-
*/
|
|
2656
|
-
const decodeAndSetUser = (token) => {
|
|
2657
|
-
const userData = decodeToken(token);
|
|
2658
|
-
if (userData) {
|
|
2659
|
-
user.set(userData);
|
|
2660
|
-
return true;
|
|
2661
|
-
}
|
|
2662
|
-
return false;
|
|
2663
|
-
};
|
|
2664
|
-
/**
|
|
2665
|
-
* Checks if a token is expired based on the expiration timestamp
|
|
2666
|
-
* @param expireAt The expiration timestamp in milliseconds
|
|
2667
|
-
* @returns True if the token is expired, false otherwise
|
|
2668
|
-
*/
|
|
2669
|
-
const isTokenExpired = (expireAt) => {
|
|
2670
|
-
if (!expireAt) return true;
|
|
2671
|
-
return Date.now() >= expireAt;
|
|
2672
|
-
};
|
|
2673
|
-
|
|
2674
|
-
//#endregion
|
|
2675
|
-
//#region src/auth/authStore.ts
|
|
2676
|
-
const isLogged = shared("isLogged", () => atom(initVals["isLogged"] === "true" || detectProvider() !== void 0));
|
|
2677
|
-
const accessToken = shared("accessToken", () => atom(initVals["accessToken"]));
|
|
2678
|
-
const refreshToken = shared("refreshToken", () => atom(initVals["refreshToken"]));
|
|
2679
|
-
const expireAt = shared("expireAt", () => atom(Number(initVals["expireAt"])));
|
|
2680
|
-
const authError = shared("authError", () => atom(null));
|
|
2681
|
-
const requiresAction = shared("requiresAction", () => atom(initVals["requiresAction"] || null));
|
|
2682
|
-
const limitedAccessToken = shared("limitedAccessToken", () => atom(initVals["limitedAccessToken"] || null));
|
|
2683
|
-
let currentTokenPromise = null;
|
|
2684
|
-
const PROVIDER_URL_MAP = {
|
|
2685
|
-
google: googleAuthUrl,
|
|
2686
|
-
apple: appleAuthUrl,
|
|
2687
|
-
microsoft: microsoftAuthUrl,
|
|
2688
|
-
telegram: telegramAuthUrl
|
|
2689
|
-
};
|
|
2690
|
-
const login = async (provider) => {
|
|
2691
|
-
await initDeferred.promise;
|
|
2692
|
-
const authUrlAtom = PROVIDER_URL_MAP[provider];
|
|
2693
|
-
if (!authUrlAtom) throw new Error(`Unsupported provider: ${provider}`);
|
|
2694
|
-
const authUrl = authUrlAtom.get();
|
|
2695
|
-
if (authUrl) window.location.href = authUrl;
|
|
2696
|
-
else throw new Error(`${provider} provider is not configured. Please check your initClient configuration.`);
|
|
2697
|
-
};
|
|
2698
|
-
const refreshAccessToken = async (refresh) => {
|
|
2699
|
-
const result = await refreshTokens("Bearer", refresh);
|
|
2700
|
-
if (!("requires_action" in result)) setTokens(result.access_token, result.refresh_token, result.expires_in);
|
|
2701
|
-
};
|
|
2702
|
-
const ensureValidAccessToken = async (refresh) => {
|
|
2703
|
-
if (accessToken.get() && !isTokenExpired(expireAt.get())) return;
|
|
2704
|
-
try {
|
|
2705
|
-
await refreshAccessToken(refresh);
|
|
2706
|
-
} catch (refreshError) {
|
|
2707
|
-
console.error("Token refresh failed in getToken:", refreshError);
|
|
2708
|
-
removeTokens();
|
|
2709
|
-
throw refreshError;
|
|
2710
|
-
}
|
|
2711
|
-
};
|
|
2712
|
-
const getToken = async () => {
|
|
2713
|
-
if (currentTokenPromise) return currentTokenPromise;
|
|
2714
|
-
currentTokenPromise = (async () => {
|
|
2715
|
-
try {
|
|
2716
|
-
await initDeferred.promise;
|
|
2717
|
-
if (requiresAction.get()) return void 0;
|
|
2718
|
-
const currentRefreshToken = refreshToken.get();
|
|
2719
|
-
if (!currentRefreshToken) return void 0;
|
|
2720
|
-
await ensureValidAccessToken(currentRefreshToken);
|
|
2721
|
-
const token = accessToken.get();
|
|
2722
|
-
if (token) decodeAndSetUser(token);
|
|
2723
|
-
return token;
|
|
2724
|
-
} catch (error) {
|
|
2725
|
-
console.warn("Failed to getToken(). Error: ", error);
|
|
2726
|
-
throw error;
|
|
2727
|
-
} finally {
|
|
2728
|
-
currentTokenPromise = null;
|
|
2729
|
-
}
|
|
2730
|
-
})();
|
|
2731
|
-
return currentTokenPromise;
|
|
2732
|
-
};
|
|
2733
|
-
/**
|
|
2734
|
-
* Sets authentication tokens in the store
|
|
2735
|
-
* @param access The access token
|
|
2736
|
-
* @param refresh The refresh token
|
|
2737
|
-
* @param expiresIn The token expiration time in seconds
|
|
2738
|
-
*/
|
|
2739
|
-
const setTokens = (access, refresh, expiresIn) => {
|
|
2740
|
-
accessToken.set(access);
|
|
2741
|
-
refreshToken.set(refresh);
|
|
2742
|
-
expireAt.set(Date.now() + expiresIn * 1e3);
|
|
2743
|
-
isLogged.set(true);
|
|
2744
|
-
limitedAccessToken.set(null);
|
|
2745
|
-
requiresAction.set(null);
|
|
2746
|
-
authError.set(null);
|
|
2747
|
-
decodeAndSetUser(access);
|
|
2748
|
-
};
|
|
2749
|
-
/**
|
|
2750
|
-
* Removes authentication tokens from the store
|
|
2751
|
-
*/
|
|
2752
|
-
const removeTokens = () => {
|
|
2753
|
-
accessToken.set("");
|
|
2754
|
-
refreshToken.set("");
|
|
2755
|
-
expireAt.set(0);
|
|
2756
|
-
isLogged.set(false);
|
|
2757
|
-
user.set(void 0);
|
|
2758
|
-
limitedAccessToken.set(null);
|
|
2759
|
-
requiresAction.set(null);
|
|
2760
|
-
authError.set(null);
|
|
2761
|
-
};
|
|
2762
|
-
/**
|
|
2763
|
-
* Clears the auth error from the store
|
|
2764
|
-
*/
|
|
2765
|
-
const clearAuthError = () => {
|
|
2766
|
-
authError.set(null);
|
|
2767
|
-
};
|
|
2768
|
-
/**
|
|
2769
|
-
* Sets limited access state for users requiring additional action (e.g., Telegram users without email)
|
|
2770
|
-
* @param token The limited scope access token
|
|
2771
|
-
* @param action The required action (e.g., "add_email")
|
|
2772
|
-
*/
|
|
2773
|
-
const setLimitedAccessState = (token, action) => {
|
|
2774
|
-
limitedAccessToken.set(token);
|
|
2775
|
-
requiresAction.set(action);
|
|
2776
|
-
authError.set(null);
|
|
2777
|
-
isLogged.set(true);
|
|
2778
|
-
};
|
|
2779
|
-
/**
|
|
2780
|
-
* Clears the limited access state (after email verification completes or user logs out)
|
|
2781
|
-
*/
|
|
2782
|
-
const clearLimitedAccessState = () => {
|
|
2783
|
-
limitedAccessToken.set(null);
|
|
2784
|
-
requiresAction.set(null);
|
|
2785
|
-
if (!(!!accessToken.get() && !!refreshToken.get())) isLogged.set(false);
|
|
2786
|
-
};
|
|
2787
|
-
isLogged.subscribe((value) => setStoreCookie("isLogged", value));
|
|
2788
|
-
accessToken.subscribe((value) => setStoreCookie("accessToken", value));
|
|
2789
|
-
refreshToken.subscribe((value) => setStoreCookie("refreshToken", value));
|
|
2790
|
-
expireAt.subscribe((value) => setStoreCookie("expireAt", value));
|
|
2791
|
-
requiresAction.subscribe((value) => setStoreCookie("requiresAction", value));
|
|
2792
|
-
limitedAccessToken.subscribe((value) => setStoreCookie("limitedAccessToken", value));
|
|
2793
|
-
|
|
2794
|
-
//#endregion
|
|
2795
|
-
//#region src/auth/api/types.ts
|
|
2796
|
-
/**
|
|
2797
|
-
* Generic API error class - wraps ky's HTTPError for consistency
|
|
2798
|
-
*/
|
|
2799
|
-
var ApiError = class extends Error {
|
|
2800
|
-
status;
|
|
2801
|
-
endpoint;
|
|
2802
|
-
data;
|
|
2803
|
-
constructor(message, ...rest) {
|
|
2804
|
-
super(message);
|
|
2805
|
-
this.name = "ApiError";
|
|
2806
|
-
const firstArg = rest[0];
|
|
2807
|
-
if (typeof firstArg === "number") {
|
|
2808
|
-
this.status = firstArg;
|
|
2809
|
-
this.endpoint = rest[1] ?? "";
|
|
2810
|
-
this.data = rest[2];
|
|
2811
|
-
return;
|
|
2812
|
-
}
|
|
2813
|
-
this.status = firstArg.status;
|
|
2814
|
-
this.endpoint = firstArg.endpoint;
|
|
2815
|
-
this.data = firstArg.data;
|
|
2816
|
-
}
|
|
2817
|
-
};
|
|
2818
|
-
|
|
2819
|
-
//#endregion
|
|
2820
|
-
//#region src/auth/api-url.ts
|
|
2821
|
-
/**
|
|
2822
|
-
* Global API base URL store
|
|
2823
|
-
*/
|
|
2824
|
-
const apiURL = shared("apiURL", () => atom(""));
|
|
2825
|
-
|
|
2826
|
-
//#endregion
|
|
2827
|
-
//#region src/auth/api/sdk-client.ts
|
|
2828
|
-
function isWireErrorBody(error) {
|
|
2829
|
-
return typeof error === "object" && error !== null;
|
|
2830
|
-
}
|
|
2831
|
-
const state = shared("sdkClientState", () => ({
|
|
2832
|
-
configured: false,
|
|
2833
|
-
tokenResolver: getToken
|
|
2834
|
-
}));
|
|
2835
|
-
function setTokenResolver(resolver) {
|
|
2836
|
-
state.tokenResolver = resolver;
|
|
2837
|
-
}
|
|
2838
|
-
/**
|
|
2839
|
-
* Routes that do not require a Bearer token at the gateway edge. These
|
|
2840
|
-
* authenticate via credentials in the request body (or are webhooks verified by
|
|
2841
|
-
* signature), so attaching an Authorization header here would make the gateway
|
|
2842
|
-
* attempt to validate a stale/absent token and reject the request with 401.
|
|
2843
|
-
* Mirrors `publicRoutes` in backend/gateway/internal/routes/routes.go.
|
|
2844
|
-
*/
|
|
2845
|
-
const publicRoutes = [
|
|
2846
|
-
{
|
|
2847
|
-
method: "POST",
|
|
2848
|
-
path: "/auth/v1/token"
|
|
2849
|
-
},
|
|
2850
|
-
{
|
|
2851
|
-
method: "POST",
|
|
2852
|
-
path: "/auth/v1/register"
|
|
2853
|
-
},
|
|
2854
|
-
{
|
|
2855
|
-
method: "POST",
|
|
2856
|
-
path: "/auth/v1/login"
|
|
2857
|
-
},
|
|
2858
|
-
{
|
|
2859
|
-
method: "POST",
|
|
2860
|
-
path: "/auth/v1/email/verify"
|
|
2861
|
-
},
|
|
2862
|
-
{
|
|
2863
|
-
method: "POST",
|
|
2864
|
-
path: "/auth/v1/email/verify/resend"
|
|
2865
|
-
},
|
|
2866
|
-
{
|
|
2867
|
-
method: "POST",
|
|
2868
|
-
path: "/auth/v1/password/reset"
|
|
2869
|
-
},
|
|
2870
|
-
{
|
|
2871
|
-
method: "POST",
|
|
2872
|
-
path: "/auth/v1/password/reset/confirm"
|
|
2873
|
-
},
|
|
2874
|
-
{
|
|
2875
|
-
method: "POST",
|
|
2876
|
-
path: "/auth/v1/verify-totp"
|
|
2877
|
-
},
|
|
2878
|
-
{
|
|
2879
|
-
method: "POST",
|
|
2880
|
-
path: "/auth/v1/verify-passkey"
|
|
2881
|
-
},
|
|
2882
|
-
{
|
|
2883
|
-
method: "POST",
|
|
2884
|
-
path: "/auth/v1/invitations/",
|
|
2885
|
-
prefix: true
|
|
2886
|
-
},
|
|
2887
|
-
{
|
|
2888
|
-
method: "POST",
|
|
2889
|
-
path: "/auth/v1/passkey/login/begin"
|
|
2890
|
-
},
|
|
2891
|
-
{
|
|
2892
|
-
method: "POST",
|
|
2893
|
-
path: "/auth/v1/passkey/login/finish"
|
|
2894
|
-
},
|
|
2895
|
-
{
|
|
2896
|
-
method: "POST",
|
|
2897
|
-
path: "/auth/v1/logout"
|
|
2898
|
-
},
|
|
2899
|
-
{
|
|
2900
|
-
method: "POST",
|
|
2901
|
-
path: "/auth/v1/blog/unsubscribe/email"
|
|
2902
|
-
},
|
|
2903
|
-
{
|
|
2904
|
-
method: "POST",
|
|
2905
|
-
path: "/auth/v1/blog/broadcast"
|
|
2906
|
-
},
|
|
2907
|
-
{
|
|
2908
|
-
method: "GET",
|
|
2909
|
-
path: "/media/v1/videos/",
|
|
2910
|
-
prefix: true
|
|
2911
|
-
},
|
|
2912
|
-
{
|
|
2913
|
-
method: "GET",
|
|
2914
|
-
path: "/media/v1/images/",
|
|
2915
|
-
prefix: true
|
|
2916
|
-
},
|
|
2917
|
-
{
|
|
2918
|
-
method: "GET",
|
|
2919
|
-
path: "/media/v1/languages"
|
|
2920
|
-
},
|
|
2921
|
-
{
|
|
2922
|
-
method: "GET",
|
|
2923
|
-
path: "/posts/v1/feeds/",
|
|
2924
|
-
prefix: true
|
|
2925
|
-
},
|
|
2926
|
-
{
|
|
2927
|
-
method: "POST",
|
|
2928
|
-
path: "/billing/webhooks/stripe"
|
|
2929
|
-
},
|
|
2930
|
-
{
|
|
2931
|
-
method: "POST",
|
|
2932
|
-
path: "/webhooks/storage"
|
|
2933
|
-
},
|
|
2934
|
-
{
|
|
2935
|
-
method: "POST",
|
|
2936
|
-
path: "/platform/auth/v1/token"
|
|
2937
|
-
},
|
|
2938
|
-
{
|
|
2939
|
-
method: "POST",
|
|
2940
|
-
path: "/platform/auth/v1/refresh"
|
|
2941
|
-
}
|
|
2942
|
-
];
|
|
2943
|
-
function isPublicRoute(method, pathname) {
|
|
2944
|
-
const match = method.toUpperCase();
|
|
2945
|
-
return publicRoutes.some(({ method: m, path, prefix }) => match === m && (prefix ? pathname.startsWith(path) : pathname === path));
|
|
2946
|
-
}
|
|
2947
|
-
function configureSdkClient() {
|
|
2948
|
-
if (state.configured) return;
|
|
2949
|
-
state.configured = true;
|
|
2950
|
-
configureAllClients(apiURL.get());
|
|
2951
|
-
apiURL.subscribe((url) => {
|
|
2952
|
-
configureAllClients(url);
|
|
2953
|
-
});
|
|
2954
|
-
addClientInitializer((client) => {
|
|
2955
|
-
client.interceptors.request.use(async (request) => {
|
|
2956
|
-
if (request.headers.has("Authorization")) return request;
|
|
2957
|
-
const { pathname } = new URL(request.url);
|
|
2958
|
-
if (isPublicRoute(request.method, pathname)) return request;
|
|
2959
|
-
const token = await state.tokenResolver();
|
|
2960
|
-
if (!token) throw new ApiError("No access token available for an authenticated request", HTTP_STATUS.UNAUTHORIZED, pathname);
|
|
2961
|
-
request.headers.set("Authorization", `Bearer ${token}`);
|
|
2962
|
-
return request;
|
|
2963
|
-
});
|
|
2964
|
-
client.interceptors.error.use((error, response, request) => {
|
|
2965
|
-
if (error instanceof Error) return error;
|
|
2966
|
-
const body = isWireErrorBody(error) ? error : void 0;
|
|
2967
|
-
const status = response?.status ?? body?.code ?? 0;
|
|
2968
|
-
return new ApiError(body?.error || body?.details || (typeof error === "string" ? error : "Request failed"), status, request ? new URL(request.url).pathname : "", error);
|
|
2969
|
-
});
|
|
2970
|
-
});
|
|
2971
|
-
}
|
|
2972
|
-
|
|
2973
|
-
//#endregion
|
|
2974
|
-
//#region src/auth/social/socialState.ts
|
|
2975
|
-
const socialStoragePath = (provider) => SOCIAL_CONNECT_KEY_PREFIX + provider;
|
|
2976
|
-
/**
|
|
2977
|
-
* Sets a flag indicating that a social provider connection is being attempted
|
|
2978
|
-
* @param provider The provider identifier
|
|
2979
|
-
*/
|
|
2980
|
-
function setSocialConnectAttempt(provider) {
|
|
2981
|
-
sessionStorage.setItem(socialStoragePath(provider), "true");
|
|
2982
|
-
}
|
|
2983
|
-
/**
|
|
2984
|
-
* Checks if there's a pending social provider connection attempt
|
|
2985
|
-
* @param provider The provider identifier
|
|
2986
|
-
* @returns True if there's a pending connection attempt, false otherwise
|
|
2987
|
-
*/
|
|
2988
|
-
function hasSocialConnectAttempt(provider) {
|
|
2989
|
-
return sessionStorage.getItem(socialStoragePath(provider)) === "true";
|
|
2990
|
-
}
|
|
2991
|
-
/**
|
|
2992
|
-
* Clears the social provider connection attempt flag
|
|
2993
|
-
* @param provider The provider identifier
|
|
2994
|
-
*/
|
|
2995
|
-
function clearSocialConnectAttempt(provider) {
|
|
2996
|
-
sessionStorage.removeItem(socialStoragePath(provider));
|
|
2997
|
-
}
|
|
2998
|
-
|
|
2999
|
-
//#endregion
|
|
3000
|
-
//#region src/auth/api/error-handlers.ts
|
|
3001
|
-
/**
|
|
3002
|
-
* Helper to create error functions - reduces bundle size by reusing error creation logic
|
|
3003
|
-
*/
|
|
3004
|
-
const err = (message) => () => new Error(message);
|
|
3005
|
-
/** Reusable error handlers for common cases - reduces repetitive error messages */
|
|
3006
|
-
const commonErrors = {
|
|
3007
|
-
unauthorized: err("User is not authorized"),
|
|
3008
|
-
badRequest: err("Bad request"),
|
|
3009
|
-
notFound: err("Not found"),
|
|
3010
|
-
conflict: err("Resource already exists"),
|
|
3011
|
-
forbidden: err("Forbidden"),
|
|
3012
|
-
tooManyRequests: err("Too many requests")
|
|
3013
|
-
};
|
|
3014
|
-
/**
|
|
3015
|
-
* Standard error handler for API errors with custom status code handling
|
|
3016
|
-
*/
|
|
3017
|
-
const handleApiError = (error, statusHandlers) => {
|
|
3018
|
-
if (error instanceof ApiError) {
|
|
3019
|
-
const handler = statusHandlers[error.status];
|
|
3020
|
-
if (handler) throw new ApiError(handler().message, error.status, error.endpoint, error.data);
|
|
3021
|
-
throw error;
|
|
3022
|
-
}
|
|
3023
|
-
throw error;
|
|
3024
|
-
};
|
|
2911
|
+
throw error;
|
|
2912
|
+
};
|
|
3025
2913
|
|
|
3026
2914
|
//#endregion
|
|
3027
2915
|
//#region src/auth/api/utils.ts
|
|
@@ -3169,55 +3057,493 @@ const listSocials = async () => {
|
|
|
3169
3057
|
});
|
|
3170
3058
|
}, { [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to list providers!") });
|
|
3171
3059
|
};
|
|
3172
|
-
const connectSocialInternal = async (provider, token) => {
|
|
3173
|
-
return apiCall(async () => {
|
|
3174
|
-
const requestBody = validateInput(ConnectProviderSchema, {
|
|
3175
|
-
provider,
|
|
3176
|
-
token
|
|
3177
|
-
});
|
|
3178
|
-
const
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3060
|
+
const connectSocialInternal = async (provider, token) => {
|
|
3061
|
+
return apiCall(async () => {
|
|
3062
|
+
const requestBody = validateInput(ConnectProviderSchema, {
|
|
3063
|
+
provider,
|
|
3064
|
+
token
|
|
3065
|
+
});
|
|
3066
|
+
const sessionToken = await getToken();
|
|
3067
|
+
const headers = sessionToken ? { Authorization: `Bearer ${sessionToken}` } : {};
|
|
3068
|
+
const { data } = await authV1ProvidersServiceConnectProvider({
|
|
3069
|
+
body: {
|
|
3070
|
+
provider: toProtoProvider(normalizeProviderType(requestBody.provider)),
|
|
3071
|
+
token: requestBody.token
|
|
3072
|
+
},
|
|
3073
|
+
headers,
|
|
3074
|
+
throwOnError: true
|
|
3075
|
+
});
|
|
3076
|
+
persistTokens(data);
|
|
3077
|
+
}, { [HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to connect provider!") });
|
|
3078
|
+
};
|
|
3079
|
+
const disconnectSocial = async (provider) => {
|
|
3080
|
+
return apiCall(async () => {
|
|
3081
|
+
await authV1ProvidersServiceDisconnectProvider({
|
|
3082
|
+
path: { provider: toProtoProvider(provider) },
|
|
3083
|
+
throwOnError: true
|
|
3084
|
+
});
|
|
3085
|
+
}, {
|
|
3086
|
+
[HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to disconnect provider!"),
|
|
3087
|
+
[HTTP_STATUS.NOT_FOUND]: () => /* @__PURE__ */ new Error("Provider not found!"),
|
|
3088
|
+
[HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Cannot disconnect the last social provider!")
|
|
3089
|
+
});
|
|
3090
|
+
};
|
|
3091
|
+
const connectSocial = (provider) => {
|
|
3092
|
+
setSocialConnectAttempt(provider);
|
|
3093
|
+
login(provider);
|
|
3094
|
+
};
|
|
3095
|
+
|
|
3096
|
+
//#endregion
|
|
3097
|
+
//#region src/auth/api/refresh-tokens.ts
|
|
3098
|
+
/**
|
|
3099
|
+
* Exchange a provider credential for a Rixl session, or refresh an existing
|
|
3100
|
+
* Rixl session with a Bearer refresh token.
|
|
3101
|
+
*
|
|
3102
|
+
* - For `AuthProvider.BEARER`, the call hits `/auth/v1/token` with the stored
|
|
3103
|
+
* Rixl refresh token.
|
|
3104
|
+
* - For OAuth/Telegram providers, the call hits `/auth/v1/providers/connect`
|
|
3105
|
+
* with the provider's `id_token` or Telegram payload. The wire `provider`
|
|
3106
|
+
* value is the `auth.v1.ExternalAccountProvider` enum (e.g.
|
|
3107
|
+
* `EXTERNAL_ACCOUNT_PROVIDER_GOOGLE`), not the short SDK name.
|
|
3108
|
+
*/
|
|
3109
|
+
const refreshTokens = async (provider, token, options) => {
|
|
3110
|
+
if (provider === "Bearer") {
|
|
3111
|
+
const { data } = await authV1TokenServiceRefreshToken({
|
|
3112
|
+
body: {
|
|
3113
|
+
token_type: "Bearer",
|
|
3114
|
+
refresh_token: token,
|
|
3115
|
+
country_code: options?.countryCode,
|
|
3116
|
+
origin: options?.origin
|
|
3117
|
+
},
|
|
3118
|
+
throwOnError: true
|
|
3119
|
+
});
|
|
3120
|
+
return data;
|
|
3121
|
+
}
|
|
3122
|
+
const requestProvider = normalizeProviderType(provider);
|
|
3123
|
+
const { data } = await authV1ProvidersServiceConnectProvider({
|
|
3124
|
+
body: {
|
|
3125
|
+
provider: toProtoProvider(requestProvider),
|
|
3126
|
+
token,
|
|
3127
|
+
country_code: options?.countryCode,
|
|
3128
|
+
origin: options?.origin
|
|
3129
|
+
},
|
|
3130
|
+
throwOnError: true
|
|
3131
|
+
});
|
|
3132
|
+
return data;
|
|
3133
|
+
};
|
|
3134
|
+
|
|
3135
|
+
//#endregion
|
|
3136
|
+
//#region src/auth/cookie/util.ts
|
|
3137
|
+
const splitOnFirstEquals = (pair) => {
|
|
3138
|
+
const trimmed = pair.trim();
|
|
3139
|
+
const separator = trimmed.indexOf("=");
|
|
3140
|
+
return separator === -1 ? [trimmed, ""] : [trimmed.slice(0, separator), trimmed.slice(separator + 1).trim()];
|
|
3141
|
+
};
|
|
3142
|
+
const getAllCookiesStartWith = (startWithKey) => {
|
|
3143
|
+
if (typeof document === "undefined") return {};
|
|
3144
|
+
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 }), {});
|
|
3145
|
+
};
|
|
3146
|
+
function setCookie(name, value, options) {
|
|
3147
|
+
if (typeof document === "undefined") return;
|
|
3148
|
+
let cookieString = `${encodeName(name)}=${encodeValue(value)}`;
|
|
3149
|
+
if (options) {
|
|
3150
|
+
if (options.expires) {
|
|
3151
|
+
if (typeof options.expires === "number") {
|
|
3152
|
+
const date = /* @__PURE__ */ new Date();
|
|
3153
|
+
date.setTime(date.getTime() + options.expires * 24 * 60 * 60 * 1e3);
|
|
3154
|
+
cookieString += `; expires=${date.toUTCString()}`;
|
|
3155
|
+
} else cookieString += `; expires=${options.expires.toUTCString()}`;
|
|
3156
|
+
}
|
|
3157
|
+
if (options.path) cookieString += `; path=${options.path}`;
|
|
3158
|
+
if (options.domain) cookieString += `; domain=${options.domain}`;
|
|
3159
|
+
if (options.secure) cookieString += `; secure`;
|
|
3160
|
+
if (options.sameSite) cookieString += `; samesite=${options.sameSite}`;
|
|
3161
|
+
}
|
|
3162
|
+
document.cookie = cookieString;
|
|
3163
|
+
}
|
|
3164
|
+
function deleteCookie(name) {
|
|
3165
|
+
if (typeof document === "undefined") return;
|
|
3166
|
+
document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
|
3167
|
+
}
|
|
3168
|
+
const encodeName = (name) => encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent);
|
|
3169
|
+
const encodeValue = (value) => encodeURIComponent(value).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, decodeURIComponent);
|
|
3170
|
+
|
|
3171
|
+
//#endregion
|
|
3172
|
+
//#region src/auth/cookie/index.ts
|
|
3173
|
+
const initVals = getAllCookiesStartWith(GLOBAL_PREFIX);
|
|
3174
|
+
const setStoreCookie = (key, value) => {
|
|
3175
|
+
const expires = /* @__PURE__ */ new Date();
|
|
3176
|
+
expires.setTime(expires.getTime() + 30 * 24 * 60 * 60 * 1e3);
|
|
3177
|
+
const cookieKey = `${GLOBAL_PREFIX}_${key}`;
|
|
3178
|
+
if (!value || value === "") {
|
|
3179
|
+
deleteCookie(cookieKey);
|
|
3180
|
+
return;
|
|
3181
|
+
}
|
|
3182
|
+
const stringValue = typeof value === "string" ? value : JSON.stringify(value);
|
|
3183
|
+
setCookie(`${GLOBAL_PREFIX}_${key}`, stringValue, {
|
|
3184
|
+
expires,
|
|
3185
|
+
path: "/",
|
|
3186
|
+
sameSite: "Lax"
|
|
3187
|
+
});
|
|
3188
|
+
};
|
|
3189
|
+
|
|
3190
|
+
//#endregion
|
|
3191
|
+
//#region src/auth/userStore.ts
|
|
3192
|
+
const userPath = GLOBAL_PREFIX + "_user";
|
|
3193
|
+
const parseUser = () => {
|
|
3194
|
+
if (typeof localStorage === "undefined" || !localStorage || typeof localStorage.getItem !== "function") return;
|
|
3195
|
+
const value = localStorage.getItem(userPath);
|
|
3196
|
+
if (value && value != "undefined") try {
|
|
3197
|
+
return JSON.parse(value);
|
|
3198
|
+
} catch (err) {
|
|
3199
|
+
console.warn("Can't parse user data, error: ", err);
|
|
3200
|
+
return;
|
|
3201
|
+
}
|
|
3202
|
+
};
|
|
3203
|
+
const user = shared("user", () => {
|
|
3204
|
+
const store = atom(parseUser());
|
|
3205
|
+
store.subscribe((value) => {
|
|
3206
|
+
if (typeof localStorage === "undefined" || !localStorage || typeof localStorage.setItem !== "function") return;
|
|
3207
|
+
if (value) localStorage.setItem(userPath, JSON.stringify(value));
|
|
3208
|
+
else localStorage.removeItem(userPath);
|
|
3209
|
+
});
|
|
3210
|
+
return store;
|
|
3211
|
+
});
|
|
3212
|
+
|
|
3213
|
+
//#endregion
|
|
3214
|
+
//#region src/auth/utils/jwt.ts
|
|
3215
|
+
/**
|
|
3216
|
+
* Decodes a JWT token and extracts user information
|
|
3217
|
+
* Uses jose library for modern, secure JWT handling
|
|
3218
|
+
* @param token The JWT token to decode
|
|
3219
|
+
* @returns The decoded user data or undefined if decoding fails
|
|
3220
|
+
*/
|
|
3221
|
+
const decodeToken = (token) => {
|
|
3222
|
+
try {
|
|
3223
|
+
const decodedUser = decodeJwt(token);
|
|
3224
|
+
return {
|
|
3225
|
+
id: decodedUser.id,
|
|
3226
|
+
email: decodedUser.email,
|
|
3227
|
+
first_name: decodedUser.first_name,
|
|
3228
|
+
last_name: decodedUser.last_name,
|
|
3229
|
+
username: decodedUser.username,
|
|
3230
|
+
image_url: decodedUser.image_url,
|
|
3231
|
+
language_code: decodedUser.language_code,
|
|
3232
|
+
org_id: decodedUser.org_id
|
|
3233
|
+
};
|
|
3234
|
+
} catch (error) {
|
|
3235
|
+
console.warn("Failed to decode JWT token. Error: ", error);
|
|
3236
|
+
return;
|
|
3237
|
+
}
|
|
3238
|
+
};
|
|
3239
|
+
/**
|
|
3240
|
+
* Decodes a JWT token and sets the user in the store
|
|
3241
|
+
* @param token The JWT token to decode
|
|
3242
|
+
* @returns True if user was successfully decoded and set, false otherwise
|
|
3243
|
+
*/
|
|
3244
|
+
const decodeAndSetUser = (token) => {
|
|
3245
|
+
const userData = decodeToken(token);
|
|
3246
|
+
if (userData) {
|
|
3247
|
+
user.set(userData);
|
|
3248
|
+
return true;
|
|
3249
|
+
}
|
|
3250
|
+
return false;
|
|
3251
|
+
};
|
|
3252
|
+
/**
|
|
3253
|
+
* Checks if a token is expired based on the expiration timestamp
|
|
3254
|
+
* @param expireAt The expiration timestamp in milliseconds
|
|
3255
|
+
* @returns True if the token is expired, false otherwise
|
|
3256
|
+
*/
|
|
3257
|
+
const isTokenExpired = (expireAt) => {
|
|
3258
|
+
if (!expireAt) return true;
|
|
3259
|
+
return Date.now() >= expireAt;
|
|
3260
|
+
};
|
|
3261
|
+
|
|
3262
|
+
//#endregion
|
|
3263
|
+
//#region src/auth/authStore.ts
|
|
3264
|
+
const isLogged = shared("isLogged", () => atom(initVals["isLogged"] === "true"));
|
|
3265
|
+
const accessToken = shared("accessToken", () => atom(initVals["accessToken"]));
|
|
3266
|
+
const refreshToken = shared("refreshToken", () => atom(initVals["refreshToken"]));
|
|
3267
|
+
const expireAt = shared("expireAt", () => atom(Number(initVals["expireAt"])));
|
|
3268
|
+
const authError = shared("authError", () => atom(null));
|
|
3269
|
+
const requiresAction = shared("requiresAction", () => atom(initVals["requiresAction"] || null));
|
|
3270
|
+
const limitedAccessToken = shared("limitedAccessToken", () => atom(initVals["limitedAccessToken"] || null));
|
|
3271
|
+
const inFlight = shared("getTokenPromise", () => ({ promise: null }));
|
|
3272
|
+
const PROVIDER_URL_MAP = {
|
|
3273
|
+
google: googleAuthUrl,
|
|
3274
|
+
apple: appleAuthUrl,
|
|
3275
|
+
microsoft: microsoftAuthUrl,
|
|
3276
|
+
telegram: telegramAuthUrl
|
|
3277
|
+
};
|
|
3278
|
+
const login = async (provider) => {
|
|
3279
|
+
await initDeferred.promise;
|
|
3280
|
+
const authUrlAtom = PROVIDER_URL_MAP[provider];
|
|
3281
|
+
if (!authUrlAtom) throw new Error(`Unsupported provider: ${provider}`);
|
|
3282
|
+
const authUrl = authUrlAtom.get();
|
|
3283
|
+
if (authUrl) window.location.href = authUrl;
|
|
3284
|
+
else throw new Error(`${provider} provider is not configured. Please check your initClient configuration.`);
|
|
3285
|
+
};
|
|
3286
|
+
const refreshAccessToken = async (refresh) => {
|
|
3287
|
+
const result = await refreshTokens("Bearer", refresh);
|
|
3288
|
+
if (!("requires_action" in result)) setTokens(result.access_token, result.refresh_token, result.expires_in);
|
|
3289
|
+
};
|
|
3290
|
+
const ensureValidAccessToken = async (refresh) => {
|
|
3291
|
+
if (accessToken.get() && !isTokenExpired(expireAt.get())) return;
|
|
3292
|
+
try {
|
|
3293
|
+
await refreshAccessToken(refresh);
|
|
3294
|
+
} catch (refreshError) {
|
|
3295
|
+
console.error("Token refresh failed in getToken:", refreshError);
|
|
3296
|
+
removeTokens();
|
|
3297
|
+
throw refreshError;
|
|
3298
|
+
}
|
|
3299
|
+
};
|
|
3300
|
+
const getToken = async () => {
|
|
3301
|
+
if (inFlight.promise) return inFlight.promise;
|
|
3302
|
+
inFlight.promise = (async () => {
|
|
3303
|
+
try {
|
|
3304
|
+
await initDeferred.promise;
|
|
3305
|
+
if (requiresAction.get()) return void 0;
|
|
3306
|
+
const currentRefreshToken = refreshToken.get();
|
|
3307
|
+
if (!currentRefreshToken) return void 0;
|
|
3308
|
+
await ensureValidAccessToken(currentRefreshToken);
|
|
3309
|
+
const token = accessToken.get();
|
|
3310
|
+
if (token) decodeAndSetUser(token);
|
|
3311
|
+
return token;
|
|
3312
|
+
} catch (error) {
|
|
3313
|
+
console.warn("Failed to getToken(). Error: ", error);
|
|
3314
|
+
throw error;
|
|
3315
|
+
} finally {
|
|
3316
|
+
inFlight.promise = null;
|
|
3317
|
+
}
|
|
3318
|
+
})();
|
|
3319
|
+
return inFlight.promise;
|
|
3320
|
+
};
|
|
3321
|
+
/**
|
|
3322
|
+
* Sets authentication tokens in the store
|
|
3323
|
+
* @param access The access token
|
|
3324
|
+
* @param refresh The refresh token
|
|
3325
|
+
* @param expiresIn The token expiration time in seconds
|
|
3326
|
+
*/
|
|
3327
|
+
const setTokens = (access, refresh, expiresIn) => {
|
|
3328
|
+
accessToken.set(access);
|
|
3329
|
+
refreshToken.set(refresh);
|
|
3330
|
+
expireAt.set(Date.now() + expiresIn * 1e3);
|
|
3331
|
+
isLogged.set(true);
|
|
3332
|
+
limitedAccessToken.set(null);
|
|
3333
|
+
requiresAction.set(null);
|
|
3334
|
+
authError.set(null);
|
|
3335
|
+
decodeAndSetUser(access);
|
|
3336
|
+
};
|
|
3337
|
+
/**
|
|
3338
|
+
* Removes authentication tokens from the store
|
|
3339
|
+
*/
|
|
3340
|
+
const removeTokens = () => {
|
|
3341
|
+
accessToken.set("");
|
|
3342
|
+
refreshToken.set("");
|
|
3343
|
+
expireAt.set(0);
|
|
3344
|
+
isLogged.set(false);
|
|
3345
|
+
user.set(void 0);
|
|
3346
|
+
limitedAccessToken.set(null);
|
|
3347
|
+
requiresAction.set(null);
|
|
3348
|
+
authError.set(null);
|
|
3187
3349
|
};
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
});
|
|
3194
|
-
}, {
|
|
3195
|
-
[HTTP_STATUS.UNAUTHORIZED]: () => /* @__PURE__ */ new Error("User is not authorized to disconnect provider!"),
|
|
3196
|
-
[HTTP_STATUS.NOT_FOUND]: () => /* @__PURE__ */ new Error("Provider not found!"),
|
|
3197
|
-
[HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Cannot disconnect the last social provider!")
|
|
3198
|
-
});
|
|
3350
|
+
/**
|
|
3351
|
+
* Clears the auth error from the store
|
|
3352
|
+
*/
|
|
3353
|
+
const clearAuthError = () => {
|
|
3354
|
+
authError.set(null);
|
|
3199
3355
|
};
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3356
|
+
/**
|
|
3357
|
+
* Sets limited access state for users requiring additional action (e.g., Telegram users without email)
|
|
3358
|
+
* @param token The limited scope access token
|
|
3359
|
+
* @param action The required action (e.g., "add_email")
|
|
3360
|
+
*/
|
|
3361
|
+
const setLimitedAccessState = (token, action) => {
|
|
3362
|
+
limitedAccessToken.set(token);
|
|
3363
|
+
requiresAction.set(action);
|
|
3364
|
+
authError.set(null);
|
|
3365
|
+
isLogged.set(true);
|
|
3203
3366
|
};
|
|
3367
|
+
/**
|
|
3368
|
+
* Clears the limited access state (after email verification completes or user logs out)
|
|
3369
|
+
*/
|
|
3370
|
+
const clearLimitedAccessState = () => {
|
|
3371
|
+
limitedAccessToken.set(null);
|
|
3372
|
+
requiresAction.set(null);
|
|
3373
|
+
if (!(!!accessToken.get() && !!refreshToken.get())) isLogged.set(false);
|
|
3374
|
+
};
|
|
3375
|
+
isLogged.subscribe((value) => setStoreCookie("isLogged", value));
|
|
3376
|
+
accessToken.subscribe((value) => setStoreCookie("accessToken", value));
|
|
3377
|
+
refreshToken.subscribe((value) => setStoreCookie("refreshToken", value));
|
|
3378
|
+
expireAt.subscribe((value) => setStoreCookie("expireAt", value));
|
|
3379
|
+
requiresAction.subscribe((value) => setStoreCookie("requiresAction", value));
|
|
3380
|
+
limitedAccessToken.subscribe((value) => setStoreCookie("limitedAccessToken", value));
|
|
3204
3381
|
|
|
3205
3382
|
//#endregion
|
|
3206
|
-
//#region src/auth/api
|
|
3207
|
-
let tokenRefreshFunction = null;
|
|
3383
|
+
//#region src/auth/api-url.ts
|
|
3208
3384
|
/**
|
|
3209
|
-
*
|
|
3210
|
-
* This should be called during initialization
|
|
3385
|
+
* Global API base URL store
|
|
3211
3386
|
*/
|
|
3212
|
-
const
|
|
3213
|
-
|
|
3214
|
-
|
|
3387
|
+
const apiURL = shared("apiURL", () => atom(""));
|
|
3388
|
+
|
|
3389
|
+
//#endregion
|
|
3390
|
+
//#region src/auth/api/sdk-client.ts
|
|
3391
|
+
function isWireErrorBody(error) {
|
|
3392
|
+
return typeof error === "object" && error !== null;
|
|
3393
|
+
}
|
|
3394
|
+
const state = shared("sdkClientState", () => ({
|
|
3395
|
+
configured: false,
|
|
3396
|
+
tokenResolver: getToken
|
|
3397
|
+
}));
|
|
3398
|
+
function setTokenResolver(resolver) {
|
|
3399
|
+
state.tokenResolver = resolver;
|
|
3400
|
+
}
|
|
3401
|
+
/**
|
|
3402
|
+
* Routes that do not require a Bearer token at the gateway edge. These
|
|
3403
|
+
* authenticate via credentials in the request body (or are webhooks verified by
|
|
3404
|
+
* signature), so attaching an Authorization header here would make the gateway
|
|
3405
|
+
* attempt to validate a stale/absent token and reject the request with 401.
|
|
3406
|
+
* Mirrors `publicRoutes` in backend/gateway/internal/routes/routes.go.
|
|
3407
|
+
*/
|
|
3408
|
+
const publicRoutes = [
|
|
3409
|
+
{
|
|
3410
|
+
method: "POST",
|
|
3411
|
+
path: "/auth/v1/token"
|
|
3412
|
+
},
|
|
3413
|
+
{
|
|
3414
|
+
method: "POST",
|
|
3415
|
+
path: "/auth/v1/register"
|
|
3416
|
+
},
|
|
3417
|
+
{
|
|
3418
|
+
method: "POST",
|
|
3419
|
+
path: "/auth/v1/login"
|
|
3420
|
+
},
|
|
3421
|
+
{
|
|
3422
|
+
method: "POST",
|
|
3423
|
+
path: "/auth/v1/email/verify"
|
|
3424
|
+
},
|
|
3425
|
+
{
|
|
3426
|
+
method: "POST",
|
|
3427
|
+
path: "/auth/v1/email/verify/resend"
|
|
3428
|
+
},
|
|
3429
|
+
{
|
|
3430
|
+
method: "POST",
|
|
3431
|
+
path: "/auth/v1/password/reset"
|
|
3432
|
+
},
|
|
3433
|
+
{
|
|
3434
|
+
method: "POST",
|
|
3435
|
+
path: "/auth/v1/password/reset/confirm"
|
|
3436
|
+
},
|
|
3437
|
+
{
|
|
3438
|
+
method: "POST",
|
|
3439
|
+
path: "/auth/v1/verify-totp"
|
|
3440
|
+
},
|
|
3441
|
+
{
|
|
3442
|
+
method: "POST",
|
|
3443
|
+
path: "/auth/v1/verify-passkey"
|
|
3444
|
+
},
|
|
3445
|
+
{
|
|
3446
|
+
method: "POST",
|
|
3447
|
+
path: "/auth/v1/invitations/",
|
|
3448
|
+
prefix: true
|
|
3449
|
+
},
|
|
3450
|
+
{
|
|
3451
|
+
method: "POST",
|
|
3452
|
+
path: "/auth/v1/passkey/login/begin"
|
|
3453
|
+
},
|
|
3454
|
+
{
|
|
3455
|
+
method: "POST",
|
|
3456
|
+
path: "/auth/v1/passkey/login/finish"
|
|
3457
|
+
},
|
|
3458
|
+
{
|
|
3459
|
+
method: "POST",
|
|
3460
|
+
path: "/auth/v1/logout"
|
|
3461
|
+
},
|
|
3462
|
+
{
|
|
3463
|
+
method: "POST",
|
|
3464
|
+
path: "/auth/v1/providers/connect"
|
|
3465
|
+
},
|
|
3466
|
+
{
|
|
3467
|
+
method: "POST",
|
|
3468
|
+
path: "/auth/v1/blog/unsubscribe/email"
|
|
3469
|
+
},
|
|
3470
|
+
{
|
|
3471
|
+
method: "POST",
|
|
3472
|
+
path: "/auth/v1/blog/broadcast"
|
|
3473
|
+
},
|
|
3474
|
+
{
|
|
3475
|
+
method: "GET",
|
|
3476
|
+
path: "/media/v1/videos/",
|
|
3477
|
+
prefix: true
|
|
3478
|
+
},
|
|
3479
|
+
{
|
|
3480
|
+
method: "GET",
|
|
3481
|
+
path: "/media/v1/images/",
|
|
3482
|
+
prefix: true
|
|
3483
|
+
},
|
|
3484
|
+
{
|
|
3485
|
+
method: "GET",
|
|
3486
|
+
path: "/media/v1/languages"
|
|
3487
|
+
},
|
|
3488
|
+
{
|
|
3489
|
+
method: "GET",
|
|
3490
|
+
path: "/posts/v1/feeds/",
|
|
3491
|
+
prefix: true
|
|
3492
|
+
},
|
|
3493
|
+
{
|
|
3494
|
+
method: "POST",
|
|
3495
|
+
path: "/billing/webhooks/stripe"
|
|
3496
|
+
},
|
|
3497
|
+
{
|
|
3498
|
+
method: "POST",
|
|
3499
|
+
path: "/webhooks/storage"
|
|
3500
|
+
},
|
|
3501
|
+
{
|
|
3502
|
+
method: "POST",
|
|
3503
|
+
path: "/platform/auth/v1/token"
|
|
3504
|
+
},
|
|
3505
|
+
{
|
|
3506
|
+
method: "POST",
|
|
3507
|
+
path: "/platform/auth/v1/refresh"
|
|
3508
|
+
}
|
|
3509
|
+
];
|
|
3510
|
+
function isPublicRoute(method, pathname) {
|
|
3511
|
+
const match = method.toUpperCase();
|
|
3512
|
+
return publicRoutes.some(({ method: m, path, prefix }) => match === m && (prefix ? pathname.startsWith(path) : pathname === path));
|
|
3513
|
+
}
|
|
3514
|
+
function configureSdkClient() {
|
|
3515
|
+
if (state.configured) return;
|
|
3516
|
+
state.configured = true;
|
|
3517
|
+
configureAllClients(apiURL.get());
|
|
3518
|
+
apiURL.subscribe((url) => {
|
|
3519
|
+
configureAllClients(url);
|
|
3520
|
+
});
|
|
3521
|
+
addClientInitializer((client) => {
|
|
3522
|
+
client.interceptors.request.use(async (request) => {
|
|
3523
|
+
if (request.headers.has("Authorization")) return request;
|
|
3524
|
+
const { pathname } = new URL(request.url);
|
|
3525
|
+
if (isPublicRoute(request.method, pathname)) return request;
|
|
3526
|
+
const token = await state.tokenResolver();
|
|
3527
|
+
if (!token) throw new ApiError("No access token available for an authenticated request", HTTP_STATUS.UNAUTHORIZED, pathname);
|
|
3528
|
+
request.headers.set("Authorization", `Bearer ${token}`);
|
|
3529
|
+
return request;
|
|
3530
|
+
});
|
|
3531
|
+
client.interceptors.error.use((error, response, request) => {
|
|
3532
|
+
if (error instanceof Error) return error;
|
|
3533
|
+
const body = isWireErrorBody(error) ? error : void 0;
|
|
3534
|
+
const status = response?.status ?? body?.code ?? 0;
|
|
3535
|
+
const message = body?.error || body?.details || (typeof error === "string" ? error : "Request failed");
|
|
3536
|
+
const endpoint = request ? new URL(request.url).pathname : "";
|
|
3537
|
+
return new ApiError(message, status, endpoint, error);
|
|
3538
|
+
});
|
|
3539
|
+
});
|
|
3540
|
+
}
|
|
3215
3541
|
|
|
3216
3542
|
//#endregion
|
|
3217
3543
|
//#region src/auth/authConfig.ts
|
|
3218
|
-
|
|
3544
|
+
const config = shared("authConfig", () => ({ loginRedirectUrl: void 0 }));
|
|
3219
3545
|
const setLoginRedirectUrl = (url) => {
|
|
3220
|
-
loginRedirectUrl = url;
|
|
3546
|
+
config.loginRedirectUrl = url;
|
|
3221
3547
|
};
|
|
3222
3548
|
|
|
3223
3549
|
//#endregion
|
|
@@ -3228,24 +3554,26 @@ const setLoginRedirectUrl = (url) => {
|
|
|
3228
3554
|
* @returns A promise that resolves to the current access token (if available)
|
|
3229
3555
|
*/
|
|
3230
3556
|
const initClient = async (config) => {
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3557
|
+
try {
|
|
3558
|
+
await runInitSequence(config);
|
|
3559
|
+
} finally {
|
|
3560
|
+
completeOAuthCallback();
|
|
3561
|
+
}
|
|
3235
3562
|
return getToken();
|
|
3236
3563
|
};
|
|
3564
|
+
const runInitSequence = async (config) => {
|
|
3565
|
+
try {
|
|
3566
|
+
await initConfig(config);
|
|
3567
|
+
await initPage();
|
|
3568
|
+
} finally {
|
|
3569
|
+
initDeferred.resolve();
|
|
3570
|
+
}
|
|
3571
|
+
await initSocials();
|
|
3572
|
+
};
|
|
3237
3573
|
const initConfig = async (config) => {
|
|
3238
3574
|
apiURL.set(config.apiUrl);
|
|
3239
3575
|
configureSdkClient();
|
|
3240
3576
|
setLoginRedirectUrl(config.loginRedirectUrl);
|
|
3241
|
-
setTokenRefreshFunction(async () => {
|
|
3242
|
-
const currentRefreshToken = refreshToken.get();
|
|
3243
|
-
if (currentRefreshToken) {
|
|
3244
|
-
const result = await refreshTokens("Bearer", currentRefreshToken);
|
|
3245
|
-
if (result && !("requires_action" in result)) setTokens(result.access_token, result.refresh_token, result.expires_in);
|
|
3246
|
-
return getToken();
|
|
3247
|
-
}
|
|
3248
|
-
});
|
|
3249
3577
|
if (config.googleProvider) {
|
|
3250
3578
|
googleConfig.set(config.googleProvider);
|
|
3251
3579
|
updateGoogleAuthUrl();
|
|
@@ -3293,9 +3621,15 @@ const extractAuthErrorInfo = (error) => {
|
|
|
3293
3621
|
};
|
|
3294
3622
|
const handleInitPageApiError = (error) => {
|
|
3295
3623
|
const info = extractAuthErrorInfo(error);
|
|
3296
|
-
if (error.status === HTTP_STATUS.BAD_REQUEST && info.error === "invalid_grant")
|
|
3297
|
-
|
|
3298
|
-
|
|
3624
|
+
if (error.status === HTTP_STATUS.BAD_REQUEST && info.error === "invalid_grant") {
|
|
3625
|
+
setAuthErrorAndClear("email_not_verified", info.description, info.email);
|
|
3626
|
+
return;
|
|
3627
|
+
}
|
|
3628
|
+
if (error.status === HTTP_STATUS.CONFLICT) {
|
|
3629
|
+
setAuthErrorAndClear("provider_conflict", info.description, info.email);
|
|
3630
|
+
return;
|
|
3631
|
+
}
|
|
3632
|
+
setAuthErrorAndClear("provider_exchange_failed", info.error || info.description, info.email);
|
|
3299
3633
|
};
|
|
3300
3634
|
const exchangeProviderToken = async (provider, token) => {
|
|
3301
3635
|
const result = await refreshTokens(provider, token);
|
|
@@ -3303,14 +3637,18 @@ const exchangeProviderToken = async (provider, token) => {
|
|
|
3303
3637
|
};
|
|
3304
3638
|
const initPage = async () => {
|
|
3305
3639
|
const provider = detectProvider();
|
|
3306
|
-
if (!provider)
|
|
3640
|
+
if (!provider) {
|
|
3641
|
+
if (hasProviderResponse()) logUnusableProviderResponse();
|
|
3642
|
+
return;
|
|
3643
|
+
}
|
|
3307
3644
|
const token = getProviderToken(provider);
|
|
3308
3645
|
if (!token) return void 0;
|
|
3309
3646
|
try {
|
|
3310
3647
|
await exchangeProviderToken(provider, token);
|
|
3311
3648
|
} catch (error) {
|
|
3312
|
-
|
|
3313
|
-
throw error;
|
|
3649
|
+
logProviderExchangeFailure(provider, token, error);
|
|
3650
|
+
if (!(error instanceof ApiError)) throw error;
|
|
3651
|
+
handleInitPageApiError(error);
|
|
3314
3652
|
}
|
|
3315
3653
|
};
|
|
3316
3654
|
const initSocials = async () => {
|
|
@@ -3734,8 +4072,9 @@ const getUserInfo = async (userId) => {
|
|
|
3734
4072
|
};
|
|
3735
4073
|
const updateFullName = async (fullName) => {
|
|
3736
4074
|
return apiCall(async () => {
|
|
4075
|
+
const validatedInput = validateInput(UpdateNameSchema, { full_name: fullName });
|
|
3737
4076
|
await authV1UserServiceUpdateName({
|
|
3738
|
-
body:
|
|
4077
|
+
body: validatedInput,
|
|
3739
4078
|
throwOnError: true
|
|
3740
4079
|
});
|
|
3741
4080
|
}, {
|
|
@@ -3746,8 +4085,9 @@ const updateFullName = async (fullName) => {
|
|
|
3746
4085
|
};
|
|
3747
4086
|
const updateUsername = async (username) => {
|
|
3748
4087
|
return apiCall(async () => {
|
|
4088
|
+
const validatedInput = validateInput(UpdateUsernameSchema, { username });
|
|
3749
4089
|
await authV1UserServiceUpdateUsername({
|
|
3750
|
-
body:
|
|
4090
|
+
body: validatedInput,
|
|
3751
4091
|
throwOnError: true
|
|
3752
4092
|
});
|
|
3753
4093
|
}, {
|
|
@@ -3777,8 +4117,9 @@ const setupUserOTP = async () => {
|
|
|
3777
4117
|
};
|
|
3778
4118
|
const verifyUserOTP = async (code) => {
|
|
3779
4119
|
return apiCall(async () => {
|
|
4120
|
+
const validatedBody = validateInput(VerifyOTPCodeSchema, { code });
|
|
3780
4121
|
const { data } = await authV1OtpServiceVerifyOtp({
|
|
3781
|
-
body:
|
|
4122
|
+
body: validatedBody,
|
|
3782
4123
|
throwOnError: true
|
|
3783
4124
|
});
|
|
3784
4125
|
persistTokens(data);
|
|
@@ -3861,11 +4202,12 @@ const loginWithEmail = async (email, password) => {
|
|
|
3861
4202
|
};
|
|
3862
4203
|
const verifyTOTPForLogin = async (code, session_id) => {
|
|
3863
4204
|
return apiCall(async () => {
|
|
4205
|
+
const validatedInput = validateInput(LoginOTPVerifyRequestSchema, {
|
|
4206
|
+
code,
|
|
4207
|
+
session_id
|
|
4208
|
+
});
|
|
3864
4209
|
const { data } = await authV1OtpServiceVerifyTotpForLogin({
|
|
3865
|
-
body:
|
|
3866
|
-
code,
|
|
3867
|
-
session_id
|
|
3868
|
-
}),
|
|
4210
|
+
body: validatedInput,
|
|
3869
4211
|
throwOnError: true
|
|
3870
4212
|
});
|
|
3871
4213
|
persistTokens(data);
|
|
@@ -3916,13 +4258,14 @@ function isApiErrorBody(error) {
|
|
|
3916
4258
|
//#region src/auth/auth/register.ts
|
|
3917
4259
|
const registerWithEmail = async (email, password, subscribeToBlog, countryCode) => {
|
|
3918
4260
|
return apiCall(async () => {
|
|
4261
|
+
const validatedInput = validateInput(RegisterRequestSchema, {
|
|
4262
|
+
email,
|
|
4263
|
+
password,
|
|
4264
|
+
country_code: countryCode,
|
|
4265
|
+
subscribe_to_blog: subscribeToBlog
|
|
4266
|
+
});
|
|
3919
4267
|
const { data } = await authV1EmailServiceRegister({
|
|
3920
|
-
body:
|
|
3921
|
-
email,
|
|
3922
|
-
password,
|
|
3923
|
-
country_code: countryCode,
|
|
3924
|
-
subscribe_to_blog: subscribeToBlog
|
|
3925
|
-
}),
|
|
4268
|
+
body: validatedInput,
|
|
3926
4269
|
throwOnError: true
|
|
3927
4270
|
});
|
|
3928
4271
|
if (data.verification_id) return {
|
|
@@ -3935,8 +4278,9 @@ const registerWithEmail = async (email, password, subscribeToBlog, countryCode)
|
|
|
3935
4278
|
};
|
|
3936
4279
|
const resendEmailVerificationCode = async (email) => {
|
|
3937
4280
|
return apiCall(async () => {
|
|
4281
|
+
const validatedInput = validateInput(ResendEmailRequestSchema, { email });
|
|
3938
4282
|
const { data } = await authV1EmailServiceResendVerification({
|
|
3939
|
-
body:
|
|
4283
|
+
body: validatedInput,
|
|
3940
4284
|
throwOnError: true
|
|
3941
4285
|
});
|
|
3942
4286
|
if (data.verification_id) return {
|
|
@@ -3954,19 +4298,21 @@ const resendEmailVerificationCode = async (email) => {
|
|
|
3954
4298
|
//#region src/auth/auth/password.ts
|
|
3955
4299
|
const sendPasswordResetEmail = async (email) => {
|
|
3956
4300
|
return apiCall(async () => {
|
|
4301
|
+
const validatedInput = validateInput(ResendEmailRequestSchema, { email });
|
|
3957
4302
|
await authV1EmailServiceSendPasswordReset({
|
|
3958
|
-
body:
|
|
4303
|
+
body: validatedInput,
|
|
3959
4304
|
throwOnError: true
|
|
3960
4305
|
});
|
|
3961
4306
|
}, { [HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Bad request - invalid email or validation error") });
|
|
3962
4307
|
};
|
|
3963
4308
|
const confirmPasswordReset = async (token, password) => {
|
|
3964
4309
|
return apiCall(async () => {
|
|
4310
|
+
const validatedInput = validateInput(ResetPasswordRequestSchema, {
|
|
4311
|
+
token,
|
|
4312
|
+
new_password: password
|
|
4313
|
+
});
|
|
3965
4314
|
await authV1EmailServiceResetPassword({
|
|
3966
|
-
body:
|
|
3967
|
-
token,
|
|
3968
|
-
new_password: password
|
|
3969
|
-
}),
|
|
4315
|
+
body: validatedInput,
|
|
3970
4316
|
throwOnError: true
|
|
3971
4317
|
});
|
|
3972
4318
|
}, { [HTTP_STATUS.BAD_REQUEST]: () => /* @__PURE__ */ new Error("Bad request - invalid token or password") });
|
|
@@ -3976,8 +4322,9 @@ const confirmPasswordReset = async (token, password) => {
|
|
|
3976
4322
|
//#region src/auth/auth/email.ts
|
|
3977
4323
|
const initiateEmailChange = async (email) => {
|
|
3978
4324
|
return apiCall(async () => {
|
|
4325
|
+
const validatedInput = validateInput(ChangeEmailRequestSchema, { new_email: email });
|
|
3979
4326
|
const { data } = await authV1EmailServiceInitiateEmailChange({
|
|
3980
|
-
body:
|
|
4327
|
+
body: validatedInput,
|
|
3981
4328
|
throwOnError: true
|
|
3982
4329
|
});
|
|
3983
4330
|
if (data.verification_id) return {
|
|
@@ -3994,8 +4341,9 @@ const initiateEmailChange = async (email) => {
|
|
|
3994
4341
|
};
|
|
3995
4342
|
const addEmail = async (email) => {
|
|
3996
4343
|
return apiCall(async () => {
|
|
4344
|
+
const validatedInput = validateInput(ResendEmailRequestSchema, { email });
|
|
3997
4345
|
const { data } = await authV1EmailServiceAddEmail({
|
|
3998
|
-
body:
|
|
4346
|
+
body: validatedInput,
|
|
3999
4347
|
throwOnError: true
|
|
4000
4348
|
});
|
|
4001
4349
|
if (data.verification_id) return {
|
|
@@ -4289,10 +4637,11 @@ function serializeRegistrationCredential(cred) {
|
|
|
4289
4637
|
}
|
|
4290
4638
|
const finishPasskeyLogin = async (session_id, credential) => {
|
|
4291
4639
|
return apiCall(async () => {
|
|
4640
|
+
const serialized = serializeLoginCredential(credential);
|
|
4292
4641
|
const { data } = await authV1PasskeyServicePasskeyLoginFinish({
|
|
4293
4642
|
body: {
|
|
4294
4643
|
session_id,
|
|
4295
|
-
credential:
|
|
4644
|
+
credential: serialized
|
|
4296
4645
|
},
|
|
4297
4646
|
throwOnError: true
|
|
4298
4647
|
});
|
|
@@ -4332,11 +4681,12 @@ const beginPasskeyRegistration = async () => {
|
|
|
4332
4681
|
};
|
|
4333
4682
|
const finishPasskeyRegistration = async (session_id, name, credential) => {
|
|
4334
4683
|
return apiCall(async () => {
|
|
4684
|
+
const serialized = serializeRegistrationCredential(credential);
|
|
4335
4685
|
const { data } = await authV1PasskeyServicePasskeyRegisterFinish({
|
|
4336
4686
|
body: {
|
|
4337
4687
|
session_id,
|
|
4338
4688
|
name,
|
|
4339
|
-
credential:
|
|
4689
|
+
credential: serialized
|
|
4340
4690
|
},
|
|
4341
4691
|
throwOnError: true
|
|
4342
4692
|
});
|
|
@@ -4383,10 +4733,11 @@ const listPasskeys = async () => {
|
|
|
4383
4733
|
};
|
|
4384
4734
|
const verifyPasskeyForLogin = async (session_id, credential) => {
|
|
4385
4735
|
return apiCall(async () => {
|
|
4736
|
+
const serialized = serializeLoginCredential(credential);
|
|
4386
4737
|
const { data } = await authV1PasskeyServiceVerifyPasskeyForLogin({
|
|
4387
4738
|
body: {
|
|
4388
4739
|
session_id,
|
|
4389
|
-
credential:
|
|
4740
|
+
credential: serialized
|
|
4390
4741
|
},
|
|
4391
4742
|
throwOnError: true
|
|
4392
4743
|
});
|
|
@@ -4399,5 +4750,5 @@ const verifyPasskeyForLogin = async (session_id, credential) => {
|
|
|
4399
4750
|
};
|
|
4400
4751
|
|
|
4401
4752
|
//#endregion
|
|
4402
|
-
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 };
|
|
4753
|
+
export { DomainStatus, MembershipRole, MembershipState, PasskeyUnavailableError, addEmail, analyticsV1DashboardServiceBatchQueryChart, analyticsV1DashboardServiceCreateDashboard, analyticsV1DashboardServiceCreateWidget, analyticsV1DashboardServiceDeleteDashboard, analyticsV1DashboardServiceDeleteWidget, analyticsV1DashboardServiceGetDashboard, analyticsV1DashboardServiceGetDashboardStats, analyticsV1DashboardServiceGetFilterOptions, analyticsV1DashboardServiceGetScopeTree, analyticsV1DashboardServiceListDashboards, analyticsV1DashboardServiceListDatasets, analyticsV1DashboardServiceQueryChart, analyticsV1DashboardServiceSetDefaultDashboard, analyticsV1DashboardServiceUpdateDashboard, analyticsV1DashboardServiceUpdateDashboardLayout, analyticsV1DashboardServiceUpdateWidget, analyticsV1EventsServiceTrackEvents, analyticsV1FeedsServiceGetFeedStats, analyticsV1FeedsServiceGetTopFeeds, analyticsV1FunnelsServiceGetFunnelAnalytics, analyticsV1FunnelsServiceGetRetentionAnalytics, analyticsV1HeatmapServiceGetHotSegments, analyticsV1HeatmapServiceGetVideoHeatmap, analyticsV1ImagesServiceGetImageStats, analyticsV1ImagesServiceGetTopImages, 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, authV1OtpServiceRegenerateBackupCodes, 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 };
|
|
4403
4754
|
//# sourceMappingURL=index.js.map
|