@oxyhq/services 5.16.1 → 5.16.2

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 (175) hide show
  1. package/lib/commonjs/core/mixins/OxyServices.user.js +14 -13
  2. package/lib/commonjs/core/mixins/OxyServices.user.js.map +1 -1
  3. package/lib/commonjs/crypto/keyManager.js +164 -3
  4. package/lib/commonjs/crypto/keyManager.js.map +1 -1
  5. package/lib/commonjs/crypto/signatureService.js +26 -0
  6. package/lib/commonjs/crypto/signatureService.js.map +1 -1
  7. package/lib/commonjs/ui/components/GroupedSection.js +1 -1
  8. package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
  9. package/lib/commonjs/ui/components/OxyProvider.js +71 -24
  10. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  11. package/lib/commonjs/ui/components/profile/EditDisplayNameModal.js +1 -4
  12. package/lib/commonjs/ui/components/profile/EditDisplayNameModal.js.map +1 -1
  13. package/lib/commonjs/ui/context/OxyContext.js +177 -4
  14. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  15. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +148 -49
  16. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  17. package/lib/commonjs/ui/context/hooks/useSessionManagement.js +22 -2
  18. package/lib/commonjs/ui/context/hooks/useSessionManagement.js.map +1 -1
  19. package/lib/commonjs/ui/hooks/mutations/index.js +28 -0
  20. package/lib/commonjs/ui/hooks/mutations/index.js.map +1 -0
  21. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +314 -0
  22. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -0
  23. package/lib/commonjs/ui/hooks/mutations/useServicesMutations.js +193 -0
  24. package/lib/commonjs/ui/hooks/mutations/useServicesMutations.js.map +1 -0
  25. package/lib/commonjs/ui/hooks/queries/index.js +39 -0
  26. package/lib/commonjs/ui/hooks/queries/index.js.map +1 -0
  27. package/lib/commonjs/ui/hooks/queries/queryKeys.js +85 -0
  28. package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -0
  29. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +145 -0
  30. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -0
  31. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +138 -0
  32. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -0
  33. package/lib/commonjs/ui/hooks/queryClient.js +117 -0
  34. package/lib/commonjs/ui/hooks/queryClient.js.map +1 -0
  35. package/lib/commonjs/ui/hooks/useIdentityMutations.js +111 -0
  36. package/lib/commonjs/ui/hooks/useIdentityMutations.js.map +1 -0
  37. package/lib/commonjs/ui/hooks/useProfileEditing.js +42 -58
  38. package/lib/commonjs/ui/hooks/useProfileEditing.js.map +1 -1
  39. package/lib/commonjs/ui/hooks/useQueryClient.js +20 -0
  40. package/lib/commonjs/ui/hooks/useQueryClient.js.map +1 -0
  41. package/lib/commonjs/ui/hooks/useSessionManagement.js +22 -2
  42. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  43. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +43 -42
  44. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +63 -58
  46. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +6 -6
  48. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  49. package/lib/commonjs/ui/stores/accountStore.js +57 -42
  50. package/lib/commonjs/ui/stores/accountStore.js.map +1 -1
  51. package/lib/commonjs/ui/stores/authStore.js +4 -25
  52. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  53. package/lib/module/core/mixins/OxyServices.user.js +14 -13
  54. package/lib/module/core/mixins/OxyServices.user.js.map +1 -1
  55. package/lib/module/crypto/keyManager.js +164 -3
  56. package/lib/module/crypto/keyManager.js.map +1 -1
  57. package/lib/module/crypto/signatureService.js +26 -0
  58. package/lib/module/crypto/signatureService.js.map +1 -1
  59. package/lib/module/ui/components/GroupedSection.js +1 -1
  60. package/lib/module/ui/components/GroupedSection.js.map +1 -1
  61. package/lib/module/ui/components/OxyProvider.js +72 -25
  62. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  63. package/lib/module/ui/components/profile/EditDisplayNameModal.js +1 -4
  64. package/lib/module/ui/components/profile/EditDisplayNameModal.js.map +1 -1
  65. package/lib/module/ui/context/OxyContext.js +176 -4
  66. package/lib/module/ui/context/OxyContext.js.map +1 -1
  67. package/lib/module/ui/context/hooks/useAuthOperations.js +148 -49
  68. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  69. package/lib/module/ui/context/hooks/useSessionManagement.js +22 -2
  70. package/lib/module/ui/context/hooks/useSessionManagement.js.map +1 -1
  71. package/lib/module/ui/hooks/mutations/index.js +6 -0
  72. package/lib/module/ui/hooks/mutations/index.js.map +1 -0
  73. package/lib/module/ui/hooks/mutations/useAccountMutations.js +308 -0
  74. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -0
  75. package/lib/module/ui/hooks/mutations/useServicesMutations.js +185 -0
  76. package/lib/module/ui/hooks/mutations/useServicesMutations.js.map +1 -0
  77. package/lib/module/ui/hooks/queries/index.js +7 -0
  78. package/lib/module/ui/hooks/queries/index.js.map +1 -0
  79. package/lib/module/ui/hooks/queries/queryKeys.js +78 -0
  80. package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -0
  81. package/lib/module/ui/hooks/queries/useAccountQueries.js +136 -0
  82. package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -0
  83. package/lib/module/ui/hooks/queries/useServicesQueries.js +130 -0
  84. package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -0
  85. package/lib/module/ui/hooks/queryClient.js +110 -0
  86. package/lib/module/ui/hooks/queryClient.js.map +1 -0
  87. package/lib/module/ui/hooks/useIdentityMutations.js +105 -0
  88. package/lib/module/ui/hooks/useIdentityMutations.js.map +1 -0
  89. package/lib/module/ui/hooks/useProfileEditing.js +43 -59
  90. package/lib/module/ui/hooks/useProfileEditing.js.map +1 -1
  91. package/lib/module/ui/hooks/useQueryClient.js +15 -0
  92. package/lib/module/ui/hooks/useQueryClient.js.map +1 -0
  93. package/lib/module/ui/hooks/useSessionManagement.js +22 -2
  94. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  95. package/lib/module/ui/screens/AccountOverviewScreen.js +43 -42
  96. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  97. package/lib/module/ui/screens/AccountSettingsScreen.js +63 -58
  98. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  99. package/lib/module/ui/screens/WelcomeNewUserScreen.js +6 -6
  100. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  101. package/lib/module/ui/stores/accountStore.js +57 -42
  102. package/lib/module/ui/stores/accountStore.js.map +1 -1
  103. package/lib/module/ui/stores/authStore.js +4 -25
  104. package/lib/module/ui/stores/authStore.js.map +1 -1
  105. package/lib/typescript/core/mixins/OxyServices.user.d.ts +4 -5
  106. package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -1
  107. package/lib/typescript/core/mixins/index.d.ts +0 -1
  108. package/lib/typescript/core/mixins/index.d.ts.map +1 -1
  109. package/lib/typescript/crypto/keyManager.d.ts +19 -2
  110. package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
  111. package/lib/typescript/crypto/signatureService.d.ts +5 -0
  112. package/lib/typescript/crypto/signatureService.d.ts.map +1 -1
  113. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  114. package/lib/typescript/ui/components/profile/EditDisplayNameModal.d.ts.map +1 -1
  115. package/lib/typescript/ui/context/OxyContext.d.ts +4 -0
  116. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  117. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  118. package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts +3 -1
  119. package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts.map +1 -1
  120. package/lib/typescript/ui/hooks/mutations/index.d.ts +3 -0
  121. package/lib/typescript/ui/hooks/mutations/index.d.ts.map +1 -0
  122. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +25 -0
  123. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -0
  124. package/lib/typescript/ui/hooks/mutations/useServicesMutations.d.ts +23 -0
  125. package/lib/typescript/ui/hooks/mutations/useServicesMutations.d.ts.map +1 -0
  126. package/lib/typescript/ui/hooks/queries/index.d.ts +4 -0
  127. package/lib/typescript/ui/hooks/queries/index.d.ts.map +1 -0
  128. package/lib/typescript/ui/hooks/queries/queryKeys.d.ts +56 -0
  129. package/lib/typescript/ui/hooks/queries/queryKeys.d.ts.map +1 -0
  130. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +41 -0
  131. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -0
  132. package/lib/typescript/ui/hooks/queries/useServicesQueries.d.ts +34 -0
  133. package/lib/typescript/ui/hooks/queries/useServicesQueries.d.ts.map +1 -0
  134. package/lib/typescript/ui/hooks/queryClient.d.ts +19 -0
  135. package/lib/typescript/ui/hooks/queryClient.d.ts.map +1 -0
  136. package/lib/typescript/ui/hooks/useIdentityMutations.d.ts +29 -0
  137. package/lib/typescript/ui/hooks/useIdentityMutations.d.ts.map +1 -0
  138. package/lib/typescript/ui/hooks/useProfileEditing.d.ts.map +1 -1
  139. package/lib/typescript/ui/hooks/useQueryClient.d.ts +7 -0
  140. package/lib/typescript/ui/hooks/useQueryClient.d.ts.map +1 -0
  141. package/lib/typescript/ui/hooks/useSessionManagement.d.ts +3 -1
  142. package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -1
  143. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  144. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  145. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  146. package/lib/typescript/ui/stores/accountStore.d.ts.map +1 -1
  147. package/lib/typescript/ui/stores/authStore.d.ts +0 -4
  148. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  149. package/package.json +5 -4
  150. package/src/core/mixins/OxyServices.user.ts +17 -10
  151. package/src/crypto/keyManager.ts +177 -2
  152. package/src/crypto/signatureService.ts +30 -0
  153. package/src/ui/components/GroupedSection.tsx +1 -1
  154. package/src/ui/components/OxyProvider.tsx +91 -37
  155. package/src/ui/components/profile/EditDisplayNameModal.tsx +1 -3
  156. package/src/ui/context/OxyContext.tsx +185 -2
  157. package/src/ui/context/hooks/useAuthOperations.ts +171 -58
  158. package/src/ui/context/hooks/useSessionManagement.ts +24 -1
  159. package/src/ui/hooks/mutations/index.ts +4 -0
  160. package/src/ui/hooks/mutations/useAccountMutations.ts +277 -0
  161. package/src/ui/hooks/mutations/useServicesMutations.ts +164 -0
  162. package/src/ui/hooks/queries/index.ts +5 -0
  163. package/src/ui/hooks/queries/queryKeys.ts +73 -0
  164. package/src/ui/hooks/queries/useAccountQueries.ts +126 -0
  165. package/src/ui/hooks/queries/useServicesQueries.ts +121 -0
  166. package/src/ui/hooks/queryClient.ts +112 -0
  167. package/src/ui/hooks/useIdentityMutations.ts +115 -0
  168. package/src/ui/hooks/useProfileEditing.ts +46 -60
  169. package/src/ui/hooks/useQueryClient.ts +17 -0
  170. package/src/ui/hooks/useSessionManagement.ts +24 -1
  171. package/src/ui/screens/AccountOverviewScreen.tsx +38 -46
  172. package/src/ui/screens/AccountSettingsScreen.tsx +54 -54
  173. package/src/ui/screens/WelcomeNewUserScreen.tsx +13 -12
  174. package/src/ui/stores/accountStore.ts +54 -43
  175. package/src/ui/stores/authStore.ts +3 -17
@@ -0,0 +1,29 @@
1
+ /**
2
+ * TanStack Query mutations for identity operations
3
+ * Provides offline-first mutations for identity creation, import, and sync
4
+ * Never deletes identity on errors - preserves user data
5
+ */
6
+ import type { User } from '../../models/interfaces';
7
+ export interface CreateIdentityResult {
8
+ recoveryPhrase: string[];
9
+ synced: boolean;
10
+ }
11
+ export interface ImportIdentityResult {
12
+ synced: boolean;
13
+ }
14
+ /**
15
+ * Hook for creating a new identity with offline support
16
+ * Never deletes identity on error - preserves user data
17
+ */
18
+ export declare function useCreateIdentity(createIdentityFn: () => Promise<CreateIdentityResult>): import("@tanstack/react-query").UseMutationResult<CreateIdentityResult, Error, void, unknown>;
19
+ /**
20
+ * Hook for importing an identity from recovery phrase
21
+ * Never deletes identity on error - preserves user data
22
+ */
23
+ export declare function useImportIdentity(importIdentityFn: (phrase: string) => Promise<ImportIdentityResult>): import("@tanstack/react-query").UseMutationResult<ImportIdentityResult, Error, string, unknown>;
24
+ /**
25
+ * Hook for syncing identity with server
26
+ * Never deletes identity on error - only logs and allows retry
27
+ */
28
+ export declare function useSyncIdentity(syncIdentityFn: () => Promise<User>): import("@tanstack/react-query").UseMutationResult<User, Error, void, unknown>;
29
+ //# sourceMappingURL=useIdentityMutations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useIdentityMutations.d.ts","sourceRoot":"","sources":["../../../../src/ui/hooks/useIdentityMutations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,gBAAgB,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,iGAqBtD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,CAAC,mGAmBpE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,iFAoCpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useProfileEditing.d.ts","sourceRoot":"","sources":["../../../../src/ui/hooks/useProfileEditing.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;KAC9C,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,EAAE,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB;2BASsB,iBAAiB;yBAgEnB,MAAM,SAAS,GAAG;;CAmCnE,CAAC"}
1
+ {"version":3,"file":"useProfileEditing.d.ts","sourceRoot":"","sources":["../../../../src/ui/hooks/useProfileEditing.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;KAC9C,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,EAAE,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB;2BAOsB,iBAAiB;yBAqDnB,MAAM,SAAS,GAAG;;CAmCnE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { QueryClient } from '@tanstack/react-query';
2
+ /**
3
+ * Custom hook to access the QueryClient
4
+ * Provides type safety and ensures client is available
5
+ */
6
+ export declare const useQueryClient: () => QueryClient;
7
+ //# sourceMappingURL=useQueryClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useQueryClient.d.ts","sourceRoot":"","sources":["../../../../src/ui/hooks/useQueryClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,WAQjC,CAAC"}
@@ -2,6 +2,7 @@ import type { ApiError, User } from '../../models/interfaces';
2
2
  import type { ClientSession } from '../../models/session';
3
3
  import { getStorageKeys, type StorageInterface } from '../utils/storageHelpers';
4
4
  import type { OxyServices } from '../../core';
5
+ import type { QueryClient } from '@tanstack/react-query';
5
6
  export interface UseSessionManagementOptions {
6
7
  oxyServices: OxyServices;
7
8
  storage: StorageInterface | null;
@@ -14,6 +15,7 @@ export interface UseSessionManagementOptions {
14
15
  setAuthError?: (message: string | null) => void;
15
16
  logger?: (message: string, error?: unknown) => void;
16
17
  setTokenReady?: (ready: boolean) => void;
18
+ queryClient?: QueryClient | null;
17
19
  }
18
20
  export interface UseSessionManagementResult {
19
21
  sessions: ClientSession[];
@@ -35,5 +37,5 @@ export interface UseSessionManagementResult {
35
37
  *
36
38
  * @param options - Session management configuration
37
39
  */
38
- export declare const useSessionManagement: ({ oxyServices, storage, storageKeyPrefix, loginSuccess, logoutStore, applyLanguagePreference, onAuthStateChange, onError, setAuthError, logger, setTokenReady, }: UseSessionManagementOptions) => UseSessionManagementResult;
40
+ export declare const useSessionManagement: ({ oxyServices, storage, storageKeyPrefix, loginSuccess, logoutStore, applyLanguagePreference, onAuthStateChange, onError, setAuthError, logger, setTokenReady, queryClient, }: UseSessionManagementOptions) => UseSessionManagementResult;
39
41
  //# sourceMappingURL=useSessionManagement.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSessionManagement.d.ts","sourceRoot":"","sources":["../../../../src/ui/hooks/useSessionManagement.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,uBAAuB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACpD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,cAAc,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACnF,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,eAAe,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;IAC/C,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAKD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,kKAYlC,2BAA2B,KAAG,0BA8ThC,CAAC"}
1
+ {"version":3,"file":"useSessionManagement.d.ts","sourceRoot":"","sources":["../../../../src/ui/hooks/useSessionManagement.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,uBAAuB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACpD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,cAAc,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACnF,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,eAAe,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;IAC/C,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAKD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,+KAalC,2BAA2B,KAAG,0BAiVhC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"AccountOverviewScreen.d.ts","sourceRoot":"","sources":["../../../../src/ui/screens/AccountOverviewScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAcjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;;AAszB3D,wBAAiD"}
1
+ {"version":3,"file":"AccountOverviewScreen.d.ts","sourceRoot":"","sources":["../../../../src/ui/screens/AccountOverviewScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAcjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;;AA8yB3D,wBAAiD"}
@@ -1 +1 @@
1
- {"version":3,"file":"AccountSettingsScreen.d.ts","sourceRoot":"","sources":["../../../../src/ui/screens/AccountSettingsScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAcjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;;mBA4Cc,MAAM;qBAAmB,MAAM;;AA0gExG,wBAAiD"}
1
+ {"version":3,"file":"AccountSettingsScreen.d.ts","sourceRoot":"","sources":["../../../../src/ui/screens/AccountSettingsScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAcjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;;mBA8Cc,MAAM;qBAAmB,MAAM;;AAwgExG,wBAAiD"}
@@ -1 +1 @@
1
- {"version":3,"file":"WelcomeNewUserScreen.d.ts","sourceRoot":"","sources":["../../../../src/ui/screens/WelcomeNewUserScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAGjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AA8C3D;;;;;GAKG;AACH,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,GAAG;IAAE,OAAO,CAAC,EAAE,GAAG,CAAA;CAAE,CA0MvE,CAAC;AAgGF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"WelcomeNewUserScreen.d.ts","sourceRoot":"","sources":["../../../../src/ui/screens/WelcomeNewUserScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAGjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AA+C3D;;;;;GAKG;AACH,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,GAAG;IAAE,OAAO,CAAC,EAAE,GAAG,CAAA;CAAE,CA0MvE,CAAC;AAgGF,eAAe,oBAAoB,CAAC"}
@@ -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,YAAY,CAAC;AAE9C,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,2EAwLzB,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,YAAY,CAAC;AAE9C,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"}
@@ -13,10 +13,6 @@ export interface AuthState {
13
13
  fetchUser: (oxyServices: {
14
14
  getCurrentUser: () => Promise<User>;
15
15
  }, forceRefresh?: boolean) => Promise<void>;
16
- updateUser: (updates: Partial<User>, oxyServices: {
17
- updateProfile: (updates: Partial<User>) => Promise<User>;
18
- getCurrentUser: () => Promise<User>;
19
- }) => Promise<void>;
20
16
  setUser: (user: User) => void;
21
17
  setIdentitySynced: (synced: boolean) => void;
22
18
  setSyncing: (syncing: boolean) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"authStore.d.ts","sourceRoot":"","sources":["../../../../src/ui/stores/authStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAG7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IAEnB,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,EAAE,CAAC,WAAW,EAAE;QAAE,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3G,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE;QAAE,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtK,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAG9B,iBAAiB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,YAAY,wEAuEtB,CAAC"}
1
+ {"version":3,"file":"authStore.d.ts","sourceRoot":"","sources":["../../../../src/ui/stores/authStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAG7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IAEnB,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,EAAE,CAAC,WAAW,EAAE;QAAE,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3G,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAG9B,iBAAiB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,YAAY,wEA0DtB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/services",
3
- "version": "5.16.1",
3
+ "version": "5.16.2",
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",
@@ -90,6 +90,7 @@
90
90
  },
91
91
  "dependencies": {
92
92
  "@react-native-async-storage/async-storage": "2.1.2",
93
+ "@react-native-community/netinfo": "^11.4.1",
93
94
  "@tanstack/react-query": "^5.59.0",
94
95
  "axios": "^1.9.0",
95
96
  "bip39": "^3.1.0",
@@ -111,13 +112,14 @@
111
112
  "zustand": "^5.0.6"
112
113
  },
113
114
  "devDependencies": {
114
- "@types/color": "^3.0.6",
115
- "@types/elliptic": "^6.4.18",
116
115
  "@biomejs/biome": "^1.9.4",
117
116
  "@commitlint/cli": "^17.6.5",
118
117
  "@commitlint/config-conventional": "^17.6.5",
118
+ "@react-native/babel-preset": "^0.77.0",
119
119
  "@release-it/conventional-changelog": "^10.0.2",
120
120
  "@testing-library/jest-dom": "^6.4.2",
121
+ "@types/color": "^3.0.6",
122
+ "@types/elliptic": "^6.4.18",
121
123
  "@types/invariant": "^2.2.34",
122
124
  "@types/jest": "^29.5.14",
123
125
  "@types/jwt-decode": "^2.2.1",
@@ -132,7 +134,6 @@
132
134
  "husky": "^4.3.8",
133
135
  "jest": "~29.7.0",
134
136
  "lint-staged": "^15.2.4",
135
- "@react-native/babel-preset": "^0.77.0",
136
137
  "react-native-builder-bob": "^0.40.16",
137
138
  "react-native-gesture-handler": "~2.28.0",
138
139
  "react-native-reanimated": "~4.1.1",
@@ -129,11 +129,28 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
129
129
 
130
130
  /**
131
131
  * Update user profile
132
+ * TanStack Query handles offline queuing automatically
132
133
  */
133
134
  async updateProfile(updates: Record<string, any>): Promise<User> {
134
135
  try {
135
136
  return await this.makeRequest<User>('PUT', '/api/users/me', updates, { cache: false });
136
137
  } catch (error) {
138
+ const errorAny = error as any;
139
+ const errorMessage = error instanceof Error ? error.message : String(error);
140
+ const status = errorAny?.status || errorAny?.response?.status;
141
+
142
+ // Check if it's an authentication error (401)
143
+ const isAuthError = status === 401 ||
144
+ errorMessage.includes('Authentication required') ||
145
+ errorMessage.includes('Invalid or missing authorization header');
146
+
147
+ // If authentication error and we don't have a token, this might be an offline session
148
+ // The caller should handle syncing the session before retrying
149
+ if (isAuthError && !this.hasValidToken()) {
150
+ // Re-throw with a specific message so the caller knows to sync
151
+ throw new Error('AUTH_REQUIRED_OFFLINE_SESSION: Session needs to be synced to get a token');
152
+ }
153
+
137
154
  throw this.handleError(error);
138
155
  }
139
156
  }
@@ -219,16 +236,6 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
219
236
  }
220
237
  }
221
238
 
222
- /**
223
- * Update user by ID (admin function)
224
- */
225
- async updateUser(userId: string, updates: Record<string, any>): Promise<User> {
226
- try {
227
- return await this.makeRequest<User>('PUT', `/api/users/${userId}`, updates, { cache: false });
228
- } catch (error) {
229
- throw this.handleError(error);
230
- }
231
- }
232
239
 
233
240
  /**
234
241
  * Follow a user
@@ -17,6 +17,9 @@ const ec = new EC('secp256k1');
17
17
  const STORAGE_KEYS = {
18
18
  PRIVATE_KEY: 'oxy_identity_private_key',
19
19
  PUBLIC_KEY: 'oxy_identity_public_key',
20
+ BACKUP_PRIVATE_KEY: 'oxy_identity_backup_private_key',
21
+ BACKUP_PUBLIC_KEY: 'oxy_identity_backup_public_key',
22
+ BACKUP_TIMESTAMP: 'oxy_identity_backup_timestamp',
20
23
  } as const;
21
24
 
22
25
  /**
@@ -183,12 +186,184 @@ export class KeyManager {
183
186
 
184
187
  /**
185
188
  * Delete the stored identity (both keys)
186
- * Use with caution - this is irreversible without a recovery phrase
189
+ * Use with EXTREME caution - this is irreversible without a recovery phrase
190
+ * This should ONLY be called when explicitly requested by the user
191
+ * @param skipBackup - If true, skip backup before deletion (default: false)
192
+ * @param force - If true, skip confirmation checks (default: false)
193
+ * @param userConfirmed - If true, user has explicitly confirmed deletion (default: false)
187
194
  */
188
- static async deleteIdentity(): Promise<void> {
195
+ static async deleteIdentity(
196
+ skipBackup: boolean = false,
197
+ force: boolean = false,
198
+ userConfirmed: boolean = false
199
+ ): Promise<void> {
200
+ // CRITICAL SAFEGUARD: Require explicit user confirmation unless force is true
201
+ if (!force && !userConfirmed) {
202
+ throw new Error('Identity deletion requires explicit user confirmation. This is a safety measure to prevent accidental data loss.');
203
+ }
204
+
205
+ if (!force) {
206
+ const hasIdentity = await KeyManager.hasIdentity();
207
+ if (!hasIdentity) {
208
+ return; // Nothing to delete
209
+ }
210
+ }
211
+
189
212
  const store = await initSecureStore();
213
+
214
+ // ALWAYS create backup before deletion unless explicitly skipped
215
+ if (!skipBackup) {
216
+ try {
217
+ const backupSuccess = await KeyManager.backupIdentity();
218
+ if (!backupSuccess && typeof __DEV__ !== 'undefined' && __DEV__) {
219
+ console.warn('[KeyManager] Failed to backup identity before deletion - proceeding anyway');
220
+ }
221
+ } catch (backupError) {
222
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
223
+ console.warn('[KeyManager] Failed to backup identity before deletion:', backupError);
224
+ }
225
+ }
226
+ }
227
+
190
228
  await store.deleteItemAsync(STORAGE_KEYS.PRIVATE_KEY);
191
229
  await store.deleteItemAsync(STORAGE_KEYS.PUBLIC_KEY);
230
+
231
+ // Also clear backup if force deletion
232
+ if (force) {
233
+ try {
234
+ await store.deleteItemAsync(STORAGE_KEYS.BACKUP_PRIVATE_KEY);
235
+ await store.deleteItemAsync(STORAGE_KEYS.BACKUP_PUBLIC_KEY);
236
+ await store.deleteItemAsync(STORAGE_KEYS.BACKUP_TIMESTAMP);
237
+ } catch (error) {
238
+ // Ignore backup deletion errors
239
+ }
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Backup identity to SecureStore (separate backup storage)
245
+ * This provides a recovery mechanism if primary storage fails
246
+ */
247
+ static async backupIdentity(): Promise<boolean> {
248
+ try {
249
+ const store = await initSecureStore();
250
+ const privateKey = await KeyManager.getPrivateKey();
251
+ const publicKey = await KeyManager.getPublicKey();
252
+
253
+ if (!privateKey || !publicKey) {
254
+ return false; // Nothing to backup
255
+ }
256
+
257
+ // Store backup in SecureStore (still secure, but separate from primary storage)
258
+ await store.setItemAsync(STORAGE_KEYS.BACKUP_PRIVATE_KEY, privateKey, {
259
+ keychainAccessible: store.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
260
+ });
261
+ await store.setItemAsync(STORAGE_KEYS.BACKUP_PUBLIC_KEY, publicKey);
262
+ await store.setItemAsync(STORAGE_KEYS.BACKUP_TIMESTAMP, Date.now().toString());
263
+
264
+ return true;
265
+ } catch (error) {
266
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
267
+ console.error('[KeyManager] Failed to backup identity:', error);
268
+ }
269
+ return false;
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Verify identity integrity - checks if keys are valid and accessible
275
+ */
276
+ static async verifyIdentityIntegrity(): Promise<boolean> {
277
+ try {
278
+ const privateKey = await KeyManager.getPrivateKey();
279
+ const publicKey = await KeyManager.getPublicKey();
280
+
281
+ if (!privateKey || !publicKey) {
282
+ return false;
283
+ }
284
+
285
+ // Validate private key format
286
+ if (!KeyManager.isValidPrivateKey(privateKey)) {
287
+ return false;
288
+ }
289
+
290
+ // Validate public key format
291
+ if (!KeyManager.isValidPublicKey(publicKey)) {
292
+ return false;
293
+ }
294
+
295
+ // Verify public key can be derived from private key
296
+ const derivedPublicKey = KeyManager.derivePublicKey(privateKey);
297
+ if (derivedPublicKey !== publicKey) {
298
+ return false; // Keys don't match
299
+ }
300
+
301
+ // Verify we can create a key pair object (tests elliptic curve operations)
302
+ const keyPair = await KeyManager.getKeyPairObject();
303
+ if (!keyPair) {
304
+ return false;
305
+ }
306
+
307
+ return true;
308
+ } catch (error) {
309
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
310
+ console.error('[KeyManager] Identity integrity check failed:', error);
311
+ }
312
+ return false;
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Restore identity from backup if primary storage is corrupted
318
+ */
319
+ static async restoreIdentityFromBackup(): Promise<boolean> {
320
+ try {
321
+ const store = await initSecureStore();
322
+
323
+ // Check if backup exists
324
+ const backupPrivateKey = await store.getItemAsync(STORAGE_KEYS.BACKUP_PRIVATE_KEY);
325
+ const backupPublicKey = await store.getItemAsync(STORAGE_KEYS.BACKUP_PUBLIC_KEY);
326
+
327
+ if (!backupPrivateKey || !backupPublicKey) {
328
+ return false; // No backup available
329
+ }
330
+
331
+ // Verify backup integrity
332
+ if (!KeyManager.isValidPrivateKey(backupPrivateKey)) {
333
+ return false;
334
+ }
335
+
336
+ if (!KeyManager.isValidPublicKey(backupPublicKey)) {
337
+ return false;
338
+ }
339
+
340
+ // Verify keys match
341
+ const derivedPublicKey = KeyManager.derivePublicKey(backupPrivateKey);
342
+ if (derivedPublicKey !== backupPublicKey) {
343
+ return false; // Backup keys don't match
344
+ }
345
+
346
+ // Restore from backup
347
+ await store.setItemAsync(STORAGE_KEYS.PRIVATE_KEY, backupPrivateKey, {
348
+ keychainAccessible: store.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
349
+ });
350
+ await store.setItemAsync(STORAGE_KEYS.PUBLIC_KEY, backupPublicKey);
351
+
352
+ // Verify restoration was successful
353
+ const restored = await KeyManager.verifyIdentityIntegrity();
354
+ if (restored) {
355
+ // Update backup timestamp
356
+ await store.setItemAsync(STORAGE_KEYS.BACKUP_TIMESTAMP, Date.now().toString());
357
+ return true;
358
+ }
359
+
360
+ return false;
361
+ } catch (error) {
362
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
363
+ console.error('[KeyManager] Failed to restore identity from backup:', error);
364
+ }
365
+ return false;
366
+ }
192
367
  }
193
368
 
194
369
  /**
@@ -82,6 +82,36 @@ export interface AuthChallenge {
82
82
  }
83
83
 
84
84
  export class SignatureService {
85
+ /**
86
+ * Generate a random challenge string (for offline use)
87
+ * Uses expo-crypto in React Native, crypto.randomBytes in Node.js
88
+ */
89
+ static async generateChallenge(): Promise<string> {
90
+ if (isReactNative() || !isNodeJS()) {
91
+ // Use expo-crypto for React Native (expo-random is deprecated)
92
+ const Crypto = await initExpoCrypto();
93
+ const randomBytes = await Crypto.getRandomBytesAsync(32);
94
+ return Array.from(randomBytes)
95
+ .map((b: number) => b.toString(16).padStart(2, '0'))
96
+ .join('');
97
+ }
98
+
99
+ // Node.js fallback
100
+ try {
101
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
102
+ const getCrypto = new Function('return require("crypto")');
103
+ const crypto = getCrypto();
104
+ return crypto.randomBytes(32).toString('hex');
105
+ } catch (error) {
106
+ // Fallback to expo-crypto if Node crypto fails
107
+ const Crypto = await initExpoCrypto();
108
+ const randomBytes = await Crypto.getRandomBytesAsync(32);
109
+ return Array.from(randomBytes)
110
+ .map((b: number) => b.toString(16).padStart(2, '0'))
111
+ .join('');
112
+ }
113
+ }
114
+
85
115
  /**
86
116
  * Hash a message using SHA-256
87
117
  */
@@ -27,7 +27,7 @@ const GroupedSectionComponent = ({ items }: GroupedSectionProps) => {
27
27
  return (
28
28
  <View style={{ width: '100%' }}>
29
29
  {items.map((item, index) => (
30
- <View key={item.id} style={{ marginBottom: index < items.length - 1 ? 4 : 0 }}>
30
+ <View key={`${item.id}-${index}`} style={{ marginBottom: index < items.length - 1 ? 4 : 0 }}>
31
31
  <GroupedItem
32
32
  icon={item.icon}
33
33
  iconColor={item.iconColor}
@@ -1,14 +1,16 @@
1
- import { useEffect, useRef, type FC } from 'react';
1
+ import { useEffect, useRef, useState, type FC } from 'react';
2
2
  import { AppState } from 'react-native';
3
3
  import { GestureHandlerRootView } from 'react-native-gesture-handler';
4
4
  import { SafeAreaProvider } from 'react-native-safe-area-context';
5
5
  import { KeyboardProvider } from 'react-native-keyboard-controller';
6
6
  import type { OxyProviderProps } from '../types/navigation';
7
7
  import { OxyContextProvider } from '../context/OxyContext';
8
- import { QueryClient, QueryClientProvider, focusManager } from '@tanstack/react-query';
8
+ import { QueryClientProvider, focusManager, onlineManager } from '@tanstack/react-query';
9
9
  import { setupFonts } from './FontLoader';
10
10
  import BottomSheetRouter from './BottomSheetRouter';
11
11
  import { Toaster } from '../../lib/sonner';
12
+ import { createQueryClient } from '../hooks/queryClient';
13
+ import { useStorage } from '../hooks/useStorage';
12
14
 
13
15
  // Initialize fonts automatically
14
16
  setupFonts();
@@ -26,31 +28,32 @@ const OxyProvider: FC<OxyProviderProps> = ({
26
28
  onAuthStateChange,
27
29
  storageKeyPrefix,
28
30
  baseURL,
29
- queryClient,
31
+ queryClient: providedQueryClient,
30
32
  }) => {
31
33
  // contextOnly is retained for backwards compatibility while the UI-only
32
34
  // bottom sheet experience is removed. At the moment both modes behave the same.
33
35
  void contextOnly;
34
36
 
35
- // Initialize React Query Client (use provided client or create a default one once)
36
- const queryClientRef = useRef<QueryClient | null>(null);
37
- if (!queryClientRef.current) {
38
- const defaultClient = new QueryClient({
39
- defaultOptions: {
40
- queries: {
41
- staleTime: 30_000,
42
- gcTime: 5 * 60_000,
43
- retry: 2,
44
- refetchOnReconnect: true,
45
- refetchOnWindowFocus: false,
46
- },
47
- mutations: {
48
- retry: 1,
49
- },
50
- },
51
- });
52
- queryClientRef.current = queryClient ?? defaultClient;
53
- }
37
+ // Get storage for query persistence
38
+ const { storage, isReady: isStorageReady } = useStorage();
39
+
40
+ // Initialize React Query Client with persistence
41
+ const queryClientRef = useRef<ReturnType<typeof createQueryClient> | null>(null);
42
+ const [queryClient, setQueryClient] = useState<ReturnType<typeof createQueryClient> | null>(null);
43
+
44
+ useEffect(() => {
45
+ if (providedQueryClient) {
46
+ queryClientRef.current = providedQueryClient;
47
+ setQueryClient(providedQueryClient);
48
+ } else if (isStorageReady) {
49
+ // Create query client with persistence once storage is ready
50
+ if (!queryClientRef.current) {
51
+ const client = createQueryClient(storage);
52
+ queryClientRef.current = client;
53
+ setQueryClient(client);
54
+ }
55
+ }
56
+ }, [providedQueryClient, isStorageReady, storage]);
54
57
 
55
58
  // Hook React Query focus manager into React Native AppState
56
59
  useEffect(() => {
@@ -62,28 +65,79 @@ const OxyProvider: FC<OxyProviderProps> = ({
62
65
  };
63
66
  }, []);
64
67
 
68
+ // Setup network status monitoring for offline detection
69
+ useEffect(() => {
70
+ let cleanup: (() => void) | undefined;
71
+
72
+ const setupNetworkMonitoring = async () => {
73
+ try {
74
+ // For React Native, try to use NetInfo
75
+ if (typeof window === 'undefined' || (typeof navigator !== 'undefined' && navigator.product === 'ReactNative')) {
76
+ try {
77
+ const NetInfo = await import('@react-native-community/netinfo');
78
+ const state = await NetInfo.default.fetch();
79
+ onlineManager.setOnline(state.isConnected ?? true);
80
+
81
+ const unsubscribe = NetInfo.default.addEventListener((state: { isConnected: boolean | null }) => {
82
+ onlineManager.setOnline(state.isConnected ?? true);
83
+ });
84
+
85
+ cleanup = () => unsubscribe();
86
+ } catch {
87
+ // NetInfo not available, default to online
88
+ onlineManager.setOnline(true);
89
+ }
90
+ } else {
91
+ // For web, use navigator.onLine
92
+ onlineManager.setOnline(navigator.onLine);
93
+ const handleOnline = () => onlineManager.setOnline(true);
94
+ const handleOffline = () => onlineManager.setOnline(false);
95
+
96
+ window.addEventListener('online', handleOnline);
97
+ window.addEventListener('offline', handleOffline);
98
+
99
+ cleanup = () => {
100
+ window.removeEventListener('online', handleOnline);
101
+ window.removeEventListener('offline', handleOffline);
102
+ };
103
+ }
104
+ } catch (error) {
105
+ // Default to online if detection fails
106
+ onlineManager.setOnline(true);
107
+ }
108
+ };
109
+
110
+ setupNetworkMonitoring();
111
+
112
+ return () => {
113
+ cleanup?.();
114
+ };
115
+ }, []);
116
+
65
117
  // Ensure we have a valid QueryClient
66
- const client = queryClientRef.current;
67
- if (!client) {
68
- throw new Error('QueryClient initialization failed');
118
+ if (!queryClient) {
119
+ // Return loading state or fallback
120
+ return null;
69
121
  }
70
122
 
71
123
  return (
72
124
  <SafeAreaProvider>
73
125
  <GestureHandlerRootView style={{ flex: 1 }}>
74
126
  <KeyboardProvider>
75
- <QueryClientProvider client={client}>
76
- <OxyContextProvider
77
- oxyServices={oxyServices as any}
78
- baseURL={baseURL}
79
- storageKeyPrefix={storageKeyPrefix}
80
- onAuthStateChange={onAuthStateChange as any}
81
- >
82
- {children}
83
- <BottomSheetRouter />
84
- <Toaster />
85
- </OxyContextProvider>
86
- </QueryClientProvider>
127
+ {queryClient && (
128
+ <QueryClientProvider client={queryClient}>
129
+ <OxyContextProvider
130
+ oxyServices={oxyServices as any}
131
+ baseURL={baseURL}
132
+ storageKeyPrefix={storageKeyPrefix}
133
+ onAuthStateChange={onAuthStateChange as any}
134
+ >
135
+ {children}
136
+ <BottomSheetRouter />
137
+ <Toaster />
138
+ </OxyContextProvider>
139
+ </QueryClientProvider>
140
+ )}
87
141
  </KeyboardProvider>
88
142
  </GestureHandlerRootView>
89
143
  </SafeAreaProvider>
@@ -36,7 +36,7 @@ export const EditDisplayNameModal: React.FC<EditDisplayNameModalProps> = ({
36
36
  const colorScheme = useColorScheme();
37
37
  const themeStyles = useThemeStyles(theme || 'light', colorScheme);
38
38
  const colors = themeStyles.colors;
39
- const { updateField, isSaving } = useProfileEditing();
39
+ const { saveProfile, isSaving } = useProfileEditing();
40
40
 
41
41
  const [displayName, setDisplayName] = useState(initialDisplayName);
42
42
  const [lastName, setLastName] = useState(initialLastName);
@@ -48,8 +48,6 @@ export const EditDisplayNameModal: React.FC<EditDisplayNameModalProps> = ({
48
48
  }
49
49
  }, [visible, initialDisplayName, initialLastName]);
50
50
 
51
- const { saveProfile } = useProfileEditing();
52
-
53
51
  const handleSave = async () => {
54
52
  const updates = {
55
53
  displayName,