@oxyhq/services 6.6.1 → 6.7.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 (80) hide show
  1. package/lib/commonjs/index.js +7 -0
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/components/Avatar.js +12 -3
  4. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  5. package/lib/commonjs/ui/components/ProfileCard.js +1 -1
  6. package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
  7. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +2 -3
  8. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  9. package/lib/commonjs/ui/hooks/useAssets.js +0 -2
  10. package/lib/commonjs/ui/hooks/useAssets.js.map +1 -1
  11. package/lib/commonjs/ui/hooks/useAvatarPicker.js +3 -2
  12. package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
  13. package/lib/commonjs/ui/hooks/useFileDownloadUrl.js +26 -15
  14. package/lib/commonjs/ui/hooks/useFileDownloadUrl.js.map +1 -1
  15. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +2 -2
  16. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  17. package/lib/commonjs/ui/stores/accountStore.js +8 -39
  18. package/lib/commonjs/ui/stores/accountStore.js.map +1 -1
  19. package/lib/commonjs/ui/utils/avatarUtils.js +1 -26
  20. package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
  21. package/lib/commonjs/ui/utils/fileManagement.js +2 -2
  22. package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
  23. package/lib/module/index.js +1 -0
  24. package/lib/module/index.js.map +1 -1
  25. package/lib/module/ui/components/Avatar.js +13 -4
  26. package/lib/module/ui/components/Avatar.js.map +1 -1
  27. package/lib/module/ui/components/ProfileCard.js +1 -1
  28. package/lib/module/ui/components/ProfileCard.js.map +1 -1
  29. package/lib/module/ui/hooks/mutations/useAccountMutations.js +2 -3
  30. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  31. package/lib/module/ui/hooks/useAssets.js +0 -2
  32. package/lib/module/ui/hooks/useAssets.js.map +1 -1
  33. package/lib/module/ui/hooks/useAvatarPicker.js +4 -2
  34. package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
  35. package/lib/module/ui/hooks/useFileDownloadUrl.js +26 -15
  36. package/lib/module/ui/hooks/useFileDownloadUrl.js.map +1 -1
  37. package/lib/module/ui/screens/WelcomeNewUserScreen.js +1 -1
  38. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  39. package/lib/module/ui/stores/accountStore.js +2 -33
  40. package/lib/module/ui/stores/accountStore.js.map +1 -1
  41. package/lib/module/ui/utils/avatarUtils.js +1 -25
  42. package/lib/module/ui/utils/avatarUtils.js.map +1 -1
  43. package/lib/module/ui/utils/fileManagement.js +1 -1
  44. package/lib/module/ui/utils/fileManagement.js.map +1 -1
  45. package/lib/typescript/commonjs/index.d.ts +2 -0
  46. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/ui/components/Avatar.d.ts.map +1 -1
  48. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  49. package/lib/typescript/commonjs/ui/hooks/useAssets.d.ts.map +1 -1
  50. package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/ui/hooks/useFileDownloadUrl.d.ts +6 -3
  52. package/lib/typescript/commonjs/ui/hooks/useFileDownloadUrl.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/ui/stores/accountStore.d.ts +2 -9
  54. package/lib/typescript/commonjs/ui/stores/accountStore.d.ts.map +1 -1
  55. package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts +0 -10
  56. package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
  57. package/lib/typescript/module/index.d.ts +2 -0
  58. package/lib/typescript/module/index.d.ts.map +1 -1
  59. package/lib/typescript/module/ui/components/Avatar.d.ts.map +1 -1
  60. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  61. package/lib/typescript/module/ui/hooks/useAssets.d.ts.map +1 -1
  62. package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
  63. package/lib/typescript/module/ui/hooks/useFileDownloadUrl.d.ts +6 -3
  64. package/lib/typescript/module/ui/hooks/useFileDownloadUrl.d.ts.map +1 -1
  65. package/lib/typescript/module/ui/stores/accountStore.d.ts +2 -9
  66. package/lib/typescript/module/ui/stores/accountStore.d.ts.map +1 -1
  67. package/lib/typescript/module/ui/utils/avatarUtils.d.ts +0 -10
  68. package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
  69. package/package.json +6 -7
  70. package/src/index.ts +2 -0
  71. package/src/ui/components/Avatar.tsx +12 -3
  72. package/src/ui/components/ProfileCard.tsx +1 -1
  73. package/src/ui/hooks/mutations/useAccountMutations.ts +4 -5
  74. package/src/ui/hooks/useAssets.ts +1 -2
  75. package/src/ui/hooks/useAvatarPicker.ts +5 -3
  76. package/src/ui/hooks/useFileDownloadUrl.ts +33 -24
  77. package/src/ui/screens/WelcomeNewUserScreen.tsx +1 -1
  78. package/src/ui/stores/accountStore.ts +15 -47
  79. package/src/ui/utils/avatarUtils.ts +1 -31
  80. package/src/ui/utils/fileManagement.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useAssets.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAssets.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EACL,KAAK,EAGL,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAKrB,eAAO,MAAM,mBAAmB,GAAI,UAAU,WAAW,SAExD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;mBA6BZ,IAAI,aACC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC7B,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;oBAqDb,MAAM,OACV,MAAM,cACC,MAAM,YACR,MAAM,KACf,OAAO,CAAC,IAAI,CAAC;sBAsCL,MAAM,OACV,MAAM,cACC,MAAM,YACR,MAAM,KACf,OAAO,CAAC,IAAI,CAAC;sBA2BL,MAAM,YACL,MAAM,cACJ,MAAM,KACjB,OAAO,CAAC,MAAM,CAAC;wBAc2B,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC;2BAmBzD,MAAM,UACR,OAAO,KACb,OAAO,CAAC,IAAI,CAAC;uBAoB4B,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;2BAgBlB,MAAM;;;;;;;CAuCvD,CAAC"}
1
+ {"version":3,"file":"useAssets.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAssets.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EACL,KAAK,EAGL,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAKrB,eAAO,MAAM,mBAAmB,GAAI,UAAU,WAAW,SAExD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;mBA6BZ,IAAI,aACC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC7B,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;oBAoDb,MAAM,OACV,MAAM,cACC,MAAM,YACR,MAAM,KACf,OAAO,CAAC,IAAI,CAAC;sBAsCL,MAAM,OACV,MAAM,cACC,MAAM,YACR,MAAM,KACf,OAAO,CAAC,IAAI,CAAC;sBA2BL,MAAM,YACL,MAAM,cACJ,MAAM,KACjB,OAAO,CAAC,MAAM,CAAC;wBAc2B,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC;2BAmBzD,MAAM,UACR,OAAO,KACb,OAAO,CAAC,IAAI,CAAC;uBAoB4B,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;2BAgBlB,MAAM;;;;;;;CAuCvD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useAvatarPicker.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAvatarPicker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,UAAU,sBAAsB;IAC9B,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC3C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;CAC3F;AAED,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,eAAe,EACf,eAAe,EACf,WAAW,EACX,eAAe,GAChB,EAAE,sBAAsB;;EAgCxB"}
1
+ {"version":3,"file":"useAvatarPicker.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAvatarPicker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAItD,UAAU,sBAAsB;IAC9B,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC3C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;CAC3F;AAED,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,eAAe,EACf,eAAe,EACf,WAAW,EACX,eAAe,GAChB,EAAE,sBAAsB;;EAiCxB"}
@@ -12,8 +12,11 @@ export interface UseFileDownloadUrlResult {
12
12
  /**
13
13
  * Hook to resolve a file's download URL asynchronously.
14
14
  *
15
- * Prefers `getFileDownloadUrlAsync` and falls back to the synchronous
16
- * `getFileDownloadUrl` helper if the async call fails.
15
+ * Prefers the provided `oxyServices` instance, falls back to the module-level
16
+ * singleton set via `setOxyFileUrlInstance`.
17
+ *
18
+ * Uses `getFileDownloadUrlAsync` first, falling back to the synchronous
19
+ * `getFileDownloadUrl` if the async call fails.
17
20
  */
18
- export declare const useFileDownloadUrl: (fileId?: string | null, options?: UseFileDownloadUrlOptions) => UseFileDownloadUrlResult;
21
+ export declare const useFileDownloadUrl: (fileIdOrServices?: string | OxyServices | null, fileIdOrOptions?: string | UseFileDownloadUrlOptions | null, maybeOptions?: UseFileDownloadUrlOptions) => UseFileDownloadUrlResult;
19
22
  //# sourceMappingURL=useFileDownloadUrl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useFileDownloadUrl.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useFileDownloadUrl.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,eAAO,MAAM,qBAAqB,GAAI,UAAU,WAAW,SAE1D,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,MAAM,GAAG,IAAI,EACtB,UAAU,yBAAyB,KAClC,wBAoFF,CAAC"}
1
+ {"version":3,"file":"useFileDownloadUrl.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useFileDownloadUrl.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,eAAO,MAAM,qBAAqB,GAAI,UAAU,WAAW,SAE1D,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,mBAAmB,MAAM,GAAG,WAAW,GAAG,IAAI,EAC9C,kBAAkB,MAAM,GAAG,yBAAyB,GAAG,IAAI,EAC3D,eAAe,yBAAyB,KACvC,wBA6FF,CAAC"}
@@ -1,12 +1,6 @@
1
1
  import type { OxyServices } from '@oxyhq/core';
2
- export interface QuickAccount {
3
- sessionId: string;
4
- userId?: string;
5
- username: string;
6
- displayName: string;
7
- avatar?: string;
8
- avatarUrl?: string;
9
- }
2
+ import type { QuickAccount } from '@oxyhq/core';
3
+ export type { QuickAccount };
10
4
  interface AccountState {
11
5
  accounts: Record<string, QuickAccount>;
12
6
  accountOrder: string[];
@@ -30,5 +24,4 @@ export declare const useAccounts: () => QuickAccount[];
30
24
  export declare const useAccountLoading: () => boolean;
31
25
  export declare const useAccountError: () => string | null;
32
26
  export declare const useAccountLoadingSession: (sessionId: string) => boolean;
33
- export {};
34
27
  //# sourceMappingURL=accountStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"accountStore.d.ts","sourceRoot":"","sources":["../../../../../src/ui/stores/accountStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,YAAY;IAElB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACvC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,YAAY,EAAE,CAAC;IAG9B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAG/B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAGrB,WAAW,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAChD,UAAU,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IAC3E,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAG9C,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAGjE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAGzC,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,CAAC,EAAE,YAAY,EAAE,EAAE,aAAa,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAG5I,KAAK,EAAE,MAAM,IAAI,CAAC;CACrB;AA4CD,eAAO,MAAM,eAAe,2EAmMzB,CAAC;AAGJ,eAAO,MAAM,WAAW,QAAO,YAAY,EAE1C,CAAC;AAEF,eAAO,MAAM,iBAAiB,eAAwC,CAAC;AACvE,eAAO,MAAM,eAAe,qBAAsC,CAAC;AACnE,eAAO,MAAM,wBAAwB,GAAI,WAAW,MAAM,YACE,CAAC"}
1
+ {"version":3,"file":"accountStore.d.ts","sourceRoot":"","sources":["../../../../../src/ui/stores/accountStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,UAAU,YAAY;IAElB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACvC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,YAAY,EAAE,CAAC;IAG9B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAG/B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAGrB,WAAW,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAChD,UAAU,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IAC3E,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAG9C,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAGjE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAGzC,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,CAAC,EAAE,YAAY,EAAE,EAAE,aAAa,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAG5I,KAAK,EAAE,MAAM,IAAI,CAAC;CACrB;AAYD,eAAO,MAAM,eAAe,2EAwMzB,CAAC;AAGJ,eAAO,MAAM,WAAW,QAAO,YAAY,EAE1C,CAAC;AAEF,eAAO,MAAM,iBAAiB,eAAwC,CAAC;AACvE,eAAO,MAAM,eAAe,qBAAsC,CAAC;AACnE,eAAO,MAAM,wBAAwB,GAAI,WAAW,MAAM,YACE,CAAC"}
@@ -1,15 +1,5 @@
1
1
  import type { OxyServices, User } from '@oxyhq/core';
2
2
  import { QueryClient } from '@tanstack/react-query';
3
- /**
4
- * Updates file visibility to public for avatar use.
5
- * Handles errors gracefully, only logging non-404 errors.
6
- *
7
- * @param fileId - The file ID to update visibility for
8
- * @param oxyServices - OxyServices instance
9
- * @param contextName - Optional context name for logging
10
- * @returns Promise that resolves when visibility is updated (or skipped)
11
- */
12
- export declare function updateAvatarVisibility(fileId: string | undefined, oxyServices: OxyServices, contextName?: string): Promise<void>;
13
3
  /**
14
4
  * Refreshes avatar in accountStore with cache-busted URL to force image reload.
15
5
  *
@@ -1 +1 @@
1
- {"version":3,"file":"avatarUtils.d.ts","sourceRoot":"","sources":["../../../../../src/ui/utils/avatarUtils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,WAAW,EACxB,WAAW,GAAE,MAAsB,GAClC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,WAAW,GACvB,IAAI,CAON;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,WAAW,EAAE,WAAW,EACxB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,WAAW,EAAE,WAAW,EACxB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
1
+ {"version":3,"file":"avatarUtils.d.ts","sourceRoot":"","sources":["../../../../../src/ui/utils/avatarUtils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,WAAW,GACvB,IAAI,CAON;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,WAAW,EAAE,WAAW,EACxB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,WAAW,EAAE,WAAW,EACxB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/services",
3
- "version": "6.6.1",
3
+ "version": "6.7.0",
4
4
  "description": "OxyHQ Expo/React Native SDK — UI components, screens, and native features",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -51,15 +51,14 @@
51
51
  "author": "OxyHQ",
52
52
  "license": "MIT",
53
53
  "engines": {
54
- "node": ">=18.0.0",
55
- "npm": ">=9.0.0"
54
+ "node": ">=18.0.0"
56
55
  },
57
56
  "homepage": "https://oxy.so",
58
57
  "scripts": {
59
58
  "typescript": "tsc --skipLibCheck --noEmit",
60
59
  "lint": "biome lint --error-on-warnings ./src",
61
- "build": "npx react-native-builder-bob build && npm run copy-assets && npm run copy-dts && npm run delete-dts.js && npm run delete-debug-view",
62
- "build:js": "npx react-native-builder-bob build --target commonjs && npx react-native-builder-bob build --target module && npm run copy-assets",
60
+ "build": "bun x react-native-builder-bob build && bun run copy-assets && bun run copy-dts && bun run delete-dts.js && bun run delete-debug-view",
61
+ "build:js": "bun x react-native-builder-bob build --target commonjs && bun x react-native-builder-bob build --target module && bun run copy-assets",
63
62
  "test": "jest --passWithNoTests",
64
63
  "test:watch": "jest --watch",
65
64
  "test:coverage": "jest --coverage",
@@ -67,8 +66,8 @@
67
66
  "copy-dts": "copyfiles -u 1 \"src/**/*.d.ts\" lib/typescript",
68
67
  "delete-debug-view": "rm -rf ./lib/commonjs/components/bottomSheetDebugView ./lib/module/components/bottomSheetDebugView ./lib/typescript/components/bottomSheetDebugView || true",
69
68
  "delete-dts.js": "find ./lib/commonjs -name '*.d.js*' -delete && find ./lib/module -name '*.d.js*' -delete",
70
- "release": "rm -rf lib && npm run build && release-it",
71
- "prepublishOnly": "npm run typescript && npm test && npm run build"
69
+ "release": "rm -rf lib && bun run build && release-it",
70
+ "prepublishOnly": "bun run typescript && bun run test && bun run build"
72
71
  },
73
72
  "dependencies": {
74
73
  "@lottiefiles/dotlottie-react": "^0.13.5",
package/src/index.ts CHANGED
@@ -92,6 +92,8 @@ export { useFileFiltering } from './ui/hooks/useFileFiltering';
92
92
  export type { ViewMode, SortBy, SortOrder } from './ui/hooks/useFileFiltering';
93
93
 
94
94
  // UI components
95
+ export { default as Avatar } from './ui/components/Avatar';
96
+ export type { AvatarProps } from './ui/components/Avatar';
95
97
  export { OxySignInButton } from './ui/components/OxySignInButton';
96
98
  export { OxyLogo, FollowButton } from './ui';
97
99
 
@@ -1,5 +1,5 @@
1
1
  import type React from 'react';
2
- import { memo, useMemo } from 'react';
2
+ import { memo, useMemo, useState, useEffect } from 'react';
3
3
  import { View, Text, Image, StyleSheet, type StyleProp, type ViewStyle, type ImageStyle, type TextStyle, ActivityIndicator, Platform } from 'react-native';
4
4
  import { useThemeColors } from '../styles';
5
5
  import { fontFamilies } from '../styles/fonts';
@@ -148,6 +148,14 @@ const Avatar: React.FC<AvatarProps> = ({
148
148
  isLoading = false,
149
149
  }) => {
150
150
  const colors = useThemeColors(theme);
151
+ const [imageError, setImageError] = useState(false);
152
+
153
+ // Reset error state when uri changes
154
+ useEffect(() => {
155
+ if (uri) {
156
+ setImageError(false);
157
+ }
158
+ }, [uri]);
151
159
 
152
160
  const displayText = useMemo(
153
161
  () => text || (name ? getInitials(name) : ''),
@@ -221,8 +229,8 @@ const Avatar: React.FC<AvatarProps> = ({
221
229
  );
222
230
  }
223
231
 
224
- // Image avatar
225
- if (uri) {
232
+ // Image avatar (with fallback to initials on error)
233
+ if (uri && !imageError) {
226
234
  return (
227
235
  <View
228
236
  style={[
@@ -236,6 +244,7 @@ const Avatar: React.FC<AvatarProps> = ({
236
244
  source={{ uri }}
237
245
  style={[styles.image, containerStyle, imageStyle]}
238
246
  resizeMode="cover"
247
+ onError={() => setImageError(true)}
239
248
  />
240
249
  </View>
241
250
  );
@@ -37,7 +37,7 @@ const ProfileCard: React.FC<ProfileCardProps> = ({
37
37
  const secondaryBackgroundColor = themeStyles.secondaryBackgroundColor;
38
38
  const primaryColor = '#0066CC';
39
39
 
40
- const avatarUrl = useFileDownloadUrl(user?.avatar, { variant: 'thumb' }).url || undefined;
40
+ const avatarUrl = useFileDownloadUrl(oxyServices, user?.avatar, { variant: 'thumb' }).url || undefined;
41
41
 
42
42
  return (
43
43
  <View style={styles.headerSection}>
@@ -91,12 +91,11 @@ export const useUploadAvatar = () => {
91
91
  return useMutation({
92
92
  mutationFn: async (file: { uri: string; type?: string; name?: string; size?: number }) => {
93
93
  return authenticatedApiCall<User>(oxyServices, activeSessionId, async () => {
94
- // Upload file first
95
- const uploadResult = await oxyServices.assetUpload(file as any, 'public');
96
- const fileId = uploadResult?.file?.id || uploadResult?.id || uploadResult;
94
+ const uploadResult = await oxyServices.assetUpload(file, 'public');
95
+ const fileId = uploadResult?.file?.id;
97
96
 
98
97
  if (!fileId || typeof fileId !== 'string') {
99
- throw new Error('Failed to get file ID from upload result');
98
+ throw new Error('Upload succeeded but response did not contain a file ID');
100
99
  }
101
100
 
102
101
  // Update profile with file ID
@@ -336,7 +335,7 @@ export const useUploadFile = () => {
336
335
  return authenticatedApiCall<UploadResult>(
337
336
  oxyServices,
338
337
  activeSessionId,
339
- () => oxyServices.assetUpload(file as any, visibility, metadata, onProgress)
338
+ () => oxyServices.assetUpload(file, visibility, metadata, onProgress)
340
339
  );
341
340
  },
342
341
  });
@@ -58,8 +58,7 @@ export const useAssets = () => {
58
58
  clearErrors();
59
59
  setUploading(true);
60
60
 
61
- // Upload file (progress tracking simplified for now)
62
- const result = await oxyInstance.assetUpload(file as any, undefined, metadata);
61
+ const result = await oxyInstance.assetUpload(file, undefined, metadata);
63
62
 
64
63
  // Update progress with final status
65
64
  if (result?.file) {
@@ -12,7 +12,8 @@ import { translate } from '@oxyhq/core';
12
12
  import type { QueryClient } from '@tanstack/react-query';
13
13
  import { toast } from '../../lib/sonner';
14
14
  import type { RouteName } from '../navigation/routes';
15
- import { updateAvatarVisibility, updateProfileWithAvatar } from '../utils/avatarUtils';
15
+ import { updateAvatarVisibility } from '@oxyhq/core';
16
+ import { updateProfileWithAvatar } from '../utils/avatarUtils';
16
17
 
17
18
  interface UseAvatarPickerOptions {
18
19
  oxyServices: OxyServices;
@@ -51,8 +52,9 @@ export function useAvatarPicker({
51
52
  queryClient
52
53
  );
53
54
  toast.success(translate(currentLanguage ?? undefined, 'editProfile.toasts.avatarUpdated') || 'Avatar updated');
54
- } catch (e: any) {
55
- toast.error(e.message || translate(currentLanguage ?? undefined, 'editProfile.toasts.updateAvatarFailed') || 'Failed to update avatar');
55
+ } catch (e: unknown) {
56
+ const message = e instanceof Error ? e.message : undefined;
57
+ toast.error(message || translate(currentLanguage ?? undefined, 'editProfile.toasts.updateAvatarFailed') || 'Failed to update avatar');
56
58
  }
57
59
  },
58
60
  },
@@ -21,13 +21,34 @@ export interface UseFileDownloadUrlResult {
21
21
  /**
22
22
  * Hook to resolve a file's download URL asynchronously.
23
23
  *
24
- * Prefers `getFileDownloadUrlAsync` and falls back to the synchronous
25
- * `getFileDownloadUrl` helper if the async call fails.
24
+ * Prefers the provided `oxyServices` instance, falls back to the module-level
25
+ * singleton set via `setOxyFileUrlInstance`.
26
+ *
27
+ * Uses `getFileDownloadUrlAsync` first, falling back to the synchronous
28
+ * `getFileDownloadUrl` if the async call fails.
26
29
  */
27
30
  export const useFileDownloadUrl = (
28
- fileId?: string | null,
29
- options?: UseFileDownloadUrlOptions
31
+ fileIdOrServices?: string | OxyServices | null,
32
+ fileIdOrOptions?: string | UseFileDownloadUrlOptions | null,
33
+ maybeOptions?: UseFileDownloadUrlOptions
30
34
  ): UseFileDownloadUrlResult => {
35
+ // Support two call signatures:
36
+ // 1. useFileDownloadUrl(oxyServices, fileId, options) — preferred
37
+ // 2. useFileDownloadUrl(fileId, options) — legacy (uses singleton)
38
+ let services: OxyServices | null;
39
+ let fileId: string | null | undefined;
40
+ let options: UseFileDownloadUrlOptions | undefined;
41
+
42
+ if (fileIdOrServices instanceof OxyServices) {
43
+ services = fileIdOrServices;
44
+ fileId = typeof fileIdOrOptions === 'string' ? fileIdOrOptions : null;
45
+ options = maybeOptions;
46
+ } else {
47
+ services = oxyInstance;
48
+ fileId = typeof fileIdOrServices === 'string' ? fileIdOrServices : null;
49
+ options = typeof fileIdOrOptions === 'object' && fileIdOrOptions !== null ? fileIdOrOptions as UseFileDownloadUrlOptions : undefined;
50
+ }
51
+
31
52
  const [url, setUrl] = useState<string | null>(null);
32
53
  const [loading, setLoading] = useState(false);
33
54
  const [error, setError] = useState<Error | null>(null);
@@ -40,8 +61,7 @@ export const useFileDownloadUrl = (
40
61
  return;
41
62
  }
42
63
 
43
- if (!oxyInstance) {
44
- // Fail silently but don't crash the UI – caller can decide what to do with null URL.
64
+ if (!services) {
45
65
  setUrl(null);
46
66
  setLoading(false);
47
67
  setError(new Error('OxyServices instance not configured for useFileDownloadUrl'));
@@ -49,40 +69,33 @@ export const useFileDownloadUrl = (
49
69
  }
50
70
 
51
71
  let cancelled = false;
72
+ const instance = services;
52
73
 
53
74
  const load = async () => {
54
75
  setLoading(true);
55
76
  setError(null);
56
77
 
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
78
  try {
66
79
  const { variant, expiresIn } = options || {};
67
80
  let resolvedUrl: string | null = null;
68
81
 
69
82
  if (typeof instance.getFileDownloadUrlAsync === 'function') {
70
- resolvedUrl = await instance.getFileDownloadUrlAsync(fileId, variant, expiresIn);
83
+ resolvedUrl = await instance.getFileDownloadUrlAsync(fileId!, variant, expiresIn);
71
84
  }
72
85
 
73
86
  if (!resolvedUrl && typeof instance.getFileDownloadUrl === 'function') {
74
- resolvedUrl = instance.getFileDownloadUrl(fileId, variant, expiresIn);
87
+ resolvedUrl = instance.getFileDownloadUrl(fileId!, variant, expiresIn);
75
88
  }
76
89
 
77
90
  if (!cancelled) {
78
91
  setUrl(resolvedUrl || null);
79
92
  }
80
- } catch (err: any) {
93
+ } catch (err: unknown) {
81
94
  // Fallback to sync URL on error where possible
82
95
  try {
83
96
  if (typeof instance.getFileDownloadUrl === 'function') {
84
97
  const { variant, expiresIn } = options || {};
85
- const fallbackUrl = instance.getFileDownloadUrl(fileId, variant, expiresIn);
98
+ const fallbackUrl = instance.getFileDownloadUrl(fileId!, variant, expiresIn);
86
99
  if (!cancelled) {
87
100
  setUrl(fallbackUrl || null);
88
101
  setError(err instanceof Error ? err : new Error(String(err)));
@@ -90,7 +103,7 @@ export const useFileDownloadUrl = (
90
103
  return;
91
104
  }
92
105
  } catch {
93
- // ignore secondary failure, we'll surface the original error below
106
+ // ignore secondary failure
94
107
  }
95
108
 
96
109
  if (!cancelled) {
@@ -108,11 +121,7 @@ export const useFileDownloadUrl = (
108
121
  return () => {
109
122
  cancelled = true;
110
123
  };
111
- }, [fileId, options?.variant, options?.expiresIn]);
124
+ }, [fileId, services, options?.variant, options?.expiresIn]);
112
125
 
113
126
  return { url, loading, error };
114
127
  };
115
-
116
-
117
-
118
-
@@ -13,7 +13,7 @@ import GroupedPillButtons from '../components/internal/GroupedPillButtons';
13
13
  import { useI18n } from '../hooks/useI18n';
14
14
  import { useOxy } from '../context/OxyContext';
15
15
  import { useUpdateProfile } from '../hooks/mutations/useAccountMutations';
16
- import { updateAvatarVisibility } from '../utils/avatarUtils';
16
+ import { updateAvatarVisibility } from '@oxyhq/core';
17
17
 
18
18
  const GAP = 12;
19
19
  const INNER_GAP = 8;
@@ -1,15 +1,10 @@
1
1
  import { create } from 'zustand';
2
2
  import { shallow } from 'zustand/shallow';
3
3
  import type { OxyServices } from '@oxyhq/core';
4
+ import { buildAccountsArray, createQuickAccount } from '@oxyhq/core';
5
+ import type { QuickAccount } from '@oxyhq/core';
4
6
 
5
- export interface QuickAccount {
6
- sessionId: string;
7
- userId?: string; // User ID for deduplication
8
- username: string;
9
- displayName: string;
10
- avatar?: string;
11
- avatarUrl?: string; // Cached avatar URL to prevent recalculation
12
- }
7
+ export type { QuickAccount };
13
8
 
14
9
  interface AccountState {
15
10
  // Account data
@@ -54,38 +49,6 @@ const initialState = {
54
49
  error: null,
55
50
  };
56
51
 
57
- // Helper: Build accounts array from accounts map and order
58
- const buildAccountsArray = (accounts: Record<string, QuickAccount>, order: string[]): QuickAccount[] => {
59
- const result: QuickAccount[] = [];
60
- for (const id of order) {
61
- const account = accounts[id];
62
- if (account) result.push(account);
63
- }
64
- return result;
65
- };
66
-
67
- // Helper: Create QuickAccount from user data
68
- const createQuickAccount = (sessionId: string, userData: any, existingAccount?: QuickAccount, oxyServices?: OxyServices): QuickAccount => {
69
- const displayName = userData.name?.full || userData.name?.first || userData.username || 'Account';
70
- const userId = userData.id || userData._id?.toString();
71
-
72
- // Preserve existing avatarUrl if avatar hasn't changed (prevents image reload)
73
- let avatarUrl: string | undefined;
74
- if (existingAccount && existingAccount.avatar === userData.avatar && existingAccount.avatarUrl) {
75
- avatarUrl = existingAccount.avatarUrl; // Reuse existing URL
76
- } else if (userData.avatar && oxyServices) {
77
- avatarUrl = oxyServices.getFileDownloadUrl(userData.avatar, 'thumb');
78
- }
79
-
80
- return {
81
- sessionId,
82
- userId,
83
- username: userData.username || '',
84
- displayName,
85
- avatar: userData.avatar,
86
- avatarUrl,
87
- };
88
- };
89
52
 
90
53
  export const useAccountStore = create<AccountState>((set, get) => ({
91
54
  ...initialState,
@@ -116,7 +79,7 @@ export const useAccountStore = create<AccountState>((set, get) => ({
116
79
  existing.avatarUrl === newAccount.avatarUrl;
117
80
  });
118
81
 
119
- if (sameAccounts) return {} as any;
82
+ if (sameAccounts) return {} as Partial<AccountState>;
120
83
 
121
84
  return { accounts: accountMap, accountOrder: order, accountsArray };
122
85
  }),
@@ -127,7 +90,7 @@ export const useAccountStore = create<AccountState>((set, get) => ({
127
90
  // Update existing
128
91
  const existing = state.accounts[account.sessionId];
129
92
  if (existing.avatar === account.avatar && existing.avatarUrl === account.avatarUrl) {
130
- return {} as any; // No change
93
+ return {} as Partial<AccountState>; // No change
131
94
  }
132
95
  const newAccounts = { ...state.accounts, [account.sessionId]: account };
133
96
  return {
@@ -147,11 +110,11 @@ export const useAccountStore = create<AccountState>((set, get) => ({
147
110
 
148
111
  updateAccount: (sessionId, updates) => set((state) => {
149
112
  const existing = state.accounts[sessionId];
150
- if (!existing) return {} as any;
113
+ if (!existing) return {} as Partial<AccountState>;
151
114
 
152
115
  const updated = { ...existing, ...updates };
153
116
  if (existing.avatar === updated.avatar && existing.avatarUrl === updated.avatarUrl) {
154
- return {} as any; // No change
117
+ return {} as Partial<AccountState>; // No change
155
118
  }
156
119
 
157
120
  const newAccounts = { ...state.accounts, [sessionId]: updated };
@@ -162,7 +125,7 @@ export const useAccountStore = create<AccountState>((set, get) => ({
162
125
  }),
163
126
 
164
127
  removeAccount: (sessionId) => set((state) => {
165
- if (!state.accounts[sessionId]) return {} as any;
128
+ if (!state.accounts[sessionId]) return {} as Partial<AccountState>;
166
129
 
167
130
  const { [sessionId]: _removed, ...rest } = state.accounts;
168
131
  const newOrder = state.accountOrder.filter(id => id !== sessionId);
@@ -175,7 +138,7 @@ export const useAccountStore = create<AccountState>((set, get) => ({
175
138
  }),
176
139
 
177
140
  moveAccountToTop: (sessionId) => set((state) => {
178
- if (!state.accounts[sessionId]) return {} as any;
141
+ if (!state.accounts[sessionId]) return {} as Partial<AccountState>;
179
142
 
180
143
  const filtered = state.accountOrder.filter(id => id !== sessionId);
181
144
  const newOrder = [sessionId, ...filtered];
@@ -242,7 +205,12 @@ export const useAccountStore = create<AccountState>((set, get) => ({
242
205
  for (const { sessionId, user: userData } of batchResults) {
243
206
  if (userData && !accountMap.has(sessionId)) {
244
207
  const existing = existingMap.get(sessionId);
245
- accountMap.set(sessionId, createQuickAccount(sessionId, userData, existing, oxyServices));
208
+ accountMap.set(sessionId, createQuickAccount(
209
+ sessionId,
210
+ userData,
211
+ existing,
212
+ (fileId, variant) => oxyServices.getFileDownloadUrl(fileId, variant)
213
+ ));
246
214
  }
247
215
  }
248
216
 
@@ -5,38 +5,9 @@ import { useAuthStore } from '../stores/authStore';
5
5
  import { QueryClient } from '@tanstack/react-query';
6
6
  import { queryKeys, invalidateUserQueries, invalidateAccountQueries } from '../hooks/queries/queryKeys';
7
7
 
8
- /**
9
- * Updates file visibility to public for avatar use.
10
- * Handles errors gracefully, only logging non-404 errors.
11
- *
12
- * @param fileId - The file ID to update visibility for
13
- * @param oxyServices - OxyServices instance
14
- * @param contextName - Optional context name for logging
15
- * @returns Promise that resolves when visibility is updated (or skipped)
16
- */
17
- export async function updateAvatarVisibility(
18
- fileId: string | undefined,
19
- oxyServices: OxyServices,
20
- contextName: string = 'AvatarUtils'
21
- ): Promise<void> {
22
- // Skip if temporary asset ID or no file ID
23
- if (!fileId || fileId.startsWith('temp-')) {
24
- return;
25
- }
26
-
27
- try {
28
- await oxyServices.assetUpdateVisibility(fileId, 'public');
29
- // Visibility update is logged by the API
30
- } catch (visError: any) {
31
- // Silently handle errors - 404 means asset doesn't exist yet (which is OK)
32
- // Other errors are logged by the API, so no need to log here
33
- // Function continues gracefully regardless of visibility update success
34
- }
35
- }
36
-
37
8
  /**
38
9
  * Refreshes avatar in accountStore with cache-busted URL to force image reload.
39
- *
10
+ *
40
11
  * @param sessionId - The session ID for the account to update
41
12
  * @param avatarFileId - The new avatar file ID
42
13
  * @param oxyServices - OxyServices instance to generate download URL
@@ -99,4 +70,3 @@ export async function updateProfileWithAvatar(
99
70
 
100
71
  return data;
101
72
  }
102
-
@@ -3,7 +3,7 @@ import type { FileMetadata } from '@oxyhq/core';
3
3
  import { File as ExpoFile } from 'expo-file-system';
4
4
  import { toast } from '../../lib/sonner';
5
5
  import type { RouteName } from '../navigation/routes';
6
- import { updateAvatarVisibility } from './avatarUtils';
6
+ import { updateAvatarVisibility } from '@oxyhq/core';
7
7
 
8
8
  /**
9
9
  * Format file size in bytes to human-readable string