@oxyhq/core 1.11.24 → 2.1.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/README.md +5 -6
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/AuthManager.js +678 -4
- package/dist/cjs/AuthManagerTypes.js +13 -0
- package/dist/cjs/CrossDomainAuth.js +45 -3
- package/dist/cjs/OxyServices.base.js +16 -0
- package/dist/cjs/i18n/locales/ar-SA.json +83 -0
- package/dist/cjs/i18n/locales/ca-ES.json +83 -0
- package/dist/cjs/i18n/locales/de-DE.json +83 -0
- package/dist/cjs/i18n/locales/en-US.json +83 -0
- package/dist/cjs/i18n/locales/es-ES.json +99 -4
- package/dist/cjs/i18n/locales/fr-FR.json +83 -0
- package/dist/cjs/i18n/locales/it-IT.json +83 -0
- package/dist/cjs/i18n/locales/ja-JP.json +83 -0
- package/dist/cjs/i18n/locales/ko-KR.json +83 -0
- package/dist/cjs/i18n/locales/locales/ar-SA.json +83 -1
- package/dist/cjs/i18n/locales/locales/ca-ES.json +83 -1
- package/dist/cjs/i18n/locales/locales/de-DE.json +83 -1
- package/dist/cjs/i18n/locales/locales/en-US.json +83 -0
- package/dist/cjs/i18n/locales/locales/es-ES.json +99 -4
- package/dist/cjs/i18n/locales/locales/fr-FR.json +83 -1
- package/dist/cjs/i18n/locales/locales/it-IT.json +83 -1
- package/dist/cjs/i18n/locales/locales/ja-JP.json +200 -117
- package/dist/cjs/i18n/locales/locales/ko-KR.json +83 -1
- package/dist/cjs/i18n/locales/locales/pt-PT.json +83 -1
- package/dist/cjs/i18n/locales/locales/zh-CN.json +83 -1
- package/dist/cjs/i18n/locales/pt-PT.json +83 -0
- package/dist/cjs/i18n/locales/zh-CN.json +83 -0
- package/dist/cjs/index.js +121 -57
- package/dist/cjs/mixins/OxyServices.auth.js +235 -0
- package/dist/cjs/mixins/OxyServices.fedcm.js +36 -0
- package/dist/cjs/mixins/OxyServices.popup.js +61 -1
- package/dist/cjs/mixins/OxyServices.user.js +18 -0
- package/dist/cjs/utils/accountUtils.js +64 -1
- package/dist/cjs/utils/coldBoot.js +71 -0
- package/dist/cjs/utils/fapiAutoDetect.js +88 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/AuthManager.js +678 -4
- package/dist/esm/AuthManagerTypes.js +12 -0
- package/dist/esm/CrossDomainAuth.js +45 -3
- package/dist/esm/OxyServices.base.js +16 -0
- package/dist/esm/i18n/locales/ar-SA.json +83 -0
- package/dist/esm/i18n/locales/ca-ES.json +83 -0
- package/dist/esm/i18n/locales/de-DE.json +83 -0
- package/dist/esm/i18n/locales/en-US.json +83 -0
- package/dist/esm/i18n/locales/es-ES.json +99 -4
- package/dist/esm/i18n/locales/fr-FR.json +83 -0
- package/dist/esm/i18n/locales/it-IT.json +83 -0
- package/dist/esm/i18n/locales/ja-JP.json +83 -0
- package/dist/esm/i18n/locales/ko-KR.json +83 -0
- package/dist/esm/i18n/locales/locales/ar-SA.json +83 -1
- package/dist/esm/i18n/locales/locales/ca-ES.json +83 -1
- package/dist/esm/i18n/locales/locales/de-DE.json +83 -1
- package/dist/esm/i18n/locales/locales/en-US.json +83 -0
- package/dist/esm/i18n/locales/locales/es-ES.json +99 -4
- package/dist/esm/i18n/locales/locales/fr-FR.json +83 -1
- package/dist/esm/i18n/locales/locales/it-IT.json +83 -1
- package/dist/esm/i18n/locales/locales/ja-JP.json +200 -117
- package/dist/esm/i18n/locales/locales/ko-KR.json +83 -1
- package/dist/esm/i18n/locales/locales/pt-PT.json +83 -1
- package/dist/esm/i18n/locales/locales/zh-CN.json +83 -1
- package/dist/esm/i18n/locales/pt-PT.json +83 -0
- package/dist/esm/i18n/locales/zh-CN.json +83 -0
- package/dist/esm/index.js +74 -26
- package/dist/esm/mixins/OxyServices.auth.js +235 -0
- package/dist/esm/mixins/OxyServices.fedcm.js +36 -0
- package/dist/esm/mixins/OxyServices.popup.js +61 -1
- package/dist/esm/mixins/OxyServices.user.js +18 -0
- package/dist/esm/utils/accountUtils.js +61 -0
- package/dist/esm/utils/coldBoot.js +68 -0
- package/dist/esm/utils/fapiAutoDetect.js +85 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/AuthManager.d.ts +243 -3
- package/dist/types/AuthManagerTypes.d.ts +68 -0
- package/dist/types/CrossDomainAuth.d.ts +23 -0
- package/dist/types/OxyServices.base.d.ts +14 -0
- package/dist/types/OxyServices.d.ts +7 -0
- package/dist/types/index.d.ts +31 -17
- package/dist/types/mixins/OxyServices.analytics.d.ts +1 -0
- package/dist/types/mixins/OxyServices.appData.d.ts +1 -0
- package/dist/types/mixins/OxyServices.assets.d.ts +4 -1
- package/dist/types/mixins/OxyServices.auth.d.ts +73 -1
- package/dist/types/mixins/OxyServices.contacts.d.ts +1 -0
- package/dist/types/mixins/OxyServices.developer.d.ts +1 -0
- package/dist/types/mixins/OxyServices.devices.d.ts +1 -0
- package/dist/types/mixins/OxyServices.features.d.ts +2 -5
- package/dist/types/mixins/OxyServices.fedcm.d.ts +34 -0
- package/dist/types/mixins/OxyServices.karma.d.ts +1 -0
- package/dist/types/mixins/OxyServices.language.d.ts +1 -0
- package/dist/types/mixins/OxyServices.location.d.ts +1 -0
- package/dist/types/mixins/OxyServices.managedAccounts.d.ts +1 -0
- package/dist/types/mixins/OxyServices.payment.d.ts +1 -0
- package/dist/types/mixins/OxyServices.popup.d.ts +40 -0
- package/dist/types/mixins/OxyServices.privacy.d.ts +1 -0
- package/dist/types/mixins/OxyServices.redirect.d.ts +1 -0
- package/dist/types/mixins/OxyServices.security.d.ts +1 -0
- package/dist/types/mixins/OxyServices.topics.d.ts +1 -0
- package/dist/types/mixins/OxyServices.user.d.ts +16 -1
- package/dist/types/mixins/OxyServices.utility.d.ts +1 -0
- package/dist/types/models/interfaces.d.ts +98 -0
- package/dist/types/models/session.d.ts +8 -0
- package/dist/types/utils/accountUtils.d.ts +33 -0
- package/dist/types/utils/coldBoot.d.ts +102 -0
- package/dist/types/utils/fapiAutoDetect.d.ts +37 -0
- package/package.json +9 -18
- package/src/AuthManager.ts +776 -7
- package/src/AuthManagerTypes.ts +72 -0
- package/src/CrossDomainAuth.ts +54 -3
- package/src/OxyServices.base.ts +17 -0
- package/src/OxyServices.ts +7 -0
- package/src/__tests__/authManager.cookiePath.test.ts +339 -0
- package/src/__tests__/authManager.security.test.ts +342 -0
- package/src/__tests__/crossDomainAuth.test.ts +191 -0
- package/src/i18n/locales/ar-SA.json +83 -1
- package/src/i18n/locales/ca-ES.json +83 -1
- package/src/i18n/locales/de-DE.json +83 -1
- package/src/i18n/locales/en-US.json +83 -0
- package/src/i18n/locales/es-ES.json +99 -4
- package/src/i18n/locales/fr-FR.json +83 -1
- package/src/i18n/locales/it-IT.json +83 -1
- package/src/i18n/locales/ja-JP.json +200 -117
- package/src/i18n/locales/ko-KR.json +83 -1
- package/src/i18n/locales/pt-PT.json +83 -1
- package/src/i18n/locales/zh-CN.json +83 -1
- package/src/index.ts +309 -112
- package/src/mixins/OxyServices.auth.ts +268 -1
- package/src/mixins/OxyServices.fedcm.ts +63 -0
- package/src/mixins/OxyServices.popup.ts +79 -1
- package/src/mixins/OxyServices.user.ts +33 -1
- package/src/mixins/__tests__/popup.test.ts +307 -0
- package/src/mixins/__tests__/sessionBaseUrl.test.ts +61 -0
- package/src/models/interfaces.ts +116 -0
- package/src/models/session.ts +8 -0
- package/src/utils/__tests__/coldBoot.test.ts +226 -0
- package/src/utils/__tests__/fapiAutoDetect.test.ts +93 -0
- package/src/utils/accountUtils.ts +84 -0
- package/src/utils/coldBoot.ts +136 -0
- package/src/utils/fapiAutoDetect.ts +82 -0
- package/dist/cjs/crypto/index.js +0 -22
- package/dist/cjs/shared/index.js +0 -70
- package/dist/cjs/utils/index.js +0 -26
- package/dist/esm/crypto/index.js +0 -13
- package/dist/esm/shared/index.js +0 -31
- package/dist/esm/utils/index.js +0 -7
- package/dist/types/crypto/index.d.ts +0 -11
- package/dist/types/shared/index.d.ts +0 -28
- package/dist/types/utils/index.d.ts +0 -6
- package/src/crypto/index.ts +0 -30
- package/src/shared/index.ts +0 -82
- package/src/utils/index.ts +0 -21
|
@@ -53,6 +53,7 @@ export declare function OxyServicesContactsMixin<T extends typeof OxyServicesBas
|
|
|
53
53
|
__resetTokensForTests(): void;
|
|
54
54
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
55
55
|
getBaseURL(): string;
|
|
56
|
+
getSessionBaseUrl(): string;
|
|
56
57
|
getClient(): import("../HttpService").HttpService;
|
|
57
58
|
getMetrics(): {
|
|
58
59
|
totalRequests: number;
|
|
@@ -58,6 +58,7 @@ export declare function OxyServicesDeveloperMixin<T extends typeof OxyServicesBa
|
|
|
58
58
|
__resetTokensForTests(): void;
|
|
59
59
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
60
60
|
getBaseURL(): string;
|
|
61
|
+
getSessionBaseUrl(): string;
|
|
61
62
|
getClient(): import("../HttpService").HttpService;
|
|
62
63
|
getMetrics(): {
|
|
63
64
|
totalRequests: number;
|
|
@@ -55,6 +55,7 @@ export declare function OxyServicesDevicesMixin<T extends typeof OxyServicesBase
|
|
|
55
55
|
__resetTokensForTests(): void;
|
|
56
56
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
57
57
|
getBaseURL(): string;
|
|
58
|
+
getSessionBaseUrl(): string;
|
|
58
59
|
getClient(): import("../HttpService").HttpService;
|
|
59
60
|
getMetrics(): {
|
|
60
61
|
totalRequests: number;
|
|
@@ -183,6 +183,7 @@ export declare function OxyServicesFeaturesMixin<T extends typeof OxyServicesBas
|
|
|
183
183
|
__resetTokensForTests(): void;
|
|
184
184
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
185
185
|
getBaseURL(): string;
|
|
186
|
+
getSessionBaseUrl(): string;
|
|
186
187
|
getClient(): import("../HttpService").HttpService;
|
|
187
188
|
getMetrics(): {
|
|
188
189
|
totalRequests: number;
|
|
@@ -216,11 +217,7 @@ export declare function OxyServicesFeaturesMixin<T extends typeof OxyServicesBas
|
|
|
216
217
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
217
218
|
maxRetries?: number;
|
|
218
219
|
retryDelay?: number;
|
|
219
|
-
authTimeoutMs
|
|
220
|
-
/**
|
|
221
|
-
* Get user statistics
|
|
222
|
-
*/
|
|
223
|
-
?: number;
|
|
220
|
+
authTimeoutMs?: number;
|
|
224
221
|
}): Promise<T_1>;
|
|
225
222
|
validate(): Promise<boolean>;
|
|
226
223
|
handleError(error: unknown): Error;
|
|
@@ -234,12 +234,30 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
|
|
|
234
234
|
storeLoginHint(userId: string): void;
|
|
235
235
|
/** @internal */
|
|
236
236
|
clearLoginHint(): void;
|
|
237
|
+
/**
|
|
238
|
+
* List the authenticated user's authorized RP apps.
|
|
239
|
+
*
|
|
240
|
+
* Returns the intersection of the user's FedCM grants and the currently-
|
|
241
|
+
* approved RP catalog — what powers the "Connected apps" management UI in
|
|
242
|
+
* @oxyhq/services. Requires a real user session; service tokens are
|
|
243
|
+
* rejected by the underlying endpoint.
|
|
244
|
+
*/
|
|
245
|
+
listAuthorizedApps(): Promise<AuthorizedApp[]>;
|
|
246
|
+
/**
|
|
247
|
+
* Revoke the authenticated user's authorization for a specific RP origin.
|
|
248
|
+
*
|
|
249
|
+
* The next FedCM sign-in from that origin will require explicit re-consent.
|
|
250
|
+
* The corresponding cache entry is invalidated so a subsequent
|
|
251
|
+
* `listAuthorizedApps()` call sees fresh data.
|
|
252
|
+
*/
|
|
253
|
+
revokeAuthorizedApp(origin: string): Promise<void>;
|
|
237
254
|
httpService: import("../HttpService").HttpService;
|
|
238
255
|
cloudURL: string;
|
|
239
256
|
config: import("../OxyServices.base").OxyConfig;
|
|
240
257
|
__resetTokensForTests(): void;
|
|
241
258
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
242
259
|
getBaseURL(): string;
|
|
260
|
+
getSessionBaseUrl(): string;
|
|
243
261
|
getClient(): import("../HttpService").HttpService;
|
|
244
262
|
getMetrics(): {
|
|
245
263
|
totalRequests: number;
|
|
@@ -292,4 +310,20 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
|
|
|
292
310
|
*/
|
|
293
311
|
isFedCMSupported(): boolean;
|
|
294
312
|
} & T;
|
|
313
|
+
/**
|
|
314
|
+
* Public summary of an RP application the user has authorized — mirrors the
|
|
315
|
+
* `AuthorizedAppSummary` shape returned by `GET /fedcm/me/authorized-apps`.
|
|
316
|
+
*/
|
|
317
|
+
export interface AuthorizedApp {
|
|
318
|
+
/** Normalised RP origin. */
|
|
319
|
+
origin: string;
|
|
320
|
+
/** Friendly display name. */
|
|
321
|
+
name: string;
|
|
322
|
+
/** Optional human-readable description. */
|
|
323
|
+
description?: string;
|
|
324
|
+
/** ISO-8601 timestamp of when the user first authorized this RP. */
|
|
325
|
+
firstGrantedAt: string;
|
|
326
|
+
/** ISO-8601 timestamp of the most recent FedCM exchange for this user+RP. */
|
|
327
|
+
lastUsedAt: string;
|
|
328
|
+
}
|
|
295
329
|
export { OxyServicesFedCMMixin as FedCMMixin };
|
|
@@ -44,6 +44,7 @@ export declare function OxyServicesKarmaMixin<T extends typeof OxyServicesBase>(
|
|
|
44
44
|
__resetTokensForTests(): void;
|
|
45
45
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
46
46
|
getBaseURL(): string;
|
|
47
|
+
getSessionBaseUrl(): string;
|
|
47
48
|
getClient(): import("../HttpService").HttpService;
|
|
48
49
|
getMetrics(): {
|
|
49
50
|
totalRequests: number;
|
|
@@ -40,6 +40,7 @@ export declare function OxyServicesLanguageMixin<T extends typeof OxyServicesBas
|
|
|
40
40
|
__resetTokensForTests(): void;
|
|
41
41
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
42
42
|
getBaseURL(): string;
|
|
43
|
+
getSessionBaseUrl(): string;
|
|
43
44
|
getClient(): import("../HttpService").HttpService;
|
|
44
45
|
getMetrics(): {
|
|
45
46
|
totalRequests: number;
|
|
@@ -23,6 +23,7 @@ export declare function OxyServicesLocationMixin<T extends typeof OxyServicesBas
|
|
|
23
23
|
__resetTokensForTests(): void;
|
|
24
24
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
25
25
|
getBaseURL(): string;
|
|
26
|
+
getSessionBaseUrl(): string;
|
|
26
27
|
getClient(): import("../HttpService").HttpService;
|
|
27
28
|
getMetrics(): {
|
|
28
29
|
totalRequests: number;
|
|
@@ -80,6 +80,7 @@ export declare function OxyServicesManagedAccountsMixin<T extends typeof OxyServ
|
|
|
80
80
|
__resetTokensForTests(): void;
|
|
81
81
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
82
82
|
getBaseURL(): string;
|
|
83
|
+
getSessionBaseUrl(): string;
|
|
83
84
|
getClient(): import("../HttpService").HttpService;
|
|
84
85
|
getMetrics(): {
|
|
85
86
|
totalRequests: number;
|
|
@@ -70,6 +70,7 @@ export declare function OxyServicesPaymentMixin<T extends typeof OxyServicesBase
|
|
|
70
70
|
__resetTokensForTests(): void;
|
|
71
71
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
72
72
|
getBaseURL(): string;
|
|
73
|
+
getSessionBaseUrl(): string;
|
|
73
74
|
getClient(): import("../HttpService").HttpService;
|
|
74
75
|
getMetrics(): {
|
|
75
76
|
totalRequests: number;
|
|
@@ -5,6 +5,23 @@ export interface PopupAuthOptions {
|
|
|
5
5
|
height?: number;
|
|
6
6
|
timeout?: number;
|
|
7
7
|
mode?: 'login' | 'signup';
|
|
8
|
+
/**
|
|
9
|
+
* A popup window handle the caller already opened SYNCHRONOUSLY inside the
|
|
10
|
+
* user-gesture event handler (e.g. an `onClick`). The mixin will navigate
|
|
11
|
+
* this window to the auth URL instead of calling `window.open` itself.
|
|
12
|
+
*
|
|
13
|
+
* Why this exists: Chrome (and other modern browsers) only honor
|
|
14
|
+
* `window.open` while a transient user-activation is in scope. The
|
|
15
|
+
* activation is consumed by the FIRST `await` in the click handler — so any
|
|
16
|
+
* caller that awaits FedCM / silent SSO before reaching `signInWithPopup`
|
|
17
|
+
* loses the activation and sees the popup blocked. The caller can dodge
|
|
18
|
+
* this by opening a blank popup on the raw click via `openBlankPopup()`,
|
|
19
|
+
* then passing the handle in here.
|
|
20
|
+
*
|
|
21
|
+
* `null` is accepted (and is the same as omitting the option) so consumers
|
|
22
|
+
* can pass through the result of `openBlankPopup()` without an extra guard.
|
|
23
|
+
*/
|
|
24
|
+
popup?: Window | null;
|
|
8
25
|
}
|
|
9
26
|
export interface SilentAuthOptions {
|
|
10
27
|
timeout?: number;
|
|
@@ -100,6 +117,28 @@ export declare function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBa
|
|
|
100
117
|
* ```
|
|
101
118
|
*/
|
|
102
119
|
silentSignIn(options?: SilentAuthOptions): Promise<SessionLoginResponse | null>;
|
|
120
|
+
/**
|
|
121
|
+
* Open a blank, centered popup window SYNCHRONOUSLY.
|
|
122
|
+
*
|
|
123
|
+
* Use this in a click (or other user-gesture) handler BEFORE any `await`
|
|
124
|
+
* to capture the transient user-activation. Pass the returned handle into
|
|
125
|
+
* `signInWithPopup({ popup })` once the async portion of the flow runs.
|
|
126
|
+
*
|
|
127
|
+
* Returns `null` if the browser's popup blocker rejected the open.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* const onSignInClick = () => {
|
|
132
|
+
* const popup = oxyServices.openBlankPopup();
|
|
133
|
+
* (async () => {
|
|
134
|
+
* const silent = await oxyServices.silentSignInWithFedCM();
|
|
135
|
+
* if (silent) { popup?.close(); return; }
|
|
136
|
+
* await oxyServices.signInWithPopup({ popup });
|
|
137
|
+
* })();
|
|
138
|
+
* };
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
openBlankPopup(width?: number, height?: number): Window | null;
|
|
103
142
|
/**
|
|
104
143
|
* Open a centered popup window
|
|
105
144
|
*
|
|
@@ -160,6 +199,7 @@ export declare function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBa
|
|
|
160
199
|
__resetTokensForTests(): void;
|
|
161
200
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
162
201
|
getBaseURL(): string;
|
|
202
|
+
getSessionBaseUrl(): string;
|
|
163
203
|
getClient(): import("../HttpService").HttpService;
|
|
164
204
|
getMetrics(): {
|
|
165
205
|
totalRequests: number;
|
|
@@ -81,6 +81,7 @@ export declare function OxyServicesPrivacyMixin<T extends typeof OxyServicesBase
|
|
|
81
81
|
__resetTokensForTests(): void;
|
|
82
82
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
83
83
|
getBaseURL(): string;
|
|
84
|
+
getSessionBaseUrl(): string;
|
|
84
85
|
getClient(): import("../HttpService").HttpService;
|
|
85
86
|
getMetrics(): {
|
|
86
87
|
totalRequests: number;
|
|
@@ -197,6 +197,7 @@ export declare function OxyServicesRedirectAuthMixin<T extends typeof OxyService
|
|
|
197
197
|
__resetTokensForTests(): void;
|
|
198
198
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
199
199
|
getBaseURL(): string;
|
|
200
|
+
getSessionBaseUrl(): string;
|
|
200
201
|
getClient(): import("../HttpService").HttpService;
|
|
201
202
|
getMetrics(): {
|
|
202
203
|
totalRequests: number;
|
|
@@ -37,6 +37,7 @@ export declare function OxyServicesSecurityMixin<T extends typeof OxyServicesBas
|
|
|
37
37
|
__resetTokensForTests(): void;
|
|
38
38
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
39
39
|
getBaseURL(): string;
|
|
40
|
+
getSessionBaseUrl(): string;
|
|
40
41
|
getClient(): import("../HttpService").HttpService;
|
|
41
42
|
getMetrics(): {
|
|
42
43
|
totalRequests: number;
|
|
@@ -63,6 +63,7 @@ export declare function OxyServicesTopicsMixin<T extends typeof OxyServicesBase>
|
|
|
63
63
|
__resetTokensForTests(): void;
|
|
64
64
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
65
65
|
getBaseURL(): string;
|
|
66
|
+
getSessionBaseUrl(): string;
|
|
66
67
|
getClient(): import("../HttpService").HttpService;
|
|
67
68
|
getMetrics(): {
|
|
68
69
|
totalRequests: number;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* User Management Methods Mixin
|
|
3
3
|
*/
|
|
4
|
-
import type { User, Notification, SearchProfilesResponse, PrivacySettings } from '../models/interfaces';
|
|
4
|
+
import type { User, Notification, NotificationPreferences, UserPreferences, SearchProfilesResponse, PrivacySettings } from '../models/interfaces';
|
|
5
5
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
6
6
|
import { type PaginationParams } from '../utils/apiUtils';
|
|
7
7
|
export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
@@ -116,6 +116,20 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
116
116
|
* @param userId - The user ID (defaults to current user)
|
|
117
117
|
*/
|
|
118
118
|
updatePrivacySettings(settings: Partial<PrivacySettings>, userId?: string): Promise<PrivacySettings>;
|
|
119
|
+
/**
|
|
120
|
+
* Update the authenticated user's notification preferences.
|
|
121
|
+
*
|
|
122
|
+
* Thin wrapper over `updateProfile` that constrains the patch to known
|
|
123
|
+
* notification channels — same persistence path, same cache invalidation,
|
|
124
|
+
* but type-safe at the call site.
|
|
125
|
+
*/
|
|
126
|
+
updateNotificationPreferences(preferences: Partial<NotificationPreferences>): Promise<User>;
|
|
127
|
+
/**
|
|
128
|
+
* Update the authenticated user's general preferences (language, theme,
|
|
129
|
+
* reduce-motion, timezone). Persisted on the User document via
|
|
130
|
+
* `PUT /users/me` — same cache-invalidation behaviour as `updateProfile`.
|
|
131
|
+
*/
|
|
132
|
+
updateUserPreferences(preferences: Partial<UserPreferences>): Promise<User>;
|
|
119
133
|
/**
|
|
120
134
|
* Request account verification
|
|
121
135
|
*/
|
|
@@ -208,6 +222,7 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
208
222
|
__resetTokensForTests(): void;
|
|
209
223
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
210
224
|
getBaseURL(): string;
|
|
225
|
+
getSessionBaseUrl(): string;
|
|
211
226
|
getClient(): import("../HttpService").HttpService;
|
|
212
227
|
getMetrics(): {
|
|
213
228
|
totalRequests: number;
|
|
@@ -246,6 +246,7 @@ export declare function OxyServicesUtilityMixin<T extends typeof OxyServicesBase
|
|
|
246
246
|
__resetTokensForTests(): void;
|
|
247
247
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
248
248
|
getBaseURL(): string;
|
|
249
|
+
getSessionBaseUrl(): string;
|
|
249
250
|
getClient(): import("../HttpService").HttpService;
|
|
250
251
|
getMetrics(): {
|
|
251
252
|
totalRequests: number;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
export interface OxyConfig {
|
|
2
2
|
baseURL: string;
|
|
3
3
|
cloudURL?: string;
|
|
4
|
+
/**
|
|
5
|
+
* Base URL the SDK's first-party session/refresh calls target.
|
|
6
|
+
*
|
|
7
|
+
* Per the 2026 session architecture (docs/SESSION-ARCHITECTURE.md), every app
|
|
8
|
+
* keeps its OWN first-party session on its OWN domain. For non-`oxy.so` apps
|
|
9
|
+
* this is the app's own same-site backend (e.g. `https://api.mention.earth`),
|
|
10
|
+
* whose session bridge forwards the user's refresh credential to
|
|
11
|
+
* `api.oxy.so`. For `*.oxy.so` apps this is omitted and falls back to
|
|
12
|
+
* `baseURL` (`https://api.oxy.so`), so their behavior is unchanged.
|
|
13
|
+
*
|
|
14
|
+
* Resolve via {@link OxyServices.getSessionBaseUrl}; when unset it returns
|
|
15
|
+
* `baseURL`. This is purely additive — no refresh/auth logic reads it yet.
|
|
16
|
+
*/
|
|
17
|
+
sessionBaseUrl?: string;
|
|
4
18
|
authWebUrl?: string;
|
|
5
19
|
authRedirectUri?: string;
|
|
6
20
|
enableCache?: boolean;
|
|
@@ -98,8 +112,37 @@ export interface User {
|
|
|
98
112
|
};
|
|
99
113
|
isManagedAccount?: boolean;
|
|
100
114
|
managedBy?: string;
|
|
115
|
+
notificationPreferences?: NotificationPreferences;
|
|
116
|
+
userPreferences?: UserPreferences;
|
|
101
117
|
[key: string]: unknown;
|
|
102
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* User-controlled notification channels. Persisted on the User document.
|
|
121
|
+
*/
|
|
122
|
+
export interface NotificationPreferences {
|
|
123
|
+
/** Push notifications on registered devices. */
|
|
124
|
+
pushEnabled?: boolean;
|
|
125
|
+
/** Periodic email digest of activity. */
|
|
126
|
+
emailDigest?: boolean;
|
|
127
|
+
/** Security/account alerts (sign-ins, recovery, key changes). */
|
|
128
|
+
securityAlerts?: boolean;
|
|
129
|
+
/** Marketing / product update emails. */
|
|
130
|
+
marketingEmails?: boolean;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* General per-user preferences applied across all Oxy apps for the user.
|
|
134
|
+
* Persisted on the User document.
|
|
135
|
+
*/
|
|
136
|
+
export interface UserPreferences {
|
|
137
|
+
/** BCP-47 language tag, e.g. "en-US", "es-ES". Empty string = follow device. */
|
|
138
|
+
language?: string;
|
|
139
|
+
/** Theme mode preference. */
|
|
140
|
+
theme?: 'light' | 'dark' | 'system';
|
|
141
|
+
/** Mirror of OS reduce-motion preference, persisted server-side. */
|
|
142
|
+
reduceMotion?: boolean;
|
|
143
|
+
/** IANA timezone, e.g. "Europe/Madrid". Empty string = follow device. */
|
|
144
|
+
timezone?: string;
|
|
145
|
+
}
|
|
103
146
|
export interface LoginResponse {
|
|
104
147
|
accessToken?: string;
|
|
105
148
|
refreshToken?: string;
|
|
@@ -488,3 +531,58 @@ export interface UpdateDeviceNameResponse {
|
|
|
488
531
|
message: string;
|
|
489
532
|
deviceName: string;
|
|
490
533
|
}
|
|
534
|
+
/**
|
|
535
|
+
* Minimal user shape included in a `RefreshAllAccount` entry. The server
|
|
536
|
+
* projects a small whitelist (`username name avatar email color`) so the
|
|
537
|
+
* client can render the account chooser without an extra `/users/me` round
|
|
538
|
+
* trip per account.
|
|
539
|
+
*
|
|
540
|
+
* `avatar` and `color` are `string | null` because they are stored as nullable
|
|
541
|
+
* fields in the user document.
|
|
542
|
+
*/
|
|
543
|
+
export interface RefreshAllAccountUser {
|
|
544
|
+
id: string;
|
|
545
|
+
username: string;
|
|
546
|
+
name?: string;
|
|
547
|
+
avatar?: string | null;
|
|
548
|
+
email?: string;
|
|
549
|
+
color?: string | null;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* One rotated account entry returned by `POST /auth/refresh-all`. `authuser` is
|
|
553
|
+
* the device-local slot index (0..N-1) the cookie was bound to. The legacy
|
|
554
|
+
* un-suffixed `oxy_rt` cookie yields `authuser: null` server-side, but the SDK
|
|
555
|
+
* normalises that to `0` before exposing it (the chooser always operates on
|
|
556
|
+
* numeric indices).
|
|
557
|
+
*
|
|
558
|
+
* `user` is `null` only on the SDK-side synthesised legacy fallback (when the
|
|
559
|
+
* server is too old to support `/auth/refresh-all` and we wrap a
|
|
560
|
+
* `/auth/refresh` response — that endpoint does not project a user shape).
|
|
561
|
+
* On the modern path every accepted entry carries a non-null user.
|
|
562
|
+
*/
|
|
563
|
+
export interface RefreshAllAccount {
|
|
564
|
+
authuser: number;
|
|
565
|
+
accessToken: string;
|
|
566
|
+
expiresAt: string;
|
|
567
|
+
sessionId: string;
|
|
568
|
+
user: RefreshAllAccountUser | null;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Wire shape of `POST /auth/refresh-all`. Always 200 with a (possibly empty)
|
|
572
|
+
* accounts array — 401 means "no accounts signed in on this device" and is
|
|
573
|
+
* normalised to `{ accounts: [] }` at the SDK layer.
|
|
574
|
+
*/
|
|
575
|
+
export interface RefreshAllResponse {
|
|
576
|
+
accounts: RefreshAllAccount[];
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Wire shape of `POST /auth/refresh` (single-account refresh, optionally
|
|
580
|
+
* targeting a specific `?authuser=N` slot). The server includes `authuser` in
|
|
581
|
+
* the response when an indexed slot was rotated; the legacy slot yields
|
|
582
|
+
* `authuser: null`.
|
|
583
|
+
*/
|
|
584
|
+
export interface RefreshCookieResponse {
|
|
585
|
+
accessToken: string;
|
|
586
|
+
expiresAt: string;
|
|
587
|
+
authuser: number | null;
|
|
588
|
+
}
|
|
@@ -5,6 +5,14 @@ export interface ClientSession {
|
|
|
5
5
|
lastActive: string;
|
|
6
6
|
userId?: string;
|
|
7
7
|
isCurrent?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Web-only: the device-local refresh-cookie slot index (0..N) that backs
|
|
10
|
+
* this session. Populated from `POST /auth/refresh-all` and from login /
|
|
11
|
+
* signup / fedcm-exchange responses. Required for per-session web token
|
|
12
|
+
* refresh via `refreshTokenViaCookie({ authuser })` without a bearer token.
|
|
13
|
+
* Absent on native (RN uses the bearer-protected session id directly).
|
|
14
|
+
*/
|
|
15
|
+
authuser?: number;
|
|
8
16
|
}
|
|
9
17
|
export interface StorageKeys {
|
|
10
18
|
sessions: string;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Shared account types and pure helper functions.
|
|
3
3
|
* Used by both @oxyhq/services (React Native) and @oxyhq/auth (Web) account stores.
|
|
4
4
|
*/
|
|
5
|
+
import type { RefreshAllAccount } from '../models/interfaces';
|
|
5
6
|
export interface QuickAccount {
|
|
6
7
|
sessionId: string;
|
|
7
8
|
userId?: string;
|
|
@@ -9,6 +10,19 @@ export interface QuickAccount {
|
|
|
9
10
|
displayName: string;
|
|
10
11
|
avatar?: string;
|
|
11
12
|
avatarUrl?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Device-local account slot index, 0..N-1 (Google-style multi-account).
|
|
15
|
+
* Mirrors the server's `oxy_rt_${authuser}` cookie slot. Optional so that
|
|
16
|
+
* pre-multi-account QuickAccounts (sessionId-only, non-cookie auth on RN)
|
|
17
|
+
* remain valid; web flows always populate it after `refreshAllSessions`.
|
|
18
|
+
*/
|
|
19
|
+
authuser?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Account's preferred Bloom color preset (e.g. `"blue"`, `"oxy"`). Drives
|
|
22
|
+
* per-account theming in the account chooser. `null` / `undefined` means
|
|
23
|
+
* the account has no preference and the base theme should be used.
|
|
24
|
+
*/
|
|
25
|
+
color?: string | null;
|
|
12
26
|
}
|
|
13
27
|
/** Minimal user shape accepted by display-name helpers. Avoids importing the full User type. */
|
|
14
28
|
export interface DisplayNameUserShape {
|
|
@@ -74,3 +88,22 @@ export declare const createQuickAccount: (sessionId: string, userData: {
|
|
|
74
88
|
} | string;
|
|
75
89
|
avatar?: string;
|
|
76
90
|
}, existingAccount?: QuickAccount, getFileDownloadUrl?: (fileId: string, variant: string) => string) => QuickAccount;
|
|
91
|
+
/**
|
|
92
|
+
* Merge a fresh `/auth/refresh-all` snapshot into an existing QuickAccount
|
|
93
|
+
* list, preserving any cached fields (`avatarUrl`) for slots that didn't
|
|
94
|
+
* change. The fresh response is canonical: the resulting list contains EXACTLY
|
|
95
|
+
* the slots present in `fresh`, sorted by `authuser` ascending. Stale stored
|
|
96
|
+
* accounts that no longer appear in `fresh` are dropped (the server already
|
|
97
|
+
* authoritatively cleared the corresponding cookie).
|
|
98
|
+
*
|
|
99
|
+
* @param stored Previously persisted QuickAccount list (any order).
|
|
100
|
+
* @param fresh Server's authoritative refresh-all response.
|
|
101
|
+
* @returns Canonical merged list, sorted by `authuser` asc.
|
|
102
|
+
*/
|
|
103
|
+
export declare const mergeAccountsFromRefreshAll: (stored: QuickAccount[] | undefined, fresh: RefreshAllAccount[]) => QuickAccount[];
|
|
104
|
+
/**
|
|
105
|
+
* Return the account's preferred Bloom color preset, or `null` if it has no
|
|
106
|
+
* preference. Centralises the `color ?? null` normalisation so consumers can
|
|
107
|
+
* drive per-account theming without duplicating the nullish-handling.
|
|
108
|
+
*/
|
|
109
|
+
export declare const getAccountColor: (account: QuickAccount) => string | null;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* coldBoot — a pure, ordered, short-circuit runner for "cold boot"
|
|
3
|
+
* authentication resolution.
|
|
4
|
+
*
|
|
5
|
+
* On a fresh page load / app launch the SDK may have several ways to recover an
|
|
6
|
+
* existing session (silent FedCM, a persisted refresh token, a cross-domain
|
|
7
|
+
* claim, an explicit popup flow, …). They must be attempted in a *deterministic
|
|
8
|
+
* order*, and the FIRST one that yields a session wins — every later step is
|
|
9
|
+
* skipped. This module encodes exactly that contract and nothing else.
|
|
10
|
+
*
|
|
11
|
+
* Design constraints (all enforced):
|
|
12
|
+
* - PURE: no DOM, no `navigator`, no `window`, no React, no platform globals.
|
|
13
|
+
* - NO module-level mutable state. Every call to {@link runColdBoot} is fully
|
|
14
|
+
* self-contained, so it is safe under bundler re-evaluation (e.g. the Metro
|
|
15
|
+
* web bundle, which is precisely why the FedCM silent-SSO guard had to live
|
|
16
|
+
* in consumers rather than a core singleton).
|
|
17
|
+
* - Architecture-agnostic: both candidate cross-domain SSO designs consume
|
|
18
|
+
* this same primitive; it knows nothing about HOW a step resolves a session.
|
|
19
|
+
*
|
|
20
|
+
* A step is skipped (without running) when its `enabled` predicate returns
|
|
21
|
+
* false. Any thrown error — from either `enabled` or `run` — is reported via
|
|
22
|
+
* `onStepError` and treated as a non-fatal skip, so one broken recovery path
|
|
23
|
+
* can never prevent a later, healthy one from succeeding.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* A successful step result carrying the recovered session.
|
|
27
|
+
*/
|
|
28
|
+
export interface ColdBootSession<S> {
|
|
29
|
+
readonly kind: 'session';
|
|
30
|
+
readonly session: S;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A step result indicating this step has nothing to contribute; the runner
|
|
34
|
+
* should fall through to the next step.
|
|
35
|
+
*/
|
|
36
|
+
export interface ColdBootSkip {
|
|
37
|
+
readonly kind: 'skip';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The result of running a single cold-boot step.
|
|
41
|
+
*/
|
|
42
|
+
export type ColdBootStepResult<S> = ColdBootSession<S> | ColdBootSkip;
|
|
43
|
+
/**
|
|
44
|
+
* A single ordered cold-boot recovery step.
|
|
45
|
+
*/
|
|
46
|
+
export interface ColdBootStep<S> {
|
|
47
|
+
/** Stable identifier; surfaced as {@link ColdBootOutcome.via} on success. */
|
|
48
|
+
readonly id: string;
|
|
49
|
+
/**
|
|
50
|
+
* Optional gate. When provided and it returns `false`, `run` is NOT called
|
|
51
|
+
* and the runner moves to the next step. A throw is treated as disabled
|
|
52
|
+
* (and reported via `onStepError`).
|
|
53
|
+
*/
|
|
54
|
+
readonly enabled?: () => boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Attempts to recover a session. Resolve with `{ kind: 'session' }` to win
|
|
57
|
+
* the cold boot, or `{ kind: 'skip' }` to defer to the next step. A throw is
|
|
58
|
+
* treated as a skip (and reported via `onStepError`).
|
|
59
|
+
*/
|
|
60
|
+
readonly run: () => Promise<ColdBootStepResult<S>>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The terminal outcome of a cold boot: either the winning step's session
|
|
64
|
+
* (with the step `id` it came from), or `unauthenticated` if every step
|
|
65
|
+
* skipped, was disabled, or errored.
|
|
66
|
+
*/
|
|
67
|
+
export type ColdBootOutcome<S> = {
|
|
68
|
+
readonly kind: 'session';
|
|
69
|
+
readonly via: string;
|
|
70
|
+
readonly session: S;
|
|
71
|
+
} | {
|
|
72
|
+
readonly kind: 'unauthenticated';
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Options for {@link runColdBoot}.
|
|
76
|
+
*/
|
|
77
|
+
export interface RunColdBootOptions<S> {
|
|
78
|
+
/** Ordered steps; evaluated front to back, first session wins. */
|
|
79
|
+
readonly steps: ReadonlyArray<ColdBootStep<S>>;
|
|
80
|
+
/**
|
|
81
|
+
* Optional observer invoked whenever a step's `enabled` or `run` throws.
|
|
82
|
+
* Receives the offending step `id` and the thrown value. Must not throw;
|
|
83
|
+
* the runner does not guard against an observer that itself throws.
|
|
84
|
+
*/
|
|
85
|
+
readonly onStepError?: (id: string, error: unknown) => void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Run the ordered cold-boot steps and resolve to the first recovered session,
|
|
89
|
+
* or `unauthenticated` if none recovers one.
|
|
90
|
+
*
|
|
91
|
+
* Semantics:
|
|
92
|
+
* 1. Iterate `steps` in order.
|
|
93
|
+
* 2. If a step has an `enabled` predicate, call it inside try/catch:
|
|
94
|
+
* - throw → report via `onStepError(id, err)` → treat as disabled → continue.
|
|
95
|
+
* - returns false → continue (skip, `run` not called).
|
|
96
|
+
* 3. Otherwise await `step.run()` inside try/catch:
|
|
97
|
+
* - throw → report via `onStepError(id, err)` → continue.
|
|
98
|
+
* - `{ kind: 'session' }` → return `{ kind: 'session', via: step.id, session }`.
|
|
99
|
+
* - `{ kind: 'skip' }` → continue.
|
|
100
|
+
* 4. After the loop with no winner → `{ kind: 'unauthenticated' }`.
|
|
101
|
+
*/
|
|
102
|
+
export declare function runColdBoot<S>(options: RunColdBootOptions<S>): Promise<ColdBootOutcome<S>>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-detect the FAPI (IdP) URL from the current browser hostname.
|
|
3
|
+
*
|
|
4
|
+
* This is the canonical cross-domain IdP-resolution primitive for the Oxy
|
|
5
|
+
* ecosystem. Both candidate cross-domain SSO designs derive `auth.<rp-apex>`
|
|
6
|
+
* through this helper; do not fork it.
|
|
7
|
+
*
|
|
8
|
+
* Clerk-style multi-domain SSO depends on the IdP being reachable on a
|
|
9
|
+
* subdomain of the RP's own apex (e.g. `auth.mention.earth` CNAMEd to the
|
|
10
|
+
* central Oxy IdP). That way every FedCM endpoint, the session cookie,
|
|
11
|
+
* and any popup/redirect target are same-site with the RP — the only way
|
|
12
|
+
* to get first-party cookies in Safari ITP and Firefox Total Cookie
|
|
13
|
+
* Protection.
|
|
14
|
+
*
|
|
15
|
+
* This helper computes `https://auth.<rp-apex>` from
|
|
16
|
+
* `window.location.hostname` so a consuming app doesn't have to pass
|
|
17
|
+
* `authWebUrl` explicitly. Returns `undefined` for environments where
|
|
18
|
+
* auto-detection would be wrong:
|
|
19
|
+
*
|
|
20
|
+
* - SSR / non-browser (no `window`).
|
|
21
|
+
* - `localhost`, `127.0.0.1`, IPv4/IPv6 literals.
|
|
22
|
+
* - Hostnames with fewer than two labels.
|
|
23
|
+
* - Hostnames whose trailing two labels form a known multi-part public
|
|
24
|
+
* suffix (e.g. `co.uk`), where the naive `labels.slice(-2)` apex would be
|
|
25
|
+
* an attacker-registrable suffix like `auth.co.uk` rather than the real
|
|
26
|
+
* registrable domain.
|
|
27
|
+
*
|
|
28
|
+
* When the page is already loaded ON the IdP itself (`auth.<anything>`),
|
|
29
|
+
* the helper returns the current origin so the SDK keeps everything
|
|
30
|
+
* same-origin instead of hopping to a different IdP host.
|
|
31
|
+
*
|
|
32
|
+
* The IdP backend independently derives `iss`, `provider_urls`, and the
|
|
33
|
+
* `fedcm.json` icon URLs from the request host
|
|
34
|
+
* (`packages/auth/server/index.ts`), so an honest CNAME pair is all that
|
|
35
|
+
* is required for end-to-end FedCM correctness — no per-RP config.
|
|
36
|
+
*/
|
|
37
|
+
export declare function autoDetectAuthWebUrl(location?: Pick<Location, 'hostname' | 'protocol'> | undefined): string | undefined;
|