@oxyhq/services 5.19.0 → 5.20.1
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 +51 -42
- package/lib/commonjs/core/mixins/OxyServices.fedcm.js +46 -24
- package/lib/commonjs/core/mixins/OxyServices.fedcm.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +106 -40
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/WebOxyProvider.js +9 -10
- package/lib/commonjs/ui/components/WebOxyProvider.js.map +1 -1
- package/lib/commonjs/ui/hooks/useAuth.js +21 -8
- package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
- package/lib/commonjs/ui/hooks/useWebSSO.js +21 -2
- package/lib/commonjs/ui/hooks/useWebSSO.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.fedcm.js +46 -24
- package/lib/module/core/mixins/OxyServices.fedcm.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +106 -39
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/WebOxyProvider.js +9 -10
- package/lib/module/ui/components/WebOxyProvider.js.map +1 -1
- package/lib/module/ui/hooks/useAuth.js +21 -8
- package/lib/module/ui/hooks/useAuth.js.map +1 -1
- package/lib/module/ui/hooks/useWebSSO.js +21 -2
- package/lib/module/ui/hooks/useWebSSO.js.map +1 -1
- package/lib/typescript/commonjs/core/mixins/OxyServices.fedcm.d.ts +10 -1
- package/lib/typescript/commonjs/core/mixins/OxyServices.fedcm.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts +26 -3
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/WebOxyProvider.d.ts +9 -10
- package/lib/typescript/commonjs/ui/components/WebOxyProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useWebSSO.d.ts.map +1 -1
- package/lib/typescript/module/core/mixins/OxyServices.fedcm.d.ts +10 -1
- package/lib/typescript/module/core/mixins/OxyServices.fedcm.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyProvider.d.ts +26 -3
- package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/WebOxyProvider.d.ts +9 -10
- package/lib/typescript/module/ui/components/WebOxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useWebSSO.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/mixins/OxyServices.fedcm.ts +47 -23
- package/src/ui/components/OxyProvider.tsx +112 -47
- package/src/ui/components/WebOxyProvider.tsx +9 -10
- package/src/ui/hooks/useAuth.ts +25 -8
- package/src/ui/hooks/useWebSSO.ts +21 -2
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
import { type FC } from 'react';
|
|
2
2
|
import type { OxyProviderProps } from '../types/navigation';
|
|
3
3
|
/**
|
|
4
|
-
* OxyProvider
|
|
4
|
+
* OxyProvider - Universal provider for Expo apps (native + web)
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Zero-config authentication and session management:
|
|
7
|
+
* - Native (iOS/Android): Keychain-based identity, bottom sheet auth UI
|
|
8
|
+
* - Web: FedCM cross-domain SSO, popup fallback
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { OxyProvider, useAuth } from '@oxyhq/services';
|
|
13
|
+
*
|
|
14
|
+
* function App() {
|
|
15
|
+
* return (
|
|
16
|
+
* <OxyProvider baseURL="https://api.oxy.so">
|
|
17
|
+
* <YourApp />
|
|
18
|
+
* </OxyProvider>
|
|
19
|
+
* );
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* function MyComponent() {
|
|
23
|
+
* const { isAuthenticated, user, signIn, signOut } = useAuth();
|
|
24
|
+
*
|
|
25
|
+
* if (!isAuthenticated) {
|
|
26
|
+
* return <OxySignInButton />;
|
|
27
|
+
* }
|
|
28
|
+
* return <Text>Welcome, {user?.username}!</Text>;
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
8
31
|
*/
|
|
9
32
|
declare const OxyProvider: FC<OxyProviderProps>;
|
|
10
33
|
export default OxyProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OxyProvider.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/OxyProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"OxyProvider.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/OxyProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAI7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AA4B5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAuKrC,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WebOxyProvider -
|
|
2
|
+
* WebOxyProvider - Lightweight provider for pure React/Next.js apps
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Use this provider for web apps that DON'T use Expo/React Native.
|
|
5
|
+
* For Expo apps (native + web), use `OxyProvider` instead - it works on all platforms.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
6
8
|
* - Automatic cross-domain SSO via FedCM (Chrome 108+, Safari 16.4+, Edge 108+)
|
|
9
|
+
* - No React Native dependencies
|
|
7
10
|
* - Session management
|
|
8
11
|
* - All useOxy/useAuth functionality
|
|
9
12
|
*
|
|
10
|
-
* Zero-config: Just wrap your app and SSO works automatically across domains.
|
|
11
|
-
*
|
|
12
13
|
* Usage:
|
|
13
14
|
* ```tsx
|
|
15
|
+
* // For pure React/Next.js apps (no Expo):
|
|
14
16
|
* import { WebOxyProvider, useAuth } from '@oxyhq/services';
|
|
15
17
|
*
|
|
16
18
|
* function App() {
|
|
@@ -21,11 +23,8 @@
|
|
|
21
23
|
* );
|
|
22
24
|
* }
|
|
23
25
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* if (isAuthenticated) return <span>Welcome, {user?.username}!</span>;
|
|
27
|
-
* return <button onClick={() => signIn()}>Sign In</button>;
|
|
28
|
-
* }
|
|
26
|
+
* // For Expo apps (native + web), use OxyProvider instead:
|
|
27
|
+
* import { OxyProvider, useAuth } from '@oxyhq/services';
|
|
29
28
|
* ```
|
|
30
29
|
*/
|
|
31
30
|
import { type FC, type ReactNode } from 'react';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebOxyProvider.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/WebOxyProvider.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"WebOxyProvider.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/WebOxyProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAA+B,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;CACpD;AAED;;;;;;;;;GASG;AACH,QAAA,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CA2D3C,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAGpD,MAAM,WAAW,SAAS;IACxB,4DAA4D;IAC5D,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAElB,oCAAoC;IACpC,eAAe,EAAE,OAAO,CAAC;IAEzB,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAC;IAEnB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IAEjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;OAEG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAc,SAAQ,SAAS,EAAE,WAAW;IAC3D,6DAA6D;IAC7D,WAAW,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;CACvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,IAAI,aAAa,
|
|
1
|
+
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAGpD,MAAM,WAAW,SAAS;IACxB,4DAA4D;IAC5D,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAElB,oCAAoC;IACpC,eAAe,EAAE,OAAO,CAAC;IAEzB,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAC;IAEnB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IAEjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;OAEG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAc,SAAQ,SAAS,EAAE,WAAW;IAC3D,6DAA6D;IAC7D,WAAW,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;CACvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,IAAI,aAAa,CAqHvC;AAGD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useWebSSO.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useWebSSO.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,UAAU,gBAAgB;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,eAAe;IACvB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACrD,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,iDAAiD;IACjD,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,iBAAS,YAAY,IAAI,OAAO,CAI/B;
|
|
1
|
+
{"version":3,"file":"useWebSSO.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useWebSSO.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,UAAU,gBAAgB;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,eAAe;IACvB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACrD,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,iDAAiD;IACjD,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,iBAAS,YAAY,IAAI,OAAO,CAI/B;AAYD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,EACxB,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,OAAc,GACf,EAAE,gBAAgB,GAAG,eAAe,CA0EpC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -95,6 +95,9 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
|
|
|
95
95
|
/**
|
|
96
96
|
* Request identity credential from browser using FedCM API
|
|
97
97
|
*
|
|
98
|
+
* Uses a global lock to prevent concurrent requests, as FedCM only
|
|
99
|
+
* allows one navigator.credentials.get request at a time.
|
|
100
|
+
*
|
|
98
101
|
* @private
|
|
99
102
|
*/
|
|
100
103
|
requestIdentityCredential(options: {
|
|
@@ -178,7 +181,13 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
|
|
|
178
181
|
handleError(error: unknown): Error;
|
|
179
182
|
healthCheck(): Promise<{
|
|
180
183
|
status: string;
|
|
181
|
-
users
|
|
184
|
+
users
|
|
185
|
+
/**
|
|
186
|
+
* Get configuration for FedCM
|
|
187
|
+
*
|
|
188
|
+
* @returns FedCM configuration with browser support info
|
|
189
|
+
*/
|
|
190
|
+
?: number;
|
|
182
191
|
timestamp?: string;
|
|
183
192
|
[key: string]: any;
|
|
184
193
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OxyServices.fedcm.d.ts","sourceRoot":"","sources":["../../../../../src/core/mixins/OxyServices.fedcm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,KAAK,CAAC;CACpD;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"OxyServices.fedcm.d.ts","sourceRoot":"","sources":["../../../../../src/core/mixins/OxyServices.fedcm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,KAAK,CAAC;CACpD;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,OAAO,eAAe,EAAE,IAAI,EAAE,CAAC;kBAEtD,GAAG,EAAE;QAc5B;;WAEG;4BACiB,OAAO;QAI3B;;;;;;;;;;;;;;;;;;;;;;;WAuBG;kCAC4B,gBAAgB,GAAQ,OAAO,CAAC,oBAAoB,CAAC;QA2CpF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA6BG;iCAC4B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;QAiCnE;;;;;;;WAOG;2CAC6C;YAC9C,SAAS,EAAE,MAAM,CAAC;YAClB,QAAQ,EAAE,MAAM,CAAC;YACjB,KAAK,EAAE,MAAM,CAAC;YACd,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,SAAS,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;SAChD,GAAG,OAAO,CAAC;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;QA+CrC;;;;;;;WAOG;2CAC6C,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;QAStF;;;;;WAKG;iCAC4B,OAAO,CAAC,IAAI,CAAC;QAmB5C;;;;WAIG;0BACe,WAAW;QAQ7B;;;;WAIG;yBACqB,MAAM;QAQ9B;;;;WAIG;uBACmB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBA/IxB,CAAD;sBAGD,CAAH;yBACQ,CAAA;;;;;;;YA4GP;;;;eAIG;YACH,CANF;qBAEiB,CAAC;;;;iCA5P4B,gCAAgC;4BACrC,KAAK;IAE5C;;OAEG;wBACwB,OAAO;;MA2RnC;AAGD,OAAO,EAAE,qBAAqB,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
import { type FC } from 'react';
|
|
2
2
|
import type { OxyProviderProps } from '../types/navigation';
|
|
3
3
|
/**
|
|
4
|
-
* OxyProvider
|
|
4
|
+
* OxyProvider - Universal provider for Expo apps (native + web)
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Zero-config authentication and session management:
|
|
7
|
+
* - Native (iOS/Android): Keychain-based identity, bottom sheet auth UI
|
|
8
|
+
* - Web: FedCM cross-domain SSO, popup fallback
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { OxyProvider, useAuth } from '@oxyhq/services';
|
|
13
|
+
*
|
|
14
|
+
* function App() {
|
|
15
|
+
* return (
|
|
16
|
+
* <OxyProvider baseURL="https://api.oxy.so">
|
|
17
|
+
* <YourApp />
|
|
18
|
+
* </OxyProvider>
|
|
19
|
+
* );
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* function MyComponent() {
|
|
23
|
+
* const { isAuthenticated, user, signIn, signOut } = useAuth();
|
|
24
|
+
*
|
|
25
|
+
* if (!isAuthenticated) {
|
|
26
|
+
* return <OxySignInButton />;
|
|
27
|
+
* }
|
|
28
|
+
* return <Text>Welcome, {user?.username}!</Text>;
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
8
31
|
*/
|
|
9
32
|
declare const OxyProvider: FC<OxyProviderProps>;
|
|
10
33
|
export default OxyProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OxyProvider.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/OxyProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"OxyProvider.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/OxyProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAI7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AA4B5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAuKrC,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WebOxyProvider -
|
|
2
|
+
* WebOxyProvider - Lightweight provider for pure React/Next.js apps
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Use this provider for web apps that DON'T use Expo/React Native.
|
|
5
|
+
* For Expo apps (native + web), use `OxyProvider` instead - it works on all platforms.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
6
8
|
* - Automatic cross-domain SSO via FedCM (Chrome 108+, Safari 16.4+, Edge 108+)
|
|
9
|
+
* - No React Native dependencies
|
|
7
10
|
* - Session management
|
|
8
11
|
* - All useOxy/useAuth functionality
|
|
9
12
|
*
|
|
10
|
-
* Zero-config: Just wrap your app and SSO works automatically across domains.
|
|
11
|
-
*
|
|
12
13
|
* Usage:
|
|
13
14
|
* ```tsx
|
|
15
|
+
* // For pure React/Next.js apps (no Expo):
|
|
14
16
|
* import { WebOxyProvider, useAuth } from '@oxyhq/services';
|
|
15
17
|
*
|
|
16
18
|
* function App() {
|
|
@@ -21,11 +23,8 @@
|
|
|
21
23
|
* );
|
|
22
24
|
* }
|
|
23
25
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* if (isAuthenticated) return <span>Welcome, {user?.username}!</span>;
|
|
27
|
-
* return <button onClick={() => signIn()}>Sign In</button>;
|
|
28
|
-
* }
|
|
26
|
+
* // For Expo apps (native + web), use OxyProvider instead:
|
|
27
|
+
* import { OxyProvider, useAuth } from '@oxyhq/services';
|
|
29
28
|
* ```
|
|
30
29
|
*/
|
|
31
30
|
import { type FC, type ReactNode } from 'react';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebOxyProvider.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/WebOxyProvider.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"WebOxyProvider.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/WebOxyProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAA+B,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;CACpD;AAED;;;;;;;;;GASG;AACH,QAAA,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CA2D3C,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAGpD,MAAM,WAAW,SAAS;IACxB,4DAA4D;IAC5D,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAElB,oCAAoC;IACpC,eAAe,EAAE,OAAO,CAAC;IAEzB,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAC;IAEnB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IAEjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;OAEG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAc,SAAQ,SAAS,EAAE,WAAW;IAC3D,6DAA6D;IAC7D,WAAW,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;CACvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,IAAI,aAAa,
|
|
1
|
+
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAGpD,MAAM,WAAW,SAAS;IACxB,4DAA4D;IAC5D,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAElB,oCAAoC;IACpC,eAAe,EAAE,OAAO,CAAC;IAEzB,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAC;IAEnB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IAEjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;OAEG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAc,SAAQ,SAAS,EAAE,WAAW;IAC3D,6DAA6D;IAC7D,WAAW,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;CACvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,IAAI,aAAa,CAqHvC;AAGD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useWebSSO.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useWebSSO.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,UAAU,gBAAgB;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,eAAe;IACvB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACrD,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,iDAAiD;IACjD,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,iBAAS,YAAY,IAAI,OAAO,CAI/B;
|
|
1
|
+
{"version":3,"file":"useWebSSO.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useWebSSO.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,UAAU,gBAAgB;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,eAAe;IACvB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACrD,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,iDAAiD;IACjD,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,iBAAS,YAAY,IAAI,OAAO,CAI/B;AAYD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,EACxB,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,OAAc,GACf,EAAE,gBAAgB,GAAG,eAAe,CA0EpC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/services",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.20.1",
|
|
4
4
|
"description": "Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -13,6 +13,11 @@ export interface FedCMConfig {
|
|
|
13
13
|
clientId?: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
// Global lock to prevent concurrent FedCM requests
|
|
17
|
+
// FedCM only allows one navigator.credentials.get request at a time
|
|
18
|
+
let fedCMRequestInProgress = false;
|
|
19
|
+
let fedCMRequestPromise: Promise<any> | null = null;
|
|
20
|
+
|
|
16
21
|
/**
|
|
17
22
|
* Federated Credential Management (FedCM) Authentication Mixin
|
|
18
23
|
*
|
|
@@ -190,6 +195,9 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
190
195
|
/**
|
|
191
196
|
* Request identity credential from browser using FedCM API
|
|
192
197
|
*
|
|
198
|
+
* Uses a global lock to prevent concurrent requests, as FedCM only
|
|
199
|
+
* allows one navigator.credentials.get request at a time.
|
|
200
|
+
*
|
|
193
201
|
* @private
|
|
194
202
|
*/
|
|
195
203
|
public async requestIdentityCredential(options: {
|
|
@@ -199,34 +207,50 @@ export function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
199
207
|
context?: string;
|
|
200
208
|
mediation?: 'silent' | 'optional' | 'required';
|
|
201
209
|
}): Promise<{ token: string } | null> {
|
|
210
|
+
// If a request is already in progress, wait for it instead of starting a new one
|
|
211
|
+
if (fedCMRequestInProgress && fedCMRequestPromise) {
|
|
212
|
+
try {
|
|
213
|
+
return await fedCMRequestPromise;
|
|
214
|
+
} catch {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
fedCMRequestInProgress = true;
|
|
202
220
|
const controller = new AbortController();
|
|
203
221
|
const timeout = setTimeout(() => controller.abort(), (this.constructor as any).FEDCM_TIMEOUT);
|
|
204
222
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
223
|
+
fedCMRequestPromise = (async () => {
|
|
224
|
+
try {
|
|
225
|
+
// Type assertion needed as FedCM types may not be in all TypeScript versions
|
|
226
|
+
const credential = (await (navigator.credentials as any).get({
|
|
227
|
+
identity: {
|
|
228
|
+
providers: [
|
|
229
|
+
{
|
|
230
|
+
configURL: options.configURL,
|
|
231
|
+
clientId: options.clientId,
|
|
232
|
+
nonce: options.nonce,
|
|
233
|
+
...(options.context && { loginHint: options.context }),
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
},
|
|
237
|
+
mediation: options.mediation || 'optional',
|
|
238
|
+
signal: controller.signal,
|
|
239
|
+
})) as any;
|
|
240
|
+
|
|
241
|
+
if (!credential || credential.type !== 'identity') {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return { token: credential.token };
|
|
246
|
+
} finally {
|
|
247
|
+
clearTimeout(timeout);
|
|
248
|
+
fedCMRequestInProgress = false;
|
|
249
|
+
fedCMRequestPromise = null;
|
|
224
250
|
}
|
|
251
|
+
})();
|
|
225
252
|
|
|
226
|
-
|
|
227
|
-
} finally {
|
|
228
|
-
clearTimeout(timeout);
|
|
229
|
-
}
|
|
253
|
+
return fedCMRequestPromise;
|
|
230
254
|
}
|
|
231
255
|
|
|
232
256
|
/**
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { useEffect, useRef, useState, type FC } from 'react';
|
|
2
|
-
import { AppState } from 'react-native';
|
|
2
|
+
import { AppState, Platform } from 'react-native';
|
|
3
3
|
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
4
4
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
5
|
-
import { KeyboardProvider } from 'react-native-keyboard-controller';
|
|
6
5
|
import type { OxyProviderProps } from '../types/navigation';
|
|
7
6
|
import { OxyContextProvider } from '../context/OxyContext';
|
|
8
7
|
import { QueryClientProvider, focusManager, onlineManager } from '@tanstack/react-query';
|
|
9
8
|
import { setupFonts } from './FontLoader';
|
|
10
|
-
import BottomSheetRouter from './BottomSheetRouter';
|
|
11
9
|
import { Toaster } from '../../lib/sonner';
|
|
12
10
|
import { createQueryClient } from '../hooks/queryClient';
|
|
13
11
|
import { createPlatformStorage, type StorageInterface } from '../utils/storageHelpers';
|
|
@@ -15,11 +13,51 @@ import { createPlatformStorage, type StorageInterface } from '../utils/storageHe
|
|
|
15
13
|
// Initialize fonts automatically
|
|
16
14
|
setupFonts();
|
|
17
15
|
|
|
16
|
+
// Detect if running on web
|
|
17
|
+
const isWeb = Platform.OS === 'web';
|
|
18
|
+
|
|
19
|
+
// Conditionally import native-only components
|
|
20
|
+
let KeyboardProvider: any = ({ children }: any) => children;
|
|
21
|
+
let BottomSheetRouter: any = () => null;
|
|
22
|
+
|
|
23
|
+
if (!isWeb) {
|
|
24
|
+
try {
|
|
25
|
+
// Only import on native platforms
|
|
26
|
+
KeyboardProvider = require('react-native-keyboard-controller').KeyboardProvider;
|
|
27
|
+
BottomSheetRouter = require('./BottomSheetRouter').default;
|
|
28
|
+
} catch {
|
|
29
|
+
// Fallback if imports fail
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
18
33
|
/**
|
|
19
|
-
* OxyProvider
|
|
34
|
+
* OxyProvider - Universal provider for Expo apps (native + web)
|
|
35
|
+
*
|
|
36
|
+
* Zero-config authentication and session management:
|
|
37
|
+
* - Native (iOS/Android): Keychain-based identity, bottom sheet auth UI
|
|
38
|
+
* - Web: FedCM cross-domain SSO, popup fallback
|
|
20
39
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
40
|
+
* Usage:
|
|
41
|
+
* ```tsx
|
|
42
|
+
* import { OxyProvider, useAuth } from '@oxyhq/services';
|
|
43
|
+
*
|
|
44
|
+
* function App() {
|
|
45
|
+
* return (
|
|
46
|
+
* <OxyProvider baseURL="https://api.oxy.so">
|
|
47
|
+
* <YourApp />
|
|
48
|
+
* </OxyProvider>
|
|
49
|
+
* );
|
|
50
|
+
* }
|
|
51
|
+
*
|
|
52
|
+
* function MyComponent() {
|
|
53
|
+
* const { isAuthenticated, user, signIn, signOut } = useAuth();
|
|
54
|
+
*
|
|
55
|
+
* if (!isAuthenticated) {
|
|
56
|
+
* return <OxySignInButton />;
|
|
57
|
+
* }
|
|
58
|
+
* return <Text>Welcome, {user?.username}!</Text>;
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
23
61
|
*/
|
|
24
62
|
const OxyProvider: FC<OxyProviderProps> = ({
|
|
25
63
|
oxyServices,
|
|
@@ -72,14 +110,26 @@ const OxyProvider: FC<OxyProviderProps> = ({
|
|
|
72
110
|
};
|
|
73
111
|
}, [providedQueryClient]);
|
|
74
112
|
|
|
75
|
-
// Hook React Query focus manager into
|
|
113
|
+
// Hook React Query focus manager into app state (native) or visibility (web)
|
|
76
114
|
useEffect(() => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
115
|
+
if (isWeb) {
|
|
116
|
+
// Web: use document visibility
|
|
117
|
+
const handleVisibilityChange = () => {
|
|
118
|
+
focusManager.setFocused(document.visibilityState === 'visible');
|
|
119
|
+
};
|
|
120
|
+
document.addEventListener('visibilitychange', handleVisibilityChange);
|
|
121
|
+
return () => {
|
|
122
|
+
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
123
|
+
};
|
|
124
|
+
} else {
|
|
125
|
+
// Native: use AppState
|
|
126
|
+
const subscription = AppState.addEventListener('change', (state) => {
|
|
127
|
+
focusManager.setFocused(state === 'active');
|
|
128
|
+
});
|
|
129
|
+
return () => {
|
|
130
|
+
subscription.remove();
|
|
131
|
+
};
|
|
132
|
+
}
|
|
83
133
|
}, []);
|
|
84
134
|
|
|
85
135
|
// Setup network status monitoring for offline detection
|
|
@@ -88,35 +138,35 @@ const OxyProvider: FC<OxyProviderProps> = ({
|
|
|
88
138
|
|
|
89
139
|
const setupNetworkMonitoring = async () => {
|
|
90
140
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
141
|
+
if (isWeb) {
|
|
142
|
+
// Web: use navigator.onLine
|
|
143
|
+
onlineManager.setOnline(navigator.onLine);
|
|
144
|
+
const handleOnline = () => onlineManager.setOnline(true);
|
|
145
|
+
const handleOffline = () => onlineManager.setOnline(false);
|
|
146
|
+
|
|
147
|
+
window.addEventListener('online', handleOnline);
|
|
148
|
+
window.addEventListener('offline', handleOffline);
|
|
149
|
+
|
|
150
|
+
cleanup = () => {
|
|
151
|
+
window.removeEventListener('online', handleOnline);
|
|
152
|
+
window.removeEventListener('offline', handleOffline);
|
|
153
|
+
};
|
|
154
|
+
} else {
|
|
155
|
+
// Native: try to use NetInfo
|
|
93
156
|
try {
|
|
94
157
|
const NetInfo = await import('@react-native-community/netinfo');
|
|
95
158
|
const state = await NetInfo.default.fetch();
|
|
96
159
|
onlineManager.setOnline(state.isConnected ?? true);
|
|
97
|
-
|
|
160
|
+
|
|
98
161
|
const unsubscribe = NetInfo.default.addEventListener((state: { isConnected: boolean | null }) => {
|
|
99
162
|
onlineManager.setOnline(state.isConnected ?? true);
|
|
100
163
|
});
|
|
101
|
-
|
|
164
|
+
|
|
102
165
|
cleanup = () => unsubscribe();
|
|
103
166
|
} catch {
|
|
104
167
|
// NetInfo not available, default to online
|
|
105
168
|
onlineManager.setOnline(true);
|
|
106
169
|
}
|
|
107
|
-
} else {
|
|
108
|
-
// For web, use navigator.onLine
|
|
109
|
-
onlineManager.setOnline(navigator.onLine);
|
|
110
|
-
const handleOnline = () => onlineManager.setOnline(true);
|
|
111
|
-
const handleOffline = () => onlineManager.setOnline(false);
|
|
112
|
-
|
|
113
|
-
window.addEventListener('online', handleOnline);
|
|
114
|
-
window.addEventListener('offline', handleOffline);
|
|
115
|
-
|
|
116
|
-
cleanup = () => {
|
|
117
|
-
window.removeEventListener('online', handleOnline);
|
|
118
|
-
window.removeEventListener('offline', handleOffline);
|
|
119
|
-
};
|
|
120
170
|
}
|
|
121
171
|
} catch (error) {
|
|
122
172
|
// Default to online if detection fails
|
|
@@ -133,30 +183,45 @@ const OxyProvider: FC<OxyProviderProps> = ({
|
|
|
133
183
|
|
|
134
184
|
// Ensure we have a valid QueryClient
|
|
135
185
|
if (!queryClient) {
|
|
136
|
-
// Return loading state or fallback
|
|
137
186
|
return null;
|
|
138
187
|
}
|
|
139
188
|
|
|
189
|
+
// Core content that works on all platforms
|
|
190
|
+
const coreContent = (
|
|
191
|
+
<QueryClientProvider client={queryClient}>
|
|
192
|
+
<OxyContextProvider
|
|
193
|
+
oxyServices={oxyServices as any}
|
|
194
|
+
baseURL={baseURL}
|
|
195
|
+
authWebUrl={authWebUrl}
|
|
196
|
+
authRedirectUri={authRedirectUri}
|
|
197
|
+
storageKeyPrefix={storageKeyPrefix}
|
|
198
|
+
onAuthStateChange={onAuthStateChange as any}
|
|
199
|
+
>
|
|
200
|
+
{children}
|
|
201
|
+
{/* Only render bottom sheet router on native */}
|
|
202
|
+
{!isWeb && <BottomSheetRouter />}
|
|
203
|
+
<Toaster />
|
|
204
|
+
</OxyContextProvider>
|
|
205
|
+
</QueryClientProvider>
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
// On web, minimal wrappers (GestureHandler and SafeArea work via react-native-web)
|
|
209
|
+
if (isWeb) {
|
|
210
|
+
return (
|
|
211
|
+
<SafeAreaProvider>
|
|
212
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
213
|
+
{coreContent}
|
|
214
|
+
</GestureHandlerRootView>
|
|
215
|
+
</SafeAreaProvider>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// On native, full wrappers including KeyboardProvider
|
|
140
220
|
return (
|
|
141
221
|
<SafeAreaProvider>
|
|
142
222
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
143
223
|
<KeyboardProvider>
|
|
144
|
-
{
|
|
145
|
-
<QueryClientProvider client={queryClient}>
|
|
146
|
-
<OxyContextProvider
|
|
147
|
-
oxyServices={oxyServices as any}
|
|
148
|
-
baseURL={baseURL}
|
|
149
|
-
authWebUrl={authWebUrl}
|
|
150
|
-
authRedirectUri={authRedirectUri}
|
|
151
|
-
storageKeyPrefix={storageKeyPrefix}
|
|
152
|
-
onAuthStateChange={onAuthStateChange as any}
|
|
153
|
-
>
|
|
154
|
-
{children}
|
|
155
|
-
<BottomSheetRouter />
|
|
156
|
-
<Toaster />
|
|
157
|
-
</OxyContextProvider>
|
|
158
|
-
</QueryClientProvider>
|
|
159
|
-
)}
|
|
224
|
+
{coreContent}
|
|
160
225
|
</KeyboardProvider>
|
|
161
226
|
</GestureHandlerRootView>
|
|
162
227
|
</SafeAreaProvider>
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WebOxyProvider -
|
|
2
|
+
* WebOxyProvider - Lightweight provider for pure React/Next.js apps
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Use this provider for web apps that DON'T use Expo/React Native.
|
|
5
|
+
* For Expo apps (native + web), use `OxyProvider` instead - it works on all platforms.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
6
8
|
* - Automatic cross-domain SSO via FedCM (Chrome 108+, Safari 16.4+, Edge 108+)
|
|
9
|
+
* - No React Native dependencies
|
|
7
10
|
* - Session management
|
|
8
11
|
* - All useOxy/useAuth functionality
|
|
9
12
|
*
|
|
10
|
-
* Zero-config: Just wrap your app and SSO works automatically across domains.
|
|
11
|
-
*
|
|
12
13
|
* Usage:
|
|
13
14
|
* ```tsx
|
|
15
|
+
* // For pure React/Next.js apps (no Expo):
|
|
14
16
|
* import { WebOxyProvider, useAuth } from '@oxyhq/services';
|
|
15
17
|
*
|
|
16
18
|
* function App() {
|
|
@@ -21,11 +23,8 @@
|
|
|
21
23
|
* );
|
|
22
24
|
* }
|
|
23
25
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* if (isAuthenticated) return <span>Welcome, {user?.username}!</span>;
|
|
27
|
-
* return <button onClick={() => signIn()}>Sign In</button>;
|
|
28
|
-
* }
|
|
26
|
+
* // For Expo apps (native + web), use OxyProvider instead:
|
|
27
|
+
* import { OxyProvider, useAuth } from '@oxyhq/services';
|
|
29
28
|
* ```
|
|
30
29
|
*/
|
|
31
30
|
|