@oxyhq/services 15.0.0 → 16.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 (44) hide show
  1. package/lib/commonjs/index.js +4 -4
  2. package/lib/commonjs/ui/hooks/mutations/mutationKeys.js +1 -1
  3. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +9 -9
  4. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  5. package/lib/commonjs/ui/hooks/queries/queryKeys.js +1 -1
  6. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +7 -8
  7. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
  8. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +17 -18
  9. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
  10. package/lib/module/index.js +2 -2
  11. package/lib/module/index.js.map +1 -1
  12. package/lib/module/ui/hooks/mutations/mutationKeys.js +1 -1
  13. package/lib/module/ui/hooks/mutations/useAccountMutations.js +7 -7
  14. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  15. package/lib/module/ui/hooks/queries/queryKeys.js +1 -1
  16. package/lib/module/ui/hooks/queries/useAccountQueries.js +5 -6
  17. package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
  18. package/lib/module/ui/screens/ConnectedAppsScreen.js +19 -20
  19. package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
  20. package/lib/typescript/commonjs/index.d.ts +2 -2
  21. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  22. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +4 -4
  23. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  24. package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts +6 -7
  25. package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  26. package/lib/typescript/commonjs/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
  27. package/lib/typescript/commonjs/ui/utils/storageHelpers.d.ts +7 -7
  28. package/lib/typescript/module/index.d.ts +2 -2
  29. package/lib/typescript/module/index.d.ts.map +1 -1
  30. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +4 -4
  31. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  32. package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts +6 -7
  33. package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  34. package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
  35. package/lib/typescript/module/ui/utils/storageHelpers.d.ts +7 -7
  36. package/package.json +4 -4
  37. package/src/index.ts +2 -2
  38. package/src/ui/hooks/mutations/mutationKeys.ts +1 -1
  39. package/src/ui/hooks/mutations/useAccountMutations.ts +7 -7
  40. package/src/ui/hooks/queries/queryKeys.ts +1 -1
  41. package/src/ui/hooks/queries/useAccountQueries.ts +8 -9
  42. package/src/ui/navigation/routes.ts +1 -1
  43. package/src/ui/screens/ConnectedAppsScreen.tsx +23 -24
  44. package/src/ui/utils/storageHelpers.ts +7 -7
@@ -10,13 +10,13 @@ export interface SessionStorageKeys {
10
10
  language: string;
11
11
  /**
12
12
  * DURABLE "this device/app has had a signed-in Oxy session before" hint.
13
- *
14
- * Lives in the SAME `storageKeyPrefix`-scoped durable store as the stored
15
- * session ids, so it survives a session expiring (cleared only on explicit
16
- * full sign-out). Read at cold boot to drive the smart `sso-bounce` gate:
17
- * a returning visitor still gets ONE establish bounce so a central-only
18
- * cross-domain session recovers, while a first-time anonymous visitor is
19
- * never force-redirected. See `allowSsoBounce` in `@oxyhq/core`.
13
+ * Originally read at cold boot to drive the FedCM-era smart `sso-bounce`
14
+ * gate (a returning visitor still got one establish bounce; a first-time
15
+ * anonymous visitor was never force-redirected). That gate and
16
+ * `allowSsoBounce` were deleted in the device-first cutover this storage
17
+ * key is currently defined but not read anywhere; kept rather than removed
18
+ * here since deleting a storage key is a logic change, out of scope for a
19
+ * comment sweep. Flag for a follow-up dead-field cleanup.
20
20
  */
21
21
  priorSession: string;
22
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/services",
3
- "version": "15.0.0",
3
+ "version": "16.0.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",
@@ -106,10 +106,10 @@
106
106
  }
107
107
  },
108
108
  "dependencies": {
109
- "@oxyhq/contracts": "0.9.1"
109
+ "@oxyhq/contracts": "0.10.0"
110
110
  },
111
111
  "devDependencies": {
112
- "@oxyhq/core": "^6.0.0",
112
+ "@oxyhq/core": "^7.0.0",
113
113
  "nativewind": "5.0.0-preview.3",
114
114
  "react-native-css": "^3.0.0",
115
115
  "@react-native-async-storage/async-storage": "^2.0.0",
@@ -153,7 +153,7 @@
153
153
  "peerDependencies": {
154
154
  "@expo/vector-icons": "^15.0.3",
155
155
  "@oxyhq/bloom": ">=0.16.0",
156
- "@oxyhq/core": "^6.0.0",
156
+ "@oxyhq/core": "^7.0.0",
157
157
  "@react-native-async-storage/async-storage": "^2.0.0",
158
158
  "@react-native-community/netinfo": "^11.4.1",
159
159
  "@tanstack/query-async-storage-persister": "^5.101",
package/src/index.ts CHANGED
@@ -77,7 +77,7 @@ export {
77
77
  useUserByUsername,
78
78
  useUsersBySessions,
79
79
  usePrivacySettings,
80
- useAuthorizedApps,
80
+ useConnectedApps,
81
81
  } from './ui/hooks/queries/useAccountQueries';
82
82
  export {
83
83
  useSessions,
@@ -124,7 +124,7 @@ export {
124
124
  useUpdatePrivacySettings,
125
125
  useUpdateNotificationPreferences,
126
126
  useUpdateUserPreferences,
127
- useRevokeAuthorizedApp,
127
+ useRevokeConnectedApp,
128
128
  useUploadFile,
129
129
  } from './ui/hooks/mutations/useAccountMutations';
130
130
  export {
@@ -32,7 +32,7 @@ export const mutationKeys = {
32
32
  removeDevice: ['mutation', 'session', 'removeDevice'] as const,
33
33
  },
34
34
 
35
- // Connected apps (FedCM grants)
35
+ // Connected apps (OAuth grants)
36
36
  connectedApps: {
37
37
  revoke: ['mutation', 'connectedApps', 'revoke'] as const,
38
38
  },
@@ -632,20 +632,20 @@ export const useUpdateUserPreferences = () => {
632
632
  };
633
633
 
634
634
  /**
635
- * Revoke the authenticated user's authorization for a specific RP origin.
636
- * Removes the FedCM grant so the origin no longer appears in the user's
637
- * "Connected apps" list — next sign-in from that origin will require explicit
635
+ * Revoke the current user's grant for a connected application (by its
636
+ * `applicationId`). Removes the grant so the app no longer appears in the user's
637
+ * "Connected apps" list — next sign-in for that app will require explicit
638
638
  * re-consent.
639
639
  */
640
- export const useRevokeAuthorizedApp = () => {
640
+ export const useRevokeConnectedApp = () => {
641
641
  const { oxyServices, activeSessionId } = useOxy();
642
642
  const queryClient = useQueryClient();
643
643
 
644
644
  return useMutation({
645
645
  mutationKey: [...mutationKeys.connectedApps.revoke],
646
- mutationFn: async (origin: string) => {
646
+ mutationFn: async (applicationId: string) => {
647
647
  return authenticatedApiCall<void>(oxyServices, activeSessionId, () =>
648
- oxyServices.revokeAuthorizedApp(origin)
648
+ oxyServices.revokeAppGrant(applicationId)
649
649
  );
650
650
  },
651
651
  onSuccess: () => {
@@ -653,7 +653,7 @@ export const useRevokeAuthorizedApp = () => {
653
653
  },
654
654
  onError: (error) => {
655
655
  toast.error(
656
- error instanceof Error ? error.message : 'Failed to revoke authorized app'
656
+ error instanceof Error ? error.message : 'Failed to revoke connected app'
657
657
  );
658
658
  },
659
659
  });
@@ -77,7 +77,7 @@ export const queryKeys = {
77
77
  usage: (accountScope?: string) => [...queryKeys.storage.all, 'usage', accountScope] as const,
78
78
  },
79
79
 
80
- // Connected apps (FedCM grants the user has authorized)
80
+ // Connected apps (OAuth grants the user has authorized)
81
81
  connectedApps: {
82
82
  all: ['connectedApps'] as const,
83
83
  list: () => [...queryKeys.connectedApps.all, 'list'] as const,
@@ -1,7 +1,7 @@
1
1
  import { useEffect } from 'react';
2
2
  import { useQuery, useQueries, useQueryClient } from '@tanstack/react-query';
3
3
  import { authenticatedApiCall } from '@oxyhq/core';
4
- import type { AuthorizedApp, User } from '@oxyhq/core';
4
+ import type { ConnectedApp, User } from '@oxyhq/core';
5
5
  import { queryKeys } from './queryKeys';
6
6
  import { mutationKeys } from '../mutations/mutationKeys';
7
7
  import { useOxy } from '../../context/OxyContext';
@@ -205,21 +205,20 @@ export const useUsersBySessions = (sessionIds: string[], options?: { enabled?: b
205
205
  };
206
206
 
207
207
  /**
208
- * List the authenticated user's authorized RP apps (FedCM grants).
209
- *
210
- * Returns the intersection of the user's grants with the currently-approved
211
- * RP catalog. Drives the "Connected apps" management screen.
208
+ * List the third-party OAuth applications the current user has connected via
209
+ * the consent flow (`GET /auth/grants`). Drives the "Connected apps" management
210
+ * screen.
212
211
  */
213
- export const useAuthorizedApps = (options?: { enabled?: boolean }) => {
212
+ export const useConnectedApps = (options?: { enabled?: boolean }) => {
214
213
  const { oxyServices, activeSessionId, isAuthenticated } = useOxy();
215
214
 
216
- return useQuery<AuthorizedApp[]>({
215
+ return useQuery<ConnectedApp[]>({
217
216
  queryKey: queryKeys.connectedApps.list(),
218
217
  queryFn: async () => {
219
- return authenticatedApiCall<AuthorizedApp[]>(
218
+ return authenticatedApiCall<ConnectedApp[]>(
220
219
  oxyServices,
221
220
  activeSessionId,
222
- () => oxyServices.listAuthorizedApps()
221
+ () => oxyServices.listConnectedApps()
223
222
  );
224
223
  },
225
224
  enabled: (options?.enabled !== false) && isAuthenticated,
@@ -43,7 +43,7 @@ export type RouteName =
43
43
  | 'AccountSettings' // Per-account profile edit + members + danger zone
44
44
  | 'AvatarCrop' // Square-crop editor presented before avatar upload
45
45
  | 'Notifications' // Per-channel notification preferences
46
- | 'ConnectedApps' // FedCM-authorized RP apps the user can revoke
46
+ | 'ConnectedApps' // OAuth-authorized third-party apps the user can revoke
47
47
  | 'Preferences'; // General user preferences (theme, reduce-motion, etc.)
48
48
 
49
49
  // Lazy screen loaders - functions that return screen components on-demand
@@ -3,7 +3,7 @@ import { ActivityIndicator, FlatList, RefreshControl, StyleSheet, View } from 'r
3
3
  import { Dialog, toast, useDialogControl } from '@oxyhq/bloom';
4
4
  import { useTheme } from '@oxyhq/bloom/theme';
5
5
  import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
6
- import type { AuthorizedApp } from '@oxyhq/core';
6
+ import type { ConnectedApp } from '@oxyhq/core';
7
7
  import { logger as loggerUtil } from '@oxyhq/core';
8
8
  import type { BaseScreenProps } from '../types/navigation';
9
9
  import Header from '../components/Header';
@@ -12,8 +12,8 @@ import EmptyState from '../components/EmptyState';
12
12
  import LoadingState from '../components/LoadingState';
13
13
  import { useI18n } from '../hooks/useI18n';
14
14
  import { useOxy } from '../context/OxyContext';
15
- import { useAuthorizedApps } from '../hooks/queries/useAccountQueries';
16
- import { useRevokeAuthorizedApp } from '../hooks/mutations/useAccountMutations';
15
+ import { useConnectedApps } from '../hooks/queries/useAccountQueries';
16
+ import { useRevokeConnectedApp } from '../hooks/mutations/useAccountMutations';
17
17
 
18
18
  const APP_ICON_SIZE = 40;
19
19
 
@@ -39,12 +39,11 @@ const formatRelative = (iso: string): string => {
39
39
  };
40
40
 
41
41
  /**
42
- * ConnectedAppsScreen — list and revoke FedCM-authorized RP applications.
42
+ * ConnectedAppsScreen — list and revoke connected OAuth applications.
43
43
  *
44
- * Fetches via `useAuthorizedApps` (drives `GET /fedcm/me/authorized-apps`)
45
- * and exposes a "Revoke" action that hits `DELETE /fedcm/me/authorized-apps/
46
- * :origin`. Each revoke invalidates the connected-apps query so the list
47
- * refreshes immediately.
44
+ * Fetches via `useConnectedApps` (drives `GET /auth/grants`) and exposes a
45
+ * "Revoke" action that hits `DELETE /auth/grants/:applicationId`. Each revoke
46
+ * invalidates the connected-apps query so the list refreshes immediately.
48
47
  */
49
48
  const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) => {
50
49
  const bloomTheme = useTheme();
@@ -55,14 +54,14 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
55
54
  isLoading,
56
55
  refetch,
57
56
  isRefetching,
58
- } = useAuthorizedApps({ enabled: isAuthenticated });
59
- const revokeMutation = useRevokeAuthorizedApp();
57
+ } = useConnectedApps({ enabled: isAuthenticated });
58
+ const revokeMutation = useRevokeConnectedApp();
60
59
  const revokeDialog = useDialogControl();
61
- const [pendingRevoke, setPendingRevoke] = useState<AuthorizedApp | null>(null);
62
- const [revokingOrigin, setRevokingOrigin] = useState<string | null>(null);
60
+ const [pendingRevoke, setPendingRevoke] = useState<ConnectedApp | null>(null);
61
+ const [revokingAppId, setRevokingAppId] = useState<string | null>(null);
63
62
 
64
63
  const confirmRevoke = useCallback(
65
- (app: AuthorizedApp) => {
64
+ (app: ConnectedApp) => {
66
65
  setPendingRevoke(app);
67
66
  revokeDialog.open();
68
67
  },
@@ -74,16 +73,16 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
74
73
  return;
75
74
  }
76
75
  const target = pendingRevoke;
77
- setRevokingOrigin(target.origin);
76
+ setRevokingAppId(target.applicationId);
78
77
  try {
79
- await revokeMutation.mutateAsync(target.origin);
78
+ await revokeMutation.mutateAsync(target.applicationId);
80
79
  toast.success(
81
80
  t('connectedApps.toasts.revoked', { name: target.name })
82
81
  || `Revoked access for ${target.name}`,
83
82
  );
84
83
  } catch (error) {
85
84
  loggerUtil.warn(
86
- 'Revoke authorized app failed',
85
+ 'Revoke connected app failed',
87
86
  { component: 'ConnectedAppsScreen' },
88
87
  error,
89
88
  );
@@ -92,7 +91,7 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
92
91
  || 'Failed to revoke access',
93
92
  );
94
93
  } finally {
95
- setRevokingOrigin(null);
94
+ setRevokingAppId(null);
96
95
  setPendingRevoke(null);
97
96
  }
98
97
  }, [pendingRevoke, revokeMutation, t]);
@@ -113,18 +112,18 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
113
112
  );
114
113
 
115
114
  const renderItem = useCallback(
116
- ({ item }: { item: AuthorizedApp }) => {
117
- const isRevoking = revokingOrigin === item.origin;
115
+ ({ item }: { item: ConnectedApp }) => {
116
+ const isRevoking = revokingAppId === item.applicationId;
118
117
  return (
119
118
  <SettingsListGroup>
120
119
  <SettingsListItem
121
120
  icon={<Avatar name={item.name} size={APP_ICON_SIZE} />}
122
121
  title={item.name}
123
122
  description={
124
- t('connectedApps.item.lastUsed', {
125
- relative: formatRelative(item.lastUsedAt),
123
+ t('connectedApps.item.granted', {
124
+ relative: formatRelative(item.firstGrantedAt),
126
125
  })
127
- || `Last used ${formatRelative(item.lastUsedAt)}`
126
+ || `Granted ${formatRelative(item.firstGrantedAt)}`
128
127
  }
129
128
  onPress={isRevoking ? undefined : () => confirmRevoke(item)}
130
129
  disabled={isRevoking}
@@ -142,7 +141,7 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
142
141
  </SettingsListGroup>
143
142
  );
144
143
  },
145
- [bloomTheme.colors.error, confirmRevoke, revokingOrigin, t],
144
+ [bloomTheme.colors.error, confirmRevoke, revokingAppId, t],
146
145
  );
147
146
 
148
147
  return (
@@ -158,7 +157,7 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
158
157
  ) : (
159
158
  <FlatList
160
159
  data={apps ?? []}
161
- keyExtractor={(item) => item.origin}
160
+ keyExtractor={(item) => item.applicationId}
162
161
  renderItem={renderItem}
163
162
  contentContainerClassName="px-screen-margin py-space-16"
164
163
  contentContainerStyle={styles.listContent}
@@ -11,13 +11,13 @@ export interface SessionStorageKeys {
11
11
  language: string;
12
12
  /**
13
13
  * DURABLE "this device/app has had a signed-in Oxy session before" hint.
14
- *
15
- * Lives in the SAME `storageKeyPrefix`-scoped durable store as the stored
16
- * session ids, so it survives a session expiring (cleared only on explicit
17
- * full sign-out). Read at cold boot to drive the smart `sso-bounce` gate:
18
- * a returning visitor still gets ONE establish bounce so a central-only
19
- * cross-domain session recovers, while a first-time anonymous visitor is
20
- * never force-redirected. See `allowSsoBounce` in `@oxyhq/core`.
14
+ * Originally read at cold boot to drive the FedCM-era smart `sso-bounce`
15
+ * gate (a returning visitor still got one establish bounce; a first-time
16
+ * anonymous visitor was never force-redirected). That gate and
17
+ * `allowSsoBounce` were deleted in the device-first cutover this storage
18
+ * key is currently defined but not read anywhere; kept rather than removed
19
+ * here since deleting a storage key is a logic change, out of scope for a
20
+ * comment sweep. Flag for a follow-up dead-field cleanup.
21
21
  */
22
22
  priorSession: string;
23
23
  }