@oxyhq/core 1.5.0 → 1.6.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/cjs/AuthManager.js +1 -1
- package/dist/cjs/HttpService.js +87 -69
- package/dist/cjs/OxyServices.base.js +5 -4
- package/dist/cjs/crypto/keyManager.js +1 -13
- package/dist/cjs/crypto/signatureService.js +7 -20
- package/dist/cjs/mixins/OxyServices.analytics.js +2 -2
- package/dist/cjs/mixins/OxyServices.assets.js +14 -14
- package/dist/cjs/mixins/OxyServices.auth.js +19 -19
- package/dist/cjs/mixins/OxyServices.developer.js +6 -6
- package/dist/cjs/mixins/OxyServices.devices.js +7 -7
- package/dist/cjs/mixins/OxyServices.features.js +23 -23
- package/dist/cjs/mixins/OxyServices.fedcm.js +1 -1
- package/dist/cjs/mixins/OxyServices.karma.js +6 -6
- package/dist/cjs/mixins/OxyServices.location.js +2 -2
- package/dist/cjs/mixins/OxyServices.payment.js +6 -6
- package/dist/cjs/mixins/OxyServices.popup.js +1 -1
- package/dist/cjs/mixins/OxyServices.privacy.js +6 -6
- package/dist/cjs/mixins/OxyServices.security.js +3 -3
- package/dist/cjs/mixins/OxyServices.user.js +22 -22
- package/dist/cjs/mixins/OxyServices.utility.js +16 -7
- package/dist/cjs/utils/platform.js +14 -0
- package/dist/esm/AuthManager.js +1 -1
- package/dist/esm/HttpService.js +87 -69
- package/dist/esm/OxyServices.base.js +5 -4
- package/dist/esm/crypto/keyManager.js +1 -13
- package/dist/esm/crypto/signatureService.js +2 -15
- package/dist/esm/mixins/OxyServices.analytics.js +2 -2
- package/dist/esm/mixins/OxyServices.assets.js +14 -14
- package/dist/esm/mixins/OxyServices.auth.js +19 -19
- package/dist/esm/mixins/OxyServices.developer.js +6 -6
- package/dist/esm/mixins/OxyServices.devices.js +7 -7
- package/dist/esm/mixins/OxyServices.features.js +23 -23
- package/dist/esm/mixins/OxyServices.fedcm.js +1 -1
- package/dist/esm/mixins/OxyServices.karma.js +6 -6
- package/dist/esm/mixins/OxyServices.location.js +2 -2
- package/dist/esm/mixins/OxyServices.payment.js +6 -6
- package/dist/esm/mixins/OxyServices.popup.js +1 -1
- package/dist/esm/mixins/OxyServices.privacy.js +6 -6
- package/dist/esm/mixins/OxyServices.security.js +3 -3
- package/dist/esm/mixins/OxyServices.user.js +22 -22
- package/dist/esm/mixins/OxyServices.utility.js +16 -7
- package/dist/esm/utils/platform.js +12 -0
- package/dist/types/HttpService.d.ts +4 -1
- package/dist/types/OxyServices.base.d.ts +1 -1
- package/dist/types/mixins/OxyServices.analytics.d.ts +1 -1
- package/dist/types/mixins/OxyServices.assets.d.ts +1 -1
- package/dist/types/mixins/OxyServices.auth.d.ts +1 -1
- package/dist/types/mixins/OxyServices.developer.d.ts +1 -1
- package/dist/types/mixins/OxyServices.devices.d.ts +1 -1
- package/dist/types/mixins/OxyServices.features.d.ts +1 -1
- package/dist/types/mixins/OxyServices.fedcm.d.ts +1 -1
- package/dist/types/mixins/OxyServices.karma.d.ts +1 -1
- package/dist/types/mixins/OxyServices.language.d.ts +1 -1
- package/dist/types/mixins/OxyServices.location.d.ts +1 -1
- package/dist/types/mixins/OxyServices.payment.d.ts +1 -1
- package/dist/types/mixins/OxyServices.popup.d.ts +1 -1
- package/dist/types/mixins/OxyServices.privacy.d.ts +1 -1
- package/dist/types/mixins/OxyServices.redirect.d.ts +1 -1
- package/dist/types/mixins/OxyServices.security.d.ts +1 -1
- package/dist/types/mixins/OxyServices.user.d.ts +1 -1
- package/dist/types/mixins/OxyServices.utility.d.ts +7 -6
- package/dist/types/utils/platform.d.ts +8 -0
- package/package.json +1 -1
- package/src/AuthManager.ts +1 -1
- package/src/HttpService.ts +85 -67
- package/src/OxyServices.base.ts +5 -4
- package/src/crypto/keyManager.ts +1 -15
- package/src/crypto/signatureService.ts +2 -17
- package/src/mixins/OxyServices.analytics.ts +2 -2
- package/src/mixins/OxyServices.assets.ts +14 -14
- package/src/mixins/OxyServices.auth.ts +19 -19
- package/src/mixins/OxyServices.developer.ts +6 -6
- package/src/mixins/OxyServices.devices.ts +7 -7
- package/src/mixins/OxyServices.features.ts +23 -23
- package/src/mixins/OxyServices.fedcm.ts +1 -1
- package/src/mixins/OxyServices.karma.ts +6 -6
- package/src/mixins/OxyServices.location.ts +2 -2
- package/src/mixins/OxyServices.payment.ts +6 -6
- package/src/mixins/OxyServices.popup.ts +1 -1
- package/src/mixins/OxyServices.privacy.ts +6 -6
- package/src/mixins/OxyServices.security.ts +3 -3
- package/src/mixins/OxyServices.user.ts +22 -22
- package/src/mixins/OxyServices.utility.ts +18 -8
- package/src/utils/platform.ts +14 -0
package/dist/cjs/AuthManager.js
CHANGED
|
@@ -247,7 +247,7 @@ class AuthManager {
|
|
|
247
247
|
// Use session-based token endpoint which handles auto-refresh server-side
|
|
248
248
|
const response = await httpService.request({
|
|
249
249
|
method: 'GET',
|
|
250
|
-
url: `/
|
|
250
|
+
url: `/session/token/${sessionId}`,
|
|
251
251
|
cache: false,
|
|
252
252
|
retry: false,
|
|
253
253
|
});
|
package/dist/cjs/HttpService.js
CHANGED
|
@@ -28,7 +28,9 @@ const platform_1 = require("./utils/platform");
|
|
|
28
28
|
*/
|
|
29
29
|
const isNativeApp = (0, platform_1.isNative)();
|
|
30
30
|
/**
|
|
31
|
-
* Token store for authentication (
|
|
31
|
+
* Token store for authentication (instance-based)
|
|
32
|
+
* Each HttpService gets its own TokenStore to prevent conflicts
|
|
33
|
+
* when multiple OxyServices instances coexist server-side.
|
|
32
34
|
*/
|
|
33
35
|
class TokenStore {
|
|
34
36
|
constructor() {
|
|
@@ -37,12 +39,6 @@ class TokenStore {
|
|
|
37
39
|
this.csrfToken = null;
|
|
38
40
|
this.csrfTokenFetchPromise = null;
|
|
39
41
|
}
|
|
40
|
-
static getInstance() {
|
|
41
|
-
if (!TokenStore.instance) {
|
|
42
|
-
TokenStore.instance = new TokenStore();
|
|
43
|
-
}
|
|
44
|
-
return TokenStore.instance;
|
|
45
|
-
}
|
|
46
42
|
setTokens(accessToken, refreshToken = '') {
|
|
47
43
|
this.accessToken = accessToken;
|
|
48
44
|
this.refreshToken = refreshToken;
|
|
@@ -86,6 +82,7 @@ class TokenStore {
|
|
|
86
82
|
class HttpService {
|
|
87
83
|
constructor(config) {
|
|
88
84
|
this.tokenRefreshPromise = null;
|
|
85
|
+
this.tokenRefreshCooldownUntil = 0;
|
|
89
86
|
this._onTokenRefreshed = null;
|
|
90
87
|
// Performance monitoring
|
|
91
88
|
this.requestMetrics = {
|
|
@@ -98,7 +95,7 @@ class HttpService {
|
|
|
98
95
|
};
|
|
99
96
|
this.config = config;
|
|
100
97
|
this.baseURL = config.baseURL;
|
|
101
|
-
this.tokenStore = TokenStore
|
|
98
|
+
this.tokenStore = new TokenStore();
|
|
102
99
|
this.logger = new requestUtils_1.SimpleLogger(config.enableLogging || false, config.logLevel || 'error', 'HttpService');
|
|
103
100
|
// Initialize performance infrastructure
|
|
104
101
|
this.cache = new cache_1.TTLCache(config.cacheTTL || 5 * 60 * 1000);
|
|
@@ -250,6 +247,20 @@ class HttpService {
|
|
|
250
247
|
// Refresh failed or no token — clear tokens
|
|
251
248
|
this.tokenStore.clearTokens();
|
|
252
249
|
}
|
|
250
|
+
// On 403 with CSRF error, clear cached token and retry once
|
|
251
|
+
if (response.status === 403 && !config._isCsrfRetry) {
|
|
252
|
+
try {
|
|
253
|
+
const clonedResponse = response.clone();
|
|
254
|
+
const errBody = await clonedResponse.json();
|
|
255
|
+
if (errBody?.code === 'CSRF_TOKEN_INVALID' || errBody?.code === 'CSRF_TOKEN_MISSING') {
|
|
256
|
+
this.tokenStore.clearCsrfToken();
|
|
257
|
+
return this.request({ ...config, _isCsrfRetry: true, retry: false });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
// Failed to parse error body — not a CSRF error
|
|
262
|
+
}
|
|
263
|
+
}
|
|
253
264
|
// Try to parse error response (handle empty/malformed JSON)
|
|
254
265
|
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
255
266
|
const contentType = response.headers.get('content-type');
|
|
@@ -406,52 +417,57 @@ class HttpService {
|
|
|
406
417
|
return existingPromise;
|
|
407
418
|
}
|
|
408
419
|
const fetchPromise = (async () => {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
420
|
+
const maxAttempts = 2;
|
|
421
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
422
|
+
try {
|
|
423
|
+
if ((0, debugUtils_1.isDev)())
|
|
424
|
+
console.log('[HttpService] Fetching CSRF token from:', `${this.baseURL}/csrf-token`, `(attempt ${attempt})`);
|
|
425
|
+
// Use AbortController for timeout (more compatible than AbortSignal.timeout)
|
|
426
|
+
const controller = new AbortController();
|
|
427
|
+
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
428
|
+
const response = await fetch(`${this.baseURL}/csrf-token`, {
|
|
429
|
+
method: 'GET',
|
|
430
|
+
headers: { 'Accept': 'application/json' },
|
|
431
|
+
credentials: 'include', // Required to receive and send cookies
|
|
432
|
+
signal: controller.signal,
|
|
433
|
+
});
|
|
434
|
+
clearTimeout(timeoutId);
|
|
435
|
+
if ((0, debugUtils_1.isDev)())
|
|
436
|
+
console.log('[HttpService] CSRF fetch response:', response.status, response.ok);
|
|
437
|
+
if (response.ok) {
|
|
438
|
+
const data = await response.json();
|
|
439
|
+
if ((0, debugUtils_1.isDev)())
|
|
440
|
+
console.log('[HttpService] CSRF response data:', data);
|
|
441
|
+
const token = data.csrfToken || null;
|
|
442
|
+
this.tokenStore.setCsrfToken(token);
|
|
443
|
+
this.logger.debug('CSRF token fetched');
|
|
444
|
+
return token;
|
|
445
|
+
}
|
|
446
|
+
// Also check response header for CSRF token
|
|
447
|
+
const headerToken = response.headers.get('X-CSRF-Token');
|
|
448
|
+
if (headerToken) {
|
|
449
|
+
this.tokenStore.setCsrfToken(headerToken);
|
|
450
|
+
this.logger.debug('CSRF token from header');
|
|
451
|
+
return headerToken;
|
|
452
|
+
}
|
|
426
453
|
if ((0, debugUtils_1.isDev)())
|
|
427
|
-
console.log('[HttpService] CSRF
|
|
428
|
-
|
|
429
|
-
this.tokenStore.setCsrfToken(token);
|
|
430
|
-
this.logger.debug('CSRF token fetched');
|
|
431
|
-
return token;
|
|
454
|
+
console.log('[HttpService] CSRF fetch failed with status:', response.status);
|
|
455
|
+
this.logger.warn('Failed to fetch CSRF token:', response.status);
|
|
432
456
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
this.
|
|
437
|
-
|
|
438
|
-
|
|
457
|
+
catch (error) {
|
|
458
|
+
if ((0, debugUtils_1.isDev)())
|
|
459
|
+
console.log('[HttpService] CSRF fetch error:', error);
|
|
460
|
+
this.logger.warn('CSRF token fetch error:', error);
|
|
461
|
+
}
|
|
462
|
+
// Wait before retry (500ms)
|
|
463
|
+
if (attempt < maxAttempts) {
|
|
464
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
439
465
|
}
|
|
440
|
-
if ((0, debugUtils_1.isDev)())
|
|
441
|
-
console.log('[HttpService] CSRF fetch failed with status:', response.status);
|
|
442
|
-
this.logger.warn('Failed to fetch CSRF token:', response.status);
|
|
443
|
-
return null;
|
|
444
|
-
}
|
|
445
|
-
catch (error) {
|
|
446
|
-
if ((0, debugUtils_1.isDev)())
|
|
447
|
-
console.log('[HttpService] CSRF fetch error:', error);
|
|
448
|
-
this.logger.warn('CSRF token fetch error:', error);
|
|
449
|
-
return null;
|
|
450
|
-
}
|
|
451
|
-
finally {
|
|
452
|
-
this.tokenStore.setCsrfTokenFetchPromise(null);
|
|
453
466
|
}
|
|
454
|
-
|
|
467
|
+
return null;
|
|
468
|
+
})().finally(() => {
|
|
469
|
+
this.tokenStore.setCsrfTokenFetchPromise(null);
|
|
470
|
+
});
|
|
455
471
|
this.tokenStore.setCsrfTokenFetchPromise(fetchPromise);
|
|
456
472
|
return fetchPromise;
|
|
457
473
|
}
|
|
@@ -468,18 +484,25 @@ class HttpService {
|
|
|
468
484
|
const currentTime = Math.floor(Date.now() / 1000);
|
|
469
485
|
// If token expires in less than 60 seconds, refresh it
|
|
470
486
|
if (decoded.exp && decoded.exp - currentTime < 60 && decoded.sessionId) {
|
|
471
|
-
//
|
|
472
|
-
if (
|
|
473
|
-
|
|
487
|
+
// Skip if we recently failed a refresh (5s cooldown to prevent storms)
|
|
488
|
+
if (Date.now() < this.tokenRefreshCooldownUntil) {
|
|
489
|
+
return `Bearer ${accessToken}`;
|
|
474
490
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
491
|
+
// Deduplicate concurrent refresh attempts. The promise is shared
|
|
492
|
+
// across all concurrent callers and cleared only after it settles,
|
|
493
|
+
// so every awaiter receives the same result.
|
|
494
|
+
if (!this.tokenRefreshPromise) {
|
|
495
|
+
this.tokenRefreshPromise = this._refreshTokenFromSession(decoded.sessionId)
|
|
496
|
+
.then((result) => {
|
|
497
|
+
if (!result)
|
|
498
|
+
this.tokenRefreshCooldownUntil = Date.now() + 5000;
|
|
478
499
|
return result;
|
|
500
|
+
})
|
|
501
|
+
.finally(() => { this.tokenRefreshPromise = null; });
|
|
479
502
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
503
|
+
const result = await this.tokenRefreshPromise;
|
|
504
|
+
if (result)
|
|
505
|
+
return result;
|
|
483
506
|
}
|
|
484
507
|
return `Bearer ${accessToken}`;
|
|
485
508
|
}
|
|
@@ -490,7 +513,7 @@ class HttpService {
|
|
|
490
513
|
}
|
|
491
514
|
async _refreshTokenFromSession(sessionId) {
|
|
492
515
|
try {
|
|
493
|
-
const refreshUrl = `${this.baseURL}/
|
|
516
|
+
const refreshUrl = `${this.baseURL}/session/token/${sessionId}`;
|
|
494
517
|
const response = await fetch(refreshUrl, {
|
|
495
518
|
method: 'GET',
|
|
496
519
|
headers: { 'Accept': 'application/json' },
|
|
@@ -643,15 +666,10 @@ class HttpService {
|
|
|
643
666
|
getMetrics() {
|
|
644
667
|
return { ...this.requestMetrics };
|
|
645
668
|
}
|
|
646
|
-
// Test-only utility
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
}
|
|
651
|
-
catch (error) {
|
|
652
|
-
// Silently fail in test cleanup - this is expected behavior
|
|
653
|
-
// TokenStore might not be initialized in some test scenarios
|
|
654
|
-
}
|
|
669
|
+
// Test-only utility — clears tokens on this instance
|
|
670
|
+
__resetTokensForTests() {
|
|
671
|
+
this.tokenStore.clearTokens();
|
|
672
|
+
this.tokenStore.clearCsrfToken();
|
|
655
673
|
}
|
|
656
674
|
}
|
|
657
675
|
exports.HttpService = HttpService;
|
|
@@ -26,9 +26,10 @@ class OxyServicesBase {
|
|
|
26
26
|
// Initialize unified HTTP service (handles auth, caching, deduplication, queuing, retry)
|
|
27
27
|
this.httpService = new HttpService_1.HttpService(config);
|
|
28
28
|
}
|
|
29
|
-
// Test-only utility to reset
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
// Test-only utility to reset tokens on this instance between jest tests
|
|
30
|
+
// Note: tokens are now per-instance, so create new instances in tests for isolation
|
|
31
|
+
__resetTokensForTests() {
|
|
32
|
+
this.httpService.__resetTokensForTests();
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
35
|
* Make a request with all performance optimizations
|
|
@@ -234,7 +235,7 @@ class OxyServicesBase {
|
|
|
234
235
|
return false;
|
|
235
236
|
}
|
|
236
237
|
try {
|
|
237
|
-
const res = await this.makeRequest('GET', '/
|
|
238
|
+
const res = await this.makeRequest('GET', '/auth/validate', undefined, {
|
|
238
239
|
cache: false,
|
|
239
240
|
retry: false,
|
|
240
241
|
});
|
|
@@ -92,18 +92,6 @@ async function initSecureStore() {
|
|
|
92
92
|
}
|
|
93
93
|
return SecureStore;
|
|
94
94
|
}
|
|
95
|
-
/**
|
|
96
|
-
* Check if we're in a React Native environment
|
|
97
|
-
*/
|
|
98
|
-
function isReactNative() {
|
|
99
|
-
return typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Check if we're in a Node.js environment
|
|
103
|
-
*/
|
|
104
|
-
function isNodeJS() {
|
|
105
|
-
return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
|
|
106
|
-
}
|
|
107
95
|
/**
|
|
108
96
|
* Check if we're on web platform
|
|
109
97
|
* Identity storage is only available on native platforms (iOS/Android)
|
|
@@ -133,7 +121,7 @@ function uint8ArrayToHex(bytes) {
|
|
|
133
121
|
*/
|
|
134
122
|
async function getSecureRandomBytes(length) {
|
|
135
123
|
// In React Native, always use expo-crypto
|
|
136
|
-
if (isReactNative() || !isNodeJS()) {
|
|
124
|
+
if ((0, platform_1.isReactNative)() || !(0, platform_1.isNodeJS)()) {
|
|
137
125
|
const Crypto = await initExpoCrypto();
|
|
138
126
|
return Crypto.getRandomBytes(length);
|
|
139
127
|
}
|
|
@@ -42,21 +42,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
42
42
|
exports.SignatureService = void 0;
|
|
43
43
|
const elliptic_1 = require("elliptic");
|
|
44
44
|
const keyManager_1 = require("./keyManager");
|
|
45
|
+
const platform_1 = require("../utils/platform");
|
|
45
46
|
// Lazy import for expo-crypto
|
|
46
47
|
let ExpoCrypto = null;
|
|
47
48
|
const ec = new elliptic_1.ec('secp256k1');
|
|
48
|
-
/**
|
|
49
|
-
* Check if we're in a React Native environment
|
|
50
|
-
*/
|
|
51
|
-
function isReactNative() {
|
|
52
|
-
return typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Check if we're in a Node.js environment
|
|
56
|
-
*/
|
|
57
|
-
function isNodeJS() {
|
|
58
|
-
return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
|
|
59
|
-
}
|
|
60
49
|
/**
|
|
61
50
|
* Initialize expo-crypto module
|
|
62
51
|
*/
|
|
@@ -73,16 +62,14 @@ async function initExpoCrypto() {
|
|
|
73
62
|
*/
|
|
74
63
|
async function sha256(message) {
|
|
75
64
|
// In React Native, use expo-crypto
|
|
76
|
-
if (isReactNative()) {
|
|
65
|
+
if ((0, platform_1.isReactNative)()) {
|
|
77
66
|
const Crypto = await initExpoCrypto();
|
|
78
67
|
return Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, message);
|
|
79
68
|
}
|
|
80
69
|
// In Node.js, use Node's crypto module
|
|
81
|
-
if (isNodeJS()) {
|
|
70
|
+
if ((0, platform_1.isNodeJS)()) {
|
|
82
71
|
try {
|
|
83
|
-
|
|
84
|
-
const getCrypto = new Function('return require("crypto")');
|
|
85
|
-
const nodeCrypto = getCrypto();
|
|
72
|
+
const nodeCrypto = await Promise.resolve().then(() => __importStar(require('crypto')));
|
|
86
73
|
return nodeCrypto.createHash('sha256').update(message).digest('hex');
|
|
87
74
|
}
|
|
88
75
|
catch {
|
|
@@ -103,7 +90,7 @@ class SignatureService {
|
|
|
103
90
|
*/
|
|
104
91
|
static async generateChallenge() {
|
|
105
92
|
// In React Native, use expo-crypto
|
|
106
|
-
if (isReactNative()) {
|
|
93
|
+
if ((0, platform_1.isReactNative)()) {
|
|
107
94
|
const Crypto = await initExpoCrypto();
|
|
108
95
|
const randomBytes = await Crypto.getRandomBytesAsync(32);
|
|
109
96
|
return Array.from(randomBytes)
|
|
@@ -111,7 +98,7 @@ class SignatureService {
|
|
|
111
98
|
.join('');
|
|
112
99
|
}
|
|
113
100
|
// In Node.js, use Node's crypto module
|
|
114
|
-
if (isNodeJS()) {
|
|
101
|
+
if ((0, platform_1.isNodeJS)()) {
|
|
115
102
|
try {
|
|
116
103
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
117
104
|
const getCrypto = new Function('return require("crypto")');
|
|
@@ -178,7 +165,7 @@ class SignatureService {
|
|
|
178
165
|
*/
|
|
179
166
|
static verifySync(message, signature, publicKey) {
|
|
180
167
|
try {
|
|
181
|
-
if (!isNodeJS()) {
|
|
168
|
+
if (!(0, platform_1.isNodeJS)()) {
|
|
182
169
|
// In React Native, use async verify instead
|
|
183
170
|
throw new Error('verifySync should only be used in Node.js. Use verify() in React Native.');
|
|
184
171
|
}
|
|
@@ -14,7 +14,7 @@ function OxyServicesAnalyticsMixin(Base) {
|
|
|
14
14
|
*/
|
|
15
15
|
async trackEvent(eventName, properties) {
|
|
16
16
|
try {
|
|
17
|
-
await this.makeRequest('POST', '/
|
|
17
|
+
await this.makeRequest('POST', '/analytics/events', {
|
|
18
18
|
event: eventName,
|
|
19
19
|
properties
|
|
20
20
|
}, { cache: false, retry: false }); // Don't retry analytics events
|
|
@@ -36,7 +36,7 @@ function OxyServicesAnalyticsMixin(Base) {
|
|
|
36
36
|
params.startDate = startDate;
|
|
37
37
|
if (endDate)
|
|
38
38
|
params.endDate = endDate;
|
|
39
|
-
return await this.makeRequest('GET', '/
|
|
39
|
+
return await this.makeRequest('GET', '/analytics', params, {
|
|
40
40
|
cache: true,
|
|
41
41
|
cacheTTL: mixinHelpers_1.CACHE_TIMES.LONG,
|
|
42
42
|
});
|
|
@@ -11,7 +11,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
11
11
|
*/
|
|
12
12
|
async deleteFile(fileId) {
|
|
13
13
|
try {
|
|
14
|
-
return await this.makeRequest('DELETE', `/
|
|
14
|
+
return await this.makeRequest('DELETE', `/assets/${encodeURIComponent(fileId)}`, undefined, { cache: false });
|
|
15
15
|
}
|
|
16
16
|
catch (error) {
|
|
17
17
|
throw this.handleError(error);
|
|
@@ -32,7 +32,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
32
32
|
if (token)
|
|
33
33
|
params.set('token', token);
|
|
34
34
|
const qs = params.toString();
|
|
35
|
-
return `${base}/
|
|
35
|
+
return `${base}/assets/${encodeURIComponent(fileId)}/stream${qs ? `?${qs}` : ''}`;
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
38
|
* Get file download URL asynchronously (returns signed URL directly from CDN)
|
|
@@ -56,7 +56,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
56
56
|
paramsObj.limit = limit;
|
|
57
57
|
if (offset)
|
|
58
58
|
paramsObj.offset = offset;
|
|
59
|
-
return await this.makeRequest('GET', '/
|
|
59
|
+
return await this.makeRequest('GET', '/assets', paramsObj, {
|
|
60
60
|
cache: false,
|
|
61
61
|
});
|
|
62
62
|
}
|
|
@@ -69,7 +69,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
69
69
|
*/
|
|
70
70
|
async getAccountStorageUsage() {
|
|
71
71
|
try {
|
|
72
|
-
return await this.makeRequest('GET', '/
|
|
72
|
+
return await this.makeRequest('GET', '/storage/usage', undefined, {
|
|
73
73
|
cache: false,
|
|
74
74
|
});
|
|
75
75
|
}
|
|
@@ -112,7 +112,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
112
112
|
*/
|
|
113
113
|
async getBatchFileAccess(fileIds, context) {
|
|
114
114
|
try {
|
|
115
|
-
return await this.makeRequest('POST', '/
|
|
115
|
+
return await this.makeRequest('POST', '/assets/batch-access', {
|
|
116
116
|
fileIds,
|
|
117
117
|
context
|
|
118
118
|
});
|
|
@@ -173,7 +173,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
173
173
|
}
|
|
174
174
|
const response = await this.getClient().request({
|
|
175
175
|
method: 'POST',
|
|
176
|
-
url: '/
|
|
176
|
+
url: '/assets/upload',
|
|
177
177
|
data: formData,
|
|
178
178
|
cache: false,
|
|
179
179
|
});
|
|
@@ -231,7 +231,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
231
231
|
body.visibility = visibility;
|
|
232
232
|
if (webhookUrl)
|
|
233
233
|
body.webhookUrl = webhookUrl;
|
|
234
|
-
return await this.makeRequest('POST', `/
|
|
234
|
+
return await this.makeRequest('POST', `/assets/${fileId}/links`, body, { cache: false });
|
|
235
235
|
}
|
|
236
236
|
catch (error) {
|
|
237
237
|
throw this.handleError(error);
|
|
@@ -242,7 +242,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
242
242
|
*/
|
|
243
243
|
async assetUnlink(fileId, app, entityType, entityId) {
|
|
244
244
|
try {
|
|
245
|
-
return await this.makeRequest('DELETE', `/
|
|
245
|
+
return await this.makeRequest('DELETE', `/assets/${fileId}/links`, {
|
|
246
246
|
app,
|
|
247
247
|
entityType,
|
|
248
248
|
entityId
|
|
@@ -257,7 +257,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
257
257
|
*/
|
|
258
258
|
async assetGet(fileId) {
|
|
259
259
|
try {
|
|
260
|
-
return await this.makeRequest('GET', `/
|
|
260
|
+
return await this.makeRequest('GET', `/assets/${fileId}`, undefined, {
|
|
261
261
|
cache: true,
|
|
262
262
|
cacheTTL: 5 * 60 * 1000,
|
|
263
263
|
});
|
|
@@ -276,7 +276,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
276
276
|
params.variant = variant;
|
|
277
277
|
if (expiresIn)
|
|
278
278
|
params.expiresIn = expiresIn;
|
|
279
|
-
return await this.makeRequest('GET', `/
|
|
279
|
+
return await this.makeRequest('GET', `/assets/${fileId}/url`, params, {
|
|
280
280
|
cache: true,
|
|
281
281
|
cacheTTL: 10 * 60 * 1000,
|
|
282
282
|
});
|
|
@@ -290,7 +290,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
290
290
|
*/
|
|
291
291
|
async assetRestore(fileId) {
|
|
292
292
|
try {
|
|
293
|
-
return await this.makeRequest('POST', `/
|
|
293
|
+
return await this.makeRequest('POST', `/assets/${fileId}/restore`, undefined, { cache: false });
|
|
294
294
|
}
|
|
295
295
|
catch (error) {
|
|
296
296
|
throw this.handleError(error);
|
|
@@ -302,7 +302,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
302
302
|
async assetDelete(fileId, force = false) {
|
|
303
303
|
try {
|
|
304
304
|
const params = force ? { force: 'true' } : undefined;
|
|
305
|
-
return await this.makeRequest('DELETE', `/
|
|
305
|
+
return await this.makeRequest('DELETE', `/assets/${fileId}`, params, { cache: false });
|
|
306
306
|
}
|
|
307
307
|
catch (error) {
|
|
308
308
|
throw this.handleError(error);
|
|
@@ -325,7 +325,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
325
325
|
*/
|
|
326
326
|
async assetUpdateVisibility(fileId, visibility) {
|
|
327
327
|
try {
|
|
328
|
-
return await this.makeRequest('PATCH', `/
|
|
328
|
+
return await this.makeRequest('PATCH', `/assets/${fileId}/visibility`, {
|
|
329
329
|
visibility
|
|
330
330
|
}, { cache: false });
|
|
331
331
|
}
|
|
@@ -363,7 +363,7 @@ function OxyServicesAssetsMixin(Base) {
|
|
|
363
363
|
params.variant = variant;
|
|
364
364
|
if (expiresIn)
|
|
365
365
|
params.expiresIn = expiresIn;
|
|
366
|
-
const urlRes = await this.makeRequest('GET', `/
|
|
366
|
+
const urlRes = await this.makeRequest('GET', `/assets/${encodeURIComponent(fileId)}/url`, Object.keys(params).length ? params : undefined, {
|
|
367
367
|
cache: true,
|
|
368
368
|
cacheTTL: cacheTTL ?? 10 * 60 * 1000,
|
|
369
369
|
});
|
|
@@ -43,7 +43,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
43
43
|
if (this._serviceToken && this._serviceTokenExp > Date.now() + 60000) {
|
|
44
44
|
return this._serviceToken;
|
|
45
45
|
}
|
|
46
|
-
const response = await this.makeRequest('POST', '/
|
|
46
|
+
const response = await this.makeRequest('POST', '/auth/service-token', { apiKey: key, apiSecret: secret }, { cache: false, retry: false });
|
|
47
47
|
this._serviceToken = response.token;
|
|
48
48
|
this._serviceTokenExp = Date.now() + response.expiresIn * 1000;
|
|
49
49
|
return this._serviceToken;
|
|
@@ -77,7 +77,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
77
77
|
*/
|
|
78
78
|
async register(publicKey, signature, timestamp) {
|
|
79
79
|
try {
|
|
80
|
-
const res = await this.makeRequest('POST', '/
|
|
80
|
+
const res = await this.makeRequest('POST', '/auth/register', {
|
|
81
81
|
publicKey,
|
|
82
82
|
signature,
|
|
83
83
|
timestamp,
|
|
@@ -99,7 +99,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
99
99
|
*/
|
|
100
100
|
async requestChallenge(publicKey) {
|
|
101
101
|
try {
|
|
102
|
-
return await this.makeRequest('POST', '/
|
|
102
|
+
return await this.makeRequest('POST', '/auth/challenge', {
|
|
103
103
|
publicKey,
|
|
104
104
|
}, { cache: false });
|
|
105
105
|
}
|
|
@@ -119,7 +119,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
119
119
|
*/
|
|
120
120
|
async verifyChallenge(publicKey, challenge, signature, timestamp, deviceName, deviceFingerprint) {
|
|
121
121
|
try {
|
|
122
|
-
return await this.makeRequest('POST', '/
|
|
122
|
+
return await this.makeRequest('POST', '/auth/verify', {
|
|
123
123
|
publicKey,
|
|
124
124
|
challenge,
|
|
125
125
|
signature,
|
|
@@ -137,7 +137,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
137
137
|
*/
|
|
138
138
|
async checkPublicKeyRegistered(publicKey) {
|
|
139
139
|
try {
|
|
140
|
-
return await this.makeRequest('GET', `/
|
|
140
|
+
return await this.makeRequest('GET', `/auth/check-publickey/${encodeURIComponent(publicKey)}`, undefined, { cache: false });
|
|
141
141
|
}
|
|
142
142
|
catch (error) {
|
|
143
143
|
throw this.handleError(error);
|
|
@@ -148,7 +148,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
148
148
|
*/
|
|
149
149
|
async getUserByPublicKey(publicKey) {
|
|
150
150
|
try {
|
|
151
|
-
return await this.makeRequest('GET', `/
|
|
151
|
+
return await this.makeRequest('GET', `/auth/user/${encodeURIComponent(publicKey)}`, undefined, { cache: true, cacheTTL: 2 * 60 * 1000 });
|
|
152
152
|
}
|
|
153
153
|
catch (error) {
|
|
154
154
|
throw this.handleError(error);
|
|
@@ -159,7 +159,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
159
159
|
*/
|
|
160
160
|
async getUserBySession(sessionId) {
|
|
161
161
|
try {
|
|
162
|
-
return await this.makeRequest('GET', `/
|
|
162
|
+
return await this.makeRequest('GET', `/session/user/${sessionId}`, undefined, {
|
|
163
163
|
cache: true,
|
|
164
164
|
cacheTTL: 2 * 60 * 1000,
|
|
165
165
|
});
|
|
@@ -177,7 +177,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
177
177
|
return [];
|
|
178
178
|
}
|
|
179
179
|
const uniqueSessionIds = Array.from(new Set(sessionIds)).sort();
|
|
180
|
-
return await this.makeRequest('POST', '/
|
|
180
|
+
return await this.makeRequest('POST', '/session/users/batch', { sessionIds: uniqueSessionIds }, {
|
|
181
181
|
cache: true,
|
|
182
182
|
cacheTTL: 2 * 60 * 1000,
|
|
183
183
|
deduplicate: true,
|
|
@@ -192,7 +192,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
192
192
|
*/
|
|
193
193
|
async getTokenBySession(sessionId) {
|
|
194
194
|
try {
|
|
195
|
-
const res = await this.makeRequest('GET', `/
|
|
195
|
+
const res = await this.makeRequest('GET', `/session/token/${sessionId}`, undefined, { cache: false, retry: false });
|
|
196
196
|
this.setTokens(res.accessToken);
|
|
197
197
|
return res;
|
|
198
198
|
}
|
|
@@ -205,7 +205,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
205
205
|
*/
|
|
206
206
|
async getSessionsBySessionId(sessionId) {
|
|
207
207
|
try {
|
|
208
|
-
return await this.makeRequest('GET', `/
|
|
208
|
+
return await this.makeRequest('GET', `/session/sessions/${sessionId}`, undefined, {
|
|
209
209
|
cache: false,
|
|
210
210
|
});
|
|
211
211
|
}
|
|
@@ -219,8 +219,8 @@ function OxyServicesAuthMixin(Base) {
|
|
|
219
219
|
async logoutSession(sessionId, targetSessionId) {
|
|
220
220
|
try {
|
|
221
221
|
const url = targetSessionId
|
|
222
|
-
? `/
|
|
223
|
-
: `/
|
|
222
|
+
? `/session/logout/${sessionId}/${targetSessionId}`
|
|
223
|
+
: `/session/logout/${sessionId}`;
|
|
224
224
|
await this.makeRequest('POST', url, undefined, { cache: false });
|
|
225
225
|
}
|
|
226
226
|
catch (error) {
|
|
@@ -232,7 +232,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
232
232
|
*/
|
|
233
233
|
async logoutAllSessions(sessionId) {
|
|
234
234
|
try {
|
|
235
|
-
await this.makeRequest('POST', `/
|
|
235
|
+
await this.makeRequest('POST', `/session/logout-all/${sessionId}`, undefined, { cache: false });
|
|
236
236
|
}
|
|
237
237
|
catch (error) {
|
|
238
238
|
throw this.handleError(error);
|
|
@@ -248,11 +248,11 @@ function OxyServicesAuthMixin(Base) {
|
|
|
248
248
|
urlParams.deviceFingerprint = options.deviceFingerprint;
|
|
249
249
|
if (options.useHeaderValidation)
|
|
250
250
|
urlParams.useHeaderValidation = 'true';
|
|
251
|
-
return await this.makeRequest('GET', `/
|
|
251
|
+
return await this.makeRequest('GET', `/session/validate/${sessionId}`, urlParams, { cache: false });
|
|
252
252
|
}
|
|
253
253
|
catch (error) {
|
|
254
254
|
// Session is invalid — clear any cached user data for this session (#196)
|
|
255
|
-
this.clearCacheEntry(`GET:/
|
|
255
|
+
this.clearCacheEntry(`GET:/session/user/${sessionId}`);
|
|
256
256
|
throw this.handleError(error);
|
|
257
257
|
}
|
|
258
258
|
}
|
|
@@ -261,7 +261,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
261
261
|
*/
|
|
262
262
|
async checkUsernameAvailability(username) {
|
|
263
263
|
try {
|
|
264
|
-
return await this.makeRequest('GET', `/
|
|
264
|
+
return await this.makeRequest('GET', `/auth/check-username/${username}`, undefined, { cache: false });
|
|
265
265
|
}
|
|
266
266
|
catch (error) {
|
|
267
267
|
throw this.handleError(error);
|
|
@@ -272,7 +272,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
272
272
|
*/
|
|
273
273
|
async checkEmailAvailability(email) {
|
|
274
274
|
try {
|
|
275
|
-
return await this.makeRequest('GET', `/
|
|
275
|
+
return await this.makeRequest('GET', `/auth/check-email/${email}`, undefined, { cache: false });
|
|
276
276
|
}
|
|
277
277
|
catch (error) {
|
|
278
278
|
throw this.handleError(error);
|
|
@@ -283,7 +283,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
283
283
|
*/
|
|
284
284
|
async signUp(username, email, password, deviceName, deviceFingerprint) {
|
|
285
285
|
try {
|
|
286
|
-
return await this.makeRequest('POST', '/
|
|
286
|
+
return await this.makeRequest('POST', '/auth/signup', {
|
|
287
287
|
username,
|
|
288
288
|
email,
|
|
289
289
|
password,
|
|
@@ -300,7 +300,7 @@ function OxyServicesAuthMixin(Base) {
|
|
|
300
300
|
*/
|
|
301
301
|
async signIn(identifier, password, deviceName, deviceFingerprint) {
|
|
302
302
|
try {
|
|
303
|
-
return await this.makeRequest('POST', '/
|
|
303
|
+
return await this.makeRequest('POST', '/auth/login', {
|
|
304
304
|
identifier,
|
|
305
305
|
password,
|
|
306
306
|
deviceName,
|