@oxyhq/services 22.1.0 → 22.3.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 (100) hide show
  1. package/lib/commonjs/index.js +6 -0
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/components/FollowButton.js +24 -19
  4. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  5. package/lib/commonjs/ui/components/OxyAuthChooser.js +107 -106
  6. package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
  7. package/lib/commonjs/ui/components/oxyAuthChooserStyles.js +0 -19
  8. package/lib/commonjs/ui/components/oxyAuthChooserStyles.js.map +1 -1
  9. package/lib/commonjs/ui/components/passkeyHubPopup.js +33 -0
  10. package/lib/commonjs/ui/components/passkeyHubPopup.js.map +1 -0
  11. package/lib/commonjs/ui/context/OxyContext.js +7 -1
  12. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  13. package/lib/commonjs/ui/context/useOxyAccountGraph.js +2 -0
  14. package/lib/commonjs/ui/context/useOxyAccountGraph.js.map +1 -1
  15. package/lib/commonjs/ui/hooks/useFollow.js +53 -10
  16. package/lib/commonjs/ui/hooks/useFollow.js.map +1 -1
  17. package/lib/commonjs/ui/hooks/useSessionManagement.js +2 -0
  18. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  19. package/lib/commonjs/ui/index.js +6 -0
  20. package/lib/commonjs/ui/index.js.map +1 -1
  21. package/lib/commonjs/ui/stores/followStore.js +276 -92
  22. package/lib/commonjs/ui/stores/followStore.js.map +1 -1
  23. package/lib/commonjs/ui/stores/resetSessionScopedStores.js +14 -0
  24. package/lib/commonjs/ui/stores/resetSessionScopedStores.js.map +1 -0
  25. package/lib/module/index.js +1 -1
  26. package/lib/module/index.js.map +1 -1
  27. package/lib/module/ui/components/FollowButton.js +24 -19
  28. package/lib/module/ui/components/FollowButton.js.map +1 -1
  29. package/lib/module/ui/components/OxyAuthChooser.js +108 -107
  30. package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
  31. package/lib/module/ui/components/oxyAuthChooserStyles.js +0 -19
  32. package/lib/module/ui/components/oxyAuthChooserStyles.js.map +1 -1
  33. package/lib/module/ui/components/passkeyHubPopup.js +29 -0
  34. package/lib/module/ui/components/passkeyHubPopup.js.map +1 -0
  35. package/lib/module/ui/context/OxyContext.js +7 -1
  36. package/lib/module/ui/context/OxyContext.js.map +1 -1
  37. package/lib/module/ui/context/useOxyAccountGraph.js +2 -0
  38. package/lib/module/ui/context/useOxyAccountGraph.js.map +1 -1
  39. package/lib/module/ui/hooks/useFollow.js +51 -9
  40. package/lib/module/ui/hooks/useFollow.js.map +1 -1
  41. package/lib/module/ui/hooks/useSessionManagement.js +2 -0
  42. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  43. package/lib/module/ui/index.js +1 -1
  44. package/lib/module/ui/index.js.map +1 -1
  45. package/lib/module/ui/stores/followStore.js +274 -91
  46. package/lib/module/ui/stores/followStore.js.map +1 -1
  47. package/lib/module/ui/stores/resetSessionScopedStores.js +11 -0
  48. package/lib/module/ui/stores/resetSessionScopedStores.js.map +1 -0
  49. package/lib/typescript/commonjs/index.d.ts +1 -1
  50. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
  52. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts +0 -19
  54. package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
  55. package/lib/typescript/commonjs/ui/components/passkeyHubPopup.d.ts +23 -0
  56. package/lib/typescript/commonjs/ui/components/passkeyHubPopup.d.ts.map +1 -0
  57. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  59. package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts +13 -2
  60. package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts.map +1 -1
  61. package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
  62. package/lib/typescript/commonjs/ui/index.d.ts +1 -1
  63. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/ui/stores/followStore.d.ts +4 -1
  65. package/lib/typescript/commonjs/ui/stores/followStore.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts +3 -0
  67. package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts.map +1 -0
  68. package/lib/typescript/module/index.d.ts +1 -1
  69. package/lib/typescript/module/index.d.ts.map +1 -1
  70. package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
  71. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
  72. package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts +0 -19
  73. package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
  74. package/lib/typescript/module/ui/components/passkeyHubPopup.d.ts +23 -0
  75. package/lib/typescript/module/ui/components/passkeyHubPopup.d.ts.map +1 -0
  76. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  77. package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  78. package/lib/typescript/module/ui/hooks/useFollow.d.ts +13 -2
  79. package/lib/typescript/module/ui/hooks/useFollow.d.ts.map +1 -1
  80. package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
  81. package/lib/typescript/module/ui/index.d.ts +1 -1
  82. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  83. package/lib/typescript/module/ui/stores/followStore.d.ts +4 -1
  84. package/lib/typescript/module/ui/stores/followStore.d.ts.map +1 -1
  85. package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts +3 -0
  86. package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts.map +1 -0
  87. package/package.json +12 -12
  88. package/src/index.ts +1 -1
  89. package/src/ui/components/FollowButton.tsx +22 -20
  90. package/src/ui/components/OxyAuthChooser.tsx +125 -89
  91. package/src/ui/components/oxyAuthChooserStyles.ts +0 -19
  92. package/src/ui/components/passkeyHubPopup.ts +28 -0
  93. package/src/ui/context/OxyContext.tsx +6 -0
  94. package/src/ui/context/useOxyAccountGraph.ts +2 -0
  95. package/src/ui/hooks/useFollow.ts +51 -9
  96. package/src/ui/hooks/useSessionManagement.ts +2 -0
  97. package/src/ui/index.ts +1 -1
  98. package/src/ui/stores/__tests__/followStore.test.ts +178 -0
  99. package/src/ui/stores/followStore.ts +277 -106
  100. package/src/ui/stores/resetSessionScopedStores.ts +8 -0
@@ -28,7 +28,7 @@ const isMultiMode = props => 'userIds' in props && Array.isArray(props.userIds);
28
28
  const FollowButtonInner = /*#__PURE__*/memo(function FollowButtonInner({
29
29
  userId,
30
30
  oxyServices,
31
- initiallyFollowing = false,
31
+ initiallyFollowing,
32
32
  size = 'medium',
33
33
  onFollowChange,
34
34
  style,
@@ -42,17 +42,18 @@ const FollowButtonInner = /*#__PURE__*/memo(function FollowButtonInner({
42
42
  } = useTheme();
43
43
  const {
44
44
  isFollowing,
45
+ isKnown,
45
46
  isLoading,
46
47
  toggleFollow,
47
- setFollowStatus,
48
- fetchStatus
49
- } = useFollowForButton(userId, oxyServices);
48
+ resolveStatus
49
+ } = useFollowForButton(userId, oxyServices, initiallyFollowing);
50
50
  const handlePress = useCallback(async event => {
51
51
  if (preventParentActions && event?.preventDefault) {
52
52
  event.preventDefault();
53
53
  event.stopPropagation?.();
54
54
  }
55
- if (disabled || isLoading) return;
55
+ // Ignore presses while a mutation is in flight or the status is still unknown.
56
+ if (disabled || isLoading || !isKnown) return;
56
57
  try {
57
58
  await toggleFollow();
58
59
  onFollowChange?.(!isFollowing);
@@ -60,32 +61,36 @@ const FollowButtonInner = /*#__PURE__*/memo(function FollowButtonInner({
60
61
  const error = err instanceof Error ? err : new Error(String(err));
61
62
  toast.error(error.message || 'Failed to update follow status');
62
63
  }
63
- }, [disabled, isLoading, toggleFollow, onFollowChange, isFollowing, preventParentActions]);
64
- useEffect(() => {
65
- if (userId && !isFollowing && initiallyFollowing) {
66
- setFollowStatus(initiallyFollowing);
67
- }
68
- // eslint-disable-next-line react-hooks/exhaustive-deps
69
- }, [userId, initiallyFollowing]);
64
+ }, [disabled, isLoading, isKnown, toggleFollow, onFollowChange, isFollowing, preventParentActions]);
65
+
66
+ // Enqueue a batched status fetch ONLY when the status is genuinely unknown
67
+ // (not seeded from `initiallyFollowing`, not already resolved). All buttons
68
+ // that enqueue in the same commit coalesce into a single bulk request; known/
69
+ // seeded ids never fetch. Once resolved, `isKnown` flips true and this no-ops.
70
70
  useEffect(() => {
71
- if (userId) fetchStatus();
72
- }, [userId, fetchStatus]);
73
- const showSpinner = showLoadingState && isLoading;
71
+ if (!isKnown) resolveStatus();
72
+ }, [isKnown, resolveStatus]);
73
+
74
+ // While the status is genuinely unknown (being resolved), present a NEUTRAL,
75
+ // non-interactive state rather than a definitive "Follow".
76
+ const isBusy = isLoading || !isKnown;
77
+ const showFollowing = isKnown && isFollowing;
78
+ const showSpinner = showLoadingState && isBusy;
74
79
  return /*#__PURE__*/_jsx(Button, {
75
- variant: isFollowing ? 'secondary' : 'primary',
80
+ variant: showFollowing ? 'secondary' : 'primary',
76
81
  size: size,
77
82
  onPress: () => {
78
83
  void handlePress();
79
84
  },
80
- disabled: disabled || isLoading,
85
+ disabled: disabled || isBusy,
81
86
  style: style,
82
87
  textStyle: textStyle,
83
88
  icon: showSpinner ? /*#__PURE__*/_jsx(Loading, {
84
89
  variant: "inline",
85
90
  size: "small",
86
- color: isFollowing ? colors.text : colors.primaryForeground
91
+ color: showFollowing ? colors.text : colors.primaryForeground
87
92
  }) : undefined,
88
- children: showSpinner ? undefined : isFollowing ? 'Following' : 'Follow'
93
+ children: showSpinner ? undefined : isKnown ? isFollowing ? 'Following' : 'Follow' : undefined
89
94
  });
90
95
  });
91
96
  const FollowButtonMultiInner = /*#__PURE__*/memo(function FollowButtonMultiInner({
@@ -1 +1 @@
1
- {"version":3,"names":["useEffect","useCallback","useMemo","useState","memo","useOxy","toast","Button","Loading","useFollow","useFollowForButton","useFollowStore","useTheme","useShallow","jsx","_jsx","DEFAULT_FOLLOW_ALL_LABEL","DEFAULT_FOLLOWED_ALL_LABEL","isMultiMode","props","Array","isArray","userIds","FollowButtonInner","userId","oxyServices","initiallyFollowing","size","onFollowChange","style","textStyle","disabled","showLoadingState","preventParentActions","colors","isFollowing","isLoading","toggleFollow","setFollowStatus","fetchStatus","handlePress","event","preventDefault","stopPropagation","err","error","Error","String","message","showSpinner","variant","onPress","icon","color","text","primaryForeground","undefined","children","FollowButtonMultiInner","initiallyAllFollowing","followAllLabel","followedAllLabel","onBulkFollow","onBulkUnfollow","follow","followAllUsers","unfollowAllUsers","isAnyLoading","initialFollowStatuses","state","statuses","uid","Object","prototype","hasOwnProperty","call","followingUsers","hasKnownNotFollowing","some","storeAllFollowing","allFollowing","fetchAllStatuses","isSubmitting","setIsSubmitting","userIdsKey","join","result","allAlreadyFollowing","followedCount","results","length","every","entry","alreadyFollowing","anyFollowed","success","FollowButton","canUsePrivateApi","user","currentUser","currentUserId","id","trim","rawUserIds","multiUserIds","seen","Set","cleaned","raw","has","add","push","targetUserId"],"sourceRoot":"../../../../src","sources":["ui/components/FollowButton.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["useEffect","useCallback","useMemo","useState","memo","useOxy","toast","Button","Loading","useFollow","useFollowForButton","useFollowStore","useTheme","useShallow","jsx","_jsx","DEFAULT_FOLLOW_ALL_LABEL","DEFAULT_FOLLOWED_ALL_LABEL","isMultiMode","props","Array","isArray","userIds","FollowButtonInner","userId","oxyServices","initiallyFollowing","size","onFollowChange","style","textStyle","disabled","showLoadingState","preventParentActions","colors","isFollowing","isKnown","isLoading","toggleFollow","resolveStatus","handlePress","event","preventDefault","stopPropagation","err","error","Error","String","message","isBusy","showFollowing","showSpinner","variant","onPress","icon","color","text","primaryForeground","undefined","children","FollowButtonMultiInner","initiallyAllFollowing","followAllLabel","followedAllLabel","onBulkFollow","onBulkUnfollow","follow","followAllUsers","unfollowAllUsers","isAnyLoading","initialFollowStatuses","state","statuses","uid","Object","prototype","hasOwnProperty","call","followingUsers","hasKnownNotFollowing","some","storeAllFollowing","allFollowing","fetchAllStatuses","isSubmitting","setIsSubmitting","userIdsKey","join","result","allAlreadyFollowing","followedCount","results","length","every","entry","alreadyFollowing","anyFollowed","success","FollowButton","canUsePrivateApi","user","currentUser","currentUserId","id","trim","rawUserIds","multiUserIds","seen","Set","cleaned","raw","has","add","push","targetUserId"],"sourceRoot":"../../../../src","sources":["ui/components/FollowButton.tsx"],"mappings":"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","ignoreList":[]}
@@ -54,6 +54,7 @@ import { MaterialCommunityIcons } from '@expo/vector-icons';
54
54
  import QRCode from 'react-native-qrcode-svg';
55
55
  import { Avatar } from '@oxyhq/bloom/avatar';
56
56
  import { Button } from '@oxyhq/bloom/button';
57
+ import { toast } from '@oxyhq/bloom';
57
58
  import { Text } from '@oxyhq/bloom/typography';
58
59
  import { useTheme, BloomColorScope, APP_COLOR_NAMES, APP_COLOR_PRESETS } from '@oxyhq/bloom/theme';
59
60
  import { isOxyRpOrigin } from '@oxyhq/core';
@@ -65,7 +66,7 @@ import { getCommonsAcquisitionUrl } from "../utils/commonsStoreLinks.js";
65
66
  import { authChooserStyles as styles } from "./oxyAuthChooserStyles.js";
66
67
 
67
68
  /** Diameter of a row avatar. */
68
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
69
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
69
70
  const ROW_AVATAR_SIZE = 40;
70
71
  /** High-contrast QR colors — intentionally fixed (NOT themed) for scan reliability. */
71
72
  const QR_PLATE_BG = '#FFFFFF';
@@ -111,46 +112,51 @@ const OxyAuthChooser = ({
111
112
  } = useI18n();
112
113
  const queryClient = useQueryClient();
113
114
 
114
- // A credential minted for `oxy.so` can only be asserted there (or a loopback
115
- // dev host) — this is a hard WebAuthn RP-ID boundary, not feature detection,
116
- // so it is the ONLY gate on the passkey affordances. `isOxyRpOrigin()` is
117
- // `false` on native by construction (no `location`), so no separate native
118
- // check is needed.
119
- const passkeyAvailable = useMemo(() => isOxyRpOrigin(), []);
115
+ // A credential minted for `oxy.so` can only be ASSERTED there (or a loopback
116
+ // dev host) — a hard WebAuthn RP-ID boundary the browser enforces, not
117
+ // feature detection. On a first-party Oxy web origin the ceremony runs
118
+ // directly ('direct'). On any OTHER web origin (b2) it can't run locally, so
119
+ // the passkey action instead opens a popup at the auth.oxy.so passkey hub —
120
+ // where the SAME ceremony IS first-party — and relays the resulting session
121
+ // back via `AccountDialogController.startPasskeyHubSignIn` ('hub'). Native
122
+ // has neither: Commons owns identity there ('none'). `isOxyRpOrigin()` reads
123
+ // `location` once and is stable for the component's lifetime.
124
+ const passkeyMode = useMemo(() => {
125
+ if (!isWebBrowser()) return 'none';
126
+ return isOxyRpOrigin() ? 'direct' : 'hub';
127
+ }, []);
128
+ const passkeyAvailable = passkeyMode !== 'none';
120
129
  const [signInPasskeyPending, setSignInPasskeyPending] = useState(false);
121
- const [signInPasskeyError, setSignInPasskeyError] = useState(null);
122
130
  const handleSignInWithPasskey = useCallback(async () => {
123
131
  if (signInPasskeyPending) return;
124
132
  setSignInPasskeyPending(true);
125
- setSignInPasskeyError(null);
126
133
  try {
127
134
  await signInWithPasskey();
128
135
  onComplete?.();
129
136
  } catch (error) {
130
137
  // A cancelled/failed ceremony keeps the view open so the user can retry
131
- // or fall back to the QR — surface a concise message, never swallow.
132
- setSignInPasskeyError(error instanceof Error && error.message ? error.message : 'Passkey sign-in failed.');
138
+ // or fall back to the QR — surface the reason as a toast (owner mandate:
139
+ // errors never render inline inside the dialog), never swallow.
140
+ toast.error(error instanceof Error && error.message ? error.message : t('accountSwitcher.toasts.passkeySignInFailed') || 'Passkey sign-in failed.');
133
141
  } finally {
134
142
  setSignInPasskeyPending(false);
135
143
  }
136
- }, [signInPasskeyPending, signInWithPasskey, onComplete]);
144
+ }, [signInPasskeyPending, signInWithPasskey, onComplete, t]);
137
145
  const [createPasskeyPending, setCreatePasskeyPending] = useState(false);
138
- const [createPasskeyError, setCreatePasskeyError] = useState(null);
139
146
  const handleCreateWithPasskey = useCallback(async username => {
140
147
  if (createPasskeyPending) return;
141
148
  setCreatePasskeyPending(true);
142
- setCreatePasskeyError(null);
143
149
  try {
144
150
  await registerWithPasskey({
145
151
  username
146
152
  });
147
153
  onComplete?.();
148
154
  } catch (error) {
149
- setCreatePasskeyError(error instanceof Error && error.message ? error.message : 'Account creation failed.');
155
+ toast.error(error instanceof Error && error.message ? error.message : t('signup.toasts.passkeyCreateFailed') || 'Account creation failed.');
150
156
  } finally {
151
157
  setCreatePasskeyPending(false);
152
158
  }
153
- }, [createPasskeyPending, registerWithPasskey, onComplete]);
159
+ }, [createPasskeyPending, registerWithPasskey, onComplete, t]);
154
160
 
155
161
  // Bind the headless controller. `getSnapshot` returns a stable reference
156
162
  // between changes, so it is `useSyncExternalStore`-safe. Guard the no-provider
@@ -162,6 +168,28 @@ const OxyAuthChooser = ({
162
168
  view
163
169
  } = snapshot;
164
170
 
171
+ // Sign-in device-flow failures land on `snapshot.signIn` asynchronously (poll /
172
+ // socket / popup cancel). Toast at the controller notification site — never an
173
+ // inline banner in the QR view (owner mandate, same contract as account-switch).
174
+ useEffect(() => {
175
+ if (!controller) return;
176
+ let lastToastedSignInError = null;
177
+ const maybeToastSignInError = () => {
178
+ const {
179
+ signIn
180
+ } = controller.getSnapshot();
181
+ if (signIn.phase === 'error' && signIn.error && signIn.error !== lastToastedSignInError) {
182
+ lastToastedSignInError = signIn.error;
183
+ toast.error(signIn.error || t('accountSwitcher.toasts.signInFailed') || 'Sign-in failed. Please try again.');
184
+ }
185
+ if (signIn.phase !== 'error') {
186
+ lastToastedSignInError = null;
187
+ }
188
+ };
189
+ maybeToastSignInError();
190
+ return controller.subscribe(maybeToastSignInError);
191
+ }, [controller, t]);
192
+
165
193
  // Web: "Sign in with Oxy" auto-starts the instant the sign-in entry is
166
194
  // reached — no button tap needed. `signInWithOxy()` tries the shared
167
195
  // keychain first (silently, native-only) then falls to the QR handoff,
@@ -185,19 +213,24 @@ const OxyAuthChooser = ({
185
213
  setSwitching(true);
186
214
  try {
187
215
  await controller.switchTo(accountId);
188
- // A switch succeeds unless the controller recorded an error. On success
189
- // reload the app's account graph and drop cached account-scoped data so
190
- // the new active identity re-fetches the same side effects the
191
- // context's own `switchToAccount` performs.
192
- if (!controller.getSnapshot().error) {
193
- void refreshAccounts();
194
- queryClient.invalidateQueries();
195
- onComplete?.();
216
+ // `switchTo` never throws it records a failure on the controller's
217
+ // snapshot. Read it back at the point the switch settles and surface it
218
+ // as a toast (event-driven, at the failure site NOT an inline banner
219
+ // and NOT a snapshot-reaction). On success reload the app's account
220
+ // graph and drop cached account-scoped data so the new active identity
221
+ // re-fetches — the same side effects the context's own
222
+ // `switchToAccount` performs.
223
+ if (controller.getSnapshot().error) {
224
+ toast.error(t('accountSwitcher.toasts.switchFailed') || 'There was a problem switching accounts. Please try again.');
225
+ return;
196
226
  }
227
+ void refreshAccounts();
228
+ queryClient.invalidateQueries();
229
+ onComplete?.();
197
230
  } finally {
198
231
  setSwitching(false);
199
232
  }
200
- }, [controller, switching, snapshot.activeAccountId, onComplete, refreshAccounts, queryClient]);
233
+ }, [controller, switching, snapshot.activeAccountId, onComplete, refreshAccounts, queryClient, t]);
201
234
  const handleManage = useCallback(() => {
202
235
  onComplete?.();
203
236
  showBottomSheet?.('ManageAccount');
@@ -227,9 +260,13 @@ const OxyAuthChooser = ({
227
260
  t: t,
228
261
  onRetry: () => void controller.showQr(),
229
262
  passkeyAvailable: passkeyAvailable,
230
- onSignInWithPasskey: () => void handleSignInWithPasskey(),
231
- passkeyPending: signInPasskeyPending,
232
- passkeyError: signInPasskeyError,
263
+ onSignInWithPasskey: passkeyMode === 'direct' ? () => void handleSignInWithPasskey() : () => void controller.startPasskeyHubSignIn()
264
+ // The hub-popup flow's pending state is `snapshot.signIn` (already
265
+ // rendered elsewhere in this view) — only the DIRECT ceremony uses this
266
+ // component-local pending flag. A ceremony FAILURE is surfaced as a
267
+ // toast by `handleSignInWithPasskey`, never inline.
268
+ ,
269
+ passkeyPending: passkeyMode === 'direct' ? signInPasskeyPending : false,
233
270
  onCreateAccount: () => controller.startSignup()
234
271
  });
235
272
  }
@@ -239,10 +276,10 @@ const OxyAuthChooser = ({
239
276
  theme: theme,
240
277
  t: t,
241
278
  oxyServices: oxyServices,
242
- passkeyAvailable: passkeyAvailable,
279
+ passkeyMode: passkeyMode,
243
280
  onCreateWithPasskey: handleCreateWithPasskey,
244
281
  createPending: createPasskeyPending,
245
- createError: createPasskeyError,
282
+ onOpenHub: () => void controller.startPasskeyHubSignIn(),
246
283
  onBackToSignIn: () => controller.setView('signin')
247
284
  });
248
285
  }
@@ -261,33 +298,6 @@ const OxyAuthChooser = ({
261
298
  // Accounts view
262
299
  // ---------------------------------------------------------------------------
263
300
 
264
- /**
265
- * Inline error banner for `snapshot.error` (the account-list / switch-failure
266
- * error — distinct from `snapshot.signIn.error`, which `QrView` already
267
- * renders). `AccountsView` and `SignInView` previously swallowed it: a
268
- * blocked/failed switch left the user with no feedback outside the QR view.
269
- */
270
- const ErrorBanner = ({
271
- error,
272
- theme
273
- }) => {
274
- if (!error) return null;
275
- return /*#__PURE__*/_jsxs(View, {
276
- style: [styles.errorBanner, {
277
- backgroundColor: theme.colors.negativeSubtle
278
- }],
279
- children: [/*#__PURE__*/_jsx(MaterialCommunityIcons, {
280
- name: "alert-circle-outline",
281
- size: 18,
282
- color: theme.colors.error
283
- }), /*#__PURE__*/_jsx(Text, {
284
- style: [styles.errorBannerText, {
285
- color: theme.colors.error
286
- }],
287
- children: error
288
- })]
289
- });
290
- };
291
301
  const AccountsView = ({
292
302
  snapshot,
293
303
  theme,
@@ -311,10 +321,7 @@ const AccountsView = ({
311
321
  }
312
322
  return /*#__PURE__*/_jsxs(View, {
313
323
  style: styles.rows,
314
- children: [/*#__PURE__*/_jsx(ErrorBanner, {
315
- error: snapshot.error,
316
- theme: theme
317
- }), snapshot.accounts.map(account => /*#__PURE__*/_jsx(AccountRow, {
324
+ children: [snapshot.accounts.map(account => /*#__PURE__*/_jsx(AccountRow, {
318
325
  account: account,
319
326
  theme: theme,
320
327
  switching: snapshot.switchingAccountId === account.accountId,
@@ -440,10 +447,7 @@ const SignInView = ({
440
447
  onCreateAccount
441
448
  }) => /*#__PURE__*/_jsxs(View, {
442
449
  style: styles.signInBlock,
443
- children: [/*#__PURE__*/_jsx(ErrorBanner, {
444
- error: snapshot.error,
445
- theme: theme
446
- }), snapshot.accounts.length > 0 ? /*#__PURE__*/_jsxs(View, {
450
+ children: [snapshot.accounts.length > 0 ? /*#__PURE__*/_jsxs(View, {
447
451
  style: styles.rows,
448
452
  children: [snapshot.accounts.map(account => /*#__PURE__*/_jsx(AccountRow, {
449
453
  account: account,
@@ -544,7 +548,6 @@ const QrView = ({
544
548
  passkeyAvailable,
545
549
  onSignInWithPasskey,
546
550
  passkeyPending,
547
- passkeyError,
548
551
  onCreateAccount
549
552
  }) => {
550
553
  const {
@@ -552,25 +555,21 @@ const QrView = ({
552
555
  commonsAvailability
553
556
  } = snapshot;
554
557
  const [showQrAnyway, setShowQrAnyway] = useState(false);
555
- const passkeyLink = passkeyAvailable && signIn.phase !== 'authorized' ? /*#__PURE__*/_jsxs(_Fragment, {
556
- children: [/*#__PURE__*/_jsx(Pressable, {
557
- onPress: onSignInWithPasskey,
558
- disabled: passkeyPending,
559
- accessibilityRole: "button",
560
- style: styles.footerLink,
561
- testID: "passkey-signin-link",
562
- children: /*#__PURE__*/_jsx(Text, {
563
- style: [styles.linkText, {
564
- color: theme.colors.textSecondary
565
- }],
566
- children: passkeyPending ? t('accountSwitcher.passkeySigningIn') || 'Signing in…' : t('accountSwitcher.useIdentityOnDevice') || 'No Commons? Use a passkey on this device instead'
567
- })
568
- }), passkeyError ? /*#__PURE__*/_jsx(Text, {
569
- style: [styles.errorText, {
570
- color: theme.colors.error
558
+
559
+ // A ceremony FAILURE is surfaced as a toast by `handleSignInWithPasskey` — the
560
+ // link itself never renders an inline error (owner mandate).
561
+ const passkeyLink = passkeyAvailable && signIn.phase !== 'authorized' ? /*#__PURE__*/_jsx(Pressable, {
562
+ onPress: onSignInWithPasskey,
563
+ disabled: passkeyPending,
564
+ accessibilityRole: "button",
565
+ style: styles.footerLink,
566
+ testID: "passkey-signin-link",
567
+ children: /*#__PURE__*/_jsx(Text, {
568
+ style: [styles.linkText, {
569
+ color: theme.colors.textSecondary
571
570
  }],
572
- children: passkeyError
573
- }) : null]
571
+ children: passkeyPending ? t('accountSwitcher.passkeySigningIn') || 'Signing in…' : t('accountSwitcher.useIdentityOnDevice') || 'No Commons? Use a passkey on this device instead'
572
+ })
574
573
  }) : null;
575
574
 
576
575
  // Native, Commons confirmed NOT installed: a same-device QR is a dead
@@ -607,14 +606,11 @@ const QrView = ({
607
606
  });
608
607
  }
609
608
  if (signIn.phase === 'error') {
609
+ // The failure reason is toasted by the controller subscription above — no
610
+ // inline error copy here (owner mandate).
610
611
  return /*#__PURE__*/_jsxs(View, {
611
612
  style: styles.centeredBlock,
612
- children: [/*#__PURE__*/_jsx(Text, {
613
- style: [styles.errorText, {
614
- color: theme.colors.error
615
- }],
616
- children: signIn.error || 'Sign-in failed. Please try again.'
617
- }), /*#__PURE__*/_jsx(Button, {
613
+ children: [/*#__PURE__*/_jsx(Button, {
618
614
  variant: "secondary",
619
615
  onPress: onRetry,
620
616
  style: styles.secondaryButton,
@@ -671,7 +667,7 @@ const QrView = ({
671
667
  // ---------------------------------------------------------------------------
672
668
 
673
669
  /** Debounced username-availability check over the existing SDK method. */
674
- function useUsernameAvailability(oxyServices) {
670
+ function useUsernameAvailability(oxyServices, t) {
675
671
  const [status, setStatus] = useState('idle');
676
672
  const timerRef = useRef(null);
677
673
  const requestSeqRef = useRef(0);
@@ -689,10 +685,13 @@ function useUsernameAvailability(oxyServices) {
689
685
  setStatus(result.available ? 'available' : 'taken');
690
686
  }).catch(() => {
691
687
  if (seq !== requestSeqRef.current) return;
692
- setStatus('idle'); // network/error don't block on a stale verdict
688
+ // Reset the (now stale) verdict rather than block on it, and surface
689
+ // the failure as a toast — never an inline error inside the dialog.
690
+ setStatus('idle');
691
+ toast.error(t('accounts.create.username.checkFailed') || 'Could not check availability');
693
692
  });
694
693
  }, 400);
695
- }, [oxyServices]);
694
+ }, [oxyServices, t]);
696
695
  return {
697
696
  status,
698
697
  check
@@ -732,17 +731,17 @@ const SignUpView = ({
732
731
  theme,
733
732
  t,
734
733
  oxyServices,
735
- passkeyAvailable,
734
+ passkeyMode,
736
735
  onCreateWithPasskey,
737
736
  createPending,
738
- createError,
737
+ onOpenHub,
739
738
  onBackToSignIn
740
739
  }) => {
741
740
  const [username, setUsername] = useState('');
742
741
  const {
743
742
  status: usernameStatus,
744
743
  check: checkUsername
745
- } = useUsernameAvailability(oxyServices);
744
+ } = useUsernameAvailability(oxyServices, t);
746
745
  const canSubmit = username.trim().length >= 3 && usernameStatus === 'available' && !createPending;
747
746
 
748
747
  // Native — Commons owns identity creation. Mirrors the QR view's own
@@ -770,7 +769,7 @@ const SignUpView = ({
770
769
  // passkey creation is the de-emphasized alternative underneath for someone
771
770
  // who doesn't want to install anything — secondary button, introduced by
772
771
  // its own "No Commons?" framing, same subordination as the QR view's link.
773
- if (passkeyAvailable) {
772
+ if (passkeyMode === 'direct') {
774
773
  return /*#__PURE__*/_jsxs(View, {
775
774
  style: styles.signInBlock,
776
775
  children: [/*#__PURE__*/_jsx(Text, {
@@ -816,12 +815,7 @@ const SignUpView = ({
816
815
  status: usernameStatus,
817
816
  theme: theme,
818
817
  t: t
819
- }), createError ? /*#__PURE__*/_jsx(Text, {
820
- style: [styles.errorText, {
821
- color: theme.colors.error
822
- }],
823
- children: createError
824
- }) : null, /*#__PURE__*/_jsx(Button, {
818
+ }), /*#__PURE__*/_jsx(Button, {
825
819
  variant: "secondary",
826
820
  onPress: () => void onCreateWithPasskey(username.trim()),
827
821
  disabled: !canSubmit,
@@ -836,16 +830,23 @@ const SignUpView = ({
836
830
  });
837
831
  }
838
832
 
839
- // Web, non-Oxy origin: passkey creation here requires the cross-origin hub
840
- // relay (b2), which has not shipped yet an honest message beats a button
841
- // that would fail.
833
+ // Web, non-Oxy origin (b2): passkey creation can't run locally here the
834
+ // same WebAuthn RP-ID boundary as sign-inso this opens the SAME
835
+ // auth.oxy.so passkey hub popup `QrView`'s "No Commons?" link uses.
836
+ // Completing EITHER a sign-in OR a fresh sign-up there relays the resulting
837
+ // session back via the SAME poll/socket engine `showQr` drives.
842
838
  return /*#__PURE__*/_jsxs(View, {
843
839
  style: styles.centeredBlock,
844
840
  children: [/*#__PURE__*/_jsx(Text, {
845
841
  style: [styles.mutedText, {
846
842
  color: theme.colors.textSecondary
847
843
  }],
848
- children: t('signup.notAvailableHere') || "Account creation isn't available in this app yet — create your identity with Commons, or visit oxy.so to sign up with a passkey."
844
+ children: t('signup.hubExplainer') || 'Create your Oxy ID in a secure window, then come right back.'
845
+ }), /*#__PURE__*/_jsx(Button, {
846
+ variant: "primary",
847
+ onPress: onOpenHub,
848
+ style: styles.primaryButton,
849
+ children: t('signup.continueInWindow') || 'Continue in a new window'
849
850
  }), /*#__PURE__*/_jsx(SignInFooterLink, {
850
851
  theme: theme,
851
852
  t: t,