@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.
Files changed (277) hide show
  1. package/README.md +50 -0
  2. package/dist/cjs/AuthManager.js +361 -0
  3. package/dist/cjs/CrossDomainAuth.js +258 -0
  4. package/dist/cjs/HttpService.js +618 -0
  5. package/dist/cjs/OxyServices.base.js +263 -0
  6. package/dist/cjs/OxyServices.errors.js +22 -0
  7. package/dist/cjs/OxyServices.js +63 -0
  8. package/dist/cjs/constants/version.js +16 -0
  9. package/dist/cjs/crypto/index.js +20 -0
  10. package/dist/cjs/crypto/keyManager.js +887 -0
  11. package/dist/cjs/crypto/polyfill.js +64 -0
  12. package/dist/cjs/crypto/recoveryPhrase.js +169 -0
  13. package/dist/cjs/crypto/signatureService.js +296 -0
  14. package/dist/cjs/i18n/index.js +73 -0
  15. package/dist/cjs/i18n/locales/ar-SA.json +120 -0
  16. package/dist/cjs/i18n/locales/ca-ES.json +120 -0
  17. package/dist/cjs/i18n/locales/de-DE.json +120 -0
  18. package/dist/cjs/i18n/locales/en-US.json +956 -0
  19. package/dist/cjs/i18n/locales/es-ES.json +944 -0
  20. package/dist/cjs/i18n/locales/fr-FR.json +120 -0
  21. package/dist/cjs/i18n/locales/it-IT.json +120 -0
  22. package/dist/cjs/i18n/locales/ja-JP.json +119 -0
  23. package/dist/cjs/i18n/locales/ko-KR.json +120 -0
  24. package/dist/cjs/i18n/locales/locales/ar-SA.json +120 -0
  25. package/dist/cjs/i18n/locales/locales/ca-ES.json +120 -0
  26. package/dist/cjs/i18n/locales/locales/de-DE.json +120 -0
  27. package/dist/cjs/i18n/locales/locales/en-US.json +956 -0
  28. package/dist/cjs/i18n/locales/locales/es-ES.json +944 -0
  29. package/dist/cjs/i18n/locales/locales/fr-FR.json +120 -0
  30. package/dist/cjs/i18n/locales/locales/it-IT.json +120 -0
  31. package/dist/cjs/i18n/locales/locales/ja-JP.json +119 -0
  32. package/dist/cjs/i18n/locales/locales/ko-KR.json +120 -0
  33. package/dist/cjs/i18n/locales/locales/pt-PT.json +120 -0
  34. package/dist/cjs/i18n/locales/locales/zh-CN.json +120 -0
  35. package/dist/cjs/i18n/locales/pt-PT.json +120 -0
  36. package/dist/cjs/i18n/locales/zh-CN.json +120 -0
  37. package/dist/cjs/index.js +153 -0
  38. package/dist/cjs/mixins/OxyServices.analytics.js +49 -0
  39. package/dist/cjs/mixins/OxyServices.assets.js +380 -0
  40. package/dist/cjs/mixins/OxyServices.auth.js +259 -0
  41. package/dist/cjs/mixins/OxyServices.developer.js +97 -0
  42. package/dist/cjs/mixins/OxyServices.devices.js +116 -0
  43. package/dist/cjs/mixins/OxyServices.features.js +309 -0
  44. package/dist/cjs/mixins/OxyServices.fedcm.js +435 -0
  45. package/dist/cjs/mixins/OxyServices.karma.js +108 -0
  46. package/dist/cjs/mixins/OxyServices.language.js +154 -0
  47. package/dist/cjs/mixins/OxyServices.location.js +43 -0
  48. package/dist/cjs/mixins/OxyServices.payment.js +158 -0
  49. package/dist/cjs/mixins/OxyServices.popup.js +371 -0
  50. package/dist/cjs/mixins/OxyServices.privacy.js +162 -0
  51. package/dist/cjs/mixins/OxyServices.redirect.js +345 -0
  52. package/dist/cjs/mixins/OxyServices.security.js +81 -0
  53. package/dist/cjs/mixins/OxyServices.user.js +355 -0
  54. package/dist/cjs/mixins/OxyServices.utility.js +156 -0
  55. package/dist/cjs/mixins/index.js +79 -0
  56. package/dist/cjs/mixins/mixinHelpers.js +53 -0
  57. package/dist/cjs/models/interfaces.js +20 -0
  58. package/dist/cjs/models/session.js +2 -0
  59. package/dist/cjs/shared/index.js +70 -0
  60. package/dist/cjs/shared/utils/colorUtils.js +153 -0
  61. package/dist/cjs/shared/utils/debugUtils.js +73 -0
  62. package/dist/cjs/shared/utils/errorUtils.js +183 -0
  63. package/dist/cjs/shared/utils/index.js +49 -0
  64. package/dist/cjs/shared/utils/networkUtils.js +183 -0
  65. package/dist/cjs/shared/utils/themeUtils.js +106 -0
  66. package/dist/cjs/utils/apiUtils.js +61 -0
  67. package/dist/cjs/utils/asyncUtils.js +194 -0
  68. package/dist/cjs/utils/cache.js +226 -0
  69. package/dist/cjs/utils/deviceManager.js +205 -0
  70. package/dist/cjs/utils/errorUtils.js +154 -0
  71. package/dist/cjs/utils/index.js +26 -0
  72. package/dist/cjs/utils/languageUtils.js +165 -0
  73. package/dist/cjs/utils/loggerUtils.js +126 -0
  74. package/dist/cjs/utils/platform.js +144 -0
  75. package/dist/cjs/utils/requestUtils.js +209 -0
  76. package/dist/cjs/utils/sessionUtils.js +181 -0
  77. package/dist/cjs/utils/validationUtils.js +173 -0
  78. package/dist/esm/AuthManager.js +356 -0
  79. package/dist/esm/CrossDomainAuth.js +253 -0
  80. package/dist/esm/HttpService.js +614 -0
  81. package/dist/esm/OxyServices.base.js +259 -0
  82. package/dist/esm/OxyServices.errors.js +17 -0
  83. package/dist/esm/OxyServices.js +59 -0
  84. package/dist/esm/constants/version.js +13 -0
  85. package/dist/esm/crypto/index.js +13 -0
  86. package/dist/esm/crypto/keyManager.js +850 -0
  87. package/dist/esm/crypto/polyfill.js +61 -0
  88. package/dist/esm/crypto/recoveryPhrase.js +132 -0
  89. package/dist/esm/crypto/signatureService.js +259 -0
  90. package/dist/esm/i18n/index.js +69 -0
  91. package/dist/esm/i18n/locales/ar-SA.json +120 -0
  92. package/dist/esm/i18n/locales/ca-ES.json +120 -0
  93. package/dist/esm/i18n/locales/de-DE.json +120 -0
  94. package/dist/esm/i18n/locales/en-US.json +956 -0
  95. package/dist/esm/i18n/locales/es-ES.json +944 -0
  96. package/dist/esm/i18n/locales/fr-FR.json +120 -0
  97. package/dist/esm/i18n/locales/it-IT.json +120 -0
  98. package/dist/esm/i18n/locales/ja-JP.json +119 -0
  99. package/dist/esm/i18n/locales/ko-KR.json +120 -0
  100. package/dist/esm/i18n/locales/locales/ar-SA.json +120 -0
  101. package/dist/esm/i18n/locales/locales/ca-ES.json +120 -0
  102. package/dist/esm/i18n/locales/locales/de-DE.json +120 -0
  103. package/dist/esm/i18n/locales/locales/en-US.json +956 -0
  104. package/dist/esm/i18n/locales/locales/es-ES.json +944 -0
  105. package/dist/esm/i18n/locales/locales/fr-FR.json +120 -0
  106. package/dist/esm/i18n/locales/locales/it-IT.json +120 -0
  107. package/dist/esm/i18n/locales/locales/ja-JP.json +119 -0
  108. package/dist/esm/i18n/locales/locales/ko-KR.json +120 -0
  109. package/dist/esm/i18n/locales/locales/pt-PT.json +120 -0
  110. package/dist/esm/i18n/locales/locales/zh-CN.json +120 -0
  111. package/dist/esm/i18n/locales/pt-PT.json +120 -0
  112. package/dist/esm/i18n/locales/zh-CN.json +120 -0
  113. package/dist/esm/index.js +55 -0
  114. package/dist/esm/mixins/OxyServices.analytics.js +46 -0
  115. package/dist/esm/mixins/OxyServices.assets.js +377 -0
  116. package/dist/esm/mixins/OxyServices.auth.js +256 -0
  117. package/dist/esm/mixins/OxyServices.developer.js +94 -0
  118. package/dist/esm/mixins/OxyServices.devices.js +113 -0
  119. package/dist/esm/mixins/OxyServices.features.js +306 -0
  120. package/dist/esm/mixins/OxyServices.fedcm.js +433 -0
  121. package/dist/esm/mixins/OxyServices.karma.js +105 -0
  122. package/dist/esm/mixins/OxyServices.language.js +118 -0
  123. package/dist/esm/mixins/OxyServices.location.js +40 -0
  124. package/dist/esm/mixins/OxyServices.payment.js +155 -0
  125. package/dist/esm/mixins/OxyServices.popup.js +369 -0
  126. package/dist/esm/mixins/OxyServices.privacy.js +159 -0
  127. package/dist/esm/mixins/OxyServices.redirect.js +343 -0
  128. package/dist/esm/mixins/OxyServices.security.js +78 -0
  129. package/dist/esm/mixins/OxyServices.user.js +352 -0
  130. package/dist/esm/mixins/OxyServices.utility.js +153 -0
  131. package/dist/esm/mixins/index.js +76 -0
  132. package/dist/esm/mixins/mixinHelpers.js +48 -0
  133. package/dist/esm/models/interfaces.js +17 -0
  134. package/dist/esm/models/session.js +1 -0
  135. package/dist/esm/shared/index.js +31 -0
  136. package/dist/esm/shared/utils/colorUtils.js +143 -0
  137. package/dist/esm/shared/utils/debugUtils.js +65 -0
  138. package/dist/esm/shared/utils/errorUtils.js +170 -0
  139. package/dist/esm/shared/utils/index.js +15 -0
  140. package/dist/esm/shared/utils/networkUtils.js +173 -0
  141. package/dist/esm/shared/utils/themeUtils.js +98 -0
  142. package/dist/esm/utils/apiUtils.js +55 -0
  143. package/dist/esm/utils/asyncUtils.js +179 -0
  144. package/dist/esm/utils/cache.js +218 -0
  145. package/dist/esm/utils/deviceManager.js +168 -0
  146. package/dist/esm/utils/errorUtils.js +146 -0
  147. package/dist/esm/utils/index.js +7 -0
  148. package/dist/esm/utils/languageUtils.js +158 -0
  149. package/dist/esm/utils/loggerUtils.js +115 -0
  150. package/dist/esm/utils/platform.js +102 -0
  151. package/dist/esm/utils/requestUtils.js +203 -0
  152. package/dist/esm/utils/sessionUtils.js +171 -0
  153. package/dist/esm/utils/validationUtils.js +153 -0
  154. package/dist/types/AuthManager.d.ts +143 -0
  155. package/dist/types/CrossDomainAuth.d.ts +160 -0
  156. package/dist/types/HttpService.d.ts +163 -0
  157. package/dist/types/OxyServices.base.d.ts +126 -0
  158. package/dist/types/OxyServices.d.ts +81 -0
  159. package/dist/types/OxyServices.errors.d.ts +11 -0
  160. package/dist/types/constants/version.d.ts +13 -0
  161. package/dist/types/crypto/index.d.ts +11 -0
  162. package/dist/types/crypto/keyManager.d.ts +189 -0
  163. package/dist/types/crypto/polyfill.d.ts +11 -0
  164. package/dist/types/crypto/recoveryPhrase.d.ts +58 -0
  165. package/dist/types/crypto/signatureService.d.ts +86 -0
  166. package/dist/types/i18n/index.d.ts +3 -0
  167. package/dist/types/index.d.ts +50 -0
  168. package/dist/types/mixins/OxyServices.analytics.d.ts +66 -0
  169. package/dist/types/mixins/OxyServices.assets.d.ts +135 -0
  170. package/dist/types/mixins/OxyServices.auth.d.ts +186 -0
  171. package/dist/types/mixins/OxyServices.developer.d.ts +99 -0
  172. package/dist/types/mixins/OxyServices.devices.d.ts +96 -0
  173. package/dist/types/mixins/OxyServices.features.d.ts +228 -0
  174. package/dist/types/mixins/OxyServices.fedcm.d.ts +200 -0
  175. package/dist/types/mixins/OxyServices.karma.d.ts +85 -0
  176. package/dist/types/mixins/OxyServices.language.d.ts +81 -0
  177. package/dist/types/mixins/OxyServices.location.d.ts +64 -0
  178. package/dist/types/mixins/OxyServices.payment.d.ts +111 -0
  179. package/dist/types/mixins/OxyServices.popup.d.ts +205 -0
  180. package/dist/types/mixins/OxyServices.privacy.d.ts +122 -0
  181. package/dist/types/mixins/OxyServices.redirect.d.ts +245 -0
  182. package/dist/types/mixins/OxyServices.security.d.ts +78 -0
  183. package/dist/types/mixins/OxyServices.user.d.ts +182 -0
  184. package/dist/types/mixins/OxyServices.utility.d.ts +93 -0
  185. package/dist/types/mixins/index.d.ts +30 -0
  186. package/dist/types/mixins/mixinHelpers.d.ts +31 -0
  187. package/dist/types/models/interfaces.d.ts +415 -0
  188. package/dist/types/models/session.d.ts +27 -0
  189. package/dist/types/shared/index.d.ts +28 -0
  190. package/dist/types/shared/utils/colorUtils.d.ts +104 -0
  191. package/dist/types/shared/utils/debugUtils.d.ts +48 -0
  192. package/dist/types/shared/utils/errorUtils.d.ts +97 -0
  193. package/dist/types/shared/utils/index.d.ts +13 -0
  194. package/dist/types/shared/utils/networkUtils.d.ts +139 -0
  195. package/dist/types/shared/utils/themeUtils.d.ts +90 -0
  196. package/dist/types/utils/apiUtils.d.ts +53 -0
  197. package/dist/types/utils/asyncUtils.d.ts +58 -0
  198. package/dist/types/utils/cache.d.ts +127 -0
  199. package/dist/types/utils/deviceManager.d.ts +65 -0
  200. package/dist/types/utils/errorUtils.d.ts +46 -0
  201. package/dist/types/utils/index.d.ts +6 -0
  202. package/dist/types/utils/languageUtils.d.ts +37 -0
  203. package/dist/types/utils/loggerUtils.d.ts +48 -0
  204. package/dist/types/utils/platform.d.ts +40 -0
  205. package/dist/types/utils/requestUtils.d.ts +123 -0
  206. package/dist/types/utils/sessionUtils.d.ts +54 -0
  207. package/dist/types/utils/validationUtils.d.ts +85 -0
  208. package/package.json +84 -0
  209. package/src/AuthManager.ts +436 -0
  210. package/src/CrossDomainAuth.ts +307 -0
  211. package/src/HttpService.ts +752 -0
  212. package/src/OxyServices.base.ts +334 -0
  213. package/src/OxyServices.errors.ts +26 -0
  214. package/src/OxyServices.ts +129 -0
  215. package/src/constants/version.ts +15 -0
  216. package/src/crypto/index.ts +25 -0
  217. package/src/crypto/keyManager.ts +962 -0
  218. package/src/crypto/polyfill.ts +70 -0
  219. package/src/crypto/recoveryPhrase.ts +166 -0
  220. package/src/crypto/signatureService.ts +323 -0
  221. package/src/i18n/index.ts +75 -0
  222. package/src/i18n/locales/ar-SA.json +120 -0
  223. package/src/i18n/locales/ca-ES.json +120 -0
  224. package/src/i18n/locales/de-DE.json +120 -0
  225. package/src/i18n/locales/en-US.json +956 -0
  226. package/src/i18n/locales/es-ES.json +944 -0
  227. package/src/i18n/locales/fr-FR.json +120 -0
  228. package/src/i18n/locales/it-IT.json +120 -0
  229. package/src/i18n/locales/ja-JP.json +119 -0
  230. package/src/i18n/locales/ko-KR.json +120 -0
  231. package/src/i18n/locales/pt-PT.json +120 -0
  232. package/src/i18n/locales/zh-CN.json +120 -0
  233. package/src/index.ts +153 -0
  234. package/src/mixins/OxyServices.analytics.ts +53 -0
  235. package/src/mixins/OxyServices.assets.ts +412 -0
  236. package/src/mixins/OxyServices.auth.ts +358 -0
  237. package/src/mixins/OxyServices.developer.ts +114 -0
  238. package/src/mixins/OxyServices.devices.ts +119 -0
  239. package/src/mixins/OxyServices.features.ts +428 -0
  240. package/src/mixins/OxyServices.fedcm.ts +494 -0
  241. package/src/mixins/OxyServices.karma.ts +111 -0
  242. package/src/mixins/OxyServices.language.ts +127 -0
  243. package/src/mixins/OxyServices.location.ts +46 -0
  244. package/src/mixins/OxyServices.payment.ts +163 -0
  245. package/src/mixins/OxyServices.popup.ts +443 -0
  246. package/src/mixins/OxyServices.privacy.ts +182 -0
  247. package/src/mixins/OxyServices.redirect.ts +397 -0
  248. package/src/mixins/OxyServices.security.ts +103 -0
  249. package/src/mixins/OxyServices.user.ts +392 -0
  250. package/src/mixins/OxyServices.utility.ts +191 -0
  251. package/src/mixins/index.ts +91 -0
  252. package/src/mixins/mixinHelpers.ts +69 -0
  253. package/src/models/interfaces.ts +511 -0
  254. package/src/models/session.ts +30 -0
  255. package/src/shared/index.ts +82 -0
  256. package/src/shared/utils/colorUtils.ts +155 -0
  257. package/src/shared/utils/debugUtils.ts +73 -0
  258. package/src/shared/utils/errorUtils.ts +181 -0
  259. package/src/shared/utils/index.ts +59 -0
  260. package/src/shared/utils/networkUtils.ts +248 -0
  261. package/src/shared/utils/themeUtils.ts +115 -0
  262. package/src/types/bip39.d.ts +32 -0
  263. package/src/types/buffer.d.ts +97 -0
  264. package/src/types/color.d.ts +20 -0
  265. package/src/types/elliptic.d.ts +62 -0
  266. package/src/utils/apiUtils.ts +88 -0
  267. package/src/utils/asyncUtils.ts +252 -0
  268. package/src/utils/cache.ts +264 -0
  269. package/src/utils/deviceManager.ts +198 -0
  270. package/src/utils/errorUtils.ts +216 -0
  271. package/src/utils/index.ts +21 -0
  272. package/src/utils/languageUtils.ts +174 -0
  273. package/src/utils/loggerUtils.ts +153 -0
  274. package/src/utils/platform.ts +117 -0
  275. package/src/utils/requestUtils.ts +237 -0
  276. package/src/utils/sessionUtils.ts +206 -0
  277. 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
+ }