@oxyhq/services 17.0.0 → 18.1.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.
- package/README.md +77 -98
- package/lib/commonjs/index.js +19 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAccountDialog.js +62 -84
- package/lib/commonjs/ui/components/OxyAccountDialog.js.map +1 -1
- package/lib/commonjs/ui/components/OxyConsentScreen.js +461 -0
- package/lib/commonjs/ui/components/OxyConsentScreen.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +3 -1
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/OxySignInButton.js +176 -7
- package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
- package/lib/commonjs/ui/components/oauthNavigation.js +73 -0
- package/lib/commonjs/ui/components/oauthNavigation.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +31 -4
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +11 -0
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/index.js +2 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/OxyAccountDialog.js +63 -85
- package/lib/module/ui/components/OxyAccountDialog.js.map +1 -1
- package/lib/module/ui/components/OxyConsentScreen.js +454 -0
- package/lib/module/ui/components/OxyConsentScreen.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +3 -1
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/OxySignInButton.js +177 -7
- package/lib/module/ui/components/OxySignInButton.js.map +1 -1
- package/lib/module/ui/components/oauthNavigation.js +70 -0
- package/lib/module/ui/components/oauthNavigation.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +31 -4
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +11 -0
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts +18 -2
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts +45 -0
- package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts +56 -0
- package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts +36 -0
- package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +14 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +18 -0
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +4 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts +18 -2
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts +45 -0
- package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxySignInButton.d.ts +56 -0
- package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/oauthNavigation.d.ts +36 -0
- package/lib/typescript/module/ui/components/oauthNavigation.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts +14 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +18 -0
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +12 -1
- package/src/ui/components/OxyAccountDialog.tsx +60 -85
- package/src/ui/components/OxyConsentScreen.tsx +456 -0
- package/src/ui/components/OxyProvider.tsx +2 -0
- package/src/ui/components/OxySignInButton.tsx +222 -6
- package/src/ui/components/__tests__/OxyConsentScreen.test.tsx +130 -0
- package/src/ui/components/oauthNavigation.ts +89 -0
- package/src/ui/context/OxyContext.tsx +44 -4
- package/src/ui/context/__tests__/OxyContext.coldBoot.test.tsx +165 -0
- package/src/ui/context/hooks/useAuthOperations.ts +7 -0
- 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
|
|
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
|
-
**
|
|
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
|
-
- **
|
|
32
|
-
- **Universal Provider**: Single `OxyProvider` works on iOS, Android, and
|
|
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
|
|
48
|
-
| `@oxyhq/
|
|
49
|
-
| `@oxyhq/
|
|
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
|
|
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
|
|
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://
|
|
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
|
|
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
|
-
//
|
|
397
|
-
|
|
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
|
-
|
|
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"
|
|
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://
|
|
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
|
|
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
|
-
|
|
449
|
-
const { createIdentity, importIdentity, signIn, hasIdentity } = useOxy();
|
|
448
|
+
### How it works (device-first)
|
|
450
449
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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
|
-
|
|
458
|
-
|
|
459
|
-
const user = await importIdentity(phrase, 'username', 'email');
|
|
460
|
-
};
|
|
454
|
+
```tsx
|
|
455
|
+
import { useAuth } from '@oxyhq/services';
|
|
461
456
|
|
|
462
|
-
|
|
463
|
-
const
|
|
464
|
-
|
|
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
|
|
464
|
+
### Password Authentication
|
|
473
465
|
|
|
474
|
-
|
|
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
|
-
|
|
477
|
+
`OxySignInButton` resolves your registered Application (`GET /auth/oauth/client/:clientId`) and picks the right flow:
|
|
486
478
|
|
|
487
|
-
```
|
|
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
|
-
|
|
496
|
-
-
|
|
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
|
-
|
|
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
|
|
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('
|
|
551
|
-
title="
|
|
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
|
-
- `
|
|
567
|
-
- `
|
|
568
|
-
- `
|
|
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://
|
|
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://
|
|
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
|
-
- **[
|
|
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
|
|
package/lib/commonjs/index.js
CHANGED
|
@@ -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":"
|
|
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).
|
|
47
|
-
*
|
|
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 (!
|
|
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.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|