@oxyhq/core 1.11.6 → 1.11.8
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/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/AuthManager.js +22 -2
- package/dist/cjs/mixins/OxyServices.fedcm.js +11 -4
- package/dist/cjs/mixins/OxyServices.popup.js +10 -6
- package/dist/cjs/mixins/OxyServices.redirect.js +6 -2
- package/dist/cjs/mixins/OxyServices.user.js +12 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/AuthManager.js +22 -2
- package/dist/esm/mixins/OxyServices.fedcm.js +11 -4
- package/dist/esm/mixins/OxyServices.popup.js +10 -6
- package/dist/esm/mixins/OxyServices.redirect.js +6 -2
- package/dist/esm/mixins/OxyServices.user.js +12 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/AuthManager.d.ts +1 -1
- package/dist/types/mixins/OxyServices.fedcm.d.ts +3 -0
- package/dist/types/mixins/OxyServices.popup.d.ts +3 -1
- package/dist/types/mixins/OxyServices.redirect.d.ts +3 -1
- package/dist/types/mixins/OxyServices.user.d.ts +4 -0
- package/package.json +1 -1
- package/src/AuthManager.ts +22 -2
- package/src/mixins/OxyServices.fedcm.ts +12 -4
- package/src/mixins/OxyServices.popup.ts +11 -6
- package/src/mixins/OxyServices.redirect.ts +7 -2
- package/src/mixins/OxyServices.user.ts +12 -0
|
@@ -33,6 +33,8 @@ export interface FedCMConfig {
|
|
|
33
33
|
*/
|
|
34
34
|
export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
35
35
|
new (...args: any[]): {
|
|
36
|
+
/** Resolved FedCM config URL: derived from config.authWebUrl or uses the static default */
|
|
37
|
+
get fedcmConfigUrl(): string;
|
|
36
38
|
/**
|
|
37
39
|
* Instance method to check FedCM support
|
|
38
40
|
*/
|
|
@@ -202,6 +204,7 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
|
|
|
202
204
|
[key: string]: any;
|
|
203
205
|
}>;
|
|
204
206
|
};
|
|
207
|
+
readonly DEFAULT_AUTH_URL: "https://auth.oxy.so";
|
|
205
208
|
readonly DEFAULT_CONFIG_URL: "https://auth.oxy.so/fedcm.json";
|
|
206
209
|
readonly FEDCM_TIMEOUT: 15000;
|
|
207
210
|
readonly FEDCM_SILENT_TIMEOUT: 3000;
|
|
@@ -33,6 +33,8 @@ export interface SilentAuthOptions {
|
|
|
33
33
|
*/
|
|
34
34
|
export declare function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
35
35
|
new (...args: any[]): {
|
|
36
|
+
/** Resolved auth URL: config.authWebUrl takes precedence over the static default */
|
|
37
|
+
get authUrl(): string;
|
|
36
38
|
/**
|
|
37
39
|
* Sign in using popup window
|
|
38
40
|
*
|
|
@@ -198,7 +200,7 @@ export declare function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBa
|
|
|
198
200
|
[key: string]: any;
|
|
199
201
|
}>;
|
|
200
202
|
};
|
|
201
|
-
readonly
|
|
203
|
+
readonly DEFAULT_AUTH_URL: "https://auth.oxy.so";
|
|
202
204
|
readonly POPUP_WIDTH: 500;
|
|
203
205
|
readonly POPUP_HEIGHT: 700;
|
|
204
206
|
readonly POPUP_TIMEOUT: 60000;
|
|
@@ -31,6 +31,8 @@ export interface RedirectAuthOptions {
|
|
|
31
31
|
*/
|
|
32
32
|
export declare function OxyServicesRedirectAuthMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
33
33
|
new (...args: any[]): {
|
|
34
|
+
/** Resolved auth URL: config.authWebUrl takes precedence over the static default */
|
|
35
|
+
get authUrl(): string;
|
|
34
36
|
/**
|
|
35
37
|
* Sign in using full page redirect
|
|
36
38
|
*
|
|
@@ -237,7 +239,7 @@ export declare function OxyServicesRedirectAuthMixin<T extends typeof OxyService
|
|
|
237
239
|
[key: string]: any;
|
|
238
240
|
}>;
|
|
239
241
|
};
|
|
240
|
-
readonly
|
|
242
|
+
readonly DEFAULT_AUTH_URL: "https://auth.oxy.so";
|
|
241
243
|
readonly TOKEN_STORAGE_KEY: "oxy_access_token";
|
|
242
244
|
readonly SESSION_STORAGE_KEY: "oxy_session_id";
|
|
243
245
|
readonly STATE_STORAGE_KEY: "oxy_auth_state";
|
|
@@ -67,6 +67,10 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
67
67
|
};
|
|
68
68
|
[key: string]: unknown;
|
|
69
69
|
}>>;
|
|
70
|
+
/**
|
|
71
|
+
* Get profiles similar to a given user, based on co-follower overlap.
|
|
72
|
+
*/
|
|
73
|
+
getSimilarProfiles(userId: string, limit?: number): Promise<User[]>;
|
|
70
74
|
/**
|
|
71
75
|
* Get user by ID
|
|
72
76
|
*/
|
package/package.json
CHANGED
package/src/AuthManager.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { OxyServices } from './OxyServices';
|
|
|
11
11
|
import type { HttpService } from './HttpService';
|
|
12
12
|
import type { SessionLoginResponse, MinimalUserData } from './models/session';
|
|
13
13
|
import { retryAsync } from './utils/asyncUtils';
|
|
14
|
+
import { jwtDecode } from 'jwt-decode';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* OxyServices already declares revokeFedCMCredential via mixin type augmentation.
|
|
@@ -429,10 +430,29 @@ export class AuthManager {
|
|
|
429
430
|
}
|
|
430
431
|
|
|
431
432
|
/**
|
|
432
|
-
* Get
|
|
433
|
+
* Get a valid access token, refreshing automatically if expired or expiring soon.
|
|
433
434
|
*/
|
|
434
435
|
async getAccessToken(): Promise<string | null> {
|
|
435
|
-
|
|
436
|
+
const token = await this.storage.getItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
437
|
+
if (!token) return null;
|
|
438
|
+
|
|
439
|
+
try {
|
|
440
|
+
const decoded = jwtDecode<{ exp?: number }>(token);
|
|
441
|
+
if (decoded.exp) {
|
|
442
|
+
const now = Math.floor(Date.now() / 1000);
|
|
443
|
+
const buffer = 60; // refresh 60 seconds before expiry
|
|
444
|
+
if (decoded.exp - now < buffer) {
|
|
445
|
+
const refreshed = await this.refreshToken();
|
|
446
|
+
if (refreshed) {
|
|
447
|
+
return this.storage.getItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
} catch {
|
|
452
|
+
// Decode failed — return token as-is, let the server decide
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return token;
|
|
436
456
|
}
|
|
437
457
|
|
|
438
458
|
/**
|
|
@@ -51,7 +51,15 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
51
51
|
constructor(...args: any[]) {
|
|
52
52
|
super(...(args as [any]));
|
|
53
53
|
}
|
|
54
|
+
public static readonly DEFAULT_AUTH_URL = 'https://auth.oxy.so';
|
|
54
55
|
public static readonly DEFAULT_CONFIG_URL = 'https://auth.oxy.so/fedcm.json';
|
|
56
|
+
|
|
57
|
+
/** Resolved FedCM config URL: derived from config.authWebUrl or uses the static default */
|
|
58
|
+
public get fedcmConfigUrl(): string {
|
|
59
|
+
return this.config.authWebUrl
|
|
60
|
+
? `${this.config.authWebUrl}/fedcm.json`
|
|
61
|
+
: (this.constructor as any).DEFAULT_CONFIG_URL;
|
|
62
|
+
}
|
|
55
63
|
public static readonly FEDCM_TIMEOUT = 15000; // 15 seconds for interactive
|
|
56
64
|
public static readonly FEDCM_SILENT_TIMEOUT = 3000; // 3 seconds for silent mediation
|
|
57
65
|
|
|
@@ -113,7 +121,7 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
113
121
|
// Request credential from browser's native identity flow
|
|
114
122
|
// mode: 'button' signals this is a user-gesture-initiated flow (Chrome 125+)
|
|
115
123
|
const credential = await this.requestIdentityCredential({
|
|
116
|
-
configURL:
|
|
124
|
+
configURL: this.fedcmConfigUrl,
|
|
117
125
|
clientId,
|
|
118
126
|
nonce,
|
|
119
127
|
context: options.context,
|
|
@@ -216,7 +224,7 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
216
224
|
debug.log('Silent SSO: Attempting silent mediation...', loginHint ? `(hint: ${loginHint})` : '');
|
|
217
225
|
|
|
218
226
|
credential = await this.requestIdentityCredential({
|
|
219
|
-
configURL:
|
|
227
|
+
configURL: this.fedcmConfigUrl,
|
|
220
228
|
clientId,
|
|
221
229
|
nonce,
|
|
222
230
|
loginHint,
|
|
@@ -461,7 +469,7 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
461
469
|
if ('IdentityCredential' in window && 'disconnect' in (window as any).IdentityCredential) {
|
|
462
470
|
const clientId = this.getClientId();
|
|
463
471
|
await (window as any).IdentityCredential.disconnect({
|
|
464
|
-
configURL:
|
|
472
|
+
configURL: this.fedcmConfigUrl,
|
|
465
473
|
clientId,
|
|
466
474
|
accountHint: accountHint || '*',
|
|
467
475
|
});
|
|
@@ -480,7 +488,7 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
480
488
|
getFedCMConfig(): FedCMConfig {
|
|
481
489
|
return {
|
|
482
490
|
enabled: this.isFedCMSupported(),
|
|
483
|
-
configURL:
|
|
491
|
+
configURL: this.fedcmConfigUrl,
|
|
484
492
|
clientId: this.getClientId(),
|
|
485
493
|
};
|
|
486
494
|
}
|
|
@@ -43,7 +43,12 @@ export function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base
|
|
|
43
43
|
constructor(...args: any[]) {
|
|
44
44
|
super(...(args as [any]));
|
|
45
45
|
}
|
|
46
|
-
public static readonly
|
|
46
|
+
public static readonly DEFAULT_AUTH_URL = 'https://auth.oxy.so';
|
|
47
|
+
|
|
48
|
+
/** Resolved auth URL: config.authWebUrl takes precedence over the static default */
|
|
49
|
+
public get authUrl(): string {
|
|
50
|
+
return this.config.authWebUrl || (this.constructor as any).DEFAULT_AUTH_URL;
|
|
51
|
+
}
|
|
47
52
|
public static readonly POPUP_WIDTH = 500;
|
|
48
53
|
public static readonly POPUP_HEIGHT = 700;
|
|
49
54
|
public static readonly POPUP_TIMEOUT = 60000; // 1 minute
|
|
@@ -95,7 +100,7 @@ export function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base
|
|
|
95
100
|
state,
|
|
96
101
|
nonce,
|
|
97
102
|
clientId: window.location.origin,
|
|
98
|
-
redirectUri: `${
|
|
103
|
+
redirectUri: `${this.authUrl}/auth/callback`,
|
|
99
104
|
});
|
|
100
105
|
|
|
101
106
|
const popup = this.openCenteredPopup(authUrl, 'Oxy Sign In', width, height);
|
|
@@ -198,7 +203,7 @@ export function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base
|
|
|
198
203
|
iframe.style.height = '0';
|
|
199
204
|
iframe.style.border = 'none';
|
|
200
205
|
|
|
201
|
-
const silentUrl = `${
|
|
206
|
+
const silentUrl = `${this.authUrl}/auth/silent?` + `client_id=${encodeURIComponent(clientId)}&` + `nonce=${nonce}`;
|
|
202
207
|
|
|
203
208
|
iframe.src = silentUrl;
|
|
204
209
|
document.body.appendChild(iframe);
|
|
@@ -260,7 +265,7 @@ export function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base
|
|
|
260
265
|
}, timeout);
|
|
261
266
|
|
|
262
267
|
const messageHandler = (event: MessageEvent) => {
|
|
263
|
-
const authUrl =
|
|
268
|
+
const authUrl = this.authUrl;
|
|
264
269
|
|
|
265
270
|
// Log all messages for debugging
|
|
266
271
|
if (event.data && typeof event.data === 'object' && event.data.type) {
|
|
@@ -347,7 +352,7 @@ export function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base
|
|
|
347
352
|
|
|
348
353
|
const messageHandler = (event: MessageEvent) => {
|
|
349
354
|
// Verify origin
|
|
350
|
-
if (event.origin !==
|
|
355
|
+
if (event.origin !== this.authUrl) {
|
|
351
356
|
return;
|
|
352
357
|
}
|
|
353
358
|
|
|
@@ -382,7 +387,7 @@ export function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBase>(Base
|
|
|
382
387
|
clientId: string;
|
|
383
388
|
redirectUri: string;
|
|
384
389
|
}): string {
|
|
385
|
-
const url = new URL(`${
|
|
390
|
+
const url = new URL(`${this.authUrl}/${params.mode}`);
|
|
386
391
|
url.searchParams.set('response_type', 'token');
|
|
387
392
|
url.searchParams.set('client_id', params.clientId);
|
|
388
393
|
url.searchParams.set('redirect_uri', params.redirectUri);
|
|
@@ -37,7 +37,12 @@ export function OxyServicesRedirectAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
37
37
|
constructor(...args: any[]) {
|
|
38
38
|
super(...(args as [any]));
|
|
39
39
|
}
|
|
40
|
-
public static readonly
|
|
40
|
+
public static readonly DEFAULT_AUTH_URL = 'https://auth.oxy.so';
|
|
41
|
+
|
|
42
|
+
/** Resolved auth URL: config.authWebUrl takes precedence over the static default */
|
|
43
|
+
public get authUrl(): string {
|
|
44
|
+
return this.config.authWebUrl || (this.constructor as any).DEFAULT_AUTH_URL;
|
|
45
|
+
}
|
|
41
46
|
public static readonly TOKEN_STORAGE_KEY = 'oxy_access_token';
|
|
42
47
|
public static readonly SESSION_STORAGE_KEY = 'oxy_session_id';
|
|
43
48
|
public static readonly STATE_STORAGE_KEY = 'oxy_auth_state';
|
|
@@ -270,7 +275,7 @@ export function OxyServicesRedirectAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
270
275
|
nonce: string;
|
|
271
276
|
clientId: string;
|
|
272
277
|
}): string {
|
|
273
|
-
const url = new URL(`${
|
|
278
|
+
const url = new URL(`${this.authUrl}/${params.mode}`);
|
|
274
279
|
url.searchParams.set('redirect_uri', params.redirectUri);
|
|
275
280
|
url.searchParams.set('state', params.state);
|
|
276
281
|
url.searchParams.set('nonce', params.nonce);
|
|
@@ -149,6 +149,18 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
149
149
|
}, 'getProfileRecommendations');
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Get profiles similar to a given user, based on co-follower overlap.
|
|
154
|
+
*/
|
|
155
|
+
async getSimilarProfiles(userId: string, limit?: number): Promise<User[]> {
|
|
156
|
+
const params: Record<string, string> = {};
|
|
157
|
+
if (limit) params.limit = String(limit);
|
|
158
|
+
return await this.makeRequest<User[]>('GET', `/profiles/${userId}/similar`, params, {
|
|
159
|
+
cache: true,
|
|
160
|
+
cacheTTL: 5 * 60 * 1000, // 5 min cache
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
152
164
|
/**
|
|
153
165
|
* Get user by ID
|
|
154
166
|
*/
|