@oxyhq/auth 1.0.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 (119) hide show
  1. package/README.md +56 -0
  2. package/dist/cjs/WebOxyProvider.js +287 -0
  3. package/dist/cjs/hooks/mutations/index.js +23 -0
  4. package/dist/cjs/hooks/mutations/mutationFactory.js +126 -0
  5. package/dist/cjs/hooks/mutations/useAccountMutations.js +275 -0
  6. package/dist/cjs/hooks/mutations/useServicesMutations.js +149 -0
  7. package/dist/cjs/hooks/queries/index.js +35 -0
  8. package/dist/cjs/hooks/queries/queryKeys.js +82 -0
  9. package/dist/cjs/hooks/queries/useAccountQueries.js +141 -0
  10. package/dist/cjs/hooks/queries/useSecurityQueries.js +45 -0
  11. package/dist/cjs/hooks/queries/useServicesQueries.js +113 -0
  12. package/dist/cjs/hooks/queryClient.js +110 -0
  13. package/dist/cjs/hooks/useAssets.js +225 -0
  14. package/dist/cjs/hooks/useFileDownloadUrl.js +91 -0
  15. package/dist/cjs/hooks/useFileFiltering.js +81 -0
  16. package/dist/cjs/hooks/useFollow.js +159 -0
  17. package/dist/cjs/hooks/useFollow.types.js +4 -0
  18. package/dist/cjs/hooks/useQueryClient.js +16 -0
  19. package/dist/cjs/hooks/useSessionSocket.js +215 -0
  20. package/dist/cjs/hooks/useWebSSO.js +146 -0
  21. package/dist/cjs/index.js +115 -0
  22. package/dist/cjs/stores/accountStore.js +226 -0
  23. package/dist/cjs/stores/assetStore.js +192 -0
  24. package/dist/cjs/stores/authStore.js +47 -0
  25. package/dist/cjs/stores/followStore.js +154 -0
  26. package/dist/cjs/utils/authHelpers.js +154 -0
  27. package/dist/cjs/utils/avatarUtils.js +77 -0
  28. package/dist/cjs/utils/errorHandlers.js +128 -0
  29. package/dist/cjs/utils/sessionHelpers.js +90 -0
  30. package/dist/cjs/utils/storageHelpers.js +147 -0
  31. package/dist/esm/WebOxyProvider.js +282 -0
  32. package/dist/esm/hooks/mutations/index.js +10 -0
  33. package/dist/esm/hooks/mutations/mutationFactory.js +122 -0
  34. package/dist/esm/hooks/mutations/useAccountMutations.js +267 -0
  35. package/dist/esm/hooks/mutations/useServicesMutations.js +141 -0
  36. package/dist/esm/hooks/queries/index.js +14 -0
  37. package/dist/esm/hooks/queries/queryKeys.js +76 -0
  38. package/dist/esm/hooks/queries/useAccountQueries.js +131 -0
  39. package/dist/esm/hooks/queries/useSecurityQueries.js +40 -0
  40. package/dist/esm/hooks/queries/useServicesQueries.js +105 -0
  41. package/dist/esm/hooks/queryClient.js +104 -0
  42. package/dist/esm/hooks/useAssets.js +220 -0
  43. package/dist/esm/hooks/useFileDownloadUrl.js +86 -0
  44. package/dist/esm/hooks/useFileFiltering.js +78 -0
  45. package/dist/esm/hooks/useFollow.js +154 -0
  46. package/dist/esm/hooks/useFollow.types.js +3 -0
  47. package/dist/esm/hooks/useQueryClient.js +12 -0
  48. package/dist/esm/hooks/useSessionSocket.js +209 -0
  49. package/dist/esm/hooks/useWebSSO.js +143 -0
  50. package/dist/esm/index.js +48 -0
  51. package/dist/esm/stores/accountStore.js +219 -0
  52. package/dist/esm/stores/assetStore.js +180 -0
  53. package/dist/esm/stores/authStore.js +44 -0
  54. package/dist/esm/stores/followStore.js +151 -0
  55. package/dist/esm/utils/authHelpers.js +145 -0
  56. package/dist/esm/utils/avatarUtils.js +72 -0
  57. package/dist/esm/utils/errorHandlers.js +121 -0
  58. package/dist/esm/utils/sessionHelpers.js +84 -0
  59. package/dist/esm/utils/storageHelpers.js +108 -0
  60. package/dist/types/WebOxyProvider.d.ts +97 -0
  61. package/dist/types/hooks/mutations/index.d.ts +8 -0
  62. package/dist/types/hooks/mutations/mutationFactory.d.ts +75 -0
  63. package/dist/types/hooks/mutations/useAccountMutations.d.ts +68 -0
  64. package/dist/types/hooks/mutations/useServicesMutations.d.ts +22 -0
  65. package/dist/types/hooks/queries/index.d.ts +10 -0
  66. package/dist/types/hooks/queries/queryKeys.d.ts +64 -0
  67. package/dist/types/hooks/queries/useAccountQueries.d.ts +42 -0
  68. package/dist/types/hooks/queries/useSecurityQueries.d.ts +14 -0
  69. package/dist/types/hooks/queries/useServicesQueries.d.ts +31 -0
  70. package/dist/types/hooks/queryClient.d.ts +18 -0
  71. package/dist/types/hooks/useAssets.d.ts +34 -0
  72. package/dist/types/hooks/useFileDownloadUrl.d.ts +18 -0
  73. package/dist/types/hooks/useFileFiltering.d.ts +28 -0
  74. package/dist/types/hooks/useFollow.d.ts +61 -0
  75. package/dist/types/hooks/useFollow.types.d.ts +32 -0
  76. package/dist/types/hooks/useQueryClient.d.ts +6 -0
  77. package/dist/types/hooks/useSessionSocket.d.ts +13 -0
  78. package/dist/types/hooks/useWebSSO.d.ts +57 -0
  79. package/dist/types/index.d.ts +46 -0
  80. package/dist/types/stores/accountStore.d.ts +33 -0
  81. package/dist/types/stores/assetStore.d.ts +53 -0
  82. package/dist/types/stores/authStore.d.ts +16 -0
  83. package/dist/types/stores/followStore.d.ts +24 -0
  84. package/dist/types/utils/authHelpers.d.ts +98 -0
  85. package/dist/types/utils/avatarUtils.d.ts +33 -0
  86. package/dist/types/utils/errorHandlers.d.ts +34 -0
  87. package/dist/types/utils/sessionHelpers.d.ts +63 -0
  88. package/dist/types/utils/storageHelpers.d.ts +27 -0
  89. package/package.json +71 -0
  90. package/src/WebOxyProvider.tsx +372 -0
  91. package/src/global.d.ts +1 -0
  92. package/src/hooks/mutations/index.ts +25 -0
  93. package/src/hooks/mutations/mutationFactory.ts +215 -0
  94. package/src/hooks/mutations/useAccountMutations.ts +344 -0
  95. package/src/hooks/mutations/useServicesMutations.ts +164 -0
  96. package/src/hooks/queries/index.ts +36 -0
  97. package/src/hooks/queries/queryKeys.ts +88 -0
  98. package/src/hooks/queries/useAccountQueries.ts +152 -0
  99. package/src/hooks/queries/useSecurityQueries.ts +64 -0
  100. package/src/hooks/queries/useServicesQueries.ts +126 -0
  101. package/src/hooks/queryClient.ts +112 -0
  102. package/src/hooks/useAssets.ts +291 -0
  103. package/src/hooks/useFileDownloadUrl.ts +118 -0
  104. package/src/hooks/useFileFiltering.ts +115 -0
  105. package/src/hooks/useFollow.ts +175 -0
  106. package/src/hooks/useFollow.types.ts +33 -0
  107. package/src/hooks/useQueryClient.ts +17 -0
  108. package/src/hooks/useSessionSocket.ts +233 -0
  109. package/src/hooks/useWebSSO.ts +187 -0
  110. package/src/index.ts +144 -0
  111. package/src/stores/accountStore.ts +296 -0
  112. package/src/stores/assetStore.ts +281 -0
  113. package/src/stores/authStore.ts +63 -0
  114. package/src/stores/followStore.ts +181 -0
  115. package/src/utils/authHelpers.ts +183 -0
  116. package/src/utils/avatarUtils.ts +103 -0
  117. package/src/utils/errorHandlers.ts +194 -0
  118. package/src/utils/sessionHelpers.ts +151 -0
  119. package/src/utils/storageHelpers.ts +130 -0
@@ -0,0 +1,151 @@
1
+ import type { ClientSession } from '@oxyhq/core';
2
+
3
+ interface DeviceSession {
4
+ sessionId: string;
5
+ deviceId?: string;
6
+ deviceName?: string;
7
+ expiresAt?: string;
8
+ lastActive?: string;
9
+ user?: { id?: string; _id?: { toString(): string } };
10
+ userId?: string;
11
+ isCurrent?: boolean;
12
+ }
13
+
14
+ /**
15
+ * Service type for session helpers.
16
+ * Uses 'any' to work around TypeScript mixin composition type inference issues.
17
+ * The OxyServices class has these methods but TypeScript can't see them due to the mixin pattern.
18
+ */
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ type OxyServicesAny = any;
21
+
22
+ export interface FetchSessionsWithFallbackOptions {
23
+ fallbackDeviceId?: string;
24
+ fallbackUserId?: string;
25
+ logger?: (message: string, error?: unknown) => void;
26
+ }
27
+
28
+ export interface ValidateSessionBatchOptions {
29
+ useHeaderValidation?: boolean;
30
+ maxConcurrency?: number;
31
+ }
32
+
33
+ export interface SessionValidationResult {
34
+ sessionId: string;
35
+ valid: boolean;
36
+ user?: unknown;
37
+ raw?: unknown;
38
+ error?: unknown;
39
+ }
40
+
41
+ /**
42
+ * Normalize backend session payloads into `ClientSession` objects.
43
+ *
44
+ * @param sessions - Raw session array returned from the API
45
+ * @param fallbackDeviceId - Device identifier to use when missing from payload
46
+ * @param fallbackUserId - User identifier to use when missing from payload
47
+ */
48
+ export const mapSessionsToClient = (
49
+ sessions: DeviceSession[],
50
+ fallbackDeviceId?: string,
51
+ fallbackUserId?: string,
52
+ ): ClientSession[] => {
53
+ const now = new Date();
54
+
55
+ return sessions.map((session) => ({
56
+ sessionId: session.sessionId,
57
+ deviceId: session.deviceId || fallbackDeviceId || '',
58
+ expiresAt: session.expiresAt || new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
59
+ lastActive: session.lastActive || now.toISOString(),
60
+ userId:
61
+ session.user?.id ||
62
+ session.userId ||
63
+ (session.user?._id ? session.user._id.toString() : undefined) ||
64
+ fallbackUserId ||
65
+ '',
66
+ isCurrent: Boolean(session.isCurrent),
67
+ }));
68
+ };
69
+
70
+ /**
71
+ * Fetch device sessions with fallback to the legacy session endpoint when needed.
72
+ *
73
+ * @param oxyServices - Oxy service instance
74
+ * @param sessionId - Session identifier to fetch
75
+ * @param options - Optional fallback options
76
+ */
77
+ export const fetchSessionsWithFallback = async (
78
+ oxyServices: OxyServicesAny,
79
+ sessionId: string,
80
+ {
81
+ fallbackDeviceId,
82
+ fallbackUserId,
83
+ logger,
84
+ }: FetchSessionsWithFallbackOptions = {},
85
+ ): Promise<ClientSession[]> => {
86
+ try {
87
+ const deviceSessions = await oxyServices.getDeviceSessions(sessionId);
88
+ return mapSessionsToClient(deviceSessions, fallbackDeviceId, fallbackUserId);
89
+ } catch (error) {
90
+ if (__DEV__ && logger) {
91
+ logger('Failed to get device sessions, falling back to user sessions', error);
92
+ }
93
+
94
+ const userSessions = await oxyServices.getSessionsBySessionId(sessionId);
95
+ return mapSessionsToClient(userSessions, fallbackDeviceId, fallbackUserId);
96
+ }
97
+ };
98
+
99
+ /**
100
+ * Validate multiple sessions concurrently with configurable concurrency.
101
+ *
102
+ * @param oxyServices - Oxy service instance
103
+ * @param sessionIds - Session identifiers to validate
104
+ * @param options - Validation options
105
+ */
106
+ export const validateSessionBatch = async (
107
+ oxyServices: OxyServicesAny,
108
+ sessionIds: string[],
109
+ { useHeaderValidation = true, maxConcurrency = 5 }: ValidateSessionBatchOptions = {},
110
+ ): Promise<SessionValidationResult[]> => {
111
+ if (!sessionIds.length) {
112
+ return [];
113
+ }
114
+
115
+ const uniqueSessionIds = Array.from(new Set(sessionIds));
116
+ const safeConcurrency = Math.max(1, Math.min(maxConcurrency, uniqueSessionIds.length));
117
+ const results: SessionValidationResult[] = [];
118
+ let index = 0;
119
+
120
+ const worker = async () => {
121
+ while (index < uniqueSessionIds.length) {
122
+ const currentIndex = index;
123
+ index += 1;
124
+ const sessionId = uniqueSessionIds[currentIndex];
125
+
126
+ try {
127
+ const validation = await oxyServices.validateSession(sessionId, { useHeaderValidation });
128
+ const valid = Boolean(validation?.valid);
129
+
130
+ results.push({
131
+ sessionId,
132
+ valid,
133
+ user: validation?.user,
134
+ raw: validation,
135
+ });
136
+ } catch (error) {
137
+ results.push({
138
+ sessionId,
139
+ valid: false,
140
+ error,
141
+ });
142
+ }
143
+ }
144
+ };
145
+
146
+ await Promise.all(Array.from({ length: safeConcurrency }, worker));
147
+
148
+ return results;
149
+ };
150
+
151
+
@@ -0,0 +1,130 @@
1
+ export interface StorageInterface {
2
+ getItem: (key: string) => Promise<string | null>;
3
+ setItem: (key: string, value: string) => Promise<void>;
4
+ removeItem: (key: string) => Promise<void>;
5
+ clear: () => Promise<void>;
6
+ }
7
+
8
+ export interface SessionStorageKeys {
9
+ activeSessionId: string;
10
+ sessionIds: string;
11
+ language: string;
12
+ }
13
+
14
+ /**
15
+ * Create an in-memory storage implementation used as a safe fallback.
16
+ */
17
+ const MEMORY_STORAGE = (): StorageInterface => {
18
+ const store = new Map<string, string>();
19
+
20
+ return {
21
+ async getItem(key: string) {
22
+ return store.has(key) ? store.get(key)! : null;
23
+ },
24
+ async setItem(key: string, value: string) {
25
+ store.set(key, value);
26
+ },
27
+ async removeItem(key: string) {
28
+ store.delete(key);
29
+ },
30
+ async clear() {
31
+ store.clear();
32
+ },
33
+ };
34
+ };
35
+
36
+ /**
37
+ * Create a web storage implementation backed by `localStorage`.
38
+ * Falls back to in-memory storage when unavailable.
39
+ */
40
+ const createWebStorage = (): StorageInterface => {
41
+ if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') {
42
+ return MEMORY_STORAGE();
43
+ }
44
+
45
+ return {
46
+ async getItem(key: string) {
47
+ try {
48
+ return window.localStorage.getItem(key);
49
+ } catch {
50
+ return null;
51
+ }
52
+ },
53
+ async setItem(key: string, value: string) {
54
+ try {
55
+ window.localStorage.setItem(key, value);
56
+ } catch {
57
+ // Ignore quota or access issues for now.
58
+ }
59
+ },
60
+ async removeItem(key: string) {
61
+ try {
62
+ window.localStorage.removeItem(key);
63
+ } catch {
64
+ // Ignore failures.
65
+ }
66
+ },
67
+ async clear() {
68
+ try {
69
+ window.localStorage.clear();
70
+ } catch {
71
+ // Ignore failures.
72
+ }
73
+ },
74
+ };
75
+ };
76
+
77
+ let asyncStorageInstance: StorageInterface | null = null;
78
+
79
+ /**
80
+ * Lazily import React Native AsyncStorage implementation.
81
+ */
82
+ const createNativeStorage = async (): Promise<StorageInterface> => {
83
+ if (asyncStorageInstance) {
84
+ return asyncStorageInstance;
85
+ }
86
+
87
+ try {
88
+ const asyncStorageModule = await import('@react-native-async-storage/async-storage');
89
+ asyncStorageInstance = asyncStorageModule.default as unknown as StorageInterface;
90
+ return asyncStorageInstance;
91
+ } catch (error) {
92
+ if (__DEV__) {
93
+ console.error('Failed to import AsyncStorage:', error);
94
+ }
95
+ throw new Error('AsyncStorage is required in React Native environment');
96
+ }
97
+ };
98
+
99
+ /**
100
+ * Detect whether the current runtime is React Native.
101
+ */
102
+ export const isReactNative = (): boolean =>
103
+ typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
104
+
105
+ /**
106
+ * Create a platform-appropriate storage implementation.
107
+ * Defaults to in-memory storage when no platform storage is available.
108
+ */
109
+ export const createPlatformStorage = async (): Promise<StorageInterface> => {
110
+ if (isReactNative()) {
111
+ return createNativeStorage();
112
+ }
113
+
114
+ return createWebStorage();
115
+ };
116
+
117
+ export const STORAGE_KEY_PREFIX = 'oxy_session';
118
+
119
+ /**
120
+ * Produce strongly typed storage key names for the supplied prefix.
121
+ *
122
+ * @param prefix - Storage key prefix
123
+ */
124
+ export const getStorageKeys = (prefix: string = STORAGE_KEY_PREFIX): SessionStorageKeys => ({
125
+ activeSessionId: `${prefix}_active_session_id`,
126
+ sessionIds: `${prefix}_session_ids`,
127
+ language: `${prefix}_language`,
128
+ });
129
+
130
+