@oxyhq/services 5.12.11 → 5.13.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/lib/commonjs/core/OxyServices.js +83 -5
- package/lib/commonjs/core/OxyServices.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +56 -5
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/core/OxyServices.js +83 -5
- package/lib/module/core/OxyServices.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +56 -5
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/typescript/core/OxyServices.d.ts +35 -1
- package/lib/typescript/core/OxyServices.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts +10 -0
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/OxyServices.ts +91 -7
- package/src/ui/screens/FileManagementScreen.tsx +81 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/services",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.13.0",
|
|
4
4
|
"description": "Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
package/src/core/OxyServices.ts
CHANGED
|
@@ -1349,14 +1349,12 @@ export class OxyServices {
|
|
|
1349
1349
|
/**
|
|
1350
1350
|
* Link asset to an entity
|
|
1351
1351
|
*/
|
|
1352
|
-
async assetLink(fileId: string, app: string, entityType: string, entityId: string, visibility?: 'private' | 'public' | 'unlisted'): Promise<any> {
|
|
1352
|
+
async assetLink(fileId: string, app: string, entityType: string, entityId: string, visibility?: 'private' | 'public' | 'unlisted', webhookUrl?: string): Promise<any> {
|
|
1353
1353
|
try {
|
|
1354
|
-
const
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
visibility
|
|
1359
|
-
});
|
|
1354
|
+
const body: any = { app, entityType, entityId };
|
|
1355
|
+
if (visibility) body.visibility = visibility;
|
|
1356
|
+
if (webhookUrl) body.webhookUrl = webhookUrl;
|
|
1357
|
+
const res = await this.client.post(`/api/assets/${fileId}/links`, body);
|
|
1360
1358
|
return res.data;
|
|
1361
1359
|
} catch (error) {
|
|
1362
1360
|
throw this.handleError(error);
|
|
@@ -1508,6 +1506,92 @@ export class OxyServices {
|
|
|
1508
1506
|
}
|
|
1509
1507
|
}
|
|
1510
1508
|
|
|
1509
|
+
// ============================================================================
|
|
1510
|
+
// DEVELOPER API METHODS
|
|
1511
|
+
// ============================================================================
|
|
1512
|
+
|
|
1513
|
+
/**
|
|
1514
|
+
* Get developer apps for the current user
|
|
1515
|
+
*/
|
|
1516
|
+
async getDeveloperApps(): Promise<any[]> {
|
|
1517
|
+
try {
|
|
1518
|
+
const res = await this.client.get('/api/developer/apps');
|
|
1519
|
+
return res.data;
|
|
1520
|
+
} catch (error) {
|
|
1521
|
+
throw this.handleError(error);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
/**
|
|
1526
|
+
* Create a new developer app
|
|
1527
|
+
*/
|
|
1528
|
+
async createDeveloperApp(data: {
|
|
1529
|
+
name: string;
|
|
1530
|
+
description?: string;
|
|
1531
|
+
webhookUrl?: string;
|
|
1532
|
+
scopes?: string[];
|
|
1533
|
+
}): Promise<any> {
|
|
1534
|
+
try {
|
|
1535
|
+
const res = await this.client.post('/api/developer/apps', data);
|
|
1536
|
+
return res.data;
|
|
1537
|
+
} catch (error) {
|
|
1538
|
+
throw this.handleError(error);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* Get a specific developer app
|
|
1544
|
+
*/
|
|
1545
|
+
async getDeveloperApp(appId: string): Promise<any> {
|
|
1546
|
+
try {
|
|
1547
|
+
const res = await this.client.get(`/api/developer/apps/${appId}`);
|
|
1548
|
+
return res.data;
|
|
1549
|
+
} catch (error) {
|
|
1550
|
+
throw this.handleError(error);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
/**
|
|
1555
|
+
* Update a developer app
|
|
1556
|
+
*/
|
|
1557
|
+
async updateDeveloperApp(appId: string, data: {
|
|
1558
|
+
name?: string;
|
|
1559
|
+
description?: string;
|
|
1560
|
+
webhookUrl?: string;
|
|
1561
|
+
scopes?: string[];
|
|
1562
|
+
}): Promise<any> {
|
|
1563
|
+
try {
|
|
1564
|
+
const res = await this.client.patch(`/api/developer/apps/${appId}`, data);
|
|
1565
|
+
return res.data;
|
|
1566
|
+
} catch (error) {
|
|
1567
|
+
throw this.handleError(error);
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
/**
|
|
1572
|
+
* Regenerate API secret for a developer app
|
|
1573
|
+
*/
|
|
1574
|
+
async regenerateDeveloperAppSecret(appId: string): Promise<any> {
|
|
1575
|
+
try {
|
|
1576
|
+
const res = await this.client.post(`/api/developer/apps/${appId}/regenerate-secret`);
|
|
1577
|
+
return res.data;
|
|
1578
|
+
} catch (error) {
|
|
1579
|
+
throw this.handleError(error);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
/**
|
|
1584
|
+
* Delete a developer app
|
|
1585
|
+
*/
|
|
1586
|
+
async deleteDeveloperApp(appId: string): Promise<any> {
|
|
1587
|
+
try {
|
|
1588
|
+
const res = await this.client.delete(`/api/developer/apps/${appId}`);
|
|
1589
|
+
return res.data;
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
throw this.handleError(error);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1511
1595
|
// ============================================================================
|
|
1512
1596
|
// LOCATION METHODS
|
|
1513
1597
|
// ============================================================================
|
|
@@ -55,6 +55,16 @@ export interface FileManagementScreenProps extends BaseScreenProps {
|
|
|
55
55
|
* Useful for third-party apps that want files to be public (e.g., GIF selector)
|
|
56
56
|
*/
|
|
57
57
|
defaultVisibility?: 'private' | 'public' | 'unlisted';
|
|
58
|
+
/**
|
|
59
|
+
* Link context for tracking file usage by third-party apps
|
|
60
|
+
* When provided, selected files will be linked to this entity
|
|
61
|
+
*/
|
|
62
|
+
linkContext?: {
|
|
63
|
+
app: string; // App identifier (e.g., 'chat-app', 'post-composer')
|
|
64
|
+
entityType: string; // Type of entity (e.g., 'message', 'post', 'profile')
|
|
65
|
+
entityId: string; // Unique ID of the entity using this file
|
|
66
|
+
webhookUrl?: string; // Optional webhook URL to receive file events
|
|
67
|
+
};
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
// Add this helper function near the top (after imports):
|
|
@@ -79,6 +89,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
79
89
|
afterSelect = 'close',
|
|
80
90
|
allowUploadInSelectMode = true,
|
|
81
91
|
defaultVisibility = 'private',
|
|
92
|
+
linkContext,
|
|
82
93
|
}) => {
|
|
83
94
|
const { user, oxyServices } = useOxy();
|
|
84
95
|
|
|
@@ -139,7 +150,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
139
150
|
}
|
|
140
151
|
}, [initialSelectedIds]);
|
|
141
152
|
|
|
142
|
-
const toggleSelect = useCallback((file: FileMetadata) => {
|
|
153
|
+
const toggleSelect = useCallback(async (file: FileMetadata) => {
|
|
143
154
|
if (!selectMode) return;
|
|
144
155
|
if (disabledMimeTypes.length) {
|
|
145
156
|
const blocked = disabledMimeTypes.some(mt => file.contentType === mt || file.contentType.startsWith(mt.endsWith('/') ? mt : mt + '/'));
|
|
@@ -148,6 +159,37 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
148
159
|
return;
|
|
149
160
|
}
|
|
150
161
|
}
|
|
162
|
+
|
|
163
|
+
// Update file visibility if it differs from defaultVisibility
|
|
164
|
+
const fileVisibility = (file.metadata as any)?.visibility || 'private';
|
|
165
|
+
if (fileVisibility !== defaultVisibility) {
|
|
166
|
+
try {
|
|
167
|
+
await oxyServices.assetUpdateVisibility(file.id, defaultVisibility);
|
|
168
|
+
console.log(`Updated file ${file.id} visibility from ${fileVisibility} to ${defaultVisibility}`);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error('Failed to update file visibility:', error);
|
|
171
|
+
// Continue anyway - selection shouldn't fail if visibility update fails
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Link file to entity if linkContext is provided
|
|
176
|
+
if (linkContext) {
|
|
177
|
+
try {
|
|
178
|
+
await oxyServices.assetLink(
|
|
179
|
+
file.id,
|
|
180
|
+
linkContext.app,
|
|
181
|
+
linkContext.entityType,
|
|
182
|
+
linkContext.entityId,
|
|
183
|
+
defaultVisibility,
|
|
184
|
+
(linkContext as any).webhookUrl
|
|
185
|
+
);
|
|
186
|
+
console.log(`Linked file ${file.id} to ${linkContext.app}/${linkContext.entityType}/${linkContext.entityId}`);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.error('Failed to link file:', error);
|
|
189
|
+
// Continue anyway - selection shouldn't fail if linking fails
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
151
193
|
if (!multiSelect) {
|
|
152
194
|
onSelect?.(file);
|
|
153
195
|
if (afterSelect === 'back') {
|
|
@@ -171,16 +213,51 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
171
213
|
}
|
|
172
214
|
return next;
|
|
173
215
|
});
|
|
174
|
-
}, [selectMode, multiSelect, onSelect, onClose, goBack, disabledMimeTypes, maxSelection, afterSelect]);
|
|
216
|
+
}, [selectMode, multiSelect, onSelect, onClose, goBack, disabledMimeTypes, maxSelection, afterSelect, defaultVisibility, oxyServices, linkContext]);
|
|
175
217
|
|
|
176
|
-
const confirmMultiSelection = useCallback(() => {
|
|
218
|
+
const confirmMultiSelection = useCallback(async () => {
|
|
177
219
|
if (!selectMode || !multiSelect) return;
|
|
178
220
|
const map: Record<string, FileMetadata> = {};
|
|
179
221
|
files.forEach(f => { map[f.id] = f; });
|
|
180
222
|
const chosen = Array.from(selectedIds).map(id => map[id]).filter(Boolean);
|
|
223
|
+
|
|
224
|
+
// Update visibility and link files if needed
|
|
225
|
+
const updatePromises = chosen.map(async (file) => {
|
|
226
|
+
// Update visibility if needed
|
|
227
|
+
const fileVisibility = (file.metadata as any)?.visibility || 'private';
|
|
228
|
+
if (fileVisibility !== defaultVisibility) {
|
|
229
|
+
try {
|
|
230
|
+
await oxyServices.assetUpdateVisibility(file.id, defaultVisibility);
|
|
231
|
+
console.log(`Updated file ${file.id} visibility from ${fileVisibility} to ${defaultVisibility}`);
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.error(`Failed to update visibility for ${file.id}:`, error);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Link file to entity if linkContext provided
|
|
238
|
+
if (linkContext) {
|
|
239
|
+
try {
|
|
240
|
+
await oxyServices.assetLink(
|
|
241
|
+
file.id,
|
|
242
|
+
linkContext.app,
|
|
243
|
+
linkContext.entityType,
|
|
244
|
+
linkContext.entityId,
|
|
245
|
+
defaultVisibility,
|
|
246
|
+
(linkContext as any).webhookUrl
|
|
247
|
+
);
|
|
248
|
+
console.log(`Linked file ${file.id} to ${linkContext.app}/${linkContext.entityType}/${linkContext.entityId}`);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.error(`Failed to link file ${file.id}:`, error);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Wait for all updates (but don't block on failures)
|
|
256
|
+
await Promise.allSettled(updatePromises);
|
|
257
|
+
|
|
181
258
|
onConfirmSelection?.(chosen);
|
|
182
259
|
onClose?.();
|
|
183
|
-
}, [selectMode, multiSelect, selectedIds, files, onConfirmSelection, onClose]);
|
|
260
|
+
}, [selectMode, multiSelect, selectedIds, files, onConfirmSelection, onClose, defaultVisibility, oxyServices, linkContext]);
|
|
184
261
|
|
|
185
262
|
const endUpload = useCallback(() => {
|
|
186
263
|
const started = uploadStartRef.current;
|