@octopus-community/react-native 1.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 (106) hide show
  1. package/LICENSE.md +143 -0
  2. package/OctopusReactNativeSdk.podspec +33 -0
  3. package/README.md +161 -0
  4. package/android/build.gradle +92 -0
  5. package/android/gradle.properties +9 -0
  6. package/android/src/main/AndroidManifest.xml +9 -0
  7. package/android/src/main/AndroidManifestNew.xml +8 -0
  8. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusEventEmitter.kt +48 -0
  9. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusReactNativeSdkModule.kt +73 -0
  10. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusReactNativeSdkPackage.kt +17 -0
  11. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusSDKInitializer.kt +55 -0
  12. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusSSOAuthenticator.kt +124 -0
  13. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIActivity.kt +71 -0
  14. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIController.kt +34 -0
  15. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/ProfileFieldMapper.kt +39 -0
  16. package/ios/OctopusEventManager.swift +44 -0
  17. package/ios/OctopusReactNativeSdk-Bridging-Header.h +3 -0
  18. package/ios/OctopusReactNativeSdk.mm +37 -0
  19. package/ios/OctopusReactNativeSdk.swift +148 -0
  20. package/ios/OctopusSDKInitializer.swift +62 -0
  21. package/ios/OctopusSSOAuthenticator.swift +157 -0
  22. package/ios/OctopusUIManager.swift +40 -0
  23. package/ios/ProfileFieldMapper.swift +43 -0
  24. package/lib/module/addEditUserListener.js +13 -0
  25. package/lib/module/addEditUserListener.js.map +1 -0
  26. package/lib/module/addLoginRequiredListener.js +14 -0
  27. package/lib/module/addLoginRequiredListener.js.map +1 -0
  28. package/lib/module/addUserTokenRequestListener.js +26 -0
  29. package/lib/module/addUserTokenRequestListener.js.map +1 -0
  30. package/lib/module/closeUI.js +11 -0
  31. package/lib/module/closeUI.js.map +1 -0
  32. package/lib/module/connectUser.js +14 -0
  33. package/lib/module/connectUser.js.map +1 -0
  34. package/lib/module/disconnectUser.js +7 -0
  35. package/lib/module/disconnectUser.js.map +1 -0
  36. package/lib/module/enums/LogLevel.enum.js +13 -0
  37. package/lib/module/enums/LogLevel.enum.js.map +1 -0
  38. package/lib/module/index.js +15 -0
  39. package/lib/module/index.js.map +1 -0
  40. package/lib/module/initialize.js +38 -0
  41. package/lib/module/initialize.js.map +1 -0
  42. package/lib/module/internals/eventEmitter.js +6 -0
  43. package/lib/module/internals/eventEmitter.js.map +1 -0
  44. package/lib/module/internals/logger.js +42 -0
  45. package/lib/module/internals/logger.js.map +1 -0
  46. package/lib/module/internals/nativeModule.js +13 -0
  47. package/lib/module/internals/nativeModule.js.map +1 -0
  48. package/lib/module/logger.js +4 -0
  49. package/lib/module/logger.js.map +1 -0
  50. package/lib/module/openUI.js +11 -0
  51. package/lib/module/openUI.js.map +1 -0
  52. package/lib/module/package.json +1 -0
  53. package/lib/module/types/userProfileField.js +2 -0
  54. package/lib/module/types/userProfileField.js.map +1 -0
  55. package/lib/module/useUserTokenProvider.js +33 -0
  56. package/lib/module/useUserTokenProvider.js.map +1 -0
  57. package/lib/typescript/package.json +1 -0
  58. package/lib/typescript/src/addEditUserListener.d.ts +14 -0
  59. package/lib/typescript/src/addEditUserListener.d.ts.map +1 -0
  60. package/lib/typescript/src/addLoginRequiredListener.d.ts +10 -0
  61. package/lib/typescript/src/addLoginRequiredListener.d.ts.map +1 -0
  62. package/lib/typescript/src/addUserTokenRequestListener.d.ts +10 -0
  63. package/lib/typescript/src/addUserTokenRequestListener.d.ts.map +1 -0
  64. package/lib/typescript/src/closeUI.d.ts +5 -0
  65. package/lib/typescript/src/closeUI.d.ts.map +1 -0
  66. package/lib/typescript/src/connectUser.d.ts +30 -0
  67. package/lib/typescript/src/connectUser.d.ts.map +1 -0
  68. package/lib/typescript/src/disconnectUser.d.ts +2 -0
  69. package/lib/typescript/src/disconnectUser.d.ts.map +1 -0
  70. package/lib/typescript/src/enums/LogLevel.enum.d.ts +10 -0
  71. package/lib/typescript/src/enums/LogLevel.enum.d.ts.map +1 -0
  72. package/lib/typescript/src/index.d.ts +13 -0
  73. package/lib/typescript/src/index.d.ts.map +1 -0
  74. package/lib/typescript/src/initialize.d.ts +50 -0
  75. package/lib/typescript/src/initialize.d.ts.map +1 -0
  76. package/lib/typescript/src/internals/eventEmitter.d.ts +3 -0
  77. package/lib/typescript/src/internals/eventEmitter.d.ts.map +1 -0
  78. package/lib/typescript/src/internals/logger.d.ts +20 -0
  79. package/lib/typescript/src/internals/logger.d.ts.map +1 -0
  80. package/lib/typescript/src/internals/nativeModule.d.ts +2 -0
  81. package/lib/typescript/src/internals/nativeModule.d.ts.map +1 -0
  82. package/lib/typescript/src/logger.d.ts +3 -0
  83. package/lib/typescript/src/logger.d.ts.map +1 -0
  84. package/lib/typescript/src/openUI.d.ts +5 -0
  85. package/lib/typescript/src/openUI.d.ts.map +1 -0
  86. package/lib/typescript/src/types/userProfileField.d.ts +14 -0
  87. package/lib/typescript/src/types/userProfileField.d.ts.map +1 -0
  88. package/lib/typescript/src/useUserTokenProvider.d.ts +17 -0
  89. package/lib/typescript/src/useUserTokenProvider.d.ts.map +1 -0
  90. package/package.json +136 -0
  91. package/src/addEditUserListener.ts +19 -0
  92. package/src/addLoginRequiredListener.ts +16 -0
  93. package/src/addUserTokenRequestListener.ts +32 -0
  94. package/src/closeUI.ts +8 -0
  95. package/src/connectUser.ts +34 -0
  96. package/src/disconnectUser.ts +5 -0
  97. package/src/enums/LogLevel.enum.ts +9 -0
  98. package/src/index.ts +12 -0
  99. package/src/initialize.ts +56 -0
  100. package/src/internals/eventEmitter.ts +4 -0
  101. package/src/internals/logger.ts +60 -0
  102. package/src/internals/nativeModule.ts +18 -0
  103. package/src/logger.ts +7 -0
  104. package/src/openUI.ts +8 -0
  105. package/src/types/userProfileField.ts +13 -0
  106. package/src/useUserTokenProvider.ts +36 -0
package/LICENSE.md ADDED
@@ -0,0 +1,143 @@
1
+ # Octopus Community Mobile SDK License Agreement
2
+
3
+ **By downloading, installing, accessing, or otherwise using the SDK, Licensee acknowledges that it has read this Agreement, understands it, and agrees to be bound by its terms.**
4
+
5
+ This Mobile SDK License Agreement (the “**Agreement**”) is entered into by and between Octopus Community SAS (“**Licensor**”) and you or the entity you represent (“**Licensee**”). By downloading, accessing, or using the Octopus Community Mobile SDK (“**SDK**”), Licensee agrees to be bound by this Agreement.
6
+
7
+ ## 1. Definitions
8
+
9
+ 1.1 **“API”** means the application programming interface made available by Licensor, including any accompanying or related documentation, source code, executable applications, and other materials provided by Licensor for use in conjunction with the SDK.
10
+
11
+ 1.2 **“SaaS Service”** means the proprietary software-as-a-service platform provided by Licensor, which is accessed via the API.
12
+
13
+ 1.3 **“Authorized Application”** means a software application developed by Licensee using the SDK solely for interacting with the SaaS Service.
14
+
15
+ 1.4 **“Confidential Information”** means any information disclosed by Licensor to Licensee that is identified as confidential or proprietary, or that would otherwise reasonably be understood to be confidential in nature, including but not limited to source code, trade secrets, and non-public business information.
16
+
17
+ ## 2. Grant of License
18
+
19
+ 2.1 **License Grant**
20
+
21
+ Subject to Licensee’s compliance with this Agreement, Licensor grants Licensee a limited, non-exclusive, non-transferable, non-sublicensable, revocable license to:
22
+
23
+ - Download, install, and use the SDK in source or binary form **solely** to develop and test Authorized Applications that interface with and depend on Licensor’s SaaS Service via the API.
24
+
25
+ 2.2 **Access to Source Code**
26
+
27
+ Licensor may provide the SDK source code for reference, debugging, and integration purposes. **This provision does not constitute an open-source license**; rather, it grants Licensee the right to view and compile the provided source code only as necessary for development of Authorized Applications in conjunction with the SaaS Service.
28
+
29
+ ## 3. License Restrictions
30
+
31
+ 3.1 **Permitted Use**
32
+
33
+ Licensee may use the SDK **only** to develop Authorized Applications that exclusively interact with the SaaS Service via the API. Any other use, including use with any third-party services or products, is prohibited unless expressly authorized in writing by Licensor.
34
+
35
+ 3.2 **Modifications**
36
+
37
+ Licensee shall not modify, translate, adapt, arrange, or create derivative works of the SDK, in whole or in part, for any purpose other than (a) debug or integration efforts necessary for the Authorized Application to properly interface with the SaaS Service, and (b) as otherwise expressly permitted by Licensor in writing. **Under no circumstances** shall any modifications be used independently of the SaaS Service or for any other commercial or non-commercial use.
38
+
39
+ 3.3 **Distribution**
40
+
41
+ Licensee may distribute the SDK (in compiled or other form) **only** as embedded or integrated in the Authorized Application, **solely** for the purpose of enabling end users to connect to and use the SaaS Service. Licensee is prohibited from redistributing the SDK as a standalone product or library.
42
+
43
+ 3.4 **Prohibitions**
44
+
45
+ Licensee shall not:
46
+
47
+ - Sell, license, lease, rent, loan, resell, or otherwise distribute the SDK except as expressly set forth herein.
48
+ - Remove, alter, or obscure any copyright notices, trademarks, or other proprietary notices or legends from the SDK.
49
+ - Use the SDK in any manner that infringes, misappropriates, or violates any intellectual property, publicity, privacy, or other right of any third party.
50
+ - Disassemble, decompile, or reverse engineer the SDK, or attempt to discover any source code therein (except to the extent that the SDK is provided in source form or as otherwise permitted under applicable law).
51
+
52
+ 3.5 **No Competitive Use**
53
+
54
+ Licensee shall not use the SDK (in whole or in part) to develop or assist in the development of any product or service that competes with Licensor’s SaaS Service or any other product or service offered by Licensor. Additionally, Licensee shall not use the SDK to replicate or replace the core functionality of the SaaS Service.
55
+
56
+ ## 4. Intellectual Property Rights
57
+
58
+ 4.1 **Reservation of Rights**
59
+
60
+ All rights not expressly granted in this Agreement are reserved by Licensor. Licensor retains all right, title, and interest, including all intellectual property rights, in and to the SDK, the SaaS Service, the API, and any associated documentation or materials.
61
+
62
+ 4.2 **Feedback**
63
+
64
+ If Licensee provides any suggestions, feedback, or comments regarding the SDK or the SaaS Service (collectively, “**Feedback**”), Licensor shall be free to use, disclose, reproduce, license, or otherwise distribute and exploit the Feedback without any obligation or restriction, provided that such Feedback does not include Licensee’s Confidential Information.
65
+
66
+ ## 5. Confidentiality
67
+
68
+ 5.1 **Obligation**
69
+
70
+ Licensee shall maintain the Confidential Information in strict confidence and shall use the same standard of care used to protect its own confidential or proprietary information of a similar nature, but not less than a reasonable standard of care, to prevent unauthorized access to or disclosure of the Confidential Information.
71
+
72
+ 5.2 **Exceptions**
73
+
74
+ Licensee’s obligations under Section 5.1 do not apply to information that:
75
+
76
+ - Is already known to Licensee without obligation of confidentiality.
77
+ - Becomes publicly available without Licensee’s breach of any obligation owed to Licensor.
78
+ - Is rightfully received from a third party without breach of any obligation owed to Licensor.
79
+ - Is independently developed by Licensee without use of or reference to the Confidential Information.
80
+
81
+ ## 6. Term and Termination
82
+
83
+ 6.1 **Term**
84
+
85
+ This Agreement is effective as of the Effective Date and will continue until terminated as provided herein.
86
+
87
+ 6.2 **Termination by Licensor**
88
+
89
+ Licensor may terminate this Agreement immediately if Licensee breaches any provision of this Agreement and fails to cure such breach within ten (10) days after receiving written notice.
90
+
91
+ 6.3 **Effect of Termination**
92
+
93
+ Upon termination of this Agreement for any reason:
94
+
95
+ - All licenses granted hereunder shall immediately terminate, and Licensee shall cease using the SDK.
96
+ - Licensee shall return or destroy (at Licensor’s option) all copies of the SDK, including any Confidential Information.
97
+ - Sections 3, 4, 5, 7, 8, and 9 shall survive termination.
98
+
99
+ ## 7. Disclaimer of Warranties
100
+
101
+ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE SDK IS PROVIDED “AS IS” AND “AS AVAILABLE,” WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND. LICENSOR EXPRESSLY DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. LICENSOR DOES NOT WARRANT THAT THE SDK OR THE SAAS SERVICE WILL MEET LICENSEE’S REQUIREMENTS, THAT THE OPERATION OF THE SDK OR THE SAAS SERVICE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE SDK CAN OR WILL BE CORRECTED.
102
+
103
+ ## 8. Limitation of Liability
104
+
105
+ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL LICENSOR BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR EXEMPLARY DAMAGES (INCLUDING, BUT NOT LIMITED TO, DAMAGES FOR LOSS OF PROFITS, GOODWILL, OR DATA) ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN NO EVENT SHALL LICENSOR’S TOTAL CUMULATIVE LIABILITY FOR ALL CLAIMS ARISING FROM OR RELATING TO THIS AGREEMENT EXCEED THE GREATER OF (A) ONE HUNDRED U.S. DOLLARS ($100), OR (B) THE AMOUNT ACTUALLY PAID BY LICENSEE TO LICENSOR UNDER THIS AGREEMENT IN THE SIX (6) MONTH PERIOD PRECEDING THE CLAIM.
106
+
107
+ ## 9. General Provisions
108
+
109
+ 9.1 **Governing Law**
110
+
111
+ This Agreement shall be governed by and construed in accordance with the laws of France, without regard to its conflict-of-laws principles. Any dispute arising out of or relating to this Agreement shall be brought exclusively in the courts of France, and the parties hereby consent to the personal jurisdiction and venue therein.
112
+
113
+ 9.2 **Entire Agreement**
114
+
115
+ This Agreement constitutes the entire agreement between the parties with respect to the subject matter hereof and supersedes all prior understandings and agreements, whether written or oral, regarding such subject matter.
116
+
117
+ 9.3 **Amendment**
118
+
119
+ No amendment, modification, or supplement to this Agreement shall be binding unless it is in writing and signed by both parties.
120
+
121
+ 9.4 **Assignment**
122
+
123
+ Licensee may not assign or transfer this Agreement, in whole or in part, without Licensor’s prior written consent. Any attempt to assign or transfer in violation of this Section shall be null and void.
124
+
125
+ 9.5 **Severability**
126
+
127
+ If any provision of this Agreement is held to be invalid or unenforceable, that provision shall be deemed modified to the least extent necessary to make it valid or enforceable, and the remaining provisions of this Agreement shall remain in full force and effect.
128
+
129
+ 9.6 **Waiver**
130
+
131
+ No waiver of any provision of this Agreement shall be effective unless it is in writing and signed by the party granting the waiver. The failure of Licensor to enforce any provision of this Agreement shall not be construed as a waiver of such provision or any other provision hereof.
132
+
133
+ 9.7 **Independent Contractors**
134
+
135
+ The parties are independent contractors. Nothing in this Agreement shall be construed to create a partnership, joint venture, agency, or any other relationship between the parties.
136
+
137
+ 9.8 **Notices**
138
+
139
+ All notices under this Agreement shall be in writing and sent to the addresses designated by the parties from time to time.
140
+
141
+ ---
142
+
143
+ **By downloading, installing, accessing, or otherwise using the SDK, Licensee acknowledges that it has read this Agreement, understands it, and agrees to be bound by its terms.**
@@ -0,0 +1,33 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+ octopus_version = '~> 1.5.1'
5
+
6
+ Pod::Spec.new do |s|
7
+ s.name = "OctopusReactNativeSdk"
8
+ s.version = package["version"]
9
+ s.summary = package["description"]
10
+ s.homepage = package["homepage"]
11
+ s.license = package["license"]
12
+ s.authors = package["author"]
13
+
14
+ s.platforms = { :ios => min_ios_version_supported }
15
+ s.source = { :git => "https://github.com/Octopus-Community/octopus-sdk-react-native.git", :tag => "#{s.version}" }
16
+
17
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
18
+
19
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
20
+ # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
21
+ if respond_to?(:install_modules_dependencies, true)
22
+ install_modules_dependencies(s)
23
+ else
24
+ s.dependency "React-Core"
25
+ end
26
+
27
+ s.dependency 'OctopusCommunity', octopus_version
28
+ s.dependency 'OctopusCommunityUI', octopus_version
29
+ s.dependency 'OctopusCommunityCore', octopus_version
30
+ s.dependency 'OctopusCommunityRemoteClient', octopus_version
31
+ s.dependency 'OctopusCommunityGrpcModels', octopus_version
32
+ s.dependency 'OctopusCommunityDependencyInjection', octopus_version
33
+ end
package/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # @octopus-community/react-native
2
+
3
+ React Native module for the Octopus Community [Android](https://github.com/Octopus-Community/octopus-sdk-android) and [Swift](https://github.com/Octopus-Community/octopus-sdk-swift) SDKs
4
+
5
+ - [Installation](#installation)
6
+ - [iOS setup](#ios-setup)
7
+ - [Compatibility table](#compatibility-table)
8
+ - [Usage](#usage)
9
+ - [Initialization](#initialization)
10
+ - [Show the UI](#show-the-ui)
11
+ - [API docs](./docs/api/README.md)
12
+ - [Example app](./example)
13
+ - [Troubleshooting](#troubleshooting)
14
+
15
+ ## Installation
16
+
17
+ ```sh
18
+ npm install @octopus-community/react-native
19
+ ```
20
+
21
+ ### iOS setup
22
+
23
+ Make sure to `use_frameworks` in your `Podfile`.
24
+
25
+ ```ruby
26
+ # Podfile
27
+ linkage = :static # or :dynamic
28
+ if linkage != nil
29
+ Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
30
+ use_frameworks! :linkage => linkage.to_sym
31
+ end
32
+ ```
33
+
34
+ Due to a bug in XCode 15, you might need to set `ENABLE_USER_SCRIPT_SANDBOXING` to YES and then to NO in order to compile (see [this issue](https://github.com/CocoaPods/CocoaPods/issues/11946#issuecomment-1948423786)).
35
+
36
+ ### Compatibility table
37
+
38
+ | React Native version(s) | Android | iOS | Old arch | New arch | Supporting version(s) |
39
+ |-------------------------| ------- |-------| -------- | ------------- | --------------------- |
40
+ | v0.78+ | 5.0+ | 14.0+ | ✅ | Interop layer | v1+ |
41
+
42
+ * Older React Native versions might be supported but were untested
43
+ * New arch is currently supported with the interoperability layer
44
+ * Other requirements for current version:
45
+ * Android
46
+ * Kotlin version 2
47
+ * iOS
48
+ * XCode 16.0+
49
+
50
+ ### Expo
51
+
52
+ An expo plugin will be available shortly.
53
+
54
+ ## Usage
55
+
56
+ ### Initialization
57
+
58
+ Initialize the SDK with your API key with [`initialize`](./docs/api/functions/initialize.md).
59
+
60
+ Choose whether your app or Octopus handles user authentification:
61
+
62
+ #### Octopus-handled authentification
63
+
64
+ ```ts
65
+ import { initialize } from '@octopus-community/react-native';
66
+
67
+ await initialize({
68
+ apiKey: 'YOUR_OCTOPUS_API_KEY',
69
+ connectionMode: { type: 'octopus' }
70
+ });
71
+ ```
72
+
73
+ #### Single Sign-On (SSO)
74
+
75
+ For SSO mode:
76
+
77
+ * your app manages user authentication and certain profile fields. You specify which profile fields your app will handle directly
78
+ * you need to provide a token provider function that returns a valid JWT token for the authenticated user.
79
+ * use the `useUserTokenProvider` hook in React components:
80
+
81
+ ```ts
82
+ import {
83
+ initialize,
84
+ addEditUserListener,
85
+ addLoginRequiredListener,
86
+ connectUser,
87
+ disconnectUser,
88
+ useUserTokenProvider,
89
+ closeUI,
90
+ } from '@octopus-community/react-native';
91
+
92
+ // Initialize with SSO mode
93
+ await initialize({
94
+ apiKey: 'YOUR_OCTOPUS_API_KEY',
95
+ connectionMode: {
96
+ type: 'sso',
97
+ appManagedFields: ['username', 'profilePicture', 'biography']
98
+ }
99
+ });
100
+
101
+ // Listen for when authentication is required
102
+ const loginRequiredSubscription = addLoginRequiredListener(() => {
103
+ // Navigate to your app's login screen
104
+ console.log('User needs to log in');
105
+ closeUI();
106
+ });
107
+
108
+ // Listen for when users want to edit their profile
109
+ const editUserSubscription = addEditUserListener(({ fieldToEdit }) => {
110
+ // Navigate to your app's profile editing screen
111
+ // for the specific field (username, profilePicture, etc.)
112
+ console.log(`User wants to edit: ${fieldToEdit}`);
113
+ closeUI();
114
+ });
115
+
116
+ // Set up token provider (in a React component)
117
+ useUserTokenProvider(async () => {
118
+ const token = await refreshUserToken();
119
+ return token;
120
+ });
121
+
122
+ // Connect a user after they log in
123
+ await connectUser({
124
+ userId: 'unique-user-id',
125
+ profile: {
126
+ username: 'john_doe',
127
+ profilePicture: 'https://example.com/avatar.jpg',
128
+ biography: 'Software developer',
129
+ legalAgeReached: true,
130
+ },
131
+ });
132
+
133
+ // Disconnect the user when they log out
134
+ await disconnectUser();
135
+
136
+ // Cleanup listeners when appropriate (eg. in return of a useEffect)
137
+ loginRequiredSubscription.remove();
138
+ editUserSubscription.remove();
139
+ ```
140
+
141
+ ### Show the UI
142
+
143
+ Show the Octopus home screen with the [`openUI()`](./docs/api/functions/openUI.md) method.
144
+
145
+ Future versions of this React Native module will let you show the UI in your React components. Please reach out if you need this prioritized.
146
+
147
+ ### API docs
148
+
149
+ For details about the Typescript API, head to the [API docs](./docs/api/README.md).
150
+
151
+ ### Example app
152
+
153
+ Take a look at our [example app](./example/src/App.tsx).
154
+
155
+ ## Troubleshooting
156
+
157
+ Any error that might be intercepted by the React Native module will be rejected in the methods you call. If it cannot be intercepted, you may see the underlying SDK's logs in your native logs.
158
+
159
+ ## Contributing
160
+
161
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
@@ -0,0 +1,92 @@
1
+ buildscript {
2
+ ext.getExtOrDefault = {name ->
3
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['OctopusReactNativeSdk_' + name]
4
+ }
5
+
6
+ repositories {
7
+ google()
8
+ mavenCentral()
9
+ }
10
+
11
+ dependencies {
12
+ classpath "com.android.tools.build:gradle:8.7.2"
13
+ // noinspection DifferentKotlinGradleVersion
14
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
15
+ classpath "org.jetbrains.kotlin:compose-compiler-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
16
+ }
17
+ }
18
+
19
+ apply plugin: "com.android.library"
20
+ apply plugin: "kotlin-android"
21
+ apply plugin: "org.jetbrains.kotlin.plugin.compose"
22
+
23
+ def getExtOrIntegerDefault(name) {
24
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["OctopusReactNativeSdk_" + name]).toInteger()
25
+ }
26
+
27
+ def supportsNamespace() {
28
+ def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
29
+ def major = parsed[0].toInteger()
30
+ def minor = parsed[1].toInteger()
31
+
32
+ // Namespace support was added in 7.3.0
33
+ return (major == 7 && minor >= 3) || major >= 8
34
+ }
35
+
36
+ android {
37
+ if (supportsNamespace()) {
38
+ namespace "com.octopuscommunity.octopusreactnativesdk"
39
+
40
+ sourceSets {
41
+ main {
42
+ manifest.srcFile "src/main/AndroidManifestNew.xml"
43
+ }
44
+ }
45
+ }
46
+
47
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
48
+
49
+ defaultConfig {
50
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
51
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
52
+ }
53
+
54
+ buildTypes {
55
+ release {
56
+ minifyEnabled false
57
+ }
58
+ }
59
+
60
+ lintOptions {
61
+ disable "GradleCompatible"
62
+ }
63
+
64
+ buildFeatures {
65
+ compose true
66
+ }
67
+
68
+ compileOptions {
69
+ sourceCompatibility JavaVersion.VERSION_1_8
70
+ targetCompatibility JavaVersion.VERSION_1_8
71
+ }
72
+ }
73
+
74
+ repositories {
75
+ mavenCentral()
76
+ google()
77
+ }
78
+
79
+ def kotlin_version = getExtOrDefault("kotlinVersion")
80
+ def octopus_community_version = getExtOrDefault("octopusCommunityVersion")
81
+ def compose_bom_version = getExtOrDefault("composeBomVersion")
82
+ def android_x_navigation_version = getExtOrDefault("androidXNavigationVersion")
83
+
84
+ dependencies {
85
+ implementation "com.facebook.react:react-android"
86
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
87
+ implementation platform("androidx.compose:compose-bom:$compose_bom_version")
88
+ implementation "androidx.navigation:navigation-compose:$android_x_navigation_version"
89
+
90
+ api "com.octopuscommunity:octopus-sdk:$octopus_community_version"
91
+ api "com.octopuscommunity:octopus-sdk-ui:$octopus_community_version"
92
+ }
@@ -0,0 +1,9 @@
1
+ OctopusReactNativeSdk_kotlinVersion=2.1.10
2
+ OctopusReactNativeSdk_minSdkVersion=24
3
+ OctopusReactNativeSdk_targetSdkVersion=34
4
+ OctopusReactNativeSdk_compileSdkVersion=35
5
+ OctopusReactNativeSdk_ndkVersion=27.1.12297006
6
+ OctopusReactNativeSdk_composeBomVersion=2025.06.01
7
+ OctopusReactNativeSdk_androidXNavigationVersion=2.9.0
8
+
9
+ OctopusReactNativeSdk_octopusCommunityVersion=1.5.0
@@ -0,0 +1,9 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.octopuscommunity.octopusreactnativesdk">
3
+ <application>
4
+ <activity
5
+ android:name=".OctopusUIActivity"
6
+ android:exported="false"
7
+ android:theme="@style/Theme.AppCompat.DayNight.NoActionBar"/>
8
+ </application>
9
+ </manifest>
@@ -0,0 +1,8 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <application>
3
+ <activity
4
+ android:name=".OctopusUIActivity"
5
+ android:exported="false"
6
+ android:theme="@style/Theme.AppCompat.DayNight.NoActionBar"/>
7
+ </application>
8
+ </manifest>
@@ -0,0 +1,48 @@
1
+ package com.octopuscommunity.octopusreactnativesdk
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.ReactContext
5
+ import com.facebook.react.bridge.WritableMap
6
+ import com.facebook.react.modules.core.DeviceEventManagerModule
7
+ import com.octopuscommunity.sdk.domain.model.ProfileField
8
+
9
+ class OctopusEventEmitter(private val reactContext: ReactContext) {
10
+
11
+ private var listenerCount = 0
12
+
13
+ fun addListener(eventName: String) {
14
+ listenerCount += 1
15
+ }
16
+
17
+ fun removeListeners(count: Int) {
18
+ listenerCount -= count
19
+ }
20
+
21
+ fun emitLoginRequired() {
22
+ sendEvent("loginRequired", null)
23
+ }
24
+
25
+ fun emitEditUser(profileField: ProfileField?) {
26
+ val params = Arguments.createMap()
27
+ params.putString("fieldToEdit", ProfileFieldMapper.toReactNativeString(profileField))
28
+ sendEvent("editUser", params)
29
+ }
30
+
31
+ fun emitUserTokenRequest(requestId: String) {
32
+ val params = Arguments.createMap()
33
+ params.putString("requestId", requestId)
34
+ sendEvent("userTokenRequest", params)
35
+ }
36
+
37
+ private fun sendEvent(eventName: String, params: WritableMap?) {
38
+ if (listenerCount > 0) {
39
+ reactContext
40
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
41
+ .emit(eventName, params)
42
+ }
43
+ }
44
+
45
+ companion object {
46
+ var instance: OctopusEventEmitter? = null
47
+ }
48
+ }
@@ -0,0 +1,73 @@
1
+ package com.octopuscommunity.octopusreactnativesdk
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
5
+ import com.facebook.react.bridge.ReactMethod
6
+ import com.facebook.react.bridge.Promise
7
+ import com.facebook.react.bridge.ReadableMap
8
+
9
+ class OctopusReactNativeSdkModule(reactContext: ReactApplicationContext) :
10
+ ReactContextBaseJavaModule(reactContext) {
11
+
12
+ private val sdkInitializer = OctopusSDKInitializer()
13
+ private val eventEmitter = OctopusEventEmitter(reactContext)
14
+ private val uiController = OctopusUIController(reactContext)
15
+ private val ssoAuthenticator = OctopusSSOAuthenticator(eventEmitter)
16
+
17
+ override fun getName(): String = NAME
18
+
19
+ @ReactMethod
20
+ fun initialize(options: ReadableMap, promise: Promise) {
21
+ sdkInitializer.initialize(reactApplicationContext, options, promise)
22
+ }
23
+
24
+ @ReactMethod
25
+ fun openUI(promise: Promise) {
26
+ uiController.openUI(promise)
27
+ }
28
+
29
+ @ReactMethod
30
+ fun closeUI(promise: Promise) {
31
+ uiController.closeUI(promise)
32
+ }
33
+
34
+ @ReactMethod
35
+ fun connectUser(params: ReadableMap, promise: Promise) {
36
+ ssoAuthenticator.connectUser(params, promise)
37
+ }
38
+
39
+ @ReactMethod
40
+ fun disconnectUser(promise: Promise) {
41
+ ssoAuthenticator.disconnectUser(promise)
42
+ }
43
+
44
+ @ReactMethod
45
+ fun completeUserTokenRequest(requestId: String, token: String, promise: Promise) {
46
+ ssoAuthenticator.completeTokenRequest(requestId, token)
47
+ promise.resolve(null)
48
+ }
49
+
50
+ @ReactMethod
51
+ fun cancelUserTokenRequest(requestId: String, promise: Promise) {
52
+ ssoAuthenticator.cancelTokenRequest(requestId)
53
+ promise.resolve(null)
54
+ }
55
+
56
+ @ReactMethod
57
+ fun addListener(eventName: String) {
58
+ eventEmitter.addListener(eventName)
59
+ }
60
+
61
+ @ReactMethod
62
+ fun removeListeners(count: Int) {
63
+ eventEmitter.removeListeners(count)
64
+ }
65
+
66
+ companion object {
67
+ const val NAME = "OctopusReactNativeSdk"
68
+ }
69
+
70
+ init {
71
+ OctopusEventEmitter.instance = eventEmitter
72
+ }
73
+ }
@@ -0,0 +1,17 @@
1
+ package com.octopuscommunity.octopusreactnativesdk
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+
9
+ class OctopusReactNativeSdkPackage : ReactPackage {
10
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11
+ return listOf(OctopusReactNativeSdkModule(reactContext))
12
+ }
13
+
14
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
+ return emptyList()
16
+ }
17
+ }
@@ -0,0 +1,55 @@
1
+ package com.octopuscommunity.octopusreactnativesdk
2
+
3
+ import com.facebook.react.bridge.Promise
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.ReadableMap
6
+ import com.octopuscommunity.sdk.OctopusSDK
7
+ import com.octopuscommunity.sdk.domain.model.ConnectionMode
8
+
9
+ class OctopusSDKInitializer {
10
+
11
+ fun initialize(context: ReactApplicationContext, options: ReadableMap, promise: Promise) {
12
+ val apiKey = options.getString("apiKey")
13
+ if (apiKey == null) {
14
+ promise.reject("INITIALIZE_ERROR", "Missing API key")
15
+ return
16
+ }
17
+
18
+ try {
19
+ val connectionMode = parseConnectionMode(options)
20
+ OctopusSDK.initialize(
21
+ context = context,
22
+ apiKey = apiKey,
23
+ connectionMode = connectionMode
24
+ )
25
+ promise.resolve(null)
26
+ } catch (e: InvalidConnectionModeException) {
27
+ promise.reject("INITIALIZE_ERROR", e.message, e)
28
+ } catch (e: Exception) {
29
+ promise.reject("INITIALIZE_ERROR", "Failed to initialize Octopus SDK", e)
30
+ }
31
+ }
32
+
33
+ private fun parseConnectionMode(options: ReadableMap): ConnectionMode {
34
+ val connectionModeMap = options.getMap("connectionMode")
35
+ return when (val connectionModeType = connectionModeMap?.getString("type")) {
36
+ "sso" -> {
37
+ ConnectionMode.SSO(
38
+ appManagedFields = ProfileFieldMapper.fromReactNativeArray(
39
+ connectionModeMap.getArray("appManagedFields")
40
+ )
41
+ )
42
+ }
43
+
44
+ "octopus" -> {
45
+ ConnectionMode.Octopus
46
+ }
47
+
48
+ else -> {
49
+ throw InvalidConnectionModeException("Invalid connection mode type: $connectionModeType")
50
+ }
51
+ }
52
+ }
53
+
54
+ private class InvalidConnectionModeException(message: String) : Exception(message)
55
+ }