@oxyhq/services 5.13.15 → 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.
- package/README.md +10 -0
- package/lib/commonjs/core/OxyServices.base.js +271 -0
- package/lib/commonjs/core/OxyServices.base.js.map +1 -0
- package/lib/commonjs/core/OxyServices.errors.js +26 -0
- package/lib/commonjs/core/OxyServices.errors.js.map +1 -0
- package/lib/commonjs/core/OxyServices.js +58 -2168
- package/lib/commonjs/core/OxyServices.js.map +1 -1
- package/lib/commonjs/core/mixins/OxyServices.analytics.js +60 -0
- package/lib/commonjs/core/mixins/OxyServices.analytics.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.assets.js +406 -0
- package/lib/commonjs/core/mixins/OxyServices.assets.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.auth.js +303 -0
- package/lib/commonjs/core/mixins/OxyServices.auth.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.developer.js +115 -0
- package/lib/commonjs/core/mixins/OxyServices.developer.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.devices.js +119 -0
- package/lib/commonjs/core/mixins/OxyServices.devices.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.karma.js +117 -0
- package/lib/commonjs/core/mixins/OxyServices.karma.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.language.js +124 -0
- package/lib/commonjs/core/mixins/OxyServices.language.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.location.js +55 -0
- package/lib/commonjs/core/mixins/OxyServices.location.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.payment.js +66 -0
- package/lib/commonjs/core/mixins/OxyServices.payment.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.privacy.js +174 -0
- package/lib/commonjs/core/mixins/OxyServices.privacy.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.totp.js +53 -0
- package/lib/commonjs/core/mixins/OxyServices.totp.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.user.js +389 -0
- package/lib/commonjs/core/mixins/OxyServices.user.js.map +1 -0
- package/lib/commonjs/core/mixins/OxyServices.utility.js +161 -0
- package/lib/commonjs/core/mixins/OxyServices.utility.js.map +1 -0
- package/lib/commonjs/core/mixins/index.js +39 -0
- package/lib/commonjs/core/mixins/index.js.map +1 -0
- package/lib/commonjs/core/mixins/mixinHelpers.js +62 -0
- package/lib/commonjs/core/mixins/mixinHelpers.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +27 -2
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/module/core/OxyServices.base.js +265 -0
- package/lib/module/core/OxyServices.base.js.map +1 -0
- package/lib/module/core/OxyServices.errors.js +20 -0
- package/lib/module/core/OxyServices.errors.js.map +1 -0
- package/lib/module/core/OxyServices.js +43 -2164
- package/lib/module/core/OxyServices.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.analytics.js +56 -0
- package/lib/module/core/mixins/OxyServices.analytics.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.assets.js +402 -0
- package/lib/module/core/mixins/OxyServices.assets.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.auth.js +299 -0
- package/lib/module/core/mixins/OxyServices.auth.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.developer.js +111 -0
- package/lib/module/core/mixins/OxyServices.developer.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.devices.js +115 -0
- package/lib/module/core/mixins/OxyServices.devices.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.karma.js +113 -0
- package/lib/module/core/mixins/OxyServices.karma.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.language.js +120 -0
- package/lib/module/core/mixins/OxyServices.language.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.location.js +51 -0
- package/lib/module/core/mixins/OxyServices.location.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.payment.js +62 -0
- package/lib/module/core/mixins/OxyServices.payment.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.privacy.js +170 -0
- package/lib/module/core/mixins/OxyServices.privacy.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.totp.js +49 -0
- package/lib/module/core/mixins/OxyServices.totp.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.user.js +385 -0
- package/lib/module/core/mixins/OxyServices.user.js.map +1 -0
- package/lib/module/core/mixins/OxyServices.utility.js +156 -0
- package/lib/module/core/mixins/OxyServices.utility.js.map +1 -0
- package/lib/module/core/mixins/index.js +36 -0
- package/lib/module/core/mixins/index.js.map +1 -0
- package/lib/module/core/mixins/mixinHelpers.js +56 -0
- package/lib/module/core/mixins/mixinHelpers.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +27 -2
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/typescript/core/OxyServices.base.d.ts +123 -0
- package/lib/typescript/core/OxyServices.base.d.ts.map +1 -0
- package/lib/typescript/core/OxyServices.d.ts +969 -746
- package/lib/typescript/core/OxyServices.d.ts.map +1 -1
- package/lib/typescript/core/OxyServices.errors.d.ts +12 -0
- package/lib/typescript/core/OxyServices.errors.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.analytics.d.ts +70 -0
- package/lib/typescript/core/mixins/OxyServices.analytics.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.assets.d.ts +159 -0
- package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts +168 -0
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.developer.d.ts +103 -0
- package/lib/typescript/core/mixins/OxyServices.developer.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.devices.d.ts +93 -0
- package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.karma.d.ts +89 -0
- package/lib/typescript/core/mixins/OxyServices.karma.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.language.d.ts +85 -0
- package/lib/typescript/core/mixins/OxyServices.language.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.location.d.ts +68 -0
- package/lib/typescript/core/mixins/OxyServices.location.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.payment.d.ts +74 -0
- package/lib/typescript/core/mixins/OxyServices.payment.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.privacy.d.ts +126 -0
- package/lib/typescript/core/mixins/OxyServices.privacy.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.totp.d.ts +69 -0
- package/lib/typescript/core/mixins/OxyServices.totp.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.user.d.ts +189 -0
- package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -0
- package/lib/typescript/core/mixins/OxyServices.utility.d.ts +97 -0
- package/lib/typescript/core/mixins/OxyServices.utility.d.ts.map +1 -0
- package/lib/typescript/core/mixins/index.d.ts +898 -0
- package/lib/typescript/core/mixins/index.d.ts.map +1 -0
- package/lib/typescript/core/mixins/mixinHelpers.d.ts +32 -0
- package/lib/typescript/core/mixins/mixinHelpers.d.ts.map +1 -0
- package/lib/typescript/models/interfaces.d.ts +10 -0
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +2 -0
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/OxyServices.base.ts +311 -0
- package/src/core/OxyServices.errors.ts +26 -0
- package/src/core/OxyServices.ts +43 -2199
- package/src/core/mixins/OxyServices.analytics.ts +53 -0
- package/src/core/mixins/OxyServices.assets.ts +390 -0
- package/src/core/mixins/OxyServices.auth.ts +275 -0
- package/src/core/mixins/OxyServices.developer.ts +114 -0
- package/src/core/mixins/OxyServices.devices.ts +103 -0
- package/src/core/mixins/OxyServices.karma.ts +111 -0
- package/src/core/mixins/OxyServices.language.ts +127 -0
- package/src/core/mixins/OxyServices.location.ts +46 -0
- package/src/core/mixins/OxyServices.payment.ts +59 -0
- package/src/core/mixins/OxyServices.privacy.ts +182 -0
- package/src/core/mixins/OxyServices.totp.ts +36 -0
- package/src/core/mixins/OxyServices.user.ts +380 -0
- package/src/core/mixins/OxyServices.utility.ts +187 -0
- package/src/core/mixins/index.ts +58 -0
- package/src/core/mixins/mixinHelpers.ts +69 -0
- package/src/models/interfaces.ts +12 -0
- package/src/ui/context/OxyContext.tsx +36 -0
|
@@ -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
|
+
|