@oxyhq/services 5.13.26 → 5.13.27

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 (54) hide show
  1. package/README.md +5 -6
  2. package/lib/commonjs/core/OxyServices.js +2 -2
  3. package/lib/commonjs/core/mixins/OxyServices.assets.js +0 -7
  4. package/lib/commonjs/core/mixins/OxyServices.assets.js.map +1 -1
  5. package/lib/commonjs/index.js +15 -0
  6. package/lib/commonjs/index.js.map +1 -1
  7. package/lib/commonjs/ui/components/ProfileCard.js +5 -1
  8. package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
  9. package/lib/commonjs/ui/hooks/index.js +13 -0
  10. package/lib/commonjs/ui/hooks/index.js.map +1 -1
  11. package/lib/commonjs/ui/hooks/useFileDownloadUrl.js +103 -0
  12. package/lib/commonjs/ui/hooks/useFileDownloadUrl.js.map +1 -0
  13. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +1 -1
  14. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  15. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +0 -3
  16. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  17. package/lib/module/core/OxyServices.js +2 -2
  18. package/lib/module/core/mixins/OxyServices.assets.js +0 -7
  19. package/lib/module/core/mixins/OxyServices.assets.js.map +1 -1
  20. package/lib/module/index.js +1 -0
  21. package/lib/module/index.js.map +1 -1
  22. package/lib/module/ui/components/ProfileCard.js +5 -1
  23. package/lib/module/ui/components/ProfileCard.js.map +1 -1
  24. package/lib/module/ui/hooks/index.js +1 -0
  25. package/lib/module/ui/hooks/index.js.map +1 -1
  26. package/lib/module/ui/hooks/useFileDownloadUrl.js +97 -0
  27. package/lib/module/ui/hooks/useFileDownloadUrl.js.map +1 -0
  28. package/lib/module/ui/screens/AccountOverviewScreen.js +1 -1
  29. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  30. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +1 -4
  31. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  32. package/lib/typescript/core/OxyServices.d.ts +2 -2
  33. package/lib/typescript/core/mixins/OxyServices.assets.d.ts +0 -4
  34. package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -1
  35. package/lib/typescript/core/mixins/index.d.ts +0 -1
  36. package/lib/typescript/core/mixins/index.d.ts.map +1 -1
  37. package/lib/typescript/index.d.ts +1 -0
  38. package/lib/typescript/index.d.ts.map +1 -1
  39. package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -1
  40. package/lib/typescript/ui/hooks/index.d.ts +1 -0
  41. package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
  42. package/lib/typescript/ui/hooks/useFileDownloadUrl.d.ts +19 -0
  43. package/lib/typescript/ui/hooks/useFileDownloadUrl.d.ts.map +1 -0
  44. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  45. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -1
  46. package/package.json +1 -1
  47. package/src/core/OxyServices.ts +2 -2
  48. package/src/core/mixins/OxyServices.assets.ts +0 -7
  49. package/src/index.ts +1 -0
  50. package/src/ui/components/ProfileCard.tsx +4 -1
  51. package/src/ui/hooks/index.ts +2 -1
  52. package/src/ui/hooks/useFileDownloadUrl.ts +118 -0
  53. package/src/ui/screens/AccountOverviewScreen.tsx +4 -1
  54. package/src/ui/screens/karma/KarmaFAQScreen.tsx +1 -5
@@ -22,8 +22,8 @@
22
22
  * const file = fileInput.files[0];
23
23
  * await oxy.uploadRawFile(file);
24
24
  *
25
- * // Get a file stream URL for <img src>
26
- * const url = oxy.getFileStreamUrl('fileId');
25
+ * // Get a file download URL for <img src>
26
+ * const url = oxy.getFileDownloadUrl('fileId', 'thumb');
27
27
  * ```
28
28
  *
29
29
  * ## Node.js (CommonJS/TypeScript)
@@ -66,13 +66,6 @@ export function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>(Base: T
66
66
  }
67
67
  }
68
68
 
69
- /**
70
- * Get file stream URL (direct Oxy Cloud/CDN URL, no token)
71
- */
72
- getFileStreamUrl(fileId: string): string {
73
- return `${this.getCloudURL()}/files/${fileId}/stream`;
74
- }
75
-
76
69
  /**
77
70
  * List user files
78
71
  */
package/src/index.ts CHANGED
@@ -97,6 +97,7 @@ export { useAuthStore } from './ui/stores/authStore';
97
97
  export { useAssetStore, useAssets as useAssetsStore, useAsset, useUploadProgress, useAssetLoading, useAssetErrors, useAssetsByApp, useAssetsByEntity, useAssetUsageCount, useIsAssetLinked } from './ui/stores/assetStore';
98
98
  export { useSessionSocket } from './ui/hooks/useSessionSocket';
99
99
  export { useAssets, setOxyAssetInstance } from './ui/hooks/useAssets';
100
+ export { useFileDownloadUrl, setOxyFileUrlInstance } from './ui/hooks/useFileDownloadUrl';
100
101
 
101
102
  // UI components
102
103
  export { OxySignInButton } from './ui/components/OxySignInButton';
@@ -4,6 +4,7 @@ import { Ionicons } from '@expo/vector-icons';
4
4
  import { useI18n } from '../hooks/useI18n';
5
5
  import Avatar from './Avatar';
6
6
  import { useOxy } from '../context/OxyContext';
7
+ import { useFileDownloadUrl } from '../hooks';
7
8
  import { fontFamilies } from '../styles/fonts';
8
9
 
9
10
  interface ProfileCardProps {
@@ -33,6 +34,8 @@ const ProfileCard: React.FC<ProfileCardProps> = ({
33
34
  const secondaryBackgroundColor = isDarkTheme ? '#222222' : '#FFFFFF';
34
35
  const primaryColor = '#0066CC';
35
36
 
37
+ const avatarUrl = useFileDownloadUrl(user?.avatar, { variant: 'thumb' }).url || undefined;
38
+
36
39
  return (
37
40
  <View style={styles.headerSection}>
38
41
  <View style={[
@@ -43,7 +46,7 @@ const ProfileCard: React.FC<ProfileCardProps> = ({
43
46
  ]}>
44
47
  <View style={styles.userProfile}>
45
48
  <Avatar
46
- uri={user?.avatar ? oxyServices.getFileDownloadUrl(user.avatar as string, 'thumb') : undefined}
49
+ uri={user?.avatar ? avatarUrl : undefined}
47
50
  name={user?.name?.full || user?.username}
48
51
  size={60}
49
52
  theme={theme}
@@ -1 +1,2 @@
1
- export { useFollow, useFollowerCounts } from './useFollow';
1
+ export { useFollow, useFollowerCounts } from './useFollow';
2
+ export { useFileDownloadUrl, setOxyFileUrlInstance } from './useFileDownloadUrl';
@@ -0,0 +1,118 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { OxyServices } from '../../core/OxyServices';
3
+
4
+ let oxyInstance: OxyServices | null = null;
5
+
6
+ export const setOxyFileUrlInstance = (instance: OxyServices) => {
7
+ oxyInstance = instance;
8
+ };
9
+
10
+ export interface UseFileDownloadUrlOptions {
11
+ variant?: string;
12
+ expiresIn?: number;
13
+ }
14
+
15
+ export interface UseFileDownloadUrlResult {
16
+ url: string | null;
17
+ loading: boolean;
18
+ error: Error | null;
19
+ }
20
+
21
+ /**
22
+ * Hook to resolve a file's download URL asynchronously.
23
+ *
24
+ * Prefers `getFileDownloadUrlAsync` and falls back to the synchronous
25
+ * `getFileDownloadUrl` helper if the async call fails.
26
+ */
27
+ export const useFileDownloadUrl = (
28
+ fileId?: string | null,
29
+ options?: UseFileDownloadUrlOptions
30
+ ): UseFileDownloadUrlResult => {
31
+ const [url, setUrl] = useState<string | null>(null);
32
+ const [loading, setLoading] = useState(false);
33
+ const [error, setError] = useState<Error | null>(null);
34
+
35
+ useEffect(() => {
36
+ if (!fileId) {
37
+ setUrl(null);
38
+ setLoading(false);
39
+ setError(null);
40
+ return;
41
+ }
42
+
43
+ if (!oxyInstance) {
44
+ // Fail silently but don't crash the UI – caller can decide what to do with null URL.
45
+ setUrl(null);
46
+ setLoading(false);
47
+ setError(new Error('OxyServices instance not configured for useFileDownloadUrl'));
48
+ return;
49
+ }
50
+
51
+ let cancelled = false;
52
+
53
+ const load = async () => {
54
+ setLoading(true);
55
+ setError(null);
56
+
57
+ // Store instance in local variable for TypeScript null checking
58
+ const instance = oxyInstance;
59
+ if (!instance) {
60
+ setLoading(false);
61
+ setError(new Error('OxyServices instance not configured for useFileDownloadUrl'));
62
+ return;
63
+ }
64
+
65
+ try {
66
+ const { variant, expiresIn } = options || {};
67
+ let resolvedUrl: string | null = null;
68
+
69
+ if (typeof instance.getFileDownloadUrlAsync === 'function') {
70
+ resolvedUrl = await instance.getFileDownloadUrlAsync(fileId, variant, expiresIn);
71
+ }
72
+
73
+ if (!resolvedUrl && typeof instance.getFileDownloadUrl === 'function') {
74
+ resolvedUrl = instance.getFileDownloadUrl(fileId, variant, expiresIn);
75
+ }
76
+
77
+ if (!cancelled) {
78
+ setUrl(resolvedUrl || null);
79
+ }
80
+ } catch (err: any) {
81
+ // Fallback to sync URL on error where possible
82
+ try {
83
+ if (typeof instance.getFileDownloadUrl === 'function') {
84
+ const { variant, expiresIn } = options || {};
85
+ const fallbackUrl = instance.getFileDownloadUrl(fileId, variant, expiresIn);
86
+ if (!cancelled) {
87
+ setUrl(fallbackUrl || null);
88
+ setError(err instanceof Error ? err : new Error(String(err)));
89
+ }
90
+ return;
91
+ }
92
+ } catch {
93
+ // ignore secondary failure, we'll surface the original error below
94
+ }
95
+
96
+ if (!cancelled) {
97
+ setError(err instanceof Error ? err : new Error(String(err)));
98
+ }
99
+ } finally {
100
+ if (!cancelled) {
101
+ setLoading(false);
102
+ }
103
+ }
104
+ };
105
+
106
+ load();
107
+
108
+ return () => {
109
+ cancelled = true;
110
+ };
111
+ }, [fileId, options?.variant, options?.expiresIn]);
112
+
113
+ return { url, loading, error };
114
+ };
115
+
116
+
117
+
118
+
@@ -420,7 +420,10 @@ const AccountOverviewScreen: React.FC<BaseScreenProps> = ({
420
420
  <>
421
421
  <View style={styles.userIcon}>
422
422
  {account.avatar ? (
423
- <Image source={{ uri: oxyServices.getFileStreamUrl(account.avatar as string) }} style={styles.accountAvatarImage} />
423
+ <Image
424
+ source={{ uri: oxyServices.getFileDownloadUrl(account.avatar as string, 'thumb') }}
425
+ style={styles.accountAvatarImage}
426
+ />
424
427
  ) : (
425
428
  <View style={styles.accountAvatarFallback}>
426
429
  <Text style={styles.accountAvatarText}>
@@ -1,14 +1,10 @@
1
1
  import React, { useState, useMemo, useCallback } from 'react';
2
- import { View, Text, StyleSheet, ScrollView, Platform, TouchableOpacity, TextInput, LayoutAnimation, UIManager } from 'react-native';
2
+ import { View, Text, StyleSheet, ScrollView, Platform, TouchableOpacity, TextInput, LayoutAnimation } from 'react-native';
3
3
  import type { BaseScreenProps } from '../../navigation/types';
4
4
  import { Ionicons } from '@expo/vector-icons';
5
5
  import { Header } from '../../components';
6
6
  import { useI18n } from '../../hooks/useI18n';
7
7
 
8
- if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
9
- UIManager.setLayoutAnimationEnabledExperimental(true);
10
- }
11
-
12
8
  const FAQ_KEYS = ['what', 'earn', 'lose', 'use', 'transfer', 'support'] as const;
13
9
 
14
10
  /**