@oxyhq/services 5.13.12 → 5.13.16

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 (209) hide show
  1. package/README.md +10 -0
  2. package/lib/commonjs/core/OxyServices.base.js +271 -0
  3. package/lib/commonjs/core/OxyServices.base.js.map +1 -0
  4. package/lib/commonjs/core/OxyServices.errors.js +26 -0
  5. package/lib/commonjs/core/OxyServices.errors.js.map +1 -0
  6. package/lib/commonjs/core/OxyServices.js +58 -2009
  7. package/lib/commonjs/core/OxyServices.js.map +1 -1
  8. package/lib/commonjs/core/mixins/OxyServices.analytics.js +60 -0
  9. package/lib/commonjs/core/mixins/OxyServices.analytics.js.map +1 -0
  10. package/lib/commonjs/core/mixins/OxyServices.assets.js +406 -0
  11. package/lib/commonjs/core/mixins/OxyServices.assets.js.map +1 -0
  12. package/lib/commonjs/core/mixins/OxyServices.auth.js +303 -0
  13. package/lib/commonjs/core/mixins/OxyServices.auth.js.map +1 -0
  14. package/lib/commonjs/core/mixins/OxyServices.developer.js +115 -0
  15. package/lib/commonjs/core/mixins/OxyServices.developer.js.map +1 -0
  16. package/lib/commonjs/core/mixins/OxyServices.devices.js +119 -0
  17. package/lib/commonjs/core/mixins/OxyServices.devices.js.map +1 -0
  18. package/lib/commonjs/core/mixins/OxyServices.karma.js +117 -0
  19. package/lib/commonjs/core/mixins/OxyServices.karma.js.map +1 -0
  20. package/lib/commonjs/core/mixins/OxyServices.language.js +124 -0
  21. package/lib/commonjs/core/mixins/OxyServices.language.js.map +1 -0
  22. package/lib/commonjs/core/mixins/OxyServices.location.js +55 -0
  23. package/lib/commonjs/core/mixins/OxyServices.location.js.map +1 -0
  24. package/lib/commonjs/core/mixins/OxyServices.payment.js +66 -0
  25. package/lib/commonjs/core/mixins/OxyServices.payment.js.map +1 -0
  26. package/lib/commonjs/core/mixins/OxyServices.privacy.js +174 -0
  27. package/lib/commonjs/core/mixins/OxyServices.privacy.js.map +1 -0
  28. package/lib/commonjs/core/mixins/OxyServices.totp.js +53 -0
  29. package/lib/commonjs/core/mixins/OxyServices.totp.js.map +1 -0
  30. package/lib/commonjs/core/mixins/OxyServices.user.js +389 -0
  31. package/lib/commonjs/core/mixins/OxyServices.user.js.map +1 -0
  32. package/lib/commonjs/core/mixins/OxyServices.utility.js +161 -0
  33. package/lib/commonjs/core/mixins/OxyServices.utility.js.map +1 -0
  34. package/lib/commonjs/core/mixins/index.js +39 -0
  35. package/lib/commonjs/core/mixins/index.js.map +1 -0
  36. package/lib/commonjs/core/mixins/mixinHelpers.js +62 -0
  37. package/lib/commonjs/core/mixins/mixinHelpers.js.map +1 -0
  38. package/lib/commonjs/index.js.map +1 -1
  39. package/lib/commonjs/ui/context/OxyContext.js +26 -47
  40. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  41. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +239 -1
  42. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  43. package/lib/commonjs/utils/apiUtils.js +0 -14
  44. package/lib/commonjs/utils/apiUtils.js.map +1 -1
  45. package/lib/commonjs/utils/asyncUtils.js +0 -20
  46. package/lib/commonjs/utils/asyncUtils.js.map +1 -1
  47. package/lib/module/core/OxyServices.base.js +265 -0
  48. package/lib/module/core/OxyServices.base.js.map +1 -0
  49. package/lib/module/core/OxyServices.errors.js +20 -0
  50. package/lib/module/core/OxyServices.errors.js.map +1 -0
  51. package/lib/module/core/OxyServices.js +43 -2005
  52. package/lib/module/core/OxyServices.js.map +1 -1
  53. package/lib/module/core/mixins/OxyServices.analytics.js +56 -0
  54. package/lib/module/core/mixins/OxyServices.analytics.js.map +1 -0
  55. package/lib/module/core/mixins/OxyServices.assets.js +402 -0
  56. package/lib/module/core/mixins/OxyServices.assets.js.map +1 -0
  57. package/lib/module/core/mixins/OxyServices.auth.js +299 -0
  58. package/lib/module/core/mixins/OxyServices.auth.js.map +1 -0
  59. package/lib/module/core/mixins/OxyServices.developer.js +111 -0
  60. package/lib/module/core/mixins/OxyServices.developer.js.map +1 -0
  61. package/lib/module/core/mixins/OxyServices.devices.js +115 -0
  62. package/lib/module/core/mixins/OxyServices.devices.js.map +1 -0
  63. package/lib/module/core/mixins/OxyServices.karma.js +113 -0
  64. package/lib/module/core/mixins/OxyServices.karma.js.map +1 -0
  65. package/lib/module/core/mixins/OxyServices.language.js +120 -0
  66. package/lib/module/core/mixins/OxyServices.language.js.map +1 -0
  67. package/lib/module/core/mixins/OxyServices.location.js +51 -0
  68. package/lib/module/core/mixins/OxyServices.location.js.map +1 -0
  69. package/lib/module/core/mixins/OxyServices.payment.js +62 -0
  70. package/lib/module/core/mixins/OxyServices.payment.js.map +1 -0
  71. package/lib/module/core/mixins/OxyServices.privacy.js +170 -0
  72. package/lib/module/core/mixins/OxyServices.privacy.js.map +1 -0
  73. package/lib/module/core/mixins/OxyServices.totp.js +49 -0
  74. package/lib/module/core/mixins/OxyServices.totp.js.map +1 -0
  75. package/lib/module/core/mixins/OxyServices.user.js +385 -0
  76. package/lib/module/core/mixins/OxyServices.user.js.map +1 -0
  77. package/lib/module/core/mixins/OxyServices.utility.js +156 -0
  78. package/lib/module/core/mixins/OxyServices.utility.js.map +1 -0
  79. package/lib/module/core/mixins/index.js +36 -0
  80. package/lib/module/core/mixins/index.js.map +1 -0
  81. package/lib/module/core/mixins/mixinHelpers.js +56 -0
  82. package/lib/module/core/mixins/mixinHelpers.js.map +1 -0
  83. package/lib/module/index.js.map +1 -1
  84. package/lib/module/ui/context/OxyContext.js +26 -47
  85. package/lib/module/ui/context/OxyContext.js.map +1 -1
  86. package/lib/module/ui/navigation/types.js.map +1 -1
  87. package/lib/module/ui/screens/PrivacySettingsScreen.js +241 -3
  88. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  89. package/lib/module/utils/apiUtils.js +0 -13
  90. package/lib/module/utils/apiUtils.js.map +1 -1
  91. package/lib/module/utils/asyncUtils.js +0 -20
  92. package/lib/module/utils/asyncUtils.js.map +1 -1
  93. package/lib/typescript/core/OxyServices.base.d.ts +123 -0
  94. package/lib/typescript/core/OxyServices.base.d.ts.map +1 -0
  95. package/lib/typescript/core/OxyServices.d.ts +969 -682
  96. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  97. package/lib/typescript/core/OxyServices.errors.d.ts +12 -0
  98. package/lib/typescript/core/OxyServices.errors.d.ts.map +1 -0
  99. package/lib/typescript/core/mixins/OxyServices.analytics.d.ts +70 -0
  100. package/lib/typescript/core/mixins/OxyServices.analytics.d.ts.map +1 -0
  101. package/lib/typescript/core/mixins/OxyServices.assets.d.ts +159 -0
  102. package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -0
  103. package/lib/typescript/core/mixins/OxyServices.auth.d.ts +168 -0
  104. package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -0
  105. package/lib/typescript/core/mixins/OxyServices.developer.d.ts +103 -0
  106. package/lib/typescript/core/mixins/OxyServices.developer.d.ts.map +1 -0
  107. package/lib/typescript/core/mixins/OxyServices.devices.d.ts +93 -0
  108. package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -0
  109. package/lib/typescript/core/mixins/OxyServices.karma.d.ts +89 -0
  110. package/lib/typescript/core/mixins/OxyServices.karma.d.ts.map +1 -0
  111. package/lib/typescript/core/mixins/OxyServices.language.d.ts +85 -0
  112. package/lib/typescript/core/mixins/OxyServices.language.d.ts.map +1 -0
  113. package/lib/typescript/core/mixins/OxyServices.location.d.ts +68 -0
  114. package/lib/typescript/core/mixins/OxyServices.location.d.ts.map +1 -0
  115. package/lib/typescript/core/mixins/OxyServices.payment.d.ts +74 -0
  116. package/lib/typescript/core/mixins/OxyServices.payment.d.ts.map +1 -0
  117. package/lib/typescript/core/mixins/OxyServices.privacy.d.ts +126 -0
  118. package/lib/typescript/core/mixins/OxyServices.privacy.d.ts.map +1 -0
  119. package/lib/typescript/core/mixins/OxyServices.totp.d.ts +69 -0
  120. package/lib/typescript/core/mixins/OxyServices.totp.d.ts.map +1 -0
  121. package/lib/typescript/core/mixins/OxyServices.user.d.ts +189 -0
  122. package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -0
  123. package/lib/typescript/core/mixins/OxyServices.utility.d.ts +97 -0
  124. package/lib/typescript/core/mixins/OxyServices.utility.d.ts.map +1 -0
  125. package/lib/typescript/core/mixins/index.d.ts +898 -0
  126. package/lib/typescript/core/mixins/index.d.ts.map +1 -0
  127. package/lib/typescript/core/mixins/mixinHelpers.d.ts +32 -0
  128. package/lib/typescript/core/mixins/mixinHelpers.d.ts.map +1 -0
  129. package/lib/typescript/index.d.ts +1 -1
  130. package/lib/typescript/index.d.ts.map +1 -1
  131. package/lib/typescript/models/interfaces.d.ts +36 -0
  132. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  133. package/lib/typescript/ui/context/OxyContext.d.ts +2 -6
  134. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  135. package/lib/typescript/ui/navigation/types.d.ts +0 -1
  136. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  137. package/lib/typescript/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  138. package/lib/typescript/utils/apiUtils.d.ts +0 -7
  139. package/lib/typescript/utils/apiUtils.d.ts.map +1 -1
  140. package/lib/typescript/utils/asyncUtils.d.ts +0 -11
  141. package/lib/typescript/utils/asyncUtils.d.ts.map +1 -1
  142. package/package.json +1 -1
  143. package/src/core/OxyServices.base.ts +311 -0
  144. package/src/core/OxyServices.errors.ts +26 -0
  145. package/src/core/OxyServices.ts +43 -2026
  146. package/src/core/mixins/OxyServices.analytics.ts +53 -0
  147. package/src/core/mixins/OxyServices.assets.ts +390 -0
  148. package/src/core/mixins/OxyServices.auth.ts +275 -0
  149. package/src/core/mixins/OxyServices.developer.ts +114 -0
  150. package/src/core/mixins/OxyServices.devices.ts +103 -0
  151. package/src/core/mixins/OxyServices.karma.ts +111 -0
  152. package/src/core/mixins/OxyServices.language.ts +127 -0
  153. package/src/core/mixins/OxyServices.location.ts +46 -0
  154. package/src/core/mixins/OxyServices.payment.ts +59 -0
  155. package/src/core/mixins/OxyServices.privacy.ts +182 -0
  156. package/src/core/mixins/OxyServices.totp.ts +36 -0
  157. package/src/core/mixins/OxyServices.user.ts +380 -0
  158. package/src/core/mixins/OxyServices.utility.ts +187 -0
  159. package/src/core/mixins/index.ts +58 -0
  160. package/src/core/mixins/mixinHelpers.ts +69 -0
  161. package/src/index.ts +4 -0
  162. package/src/models/interfaces.ts +40 -0
  163. package/src/ui/context/OxyContext.tsx +35 -53
  164. package/src/ui/navigation/types.ts +0 -1
  165. package/src/ui/screens/PrivacySettingsScreen.tsx +240 -2
  166. package/src/utils/apiUtils.ts +0 -14
  167. package/src/utils/asyncUtils.ts +0 -20
  168. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +0 -192
  169. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +0 -1
  170. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +0 -142
  171. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +0 -1
  172. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js +0 -113
  173. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js.map +0 -1
  174. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js +0 -132
  175. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js.map +0 -1
  176. package/lib/commonjs/ui/screens/internal/SignUpSummaryStep.js +0 -83
  177. package/lib/commonjs/ui/screens/internal/SignUpSummaryStep.js.map +0 -1
  178. package/lib/commonjs/ui/screens/internal/SignUpWelcomeStep.js +0 -58
  179. package/lib/commonjs/ui/screens/internal/SignUpWelcomeStep.js.map +0 -1
  180. package/lib/module/ui/screens/internal/SignInPasswordStep.js +0 -186
  181. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +0 -1
  182. package/lib/module/ui/screens/internal/SignInUsernameStep.js +0 -136
  183. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +0 -1
  184. package/lib/module/ui/screens/internal/SignUpIdentityStep.js +0 -108
  185. package/lib/module/ui/screens/internal/SignUpIdentityStep.js.map +0 -1
  186. package/lib/module/ui/screens/internal/SignUpSecurityStep.js +0 -127
  187. package/lib/module/ui/screens/internal/SignUpSecurityStep.js.map +0 -1
  188. package/lib/module/ui/screens/internal/SignUpSummaryStep.js +0 -78
  189. package/lib/module/ui/screens/internal/SignUpSummaryStep.js.map +0 -1
  190. package/lib/module/ui/screens/internal/SignUpWelcomeStep.js +0 -53
  191. package/lib/module/ui/screens/internal/SignUpWelcomeStep.js.map +0 -1
  192. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +0 -28
  193. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +0 -1
  194. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +0 -25
  195. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +0 -1
  196. package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts +0 -20
  197. package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts.map +0 -1
  198. package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts +0 -24
  199. package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts.map +0 -1
  200. package/lib/typescript/ui/screens/internal/SignUpSummaryStep.d.ts +0 -15
  201. package/lib/typescript/ui/screens/internal/SignUpSummaryStep.d.ts.map +0 -1
  202. package/lib/typescript/ui/screens/internal/SignUpWelcomeStep.d.ts +0 -13
  203. package/lib/typescript/ui/screens/internal/SignUpWelcomeStep.d.ts.map +0 -1
  204. package/src/ui/screens/internal/SignInPasswordStep.tsx +0 -184
  205. package/src/ui/screens/internal/SignInUsernameStep.tsx +0 -145
  206. package/src/ui/screens/internal/SignUpIdentityStep.tsx +0 -112
  207. package/src/ui/screens/internal/SignUpSecurityStep.tsx +0 -132
  208. package/src/ui/screens/internal/SignUpSummaryStep.tsx +0 -66
  209. package/src/ui/screens/internal/SignUpWelcomeStep.tsx +0 -52
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Analytics Methods Mixin
3
+ *
4
+ * Provides methods for analytics tracking and data retrieval
5
+ */
6
+ import type { OxyServicesBase } from '../OxyServices.base';
7
+ import { CACHE_TIMES } from './mixinHelpers';
8
+
9
+ export function OxyServicesAnalyticsMixin<T extends typeof OxyServicesBase>(Base: T) {
10
+ return class extends Base {
11
+ constructor(...args: any[]) {
12
+ super(...(args as [any]));
13
+ }
14
+
15
+ /**
16
+ * Track an analytics event
17
+ * @param eventName - Name of the event to track
18
+ * @param properties - Optional event properties
19
+ */
20
+ async trackEvent(eventName: string, properties?: Record<string, any>): Promise<void> {
21
+ try {
22
+ await this.makeRequest('POST', '/api/analytics/events', {
23
+ event: eventName,
24
+ properties
25
+ }, { cache: false, retry: false }); // Don't retry analytics events
26
+ } catch (error) {
27
+ throw this.handleError(error);
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Get analytics data for a date range
33
+ * @param startDate - Optional start date (ISO string)
34
+ * @param endDate - Optional end date (ISO string)
35
+ * @returns Analytics data
36
+ */
37
+ async getAnalytics(startDate?: string, endDate?: string): Promise<any> {
38
+ try {
39
+ const params: any = {};
40
+ if (startDate) params.startDate = startDate;
41
+ if (endDate) params.endDate = endDate;
42
+
43
+ return await this.makeRequest('GET', '/api/analytics', params, {
44
+ cache: true,
45
+ cacheTTL: CACHE_TIMES.LONG,
46
+ });
47
+ } catch (error) {
48
+ throw this.handleError(error);
49
+ }
50
+ }
51
+ };
52
+ }
53
+
@@ -0,0 +1,390 @@
1
+ /**
2
+ * Asset & File Methods Mixin
3
+ */
4
+ import type { AssetInitResponse, AssetUrlResponse, AssetVariant } from '../../models/interfaces';
5
+ import type { OxyServicesBase } from '../OxyServices.base';
6
+
7
+ export function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>(Base: T) {
8
+ return class extends Base {
9
+ constructor(...args: any[]) {
10
+ super(...(args as [any]));
11
+ }
12
+ // ============================================================================
13
+ // FILE METHODS (LEGACY - Using Asset Service)
14
+ // ============================================================================
15
+
16
+ /**
17
+ * Delete file
18
+ */
19
+ async deleteFile(fileId: string): Promise<any> {
20
+ try {
21
+ // Central Asset Service delete with force=true behavior controlled by caller via assetDelete
22
+ return await this.makeRequest('DELETE', `/api/assets/${encodeURIComponent(fileId)}`, undefined, { cache: false });
23
+ } catch (error) {
24
+ throw this.handleError(error);
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Get file download URL (API streaming proxy, attaches token for <img src>)
30
+ */
31
+ getFileDownloadUrl(fileId: string, variant?: string, expiresIn?: number): string {
32
+ const base = this.getBaseURL();
33
+ const params = new URLSearchParams();
34
+ if (variant) params.set('variant', variant);
35
+ if (expiresIn) params.set('expiresIn', String(expiresIn));
36
+ params.set('fallback', 'placeholderVisible');
37
+ const token = this.getClient().getAccessToken();
38
+ if (token) params.set('token', token);
39
+
40
+ // Use params.toString() to detect whether there are query params.
41
+ // URLSearchParams.size is not a standard property across all JS runtimes
42
+ // (some environments like React Native may not implement it), which
43
+ // caused the query string to be omitted on native. Checking the
44
+ // serialized string is reliable everywhere.
45
+ const qs = params.toString();
46
+ return `${base}/api/assets/${encodeURIComponent(fileId)}/stream${qs ? `?${qs}` : ''}`;
47
+ }
48
+
49
+ /**
50
+ * Get file stream URL (direct Oxy Cloud/CDN URL, no token)
51
+ */
52
+ getFileStreamUrl(fileId: string): string {
53
+ return `${this.getCloudURL()}/files/${fileId}/stream`;
54
+ }
55
+
56
+ /**
57
+ * List user files
58
+ */
59
+ async listUserFiles(limit?: number, offset?: number): Promise<{ files: any[]; total: number; hasMore: boolean }> {
60
+ try {
61
+ const paramsObj: any = {};
62
+ if (limit) paramsObj.limit = limit;
63
+ if (offset) paramsObj.offset = offset;
64
+ return await this.makeRequest('GET', '/api/assets', paramsObj, {
65
+ cache: false, // Don't cache file lists - always get fresh data
66
+ });
67
+ } catch (error) {
68
+ throw this.handleError(error);
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Get file content as text
74
+ */
75
+ async getFileContentAsText(fileId: string, variant?: string): Promise<string> {
76
+ try {
77
+ const params: any = variant ? { variant } : undefined;
78
+ const urlRes = await this.makeRequest<{ url: string }>('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
79
+ cache: true,
80
+ cacheTTL: 10 * 60 * 1000, // 10 minutes cache for URLs
81
+ });
82
+ const downloadUrl = urlRes?.url;
83
+ const response = await fetch(downloadUrl);
84
+ return await response.text();
85
+ } catch (error) {
86
+ throw this.handleError(error);
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Get file content as blob
92
+ */
93
+ async getFileContentAsBlob(fileId: string, variant?: string): Promise<Blob> {
94
+ try {
95
+ const params: any = variant ? { variant } : undefined;
96
+ const urlRes = await this.makeRequest<{ url: string }>('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
97
+ cache: true,
98
+ cacheTTL: 10 * 60 * 1000, // 10 minutes cache for URLs
99
+ });
100
+ const downloadUrl = urlRes?.url;
101
+ const response = await fetch(downloadUrl);
102
+ return await response.blob();
103
+ } catch (error) {
104
+ throw this.handleError(error);
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Upload raw file data
110
+ */
111
+ async uploadRawFile(file: File | Blob, visibility?: 'private' | 'public' | 'unlisted', metadata?: Record<string, any>): Promise<any> {
112
+ // Switch to Central Asset Service upload flow
113
+ return this.assetUpload(file as File, visibility, metadata);
114
+ }
115
+
116
+ // ============================================================================
117
+ // CENTRAL ASSET SERVICE METHODS
118
+ // ============================================================================
119
+
120
+ /**
121
+ * Calculate SHA256 hash of file content
122
+ */
123
+ async calculateSHA256(file: File | Blob): Promise<string> {
124
+ const buffer = await file.arrayBuffer();
125
+ const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
126
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
127
+ return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
128
+ }
129
+
130
+ /**
131
+ * Initialize asset upload - returns pre-signed URL and file ID
132
+ */
133
+ async assetInit(sha256: string, size: number, mime: string): Promise<AssetInitResponse> {
134
+ try {
135
+ return await this.makeRequest<AssetInitResponse>('POST', '/api/assets/init', {
136
+ sha256,
137
+ size,
138
+ mime
139
+ }, { cache: false });
140
+ } catch (error) {
141
+ throw this.handleError(error);
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Complete asset upload - commit metadata and trigger variant generation
147
+ */
148
+ async assetComplete(fileId: string, originalName: string, size: number, mime: string, visibility?: 'private' | 'public' | 'unlisted', metadata?: Record<string, any>): Promise<any> {
149
+ try {
150
+ return await this.makeRequest('POST', '/api/assets/complete', {
151
+ fileId,
152
+ originalName,
153
+ size,
154
+ mime,
155
+ visibility,
156
+ metadata
157
+ }, { cache: false });
158
+ } catch (error) {
159
+ throw this.handleError(error);
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Upload file using Central Asset Service
165
+ */
166
+ async assetUpload(file: File, visibility?: 'private' | 'public' | 'unlisted', metadata?: Record<string, any>, onProgress?: (progress: number) => void): Promise<any> {
167
+ try {
168
+ // Calculate SHA256
169
+ const sha256 = await this.calculateSHA256(file);
170
+
171
+ // Initialize upload
172
+ const initResponse = await this.assetInit(sha256, file.size, file.type);
173
+
174
+ // Try presigned URL first
175
+ try {
176
+ await this.uploadToPresignedUrl(initResponse.uploadUrl, file, onProgress);
177
+ } catch (e) {
178
+ // Fallback: direct upload via API to avoid CORS issues
179
+ const fd = new FormData();
180
+ fd.append('file', file);
181
+ // Use httpClient directly for FormData uploads (bypasses RequestManager for special handling)
182
+ await this.getClient().request({
183
+ method: 'POST',
184
+ url: `/api/assets/${encodeURIComponent(initResponse.fileId)}/upload-direct`,
185
+ data: fd,
186
+ });
187
+ }
188
+
189
+ // Complete upload
190
+ return await this.assetComplete(
191
+ initResponse.fileId,
192
+ file.name,
193
+ file.size,
194
+ file.type,
195
+ visibility,
196
+ metadata
197
+ );
198
+ } catch (error) {
199
+ throw this.handleError(error);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Upload file to pre-signed URL
205
+ */
206
+ public async uploadToPresignedUrl(url: string, file: File, onProgress?: (progress: number) => void): Promise<void> {
207
+ return new Promise((resolve, reject) => {
208
+ const xhr = new XMLHttpRequest();
209
+
210
+ xhr.upload.addEventListener('progress', (event) => {
211
+ if (event.lengthComputable && onProgress) {
212
+ const progress = (event.loaded / event.total) * 100;
213
+ onProgress(progress);
214
+ }
215
+ });
216
+
217
+ xhr.addEventListener('load', () => {
218
+ if (xhr.status >= 200 && xhr.status < 300) {
219
+ resolve();
220
+ } else {
221
+ reject(new Error(`Upload failed with status ${xhr.status}`));
222
+ }
223
+ });
224
+
225
+ xhr.addEventListener('error', () => {
226
+ reject(new Error('Upload failed'));
227
+ });
228
+
229
+ xhr.open('PUT', url);
230
+ xhr.setRequestHeader('Content-Type', file.type);
231
+ xhr.send(file);
232
+ });
233
+ }
234
+
235
+ /**
236
+ * Link asset to an entity
237
+ */
238
+ async assetLink(fileId: string, app: string, entityType: string, entityId: string, visibility?: 'private' | 'public' | 'unlisted', webhookUrl?: string): Promise<any> {
239
+ try {
240
+ const body: any = { app, entityType, entityId };
241
+ if (visibility) body.visibility = visibility;
242
+ if (webhookUrl) body.webhookUrl = webhookUrl;
243
+ return await this.makeRequest('POST', `/api/assets/${fileId}/links`, body, { cache: false });
244
+ } catch (error) {
245
+ throw this.handleError(error);
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Unlink asset from an entity
251
+ */
252
+ async assetUnlink(fileId: string, app: string, entityType: string, entityId: string): Promise<any> {
253
+ try {
254
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}/links`, {
255
+ app,
256
+ entityType,
257
+ entityId
258
+ }, { cache: false });
259
+ } catch (error) {
260
+ throw this.handleError(error);
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Get asset metadata
266
+ */
267
+ async assetGet(fileId: string): Promise<any> {
268
+ try {
269
+ return await this.makeRequest('GET', `/api/assets/${fileId}`, undefined, {
270
+ cache: true,
271
+ cacheTTL: 5 * 60 * 1000, // 5 minutes cache
272
+ });
273
+ } catch (error) {
274
+ throw this.handleError(error);
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Get asset URL (CDN or signed URL)
280
+ */
281
+ async assetGetUrl(fileId: string, variant?: string, expiresIn?: number): Promise<AssetUrlResponse> {
282
+ try {
283
+ const params: any = {};
284
+ if (variant) params.variant = variant;
285
+ if (expiresIn) params.expiresIn = expiresIn;
286
+
287
+ return await this.makeRequest<AssetUrlResponse>('GET', `/api/assets/${fileId}/url`, params, {
288
+ cache: true,
289
+ cacheTTL: 10 * 60 * 1000, // 10 minutes cache for URLs
290
+ });
291
+ } catch (error) {
292
+ throw this.handleError(error);
293
+ }
294
+ }
295
+
296
+ /**
297
+ * Restore asset from trash
298
+ */
299
+ async assetRestore(fileId: string): Promise<any> {
300
+ try {
301
+ return await this.makeRequest('POST', `/api/assets/${fileId}/restore`, undefined, { cache: false });
302
+ } catch (error) {
303
+ throw this.handleError(error);
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Delete asset with optional force
309
+ */
310
+ async assetDelete(fileId: string, force: boolean = false): Promise<any> {
311
+ try {
312
+ const params: any = force ? { force: 'true' } : undefined;
313
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}`, params, { cache: false });
314
+ } catch (error) {
315
+ throw this.handleError(error);
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Get list of available variants for an asset
321
+ */
322
+ async assetGetVariants(fileId: string): Promise<AssetVariant[]> {
323
+ try {
324
+ const assetData = await this.assetGet(fileId);
325
+ return assetData.file?.variants || [];
326
+ } catch (error) {
327
+ throw this.handleError(error);
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Update asset visibility
333
+ * @param fileId - The file ID
334
+ * @param visibility - New visibility level ('private', 'public', or 'unlisted')
335
+ * @returns Updated asset information
336
+ */
337
+ async assetUpdateVisibility(fileId: string, visibility: 'private' | 'public' | 'unlisted'): Promise<any> {
338
+ try {
339
+ return await this.makeRequest('PATCH', `/api/assets/${fileId}/visibility`, {
340
+ visibility
341
+ }, { cache: false });
342
+ } catch (error) {
343
+ throw this.handleError(error);
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Helper: Upload and link avatar with automatic public visibility
349
+ * @param file - The avatar file
350
+ * @param userId - User ID to link to
351
+ * @param app - App name (defaults to 'profiles')
352
+ * @returns The uploaded and linked asset
353
+ */
354
+ async uploadAvatar(file: File, userId: string, app: string = 'profiles'): Promise<any> {
355
+ try {
356
+ // Upload as public
357
+ const asset = await this.assetUpload(file, 'public');
358
+
359
+ // Link to user profile as avatar
360
+ await this.assetLink(asset.file.id, app, 'avatar', userId, 'public');
361
+
362
+ return asset;
363
+ } catch (error) {
364
+ throw this.handleError(error);
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Helper: Upload and link profile banner with automatic public visibility
370
+ * @param file - The banner file
371
+ * @param userId - User ID to link to
372
+ * @param app - App name (defaults to 'profiles')
373
+ * @returns The uploaded and linked asset
374
+ */
375
+ async uploadProfileBanner(file: File, userId: string, app: string = 'profiles'): Promise<any> {
376
+ try {
377
+ // Upload as public
378
+ const asset = await this.assetUpload(file, 'public');
379
+
380
+ // Link to user profile as banner
381
+ await this.assetLink(asset.file.id, app, 'profile-banner', userId, 'public');
382
+
383
+ return asset;
384
+ } catch (error) {
385
+ throw this.handleError(error);
386
+ }
387
+ }
388
+ };
389
+ }
390
+