@oxyhq/services 17.0.0 → 18.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 (74) hide show
  1. package/README.md +77 -98
  2. package/lib/commonjs/index.js +19 -0
  3. package/lib/commonjs/index.js.map +1 -1
  4. package/lib/commonjs/ui/components/OxyAccountDialog.js +62 -84
  5. package/lib/commonjs/ui/components/OxyAccountDialog.js.map +1 -1
  6. package/lib/commonjs/ui/components/OxyConsentScreen.js +461 -0
  7. package/lib/commonjs/ui/components/OxyConsentScreen.js.map +1 -0
  8. package/lib/commonjs/ui/components/OxyProvider.js +3 -1
  9. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  10. package/lib/commonjs/ui/components/OxySignInButton.js +176 -7
  11. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  12. package/lib/commonjs/ui/components/oauthNavigation.js +73 -0
  13. package/lib/commonjs/ui/components/oauthNavigation.js.map +1 -0
  14. package/lib/commonjs/ui/context/OxyContext.js +16 -2
  15. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  16. package/lib/module/index.js +2 -2
  17. package/lib/module/index.js.map +1 -1
  18. package/lib/module/ui/components/OxyAccountDialog.js +63 -85
  19. package/lib/module/ui/components/OxyAccountDialog.js.map +1 -1
  20. package/lib/module/ui/components/OxyConsentScreen.js +454 -0
  21. package/lib/module/ui/components/OxyConsentScreen.js.map +1 -0
  22. package/lib/module/ui/components/OxyProvider.js +3 -1
  23. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  24. package/lib/module/ui/components/OxySignInButton.js +177 -7
  25. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  26. package/lib/module/ui/components/oauthNavigation.js +70 -0
  27. package/lib/module/ui/components/oauthNavigation.js.map +1 -0
  28. package/lib/module/ui/context/OxyContext.js +16 -2
  29. package/lib/module/ui/context/OxyContext.js.map +1 -1
  30. package/lib/typescript/commonjs/index.d.ts +4 -1
  31. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  32. package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts +18 -2
  33. package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +1 -1
  34. package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts +45 -0
  35. package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts.map +1 -0
  36. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  37. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts +56 -0
  38. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
  39. package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts +36 -0
  40. package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts.map +1 -0
  41. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +14 -0
  42. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  43. package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts +1 -1
  44. package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  45. package/lib/typescript/commonjs/ui/types/navigation.d.ts +18 -0
  46. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  47. package/lib/typescript/module/index.d.ts +4 -1
  48. package/lib/typescript/module/index.d.ts.map +1 -1
  49. package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts +18 -2
  50. package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +1 -1
  51. package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts +45 -0
  52. package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts.map +1 -0
  53. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  54. package/lib/typescript/module/ui/components/OxySignInButton.d.ts +56 -0
  55. package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
  56. package/lib/typescript/module/ui/components/oauthNavigation.d.ts +36 -0
  57. package/lib/typescript/module/ui/components/oauthNavigation.d.ts.map +1 -0
  58. package/lib/typescript/module/ui/context/OxyContext.d.ts +14 -0
  59. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  60. package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts +1 -1
  61. package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  62. package/lib/typescript/module/ui/types/navigation.d.ts +18 -0
  63. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  64. package/package.json +4 -4
  65. package/src/index.ts +12 -1
  66. package/src/ui/components/OxyAccountDialog.tsx +60 -85
  67. package/src/ui/components/OxyConsentScreen.tsx +456 -0
  68. package/src/ui/components/OxyProvider.tsx +2 -0
  69. package/src/ui/components/OxySignInButton.tsx +222 -6
  70. package/src/ui/components/__tests__/OxyConsentScreen.test.tsx +130 -0
  71. package/src/ui/components/oauthNavigation.ts +89 -0
  72. package/src/ui/context/OxyContext.tsx +30 -2
  73. package/src/ui/context/__tests__/OxyContext.coldBoot.test.tsx +165 -0
  74. package/src/ui/types/navigation.ts +18 -0
package/README.md CHANGED
@@ -1,12 +1,10 @@
1
1
  # @oxyhq/services
2
2
 
3
- A comprehensive TypeScript UI library for the Oxy API providing authentication, user management, and UI components for React Native and Expo applications.
3
+ A comprehensive TypeScript UI library for the Oxy API providing authentication, user management, and UI components for React Native, Expo, and web (React Native Web) applications.
4
4
 
5
- **Current published version: 6.10.6**
6
-
7
- > **For web apps (Vite, Next.js, CRA):** Use [`@oxyhq/auth`](../auth) for authentication and [`@oxyhq/core`](../core) for types and services.
5
+ > **For web apps (Vite + React Native Web):** Use this same package — `OxyProvider` is universal. See the [Platform Guide](./PLATFORM_GUIDE.md).
8
6
  >
9
- > **For backend / Node.js:** Use [`@oxyhq/core`](../core) only.
7
+ > **For backend / Node.js:** Use [`@oxyhq/core`](../core) only (`@oxyhq/core/server` for auth middleware).
10
8
  >
11
9
  > **For the full platform guide:** See [PLATFORM_GUIDE.md](./PLATFORM_GUIDE.md).
12
10
 
@@ -28,8 +26,8 @@ A comprehensive TypeScript UI library for the Oxy API providing authentication,
28
26
  ## Features
29
27
 
30
28
  - **Zero-Config Authentication**: Automatic token management and refresh
31
- - **Cross-Domain SSO**: Sign in once, authenticated everywhere (FedCM, popup, redirect)
32
- - **Universal Provider**: Single `OxyProvider` works on iOS, Android, and Expo Web
29
+ - **Device-First Sessions**: Sign in once per device; every Oxy app on the device restores silently and syncs account changes live over Socket.IO
30
+ - **Universal Provider**: Single `OxyProvider` works on iOS, Android, Expo Web, and React Native Web
33
31
  - **UI Components**: Pre-built components for auth, profiles, and more
34
32
  - **Inter Font Included**: Default Oxy ecosystem font with automatic loading
35
33
  - **Cross-Platform**: Works in Expo and React Native (iOS, Android, Web)
@@ -44,11 +42,11 @@ The OxyHQ SDK is split into three packages:
44
42
 
45
43
  | Package | Use Case | Dependencies |
46
44
  |---------|----------|--------------|
47
- | `@oxyhq/services` | Expo / React Native apps | Full (RN, Expo) |
48
- | `@oxyhq/auth` | Web apps (Vite, Next.js) | React only |
49
- | `@oxyhq/core` | All platforms (types, API client, crypto) | None |
45
+ | `@oxyhq/services` | Expo / React Native / Web (React Native Web) | Full (RN, Expo) |
46
+ | `@oxyhq/core` | All platforms (types, API client, crypto, server middleware) | None |
47
+ | `@oxyhq/contracts` | Shared API schemas (Zod) | zod only |
50
48
 
51
- This package (`@oxyhq/services`) is for **Expo and React Native** applications. It provides `OxyProvider`, UI components, screens, bottom sheet routing, fonts, and hooks.
49
+ This package (`@oxyhq/services`) is the **single UI SDK** for every React surface. It provides `OxyProvider`, the unified account dialog, UI components, screens, bottom sheet routing, fonts, and hooks.
52
50
 
53
51
  See [PLATFORM_GUIDE.md](./PLATFORM_GUIDE.md) for the complete architecture guide.
54
52
 
@@ -95,7 +93,10 @@ import { OxyProvider, useAuth } from '@oxyhq/services';
95
93
 
96
94
  function App() {
97
95
  return (
98
- <OxyProvider baseURL="https://api.oxy.so">
96
+ <OxyProvider
97
+ baseURL="https://api.oxy.so"
98
+ clientId={process.env.EXPO_PUBLIC_OXY_CLIENT_ID}
99
+ >
99
100
  <YourApp />
100
101
  </OxyProvider>
101
102
  );
@@ -246,7 +247,7 @@ import { OxyProvider } from '@oxyhq/services';
246
247
 
247
248
  function App() {
248
249
  return (
249
- <OxyProvider baseURL="https://cloud.oxy.so">
250
+ <OxyProvider baseURL="https://api.oxy.so">
250
251
  <YourApp />
251
252
  </OxyProvider>
252
253
  );
@@ -384,22 +385,24 @@ const {
384
385
  user,
385
386
  isAuthenticated,
386
387
  isLoading,
388
+ canUsePrivateApi, // Gate private API calls on this
389
+ isPrivateApiPending,
387
390
  error,
388
391
 
389
- // Identity management (Public Key Authentication)
390
- createIdentity, // Create new identity with recovery phrase
391
- importIdentity, // Import identity from recovery phrase
392
+ // Identity (public-key auth; identities are created in Commons by Oxy)
392
393
  signIn, // Sign in with stored identity
393
394
  hasIdentity, // Check if identity exists on device
394
395
  getPublicKey, // Get stored public key
395
396
 
396
- // Session management
397
- logout,
397
+ // Account dialog (switcher + sign-in)
398
+ openAccountDialog,
399
+ closeAccountDialog,
398
400
 
399
401
  // Session management
402
+ logout,
400
403
  sessions,
401
404
  activeSessionId,
402
- switchSession,
405
+ switchToAccount, // Switch active account (device session + account graph)
403
406
  removeSession
404
407
  } = useOxy();
405
408
  ```
@@ -410,7 +413,8 @@ const {
410
413
 
411
414
  ```typescript
412
415
  <OxyProvider
413
- baseURL="https://api.oxy.so" // API base URL
416
+ baseURL="https://api.oxy.so" // API base URL
417
+ clientId="oxy_dk_..." // Registered Application credential (Oxy Console)
414
418
  storageKeyPrefix="oxy_session" // Storage key prefix
415
419
  onAuthStateChange={(user) => {}} // Auth state callback
416
420
  onError={(error) => {}} // Error callback
@@ -424,6 +428,7 @@ const {
424
428
  ```bash
425
429
  # .env
426
430
  EXPO_PUBLIC_API_URL=https://api.oxy.so
431
+ EXPO_PUBLIC_OXY_CLIENT_ID=oxy_dk_...
427
432
  ```
428
433
 
429
434
  ### Custom Configuration
@@ -432,46 +437,33 @@ EXPO_PUBLIC_API_URL=https://api.oxy.so
432
437
  import { OxyServices } from '@oxyhq/core';
433
438
 
434
439
  const oxy = new OxyServices({
435
- baseURL: process.env.OXY_API_URL || 'https://cloud.oxy.so'
440
+ baseURL: process.env.OXY_API_URL || 'https://api.oxy.so'
436
441
  });
437
442
  ```
438
443
 
439
444
  ## Authentication
440
445
 
441
- Oxy supports **public/private key cryptography** (ECDSA secp256k1) as the primary identity system, with optional password-based accounts for the web gateway. Users manage their cryptographic identity in the **Oxy Accounts** app, and other apps can integrate "Sign in with Oxy" for seamless authentication.
442
-
443
- ### Public Key Authentication
444
-
445
- ```typescript
446
- import { useOxy } from '@oxyhq/services';
446
+ Oxy supports **public/private key cryptography** (ECDSA secp256k1) as the primary identity system, with optional password-based accounts. Users create and manage their cryptographic identity in the **Commons by Oxy** app (the native identity vault); every app integrates the same **"Sign in with Oxy"** surface.
447
447
 
448
- function AuthScreen() {
449
- const { createIdentity, importIdentity, signIn, hasIdentity } = useOxy();
448
+ ### How it works (device-first)
450
449
 
451
- // Create new identity (in Oxy Accounts app)
452
- const handleCreate = async () => {
453
- const { user, recoveryPhrase } = await createIdentity('username', 'email');
454
- // Show recoveryPhrase to user - they must save it!
455
- };
450
+ - **Cold boot is silent.** On mount, `OxyProvider` restores the ambient device session — the server-side `DeviceSession` records which accounts are signed in on this device and which one is active. No redirects, no browser identity APIs, no UI. See [device sessions](../../docs/auth/device-session.md).
451
+ - **Interactive sign-in is a dialog.** `useAuth().signIn()` or `useOxy().openAccountDialog('signin')` opens the unified account dialog (Bloom Dialog — bottom sheet on phones, centered on desktop): account switcher, Sign in with Oxy via the Oxy app (QR on web, deep link / shared keychain on native), and a collapsed password form.
452
+ - **Cross-app sync.** Adding, switching, or signing out an account bumps the device-session revision and is pushed over the `session_state` socket event to every Oxy app on the device.
456
453
 
457
- // Import existing identity
458
- const handleImport = async (phrase: string) => {
459
- const user = await importIdentity(phrase, 'username', 'email');
460
- };
454
+ ```tsx
455
+ import { useAuth } from '@oxyhq/services';
461
456
 
462
- // Sign in with stored identity
463
- const handleSignIn = async () => {
464
- const user = await signIn();
465
- };
466
-
467
- // Check if identity exists
468
- const hasStoredIdentity = await hasIdentity();
457
+ function SignInCTA() {
458
+ const { isAuthenticated, signIn } = useAuth();
459
+ if (isAuthenticated) return null;
460
+ return <Button title="Sign in" onPress={() => signIn()} />; // opens the dialog
469
461
  }
470
462
  ```
471
463
 
472
- ### Password Authentication (Web Gateway)
464
+ ### Password Authentication
473
465
 
474
- For web gateway flows, Oxy also supports password sign-in (email/username + password). Use the auth gateway (`/login`, `/signup`, `/recover`) for browser-based flows, or call the API directly:
466
+ Oxy also supports password sign-in (email/username + password) shown collapsed inside the account dialog, or callable directly:
475
467
 
476
468
  ```typescript
477
469
  import { oxyClient } from '@oxyhq/core';
@@ -482,9 +474,9 @@ const session2 = await oxyClient.signIn('username-or-email', 'password');
482
474
 
483
475
  ### Cross-App Authentication (Sign in with Oxy)
484
476
 
485
- For third-party apps that want to allow users to sign in with their Oxy identity:
477
+ `OxySignInButton` resolves your registered Application (`GET /auth/oauth/client/:clientId`) and picks the right flow:
486
478
 
487
- ```typescript
479
+ ```tsx
488
480
  import { OxySignInButton } from '@oxyhq/services';
489
481
 
490
482
  function LoginScreen() {
@@ -492,11 +484,10 @@ function LoginScreen() {
492
484
  }
493
485
  ```
494
486
 
495
- This displays:
496
- - A QR code that users can scan with Oxy Accounts
497
- - A button to open Oxy Accounts directly via deep link
487
+ - **Official Oxy apps** (`isOfficial` / first-party types): opens the in-app account dialog.
488
+ - **Third-party apps** (`type: 'third_party'`): starts the standard OAuth 2.0 Authorization Code + PKCE redirect to `auth.oxy.so` (the SDK generates `state` + PKCE via `@oxyhq/core`). Pass `oauthRedirectUri`; on native handle `onOAuthResult` to complete the token exchange.
498
489
 
499
- Web fallback: send users to the auth gateway at `https://accounts.oxy.so/authorize?token=...` to approve the session.
490
+ See the [integration guide](../../docs/auth/integration-guide.md) for Console registration, OAuth endpoints, and backend verification, and [AUTHENTICATION.md](../../docs/AUTHENTICATION.md) for the full model.
500
491
 
501
492
  ### Documentation
502
493
 
@@ -533,9 +524,30 @@ const styles = StyleSheet.create({
533
524
  });
534
525
  ```
535
526
 
527
+ ### Account Dialog (auth + switcher)
528
+
529
+ Sign-in and account switching do **not** use the bottom sheet — they live in the unified account dialog:
530
+
531
+ ```typescript
532
+ import { useOxy } from '@oxyhq/services';
533
+
534
+ function MyComponent() {
535
+ const { openAccountDialog } = useOxy();
536
+
537
+ return (
538
+ <Button
539
+ onPress={() => openAccountDialog('signin')}
540
+ title="Sign in with Oxy"
541
+ />
542
+ );
543
+ }
544
+ ```
545
+
546
+ Views: `'accounts'` (switcher, default), `'signin'`, `'qr'`, `'add'`. The exported `ProfileButton` component opens it for you.
547
+
536
548
  ### Bottom Sheet Routing System
537
549
 
538
- The bottom sheet routing system provides a clean, professional way to display authentication screens, account management, and other UI flows within a modal bottom sheet.
550
+ The bottom sheet routing system provides a clean, professional way to display account management and other non-auth UI flows within a modal bottom sheet.
539
551
 
540
552
  **Quick Example:**
541
553
 
@@ -547,8 +559,8 @@ function MyComponent() {
547
559
 
548
560
  return (
549
561
  <Button
550
- onPress={() => showBottomSheet('OxyAuth')}
551
- title="Sign in with Oxy"
562
+ onPress={() => showBottomSheet('ManageAccount')}
563
+ title="Manage account"
552
564
  />
553
565
  );
554
566
  }
@@ -563,41 +575,10 @@ function MyComponent() {
563
575
  - 25+ pre-built screens available
564
576
 
565
577
  **Available Screens:**
566
- - `OxyAuth` (Sign in with Oxy - for third-party apps)
567
- - `ManageAccount`, `CreateManagedAccount`
568
- - `Profile`, `SessionManagement`, `PaymentGateway`, `TrustCenter`
569
- - And many more...
570
-
571
- **Documentation:**
572
- For complete documentation, see [Bottom Sheet Routing Guide](./docs/BOTTOM_SHEET_ROUTING.md).
573
-
574
- ### Using OxyRouter Standalone
575
-
576
- If you need to embed the router in your own modal or container instead of using `showBottomSheet()`:
577
-
578
- ```typescript
579
- import { Modal } from 'react-native';
580
- import { useOxy, OxyRouter } from '@oxyhq/services';
581
-
582
- function AuthModal({ visible, onRequestClose }: { visible: boolean; onRequestClose: () => void }) {
583
- const { oxyServices } = useOxy();
584
-
585
- if (!visible || !oxyServices) return null;
586
-
587
- return (
588
- <Modal visible onRequestClose={onRequestClose} animationType="slide">
589
- <OxyRouter
590
- oxyServices={oxyServices}
591
- initialScreen="OxyAuth"
592
- onClose={onRequestClose}
593
- onAuthenticated={onRequestClose}
594
- theme="light"
595
- containerWidth={360}
596
- />
597
- </Modal>
598
- );
599
- }
600
- ```
578
+ - `ManageAccount`, `AccountSettings`, `AccountMembers`, `CreateAccount`
579
+ - `Profile`, `EditProfile`, `PaymentGateway`, `TrustCenter`, `ConnectedApps`
580
+ - `FileManagement`, `LanguageSelector`, `PrivacySettings`, `Preferences`
581
+ - And many more (see `RouteName` in `src/ui/navigation/routes.ts`)
601
582
 
602
583
  ## Internationalization (i18n)
603
584
 
@@ -676,7 +657,7 @@ import { OxyProvider } from '@oxyhq/services';
676
657
 
677
658
  function App() {
678
659
  return (
679
- <OxyProvider baseURL="https://cloud.oxy.so">
660
+ <OxyProvider baseURL="https://api.oxy.so">
680
661
  <YourApp />
681
662
  </OxyProvider>
682
663
  );
@@ -745,10 +726,6 @@ Typed returns are defined in `ui/hooks/queries/paymentTypes.ts` (`Subscription`,
745
726
 
746
727
  `@oxyhq/core` `OxyServices.verifyChallenge()` plants `setTokens(accessToken, refreshToken ?? '')` internally before returning. `useAuthOperations.performSignIn` no longer needs to hand-plant the token or call a session-token fallback — just await `verifyChallenge` and proceed.
747
728
 
748
- ## Silent SSO Run-Once Guard
749
-
750
- The cross-page-load deduplication guard lives in the consumer hooks, NOT in `@oxyhq/core`. A core module-level singleton was tried and reverted because it re-evaluates in the Metro web bundle and the guard did not hold. `useWebSSO` in this package owns a module-level `silentSSOAttempted` Set + `ssoSignature(origin|baseURL)` key for cross-mount deduplication, plus a per-instance `hasCheckedRef` fast-path. Do NOT move this guard into a core module-level singleton.
751
-
752
729
  ## Requirements
753
730
 
754
731
  - **React Native**: 0.76+ (for mobile components)
@@ -775,7 +752,7 @@ import { OxyProvider } from '@oxyhq/services';
775
752
 
776
753
  function App() {
777
754
  return (
778
- <OxyProvider baseURL="https://cloud.oxy.so">
755
+ <OxyProvider baseURL="https://api.oxy.so">
779
756
  <UserDashboard />
780
757
  </OxyProvider>
781
758
  );
@@ -830,7 +807,9 @@ Comprehensive documentation is available in the `/docs` directory:
830
807
 
831
808
  - **[Getting Started](./GET_STARTED.md)** - Quick start guide for new developers
832
809
  - **[Platform Guide](./PLATFORM_GUIDE.md)** - Platform-specific setup guide
833
- - **[CROSS_DOMAIN_AUTH.md](../../docs/CROSS_DOMAIN_AUTH.md)** - SSO deep dive
810
+ - **[AUTHENTICATION.md](../../docs/AUTHENTICATION.md)** - Authentication model (device-first sessions)
811
+ - **[Device sessions](../../docs/auth/device-session.md)** - DeviceSession API, socket events, multi-account
812
+ - **[Integration guide](../../docs/auth/integration-guide.md)** - Sign in with Oxy for third-party apps
834
813
 
835
814
  ---
836
815
 
@@ -69,12 +69,30 @@ Object.defineProperty(exports, "NotificationsScreen", {
69
69
  return _NotificationsScreen.default;
70
70
  }
71
71
  });
72
+ Object.defineProperty(exports, "OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY", {
73
+ enumerable: true,
74
+ get: function () {
75
+ return _OxySignInButton.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY;
76
+ }
77
+ });
78
+ Object.defineProperty(exports, "OXY_OAUTH_STATE_STORAGE_KEY", {
79
+ enumerable: true,
80
+ get: function () {
81
+ return _OxySignInButton.OXY_OAUTH_STATE_STORAGE_KEY;
82
+ }
83
+ });
72
84
  Object.defineProperty(exports, "OxyAuthPrompt", {
73
85
  enumerable: true,
74
86
  get: function () {
75
87
  return _OxyAuthPrompt.OxyAuthPrompt;
76
88
  }
77
89
  });
90
+ Object.defineProperty(exports, "OxyConsentScreen", {
91
+ enumerable: true,
92
+ get: function () {
93
+ return _OxyConsentScreen.OxyConsentScreen;
94
+ }
95
+ });
78
96
  Object.defineProperty(exports, "OxyLogo", {
79
97
  enumerable: true,
80
98
  get: function () {
@@ -601,6 +619,7 @@ var _Avatar = _interopRequireDefault(require("./ui/components/Avatar.js"));
601
619
  var _OxySignInButton = require("./ui/components/OxySignInButton.js");
602
620
  var _OxyAuthPrompt = require("./ui/components/OxyAuthPrompt.js");
603
621
  var _OxyLogo = _interopRequireDefault(require("./ui/components/OxyLogo.js"));
622
+ var _OxyConsentScreen = require("./ui/components/OxyConsentScreen.js");
604
623
  var _RequireOxyAuth = require("./ui/components/RequireOxyAuth.js");
605
624
  var _FollowButton = _interopRequireDefault(require("./ui/components/FollowButton.js"));
606
625
  var _LogoIcon = require("./ui/components/logo/LogoIcon.js");
@@ -1 +1 @@
1
- {"version":3,"names":["_core","require","_reactNative","_OxyProvider","_interopRequireDefault","_OxyContext","_useAuth","_FontLoader","_authStore","_assetStore","_useAssets","_useFileDownloadUrl","_useFollow","_useAccountQueries","_useServicesQueries","_useSecurityQueries","_usePaymentQueries","_useAccountMutations","_useServicesMutations","_mutationFactory","_mutationKeys","_queryKeys","_useMutationStatus","_useOnlineStatus","_errorHandlers","_useFileFiltering","_Avatar","_OxySignInButton","_OxyAuthPrompt","_OxyLogo","_RequireOxyAuth","_FollowButton","_LogoIcon","_LogoText","_ProfileButton","_useSwitchableAccounts","_ManageAccountScreen","_NotificationsScreen","_PreferencesScreen","_ConnectedAppsScreen","_CreateAccountScreen","_AccountMembersScreen","_AccountSettingsScreen","_bottomSheetManager","_accountDialogManager","e","__esModule","default","setPlatformOS","Platform","OS"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_core","require","_reactNative","_OxyProvider","_interopRequireDefault","_OxyContext","_useAuth","_FontLoader","_authStore","_assetStore","_useAssets","_useFileDownloadUrl","_useFollow","_useAccountQueries","_useServicesQueries","_useSecurityQueries","_usePaymentQueries","_useAccountMutations","_useServicesMutations","_mutationFactory","_mutationKeys","_queryKeys","_useMutationStatus","_useOnlineStatus","_errorHandlers","_useFileFiltering","_Avatar","_OxySignInButton","_OxyAuthPrompt","_OxyLogo","_OxyConsentScreen","_RequireOxyAuth","_FollowButton","_LogoIcon","_LogoText","_ProfileButton","_useSwitchableAccounts","_ManageAccountScreen","_NotificationsScreen","_PreferencesScreen","_ConnectedAppsScreen","_CreateAccountScreen","_AccountMembersScreen","_AccountSettingsScreen","_bottomSheetManager","_accountDialogManager","e","__esModule","default","setPlatformOS","Platform","OS"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
@@ -6,11 +6,11 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _react = require("react");
8
8
  var _reactNative = require("react-native");
9
- var _reactNativeGestureHandler = require("react-native-gesture-handler");
10
9
  var _vectorIcons = require("@expo/vector-icons");
11
10
  var _reactNativeQrcodeSvg = _interopRequireDefault(require("react-native-qrcode-svg"));
12
11
  var _avatar = require("@oxyhq/bloom/avatar");
13
12
  var _button = require("@oxyhq/bloom/button");
13
+ var _dialog = require("@oxyhq/bloom/dialog");
14
14
  var _typography = require("@oxyhq/bloom/typography");
15
15
  var _theme = require("@oxyhq/bloom/theme");
16
16
  var _reactQuery = require("@tanstack/react-query");
@@ -43,8 +43,24 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
43
43
  * Per-account color re-theming uses Bloom's `APP_COLOR_PRESETS` + `BloomColorScope`
44
44
  * (same visual language auth.oxy.so uses). Base theming is `useTheme()` + a
45
45
  * `StyleSheet`, so the dialog renders correctly in EVERY consumer — including apps
46
- * that do not use NativeWind (e.g. the accounts app). Modal contents are wrapped
47
- * in `<GestureHandlerRootView>` because RN's `Modal` renders into its own window.
46
+ * that do not use NativeWind (e.g. the accounts app).
47
+ *
48
+ * The surface is Bloom's `<Dialog>` (`@oxyhq/bloom/dialog`) with a responsive
49
+ * `placement` — a bottom sheet on narrow viewports, a centered card on wide ones.
50
+ * It REPLACES the hand-rolled RN `<Modal>` + `<GestureHandlerRootView>` + manual
51
+ * backdrop/card wrapper this component used before. That RN `<Modal>` is invisible
52
+ * under React StrictMode on web: react-native-web's `ModalPortal` appends its host
53
+ * node during render but removes it in an effect cleanup and never re-attaches, so
54
+ * the dialog never paints in a dev Vite build. Bloom's `<Dialog>` renders through
55
+ * its own Portal and has no such lifecycle hazard.
56
+ *
57
+ * Open/close is CONTROLLED by `isAccountDialogOpen` (the `open` prop); the Dialog
58
+ * stays mounted whenever the controller exists so it can animate its own close.
59
+ * Backdrop / swipe-to-dismiss is disabled (`dismissOnBackdrop={false}`) on purpose:
60
+ * Bloom's controlled `bottom` placement does not fire `onClose` on a gesture or
61
+ * backdrop dismissal, so allowing it would desync `isAccountDialogOpen` from the
62
+ * sheet and block reopening. The header close button (and a successful switch)
63
+ * drive `closeAccountDialog`, which flips `open` and runs the exit animation.
48
64
  */
49
65
 
50
66
  /** Diameter of a row avatar. */const ROW_AVATAR_SIZE = 40;
@@ -134,71 +150,56 @@ const OxyAccountDialog = () => {
134
150
  onManage: handleManage,
135
151
  onClose: closeAccountDialog
136
152
  }), [handleSwitch, controller, handleManage, closeAccountDialog]);
137
- if (!isAccountDialogOpen || !controller) {
153
+ if (!controller) {
138
154
  return null;
139
155
  }
140
156
  const {
141
157
  view
142
158
  } = snapshot;
143
159
  const showBack = view === 'qr' || view === 'add' && snapshot.accounts.length > 0;
144
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
145
- visible: true,
146
- transparent: true,
147
- animationType: isWeb ? 'fade' : 'slide',
148
- statusBarTranslucent: true,
149
- onRequestClose: closeAccountDialog,
150
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureHandlerRootView, {
151
- style: styles.root,
152
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
153
- style: [styles.backdrop, {
154
- backgroundColor: theme.colors.overlay
155
- }],
156
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
157
- style: _reactNative.StyleSheet.absoluteFill,
158
- onPress: closeAccountDialog,
159
- accessibilityLabel: t('common.actions.close') || 'Close',
160
- accessibilityRole: "button"
161
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
162
- style: [styles.card, isWeb ? styles.cardCentered : styles.cardSheet, {
163
- backgroundColor: theme.colors.card,
164
- borderColor: theme.colors.border
165
- }],
166
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(DialogHeader, {
167
- snapshot: snapshot,
168
- theme: theme,
169
- t: t,
170
- showBack: showBack,
171
- onBack: () => controller.setView('accounts'),
172
- onClose: closeAccountDialog
173
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
174
- style: styles.body,
175
- contentContainerStyle: styles.bodyContent,
176
- showsVerticalScrollIndicator: false,
177
- children: view === 'accounts' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(AccountsView, {
178
- snapshot: snapshot,
179
- theme: theme,
180
- t: t,
181
- handlers: handlers
182
- }) : view === 'qr' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(QrView, {
183
- snapshot: snapshot,
184
- theme: theme,
185
- t: t,
186
- onRetry: () => void controller.showQr()
187
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(SignInView, {
188
- snapshot: snapshot,
189
- theme: theme,
190
- t: t,
191
- handlers: handlers,
192
- onSignInWithOxy: () => void controller.signInWithOxy(),
193
- onScanQr: () => void controller.showQr(),
194
- onUsePassword: () => controller.openPasswordAtOxyAuth({
195
- returnUrl: isWeb ? currentHref() : undefined
196
- })
197
- })
198
- })]
199
- })]
160
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_dialog.Dialog, {
161
+ open: isAccountDialogOpen,
162
+ onClose: closeAccountDialog,
163
+ placement: {
164
+ base: 'bottom',
165
+ md: 'center'
166
+ },
167
+ dismissOnBackdrop: false,
168
+ maxWidth: 420,
169
+ label: headerCopy(view, snapshot.accounts.length, t).title,
170
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(DialogHeader, {
171
+ snapshot: snapshot,
172
+ theme: theme,
173
+ t: t,
174
+ showBack: showBack,
175
+ onBack: () => controller.setView('accounts'),
176
+ onClose: closeAccountDialog
177
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
178
+ style: styles.body,
179
+ contentContainerStyle: styles.bodyContent,
180
+ showsVerticalScrollIndicator: false,
181
+ children: view === 'accounts' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(AccountsView, {
182
+ snapshot: snapshot,
183
+ theme: theme,
184
+ t: t,
185
+ handlers: handlers
186
+ }) : view === 'qr' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(QrView, {
187
+ snapshot: snapshot,
188
+ theme: theme,
189
+ t: t,
190
+ onRetry: () => void controller.showQr()
191
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(SignInView, {
192
+ snapshot: snapshot,
193
+ theme: theme,
194
+ t: t,
195
+ handlers: handlers,
196
+ onSignInWithOxy: () => void controller.signInWithOxy(),
197
+ onScanQr: () => void controller.showQr(),
198
+ onUsePassword: () => controller.openPasswordAtOxyAuth({
199
+ returnUrl: isWeb ? currentHref() : undefined
200
+ })
200
201
  })
201
- })
202
+ })]
202
203
  });
203
204
  };
204
205
 
@@ -587,29 +588,6 @@ const EMPTY_SNAPSHOT = {
587
588
  }
588
589
  };
589
590
  const styles = _reactNative.StyleSheet.create({
590
- root: {
591
- flex: 1
592
- },
593
- backdrop: {
594
- flex: 1,
595
- justifyContent: isWeb ? 'center' : 'flex-end',
596
- alignItems: 'center'
597
- },
598
- card: {
599
- width: '100%',
600
- maxWidth: 420,
601
- borderWidth: _reactNative.StyleSheet.hairlineWidth,
602
- paddingHorizontal: 20,
603
- paddingTop: 16,
604
- paddingBottom: 24
605
- },
606
- cardCentered: {
607
- borderRadius: 28
608
- },
609
- cardSheet: {
610
- borderTopLeftRadius: 28,
611
- borderTopRightRadius: 28
612
- },
613
591
  header: {
614
592
  alignItems: 'center',
615
593
  marginBottom: 12