@oxyhq/core 1.0.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 +50 -0
- package/dist/cjs/AuthManager.js +361 -0
- package/dist/cjs/CrossDomainAuth.js +258 -0
- package/dist/cjs/HttpService.js +618 -0
- package/dist/cjs/OxyServices.base.js +263 -0
- package/dist/cjs/OxyServices.errors.js +22 -0
- package/dist/cjs/OxyServices.js +63 -0
- package/dist/cjs/constants/version.js +16 -0
- package/dist/cjs/crypto/index.js +20 -0
- package/dist/cjs/crypto/keyManager.js +887 -0
- package/dist/cjs/crypto/polyfill.js +64 -0
- package/dist/cjs/crypto/recoveryPhrase.js +169 -0
- package/dist/cjs/crypto/signatureService.js +296 -0
- package/dist/cjs/i18n/index.js +73 -0
- package/dist/cjs/i18n/locales/ar-SA.json +120 -0
- package/dist/cjs/i18n/locales/ca-ES.json +120 -0
- package/dist/cjs/i18n/locales/de-DE.json +120 -0
- package/dist/cjs/i18n/locales/en-US.json +956 -0
- package/dist/cjs/i18n/locales/es-ES.json +944 -0
- package/dist/cjs/i18n/locales/fr-FR.json +120 -0
- package/dist/cjs/i18n/locales/it-IT.json +120 -0
- package/dist/cjs/i18n/locales/ja-JP.json +119 -0
- package/dist/cjs/i18n/locales/ko-KR.json +120 -0
- package/dist/cjs/i18n/locales/locales/ar-SA.json +120 -0
- package/dist/cjs/i18n/locales/locales/ca-ES.json +120 -0
- package/dist/cjs/i18n/locales/locales/de-DE.json +120 -0
- package/dist/cjs/i18n/locales/locales/en-US.json +956 -0
- package/dist/cjs/i18n/locales/locales/es-ES.json +944 -0
- package/dist/cjs/i18n/locales/locales/fr-FR.json +120 -0
- package/dist/cjs/i18n/locales/locales/it-IT.json +120 -0
- package/dist/cjs/i18n/locales/locales/ja-JP.json +119 -0
- package/dist/cjs/i18n/locales/locales/ko-KR.json +120 -0
- package/dist/cjs/i18n/locales/locales/pt-PT.json +120 -0
- package/dist/cjs/i18n/locales/locales/zh-CN.json +120 -0
- package/dist/cjs/i18n/locales/pt-PT.json +120 -0
- package/dist/cjs/i18n/locales/zh-CN.json +120 -0
- package/dist/cjs/index.js +153 -0
- package/dist/cjs/mixins/OxyServices.analytics.js +49 -0
- package/dist/cjs/mixins/OxyServices.assets.js +380 -0
- package/dist/cjs/mixins/OxyServices.auth.js +259 -0
- package/dist/cjs/mixins/OxyServices.developer.js +97 -0
- package/dist/cjs/mixins/OxyServices.devices.js +116 -0
- package/dist/cjs/mixins/OxyServices.features.js +309 -0
- package/dist/cjs/mixins/OxyServices.fedcm.js +435 -0
- package/dist/cjs/mixins/OxyServices.karma.js +108 -0
- package/dist/cjs/mixins/OxyServices.language.js +154 -0
- package/dist/cjs/mixins/OxyServices.location.js +43 -0
- package/dist/cjs/mixins/OxyServices.payment.js +158 -0
- package/dist/cjs/mixins/OxyServices.popup.js +371 -0
- package/dist/cjs/mixins/OxyServices.privacy.js +162 -0
- package/dist/cjs/mixins/OxyServices.redirect.js +345 -0
- package/dist/cjs/mixins/OxyServices.security.js +81 -0
- package/dist/cjs/mixins/OxyServices.user.js +355 -0
- package/dist/cjs/mixins/OxyServices.utility.js +156 -0
- package/dist/cjs/mixins/index.js +79 -0
- package/dist/cjs/mixins/mixinHelpers.js +53 -0
- package/dist/cjs/models/interfaces.js +20 -0
- package/dist/cjs/models/session.js +2 -0
- package/dist/cjs/shared/index.js +70 -0
- package/dist/cjs/shared/utils/colorUtils.js +153 -0
- package/dist/cjs/shared/utils/debugUtils.js +73 -0
- package/dist/cjs/shared/utils/errorUtils.js +183 -0
- package/dist/cjs/shared/utils/index.js +49 -0
- package/dist/cjs/shared/utils/networkUtils.js +183 -0
- package/dist/cjs/shared/utils/themeUtils.js +106 -0
- package/dist/cjs/utils/apiUtils.js +61 -0
- package/dist/cjs/utils/asyncUtils.js +194 -0
- package/dist/cjs/utils/cache.js +226 -0
- package/dist/cjs/utils/deviceManager.js +205 -0
- package/dist/cjs/utils/errorUtils.js +154 -0
- package/dist/cjs/utils/index.js +26 -0
- package/dist/cjs/utils/languageUtils.js +165 -0
- package/dist/cjs/utils/loggerUtils.js +126 -0
- package/dist/cjs/utils/platform.js +144 -0
- package/dist/cjs/utils/requestUtils.js +209 -0
- package/dist/cjs/utils/sessionUtils.js +181 -0
- package/dist/cjs/utils/validationUtils.js +173 -0
- package/dist/esm/AuthManager.js +356 -0
- package/dist/esm/CrossDomainAuth.js +253 -0
- package/dist/esm/HttpService.js +614 -0
- package/dist/esm/OxyServices.base.js +259 -0
- package/dist/esm/OxyServices.errors.js +17 -0
- package/dist/esm/OxyServices.js +59 -0
- package/dist/esm/constants/version.js +13 -0
- package/dist/esm/crypto/index.js +13 -0
- package/dist/esm/crypto/keyManager.js +850 -0
- package/dist/esm/crypto/polyfill.js +61 -0
- package/dist/esm/crypto/recoveryPhrase.js +132 -0
- package/dist/esm/crypto/signatureService.js +259 -0
- package/dist/esm/i18n/index.js +69 -0
- package/dist/esm/i18n/locales/ar-SA.json +120 -0
- package/dist/esm/i18n/locales/ca-ES.json +120 -0
- package/dist/esm/i18n/locales/de-DE.json +120 -0
- package/dist/esm/i18n/locales/en-US.json +956 -0
- package/dist/esm/i18n/locales/es-ES.json +944 -0
- package/dist/esm/i18n/locales/fr-FR.json +120 -0
- package/dist/esm/i18n/locales/it-IT.json +120 -0
- package/dist/esm/i18n/locales/ja-JP.json +119 -0
- package/dist/esm/i18n/locales/ko-KR.json +120 -0
- package/dist/esm/i18n/locales/locales/ar-SA.json +120 -0
- package/dist/esm/i18n/locales/locales/ca-ES.json +120 -0
- package/dist/esm/i18n/locales/locales/de-DE.json +120 -0
- package/dist/esm/i18n/locales/locales/en-US.json +956 -0
- package/dist/esm/i18n/locales/locales/es-ES.json +944 -0
- package/dist/esm/i18n/locales/locales/fr-FR.json +120 -0
- package/dist/esm/i18n/locales/locales/it-IT.json +120 -0
- package/dist/esm/i18n/locales/locales/ja-JP.json +119 -0
- package/dist/esm/i18n/locales/locales/ko-KR.json +120 -0
- package/dist/esm/i18n/locales/locales/pt-PT.json +120 -0
- package/dist/esm/i18n/locales/locales/zh-CN.json +120 -0
- package/dist/esm/i18n/locales/pt-PT.json +120 -0
- package/dist/esm/i18n/locales/zh-CN.json +120 -0
- package/dist/esm/index.js +55 -0
- package/dist/esm/mixins/OxyServices.analytics.js +46 -0
- package/dist/esm/mixins/OxyServices.assets.js +377 -0
- package/dist/esm/mixins/OxyServices.auth.js +256 -0
- package/dist/esm/mixins/OxyServices.developer.js +94 -0
- package/dist/esm/mixins/OxyServices.devices.js +113 -0
- package/dist/esm/mixins/OxyServices.features.js +306 -0
- package/dist/esm/mixins/OxyServices.fedcm.js +433 -0
- package/dist/esm/mixins/OxyServices.karma.js +105 -0
- package/dist/esm/mixins/OxyServices.language.js +118 -0
- package/dist/esm/mixins/OxyServices.location.js +40 -0
- package/dist/esm/mixins/OxyServices.payment.js +155 -0
- package/dist/esm/mixins/OxyServices.popup.js +369 -0
- package/dist/esm/mixins/OxyServices.privacy.js +159 -0
- package/dist/esm/mixins/OxyServices.redirect.js +343 -0
- package/dist/esm/mixins/OxyServices.security.js +78 -0
- package/dist/esm/mixins/OxyServices.user.js +352 -0
- package/dist/esm/mixins/OxyServices.utility.js +153 -0
- package/dist/esm/mixins/index.js +76 -0
- package/dist/esm/mixins/mixinHelpers.js +48 -0
- package/dist/esm/models/interfaces.js +17 -0
- package/dist/esm/models/session.js +1 -0
- package/dist/esm/shared/index.js +31 -0
- package/dist/esm/shared/utils/colorUtils.js +143 -0
- package/dist/esm/shared/utils/debugUtils.js +65 -0
- package/dist/esm/shared/utils/errorUtils.js +170 -0
- package/dist/esm/shared/utils/index.js +15 -0
- package/dist/esm/shared/utils/networkUtils.js +173 -0
- package/dist/esm/shared/utils/themeUtils.js +98 -0
- package/dist/esm/utils/apiUtils.js +55 -0
- package/dist/esm/utils/asyncUtils.js +179 -0
- package/dist/esm/utils/cache.js +218 -0
- package/dist/esm/utils/deviceManager.js +168 -0
- package/dist/esm/utils/errorUtils.js +146 -0
- package/dist/esm/utils/index.js +7 -0
- package/dist/esm/utils/languageUtils.js +158 -0
- package/dist/esm/utils/loggerUtils.js +115 -0
- package/dist/esm/utils/platform.js +102 -0
- package/dist/esm/utils/requestUtils.js +203 -0
- package/dist/esm/utils/sessionUtils.js +171 -0
- package/dist/esm/utils/validationUtils.js +153 -0
- package/dist/types/AuthManager.d.ts +143 -0
- package/dist/types/CrossDomainAuth.d.ts +160 -0
- package/dist/types/HttpService.d.ts +163 -0
- package/dist/types/OxyServices.base.d.ts +126 -0
- package/dist/types/OxyServices.d.ts +81 -0
- package/dist/types/OxyServices.errors.d.ts +11 -0
- package/dist/types/constants/version.d.ts +13 -0
- package/dist/types/crypto/index.d.ts +11 -0
- package/dist/types/crypto/keyManager.d.ts +189 -0
- package/dist/types/crypto/polyfill.d.ts +11 -0
- package/dist/types/crypto/recoveryPhrase.d.ts +58 -0
- package/dist/types/crypto/signatureService.d.ts +86 -0
- package/dist/types/i18n/index.d.ts +3 -0
- package/dist/types/index.d.ts +50 -0
- package/dist/types/mixins/OxyServices.analytics.d.ts +66 -0
- package/dist/types/mixins/OxyServices.assets.d.ts +135 -0
- package/dist/types/mixins/OxyServices.auth.d.ts +186 -0
- package/dist/types/mixins/OxyServices.developer.d.ts +99 -0
- package/dist/types/mixins/OxyServices.devices.d.ts +96 -0
- package/dist/types/mixins/OxyServices.features.d.ts +228 -0
- package/dist/types/mixins/OxyServices.fedcm.d.ts +200 -0
- package/dist/types/mixins/OxyServices.karma.d.ts +85 -0
- package/dist/types/mixins/OxyServices.language.d.ts +81 -0
- package/dist/types/mixins/OxyServices.location.d.ts +64 -0
- package/dist/types/mixins/OxyServices.payment.d.ts +111 -0
- package/dist/types/mixins/OxyServices.popup.d.ts +205 -0
- package/dist/types/mixins/OxyServices.privacy.d.ts +122 -0
- package/dist/types/mixins/OxyServices.redirect.d.ts +245 -0
- package/dist/types/mixins/OxyServices.security.d.ts +78 -0
- package/dist/types/mixins/OxyServices.user.d.ts +182 -0
- package/dist/types/mixins/OxyServices.utility.d.ts +93 -0
- package/dist/types/mixins/index.d.ts +30 -0
- package/dist/types/mixins/mixinHelpers.d.ts +31 -0
- package/dist/types/models/interfaces.d.ts +415 -0
- package/dist/types/models/session.d.ts +27 -0
- package/dist/types/shared/index.d.ts +28 -0
- package/dist/types/shared/utils/colorUtils.d.ts +104 -0
- package/dist/types/shared/utils/debugUtils.d.ts +48 -0
- package/dist/types/shared/utils/errorUtils.d.ts +97 -0
- package/dist/types/shared/utils/index.d.ts +13 -0
- package/dist/types/shared/utils/networkUtils.d.ts +139 -0
- package/dist/types/shared/utils/themeUtils.d.ts +90 -0
- package/dist/types/utils/apiUtils.d.ts +53 -0
- package/dist/types/utils/asyncUtils.d.ts +58 -0
- package/dist/types/utils/cache.d.ts +127 -0
- package/dist/types/utils/deviceManager.d.ts +65 -0
- package/dist/types/utils/errorUtils.d.ts +46 -0
- package/dist/types/utils/index.d.ts +6 -0
- package/dist/types/utils/languageUtils.d.ts +37 -0
- package/dist/types/utils/loggerUtils.d.ts +48 -0
- package/dist/types/utils/platform.d.ts +40 -0
- package/dist/types/utils/requestUtils.d.ts +123 -0
- package/dist/types/utils/sessionUtils.d.ts +54 -0
- package/dist/types/utils/validationUtils.d.ts +85 -0
- package/package.json +84 -0
- package/src/AuthManager.ts +436 -0
- package/src/CrossDomainAuth.ts +307 -0
- package/src/HttpService.ts +752 -0
- package/src/OxyServices.base.ts +334 -0
- package/src/OxyServices.errors.ts +26 -0
- package/src/OxyServices.ts +129 -0
- package/src/constants/version.ts +15 -0
- package/src/crypto/index.ts +25 -0
- package/src/crypto/keyManager.ts +962 -0
- package/src/crypto/polyfill.ts +70 -0
- package/src/crypto/recoveryPhrase.ts +166 -0
- package/src/crypto/signatureService.ts +323 -0
- package/src/i18n/index.ts +75 -0
- package/src/i18n/locales/ar-SA.json +120 -0
- package/src/i18n/locales/ca-ES.json +120 -0
- package/src/i18n/locales/de-DE.json +120 -0
- package/src/i18n/locales/en-US.json +956 -0
- package/src/i18n/locales/es-ES.json +944 -0
- package/src/i18n/locales/fr-FR.json +120 -0
- package/src/i18n/locales/it-IT.json +120 -0
- package/src/i18n/locales/ja-JP.json +119 -0
- package/src/i18n/locales/ko-KR.json +120 -0
- package/src/i18n/locales/pt-PT.json +120 -0
- package/src/i18n/locales/zh-CN.json +120 -0
- package/src/index.ts +153 -0
- package/src/mixins/OxyServices.analytics.ts +53 -0
- package/src/mixins/OxyServices.assets.ts +412 -0
- package/src/mixins/OxyServices.auth.ts +358 -0
- package/src/mixins/OxyServices.developer.ts +114 -0
- package/src/mixins/OxyServices.devices.ts +119 -0
- package/src/mixins/OxyServices.features.ts +428 -0
- package/src/mixins/OxyServices.fedcm.ts +494 -0
- package/src/mixins/OxyServices.karma.ts +111 -0
- package/src/mixins/OxyServices.language.ts +127 -0
- package/src/mixins/OxyServices.location.ts +46 -0
- package/src/mixins/OxyServices.payment.ts +163 -0
- package/src/mixins/OxyServices.popup.ts +443 -0
- package/src/mixins/OxyServices.privacy.ts +182 -0
- package/src/mixins/OxyServices.redirect.ts +397 -0
- package/src/mixins/OxyServices.security.ts +103 -0
- package/src/mixins/OxyServices.user.ts +392 -0
- package/src/mixins/OxyServices.utility.ts +191 -0
- package/src/mixins/index.ts +91 -0
- package/src/mixins/mixinHelpers.ts +69 -0
- package/src/models/interfaces.ts +511 -0
- package/src/models/session.ts +30 -0
- package/src/shared/index.ts +82 -0
- package/src/shared/utils/colorUtils.ts +155 -0
- package/src/shared/utils/debugUtils.ts +73 -0
- package/src/shared/utils/errorUtils.ts +181 -0
- package/src/shared/utils/index.ts +59 -0
- package/src/shared/utils/networkUtils.ts +248 -0
- package/src/shared/utils/themeUtils.ts +115 -0
- package/src/types/bip39.d.ts +32 -0
- package/src/types/buffer.d.ts +97 -0
- package/src/types/color.d.ts +20 -0
- package/src/types/elliptic.d.ts +62 -0
- package/src/utils/apiUtils.ts +88 -0
- package/src/utils/asyncUtils.ts +252 -0
- package/src/utils/cache.ts +264 -0
- package/src/utils/deviceManager.ts +198 -0
- package/src/utils/errorUtils.ts +216 -0
- package/src/utils/index.ts +21 -0
- package/src/utils/languageUtils.ts +174 -0
- package/src/utils/loggerUtils.ts +153 -0
- package/src/utils/platform.ts +117 -0
- package/src/utils/requestUtils.ts +237 -0
- package/src/utils/sessionUtils.ts +206 -0
- package/src/utils/validationUtils.ts +174 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
export function OxyServicesAssetsMixin(Base) {
|
|
2
|
+
return class extends Base {
|
|
3
|
+
constructor(...args) {
|
|
4
|
+
super(...args);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Delete file
|
|
8
|
+
*/
|
|
9
|
+
async deleteFile(fileId) {
|
|
10
|
+
try {
|
|
11
|
+
return await this.makeRequest('DELETE', `/api/assets/${encodeURIComponent(fileId)}`, undefined, { cache: false });
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
throw this.handleError(error);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get file download URL (synchronous - uses stream endpoint for images to avoid ORB blocking)
|
|
19
|
+
*/
|
|
20
|
+
getFileDownloadUrl(fileId, variant, expiresIn) {
|
|
21
|
+
const base = this.getBaseURL();
|
|
22
|
+
const params = new URLSearchParams();
|
|
23
|
+
if (variant)
|
|
24
|
+
params.set('variant', variant);
|
|
25
|
+
if (expiresIn)
|
|
26
|
+
params.set('expiresIn', String(expiresIn));
|
|
27
|
+
params.set('fallback', 'placeholderVisible');
|
|
28
|
+
const token = this.getClient().getAccessToken();
|
|
29
|
+
if (token)
|
|
30
|
+
params.set('token', token);
|
|
31
|
+
const qs = params.toString();
|
|
32
|
+
return `${base}/api/assets/${encodeURIComponent(fileId)}/stream${qs ? `?${qs}` : ''}`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get file download URL asynchronously (returns signed URL directly from CDN)
|
|
36
|
+
*/
|
|
37
|
+
async getFileDownloadUrlAsync(fileId, variant, expiresIn) {
|
|
38
|
+
try {
|
|
39
|
+
const url = await this.fetchAssetDownloadUrl(fileId, variant, this.getAssetUrlCacheTTL(expiresIn), expiresIn);
|
|
40
|
+
return url || this.getFileDownloadUrl(fileId, variant, expiresIn);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return this.getFileDownloadUrl(fileId, variant, expiresIn);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* List user files
|
|
48
|
+
*/
|
|
49
|
+
async listUserFiles(limit, offset) {
|
|
50
|
+
try {
|
|
51
|
+
const paramsObj = {};
|
|
52
|
+
if (limit)
|
|
53
|
+
paramsObj.limit = limit;
|
|
54
|
+
if (offset)
|
|
55
|
+
paramsObj.offset = offset;
|
|
56
|
+
return await this.makeRequest('GET', '/api/assets', paramsObj, {
|
|
57
|
+
cache: false,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw this.handleError(error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get account storage usage (server-side usage aggregated from assets)
|
|
66
|
+
*/
|
|
67
|
+
async getAccountStorageUsage() {
|
|
68
|
+
try {
|
|
69
|
+
return await this.makeRequest('GET', '/api/storage/usage', undefined, {
|
|
70
|
+
cache: false,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
throw this.handleError(error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get file content as text
|
|
79
|
+
*/
|
|
80
|
+
async getFileContentAsText(fileId, variant) {
|
|
81
|
+
try {
|
|
82
|
+
const downloadUrl = await this.fetchAssetDownloadUrl(fileId, variant, this.getAssetUrlCacheTTL());
|
|
83
|
+
if (!downloadUrl) {
|
|
84
|
+
throw new Error('No download URL returned for asset');
|
|
85
|
+
}
|
|
86
|
+
return await this.fetchAssetContent(downloadUrl, 'text');
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw this.handleError(error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get file content as blob
|
|
94
|
+
*/
|
|
95
|
+
async getFileContentAsBlob(fileId, variant) {
|
|
96
|
+
try {
|
|
97
|
+
const downloadUrl = await this.fetchAssetDownloadUrl(fileId, variant, this.getAssetUrlCacheTTL());
|
|
98
|
+
if (!downloadUrl) {
|
|
99
|
+
throw new Error('No download URL returned for asset');
|
|
100
|
+
}
|
|
101
|
+
return await this.fetchAssetContent(downloadUrl, 'blob');
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
throw this.handleError(error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get batch access to multiple files
|
|
109
|
+
*/
|
|
110
|
+
async getBatchFileAccess(fileIds, context) {
|
|
111
|
+
try {
|
|
112
|
+
return await this.makeRequest('POST', '/api/assets/batch-access', {
|
|
113
|
+
fileIds,
|
|
114
|
+
context
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
throw this.handleError(error);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get download URLs for multiple files efficiently
|
|
123
|
+
*/
|
|
124
|
+
async getFileDownloadUrls(fileIds, context) {
|
|
125
|
+
const response = await this.getBatchFileAccess(fileIds, context);
|
|
126
|
+
const urls = {};
|
|
127
|
+
const results = response.results || {};
|
|
128
|
+
for (const [id, result] of Object.entries(results)) {
|
|
129
|
+
if (result.allowed && result.url) {
|
|
130
|
+
urls[id] = result.url;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return urls;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Upload raw file data
|
|
137
|
+
*/
|
|
138
|
+
async uploadRawFile(file, visibility, metadata) {
|
|
139
|
+
return this.assetUpload(file, visibility, metadata);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Upload file using Central Asset Service
|
|
143
|
+
*/
|
|
144
|
+
async assetUpload(file, visibility, metadata, onProgress) {
|
|
145
|
+
const fileName = file.name || 'unknown';
|
|
146
|
+
const fileSize = file.size;
|
|
147
|
+
try {
|
|
148
|
+
const formData = new FormData();
|
|
149
|
+
// Convert File to Blob to avoid read-only 'name' property error in Expo 54
|
|
150
|
+
// This is a known issue in Expo SDK 52+ where FormData tries to set the read-only 'name' property
|
|
151
|
+
let fileBlob;
|
|
152
|
+
if (file instanceof Blob) {
|
|
153
|
+
// Already a Blob, use directly
|
|
154
|
+
fileBlob = file;
|
|
155
|
+
}
|
|
156
|
+
else if (typeof file.blob === 'function') {
|
|
157
|
+
// Use async blob() method if available (Expo 54+ recommended approach)
|
|
158
|
+
fileBlob = await file.blob();
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// Fallback: create Blob from File (works in all environments)
|
|
162
|
+
fileBlob = new Blob([file], { type: file.type || 'application/octet-stream' });
|
|
163
|
+
}
|
|
164
|
+
formData.append('file', fileBlob, fileName);
|
|
165
|
+
if (visibility) {
|
|
166
|
+
formData.append('visibility', visibility);
|
|
167
|
+
}
|
|
168
|
+
if (metadata) {
|
|
169
|
+
formData.append('metadata', JSON.stringify(metadata));
|
|
170
|
+
}
|
|
171
|
+
const response = await this.getClient().request({
|
|
172
|
+
method: 'POST',
|
|
173
|
+
url: '/api/assets/upload',
|
|
174
|
+
data: formData,
|
|
175
|
+
cache: false,
|
|
176
|
+
});
|
|
177
|
+
if (onProgress && response) {
|
|
178
|
+
onProgress(100);
|
|
179
|
+
}
|
|
180
|
+
return response;
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
console.error('File upload error:', error);
|
|
184
|
+
let errorMessage = 'File upload failed';
|
|
185
|
+
if (error instanceof Error) {
|
|
186
|
+
errorMessage = error.message || errorMessage;
|
|
187
|
+
}
|
|
188
|
+
else if (error && typeof error === 'object') {
|
|
189
|
+
if ('message' in error) {
|
|
190
|
+
errorMessage = String(error.message) || errorMessage;
|
|
191
|
+
}
|
|
192
|
+
else if ('error' in error && typeof error.error === 'string') {
|
|
193
|
+
errorMessage = error.error;
|
|
194
|
+
}
|
|
195
|
+
else if ('data' in error && error.data?.message) {
|
|
196
|
+
errorMessage = String(error.data.message);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
else if (error) {
|
|
200
|
+
errorMessage = String(error) || errorMessage;
|
|
201
|
+
}
|
|
202
|
+
const contextError = error;
|
|
203
|
+
if (!contextError.fileContext) {
|
|
204
|
+
contextError.fileContext = {
|
|
205
|
+
fileName,
|
|
206
|
+
fileSize,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
if (error instanceof Error && error.message) {
|
|
210
|
+
const handledError = this.handleError(contextError);
|
|
211
|
+
if (!handledError.message || handledError.message.trim() === 'An unexpected error occurred') {
|
|
212
|
+
handledError.message = errorMessage;
|
|
213
|
+
}
|
|
214
|
+
throw handledError;
|
|
215
|
+
}
|
|
216
|
+
const newError = new Error(errorMessage);
|
|
217
|
+
newError.fileContext = contextError.fileContext;
|
|
218
|
+
throw this.handleError(newError);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Link asset to an entity
|
|
223
|
+
*/
|
|
224
|
+
async assetLink(fileId, app, entityType, entityId, visibility, webhookUrl) {
|
|
225
|
+
try {
|
|
226
|
+
const body = { app, entityType, entityId };
|
|
227
|
+
if (visibility)
|
|
228
|
+
body.visibility = visibility;
|
|
229
|
+
if (webhookUrl)
|
|
230
|
+
body.webhookUrl = webhookUrl;
|
|
231
|
+
return await this.makeRequest('POST', `/api/assets/${fileId}/links`, body, { cache: false });
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
throw this.handleError(error);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Unlink asset from an entity
|
|
239
|
+
*/
|
|
240
|
+
async assetUnlink(fileId, app, entityType, entityId) {
|
|
241
|
+
try {
|
|
242
|
+
return await this.makeRequest('DELETE', `/api/assets/${fileId}/links`, {
|
|
243
|
+
app,
|
|
244
|
+
entityType,
|
|
245
|
+
entityId
|
|
246
|
+
}, { cache: false });
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
throw this.handleError(error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get asset metadata
|
|
254
|
+
*/
|
|
255
|
+
async assetGet(fileId) {
|
|
256
|
+
try {
|
|
257
|
+
return await this.makeRequest('GET', `/api/assets/${fileId}`, undefined, {
|
|
258
|
+
cache: true,
|
|
259
|
+
cacheTTL: 5 * 60 * 1000,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
throw this.handleError(error);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Get asset URL (CDN or signed URL)
|
|
268
|
+
*/
|
|
269
|
+
async assetGetUrl(fileId, variant, expiresIn) {
|
|
270
|
+
try {
|
|
271
|
+
const params = {};
|
|
272
|
+
if (variant)
|
|
273
|
+
params.variant = variant;
|
|
274
|
+
if (expiresIn)
|
|
275
|
+
params.expiresIn = expiresIn;
|
|
276
|
+
return await this.makeRequest('GET', `/api/assets/${fileId}/url`, params, {
|
|
277
|
+
cache: true,
|
|
278
|
+
cacheTTL: 10 * 60 * 1000,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
throw this.handleError(error);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Restore asset from trash
|
|
287
|
+
*/
|
|
288
|
+
async assetRestore(fileId) {
|
|
289
|
+
try {
|
|
290
|
+
return await this.makeRequest('POST', `/api/assets/${fileId}/restore`, undefined, { cache: false });
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
throw this.handleError(error);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Delete asset with optional force
|
|
298
|
+
*/
|
|
299
|
+
async assetDelete(fileId, force = false) {
|
|
300
|
+
try {
|
|
301
|
+
const params = force ? { force: 'true' } : undefined;
|
|
302
|
+
return await this.makeRequest('DELETE', `/api/assets/${fileId}`, params, { cache: false });
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
throw this.handleError(error);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Get list of available variants for an asset
|
|
310
|
+
*/
|
|
311
|
+
async assetGetVariants(fileId) {
|
|
312
|
+
try {
|
|
313
|
+
const assetData = await this.assetGet(fileId);
|
|
314
|
+
return assetData.file?.variants || [];
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
throw this.handleError(error);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Update asset visibility
|
|
322
|
+
*/
|
|
323
|
+
async assetUpdateVisibility(fileId, visibility) {
|
|
324
|
+
try {
|
|
325
|
+
return await this.makeRequest('PATCH', `/api/assets/${fileId}/visibility`, {
|
|
326
|
+
visibility
|
|
327
|
+
}, { cache: false });
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
throw this.handleError(error);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async uploadAvatar(file, userId, app = 'profiles') {
|
|
334
|
+
try {
|
|
335
|
+
const asset = await this.assetUpload(file, 'public');
|
|
336
|
+
await this.assetLink(asset.file.id, app, 'avatar', userId, 'public');
|
|
337
|
+
return asset;
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
throw this.handleError(error);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async uploadProfileBanner(file, userId, app = 'profiles') {
|
|
344
|
+
try {
|
|
345
|
+
const asset = await this.assetUpload(file, 'public');
|
|
346
|
+
await this.assetLink(asset.file.id, app, 'profile-banner', userId, 'public');
|
|
347
|
+
return asset;
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
throw this.handleError(error);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
getAssetUrlCacheTTL(expiresIn) {
|
|
354
|
+
const desiredTtlMs = (expiresIn ?? 3600) * 1000;
|
|
355
|
+
return Math.min(desiredTtlMs, 10 * 60 * 1000);
|
|
356
|
+
}
|
|
357
|
+
async fetchAssetDownloadUrl(fileId, variant, cacheTTL, expiresIn) {
|
|
358
|
+
const params = {};
|
|
359
|
+
if (variant)
|
|
360
|
+
params.variant = variant;
|
|
361
|
+
if (expiresIn)
|
|
362
|
+
params.expiresIn = expiresIn;
|
|
363
|
+
const urlRes = await this.makeRequest('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, Object.keys(params).length ? params : undefined, {
|
|
364
|
+
cache: true,
|
|
365
|
+
cacheTTL: cacheTTL ?? 10 * 60 * 1000,
|
|
366
|
+
});
|
|
367
|
+
return urlRes?.url || null;
|
|
368
|
+
}
|
|
369
|
+
async fetchAssetContent(url, type) {
|
|
370
|
+
const response = await fetch(url, { credentials: 'include' });
|
|
371
|
+
if (!response?.ok) {
|
|
372
|
+
throw new Error(`Failed to fetch asset content (status ${response?.status})`);
|
|
373
|
+
}
|
|
374
|
+
return type === 'text' ? response.text() : response.blob();
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { OxyAuthenticationError } from '../OxyServices.errors';
|
|
2
|
+
export function OxyServicesAuthMixin(Base) {
|
|
3
|
+
return class extends Base {
|
|
4
|
+
constructor(...args) {
|
|
5
|
+
super(...args);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Register a new identity with public key authentication
|
|
9
|
+
* Identity is purely cryptographic - username and profile data are optional
|
|
10
|
+
*
|
|
11
|
+
* @param publicKey - The user's ECDSA public key (hex)
|
|
12
|
+
* @param signature - Signature of the registration request
|
|
13
|
+
* @param timestamp - Timestamp when the signature was created
|
|
14
|
+
*/
|
|
15
|
+
async register(publicKey, signature, timestamp) {
|
|
16
|
+
try {
|
|
17
|
+
const res = await this.makeRequest('POST', '/api/auth/register', {
|
|
18
|
+
publicKey,
|
|
19
|
+
signature,
|
|
20
|
+
timestamp,
|
|
21
|
+
}, { cache: false });
|
|
22
|
+
if (!res || (typeof res === 'object' && Object.keys(res).length === 0)) {
|
|
23
|
+
throw new OxyAuthenticationError('Registration failed', 'REGISTER_FAILED', 400);
|
|
24
|
+
}
|
|
25
|
+
return res;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
throw this.handleError(error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Request an authentication challenge
|
|
33
|
+
* The client must sign this challenge with their private key
|
|
34
|
+
*
|
|
35
|
+
* @param publicKey - The user's public key
|
|
36
|
+
*/
|
|
37
|
+
async requestChallenge(publicKey) {
|
|
38
|
+
try {
|
|
39
|
+
return await this.makeRequest('POST', '/api/auth/challenge', {
|
|
40
|
+
publicKey,
|
|
41
|
+
}, { cache: false });
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw this.handleError(error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Verify a signed challenge and create a session
|
|
49
|
+
*
|
|
50
|
+
* @param publicKey - The user's public key
|
|
51
|
+
* @param challenge - The challenge string from requestChallenge
|
|
52
|
+
* @param signature - Signature of the auth message
|
|
53
|
+
* @param timestamp - Timestamp when the signature was created
|
|
54
|
+
* @param deviceName - Optional device name
|
|
55
|
+
* @param deviceFingerprint - Optional device fingerprint
|
|
56
|
+
*/
|
|
57
|
+
async verifyChallenge(publicKey, challenge, signature, timestamp, deviceName, deviceFingerprint) {
|
|
58
|
+
try {
|
|
59
|
+
return await this.makeRequest('POST', '/api/auth/verify', {
|
|
60
|
+
publicKey,
|
|
61
|
+
challenge,
|
|
62
|
+
signature,
|
|
63
|
+
timestamp,
|
|
64
|
+
deviceName,
|
|
65
|
+
deviceFingerprint,
|
|
66
|
+
}, { cache: false });
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
throw this.handleError(error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Check if a public key is already registered
|
|
74
|
+
*/
|
|
75
|
+
async checkPublicKeyRegistered(publicKey) {
|
|
76
|
+
try {
|
|
77
|
+
return await this.makeRequest('GET', `/api/auth/check-publickey/${encodeURIComponent(publicKey)}`, undefined, { cache: false });
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw this.handleError(error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get user by public key
|
|
85
|
+
*/
|
|
86
|
+
async getUserByPublicKey(publicKey) {
|
|
87
|
+
try {
|
|
88
|
+
return await this.makeRequest('GET', `/api/auth/user/${encodeURIComponent(publicKey)}`, undefined, { cache: true, cacheTTL: 2 * 60 * 1000 });
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
throw this.handleError(error);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get user by session ID
|
|
96
|
+
*/
|
|
97
|
+
async getUserBySession(sessionId) {
|
|
98
|
+
try {
|
|
99
|
+
return await this.makeRequest('GET', `/api/session/user/${sessionId}`, undefined, {
|
|
100
|
+
cache: true,
|
|
101
|
+
cacheTTL: 2 * 60 * 1000,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
throw this.handleError(error);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Batch get multiple user profiles by session IDs
|
|
110
|
+
*/
|
|
111
|
+
async getUsersBySessions(sessionIds) {
|
|
112
|
+
try {
|
|
113
|
+
if (!Array.isArray(sessionIds) || sessionIds.length === 0) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
const uniqueSessionIds = Array.from(new Set(sessionIds)).sort();
|
|
117
|
+
return await this.makeRequest('POST', '/api/session/users/batch', { sessionIds: uniqueSessionIds }, {
|
|
118
|
+
cache: true,
|
|
119
|
+
cacheTTL: 2 * 60 * 1000,
|
|
120
|
+
deduplicate: true,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
throw this.handleError(error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get access token by session ID
|
|
129
|
+
*/
|
|
130
|
+
async getTokenBySession(sessionId) {
|
|
131
|
+
try {
|
|
132
|
+
const res = await this.makeRequest('GET', `/api/session/token/${sessionId}`, undefined, { cache: false, retry: false });
|
|
133
|
+
this.setTokens(res.accessToken);
|
|
134
|
+
return res;
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
throw this.handleError(error);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get sessions by session ID
|
|
142
|
+
*/
|
|
143
|
+
async getSessionsBySessionId(sessionId) {
|
|
144
|
+
try {
|
|
145
|
+
return await this.makeRequest('GET', `/api/session/sessions/${sessionId}`, undefined, {
|
|
146
|
+
cache: false,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
throw this.handleError(error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Logout from a specific session
|
|
155
|
+
*/
|
|
156
|
+
async logoutSession(sessionId, targetSessionId) {
|
|
157
|
+
try {
|
|
158
|
+
const url = targetSessionId
|
|
159
|
+
? `/api/session/logout/${sessionId}/${targetSessionId}`
|
|
160
|
+
: `/api/session/logout/${sessionId}`;
|
|
161
|
+
await this.makeRequest('POST', url, undefined, { cache: false });
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
throw this.handleError(error);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Logout from all sessions
|
|
169
|
+
*/
|
|
170
|
+
async logoutAllSessions(sessionId) {
|
|
171
|
+
try {
|
|
172
|
+
await this.makeRequest('POST', `/api/session/logout-all/${sessionId}`, undefined, { cache: false });
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
throw this.handleError(error);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Validate session
|
|
180
|
+
*/
|
|
181
|
+
async validateSession(sessionId, options = {}) {
|
|
182
|
+
try {
|
|
183
|
+
const urlParams = {};
|
|
184
|
+
if (options.deviceFingerprint)
|
|
185
|
+
urlParams.deviceFingerprint = options.deviceFingerprint;
|
|
186
|
+
if (options.useHeaderValidation)
|
|
187
|
+
urlParams.useHeaderValidation = 'true';
|
|
188
|
+
return await this.makeRequest('GET', `/api/session/validate/${sessionId}`, urlParams, { cache: false });
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
throw this.handleError(error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Check username availability
|
|
196
|
+
*/
|
|
197
|
+
async checkUsernameAvailability(username) {
|
|
198
|
+
try {
|
|
199
|
+
return await this.makeRequest('GET', `/api/auth/check-username/${username}`, undefined, { cache: false });
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
throw this.handleError(error);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check email availability
|
|
207
|
+
*/
|
|
208
|
+
async checkEmailAvailability(email) {
|
|
209
|
+
try {
|
|
210
|
+
return await this.makeRequest('GET', `/api/auth/check-email/${email}`, undefined, { cache: false });
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
throw this.handleError(error);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Register a new user with email/username and password
|
|
218
|
+
*/
|
|
219
|
+
async signUp(username, email, password, deviceName, deviceFingerprint) {
|
|
220
|
+
try {
|
|
221
|
+
return await this.makeRequest('POST', '/api/auth/signup', {
|
|
222
|
+
username,
|
|
223
|
+
email,
|
|
224
|
+
password,
|
|
225
|
+
deviceName,
|
|
226
|
+
deviceFingerprint,
|
|
227
|
+
}, { cache: false });
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
throw this.handleError(error);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Sign in with email or username and password
|
|
235
|
+
*/
|
|
236
|
+
async signIn(identifier, password, deviceName, deviceFingerprint) {
|
|
237
|
+
try {
|
|
238
|
+
return await this.makeRequest('POST', '/api/auth/login', {
|
|
239
|
+
identifier,
|
|
240
|
+
password,
|
|
241
|
+
deviceName,
|
|
242
|
+
deviceFingerprint,
|
|
243
|
+
}, { cache: false });
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
throw this.handleError(error);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Convenience helper for email sign-in
|
|
251
|
+
*/
|
|
252
|
+
async signInWithEmail(email, password, deviceName, deviceFingerprint) {
|
|
253
|
+
return this.signIn(email, password, deviceName, deviceFingerprint);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|