react-native-sdk-pianoio 0.3.4 → 0.3.6

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 CHANGED
@@ -1,28 +1,13 @@
1
- # 🎹 React Native SDK for Piano.io
1
+ # React Native SDK for Piano.io
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/react-native-sdk-pianoio.svg)](https://www.npmjs.com/package/react-native-sdk-pianoio)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
-
6
- A React Native SDK for integrating Piano.io's digital monetization platform into your mobile applications. This SDK provides seamless integration with Piano's paywall, subscription, and content monetization features.
3
+ A React Native SDK for integrating Piano.io's digital monetization platform into your mobile applications. This SDK provides seamless, cross-platform integration with Piano's paywall, subscription, and content monetization features.
7
4
 
8
5
  ## ✨ Features
9
6
 
10
- ### 🚀 Core Functionality
11
- - **Piano Composer Integration**: Full integration with Piano's Composer API
12
- - **OAuth Authentication**: User authentication and token management
13
- - **Experience Execution**: Execute Piano experiences with custom configurations
14
- - **Cross-Platform**: Works on both iOS and Android (Android fully implemented)
15
-
16
- ### 📱 Platform Support
17
- - ✅ **Android**: Fully implemented and tested (91% test coverage)
18
- - 🚧 **iOS**: Basic implementation (needs feature parity)
19
-
20
- ### 🔧 Configuration Options
21
- - **Tags Management**: Add/remove tags for content categorization
22
- - **Zone Configuration**: Set zone IDs for targeted experiences
23
- - **Custom Variables**: Add custom data to experiences
24
- - **User Tokens**: Manage user authentication tokens
25
- - **URL Configuration**: Set referrer and target URLs
7
+ - **Full Piano Composer Integration**: Execute experiences, manage content access, and handle paywalls
8
+ - **Piano ID Authentication**: Complete user authentication and token management for both platforms
9
+ - **Cross-Platform Parity**: A single, unified API for both iOS and Android
10
+ - **Flexible Configuration**: Manage tags, zone IDs, custom variables, user tokens, and more
26
11
 
27
12
  ## 📦 Installation
28
13
 
@@ -36,7 +21,7 @@ yarn add react-native-sdk-pianoio
36
21
 
37
22
  ### 1. Initialize the SDK
38
23
 
39
- ```typescript
24
+ ```javascript
40
25
  import { PianoComposer } from 'react-native-sdk-pianoio';
41
26
 
42
27
  // Initialize with your Piano Application ID
@@ -45,44 +30,42 @@ const composer = await PianoComposer.create('YOUR_PIANO_AID');
45
30
 
46
31
  ### 2. Configure the Experience
47
32
 
48
- ```typescript
49
- // Add tags for content categorization
50
- await composer.addTag('premium');
51
- await composer.addTags(['article', 'featured']);
33
+ ```javascript
34
+ // Set the required parameters for the experience
35
+ await composer.setUrl('https://www.your-website.com/premium-article');
36
+ await composer.setZoneId('your_zone_id'); // e.g., 'default'
37
+ await composer.setReferrer('https://www.your-website.com/');
52
38
 
53
- // Set zone ID for targeted experiences
54
- await composer.setZoneId('Zone1');
55
-
56
- // Add custom variables
39
+ // Add optional parameters
40
+ await composer.addTag('premium-content');
57
41
  await composer.setCustomVariable('article_id', '12345');
58
-
59
- // Set user token for authentication
60
- await composer.setUserToken('user_token_123');
61
42
  ```
62
43
 
63
44
  ### 3. Execute the Experience
64
45
 
65
- ```typescript
66
- // Execute with basic configuration
67
- const result = await composer.executeExperience();
68
-
69
- // Execute with advanced configuration
70
- const result = await composer.executeExperienceWithConfig(true, true);
46
+ ```javascript
47
+ try {
48
+ const result = await composer.executeExperience();
49
+ console.log('Experience result:', result);
50
+ // Handle the event data from the Piano backend
51
+ } catch (error) {
52
+ console.error('Failed to execute experience:', error);
53
+ }
71
54
  ```
72
55
 
73
56
  ### 4. Handle Authentication
74
57
 
75
- ```typescript
76
- // Sign in user
58
+ ```javascript
59
+ // Sign in a user
77
60
  const user = await composer.signIn();
78
61
 
79
- // Check authentication status
62
+ // Check if a user is authenticated
80
63
  const isAuthenticated = await composer.isAuthenticated();
81
64
 
82
- // Get current user
65
+ // Get the current user's details
83
66
  const currentUser = await composer.getCurrentUser();
84
67
 
85
- // Sign out user
68
+ // Sign out the user
86
69
  await composer.signOut();
87
70
  ```
88
71
 
@@ -90,95 +73,48 @@ await composer.signOut();
90
73
 
91
74
  ### Core Methods
92
75
 
93
- #### `PianoComposer.create(aid: string)`
94
- Creates and initializes a new PianoComposer instance.
95
-
96
- #### `composer.addTag(tag: string)`
97
- Adds a single tag to the experience.
98
-
99
- #### `composer.addTags(tags: string[])`
100
- Adds multiple tags to the experience.
101
-
102
- #### `composer.setZoneId(zoneId: string)`
103
- Sets the zone ID for targeted experiences.
104
-
105
- #### `composer.setCustomVariable(key: string, value: string)`
106
- Adds a custom variable to the experience.
107
-
108
- #### `composer.executeExperience()`
109
- Executes the Piano experience with current configuration.
110
-
111
- ### Authentication Methods
112
-
113
- #### `composer.signIn()`
114
- Signs in the user with Piano OAuth.
115
-
116
- #### `composer.signOut()`
117
- Signs out the current user.
118
-
119
- #### `composer.getCurrentUser()`
120
- Gets information about the current authenticated user.
121
-
122
- #### `composer.isAuthenticated()`
123
- Checks if a user is currently authenticated.
124
-
125
- ### Advanced Methods
126
-
127
- #### `composer.executeExperienceWithConfig(includeUserData: boolean, debug: boolean)`
128
- Executes experience with advanced configuration options.
129
-
130
- #### `composer.createExperienceRequest(includeUserData?: boolean, debug?: boolean)`
131
- Creates an experience request with custom parameters.
132
-
133
- #### `composer.getStatus()`
134
- Gets the current status of the composer.
135
-
136
- #### `composer.testExecutionFlow()`
137
- Tests the complete execution flow.
138
-
139
- ## 🧪 Testing
140
-
141
- The SDK includes comprehensive test coverage:
142
-
143
- ```bash
144
- # Run all tests
145
- npm test
146
-
147
- # Run tests with coverage
148
- npm run test:coverage
149
-
150
- # Run Android-specific tests
151
- cd android && ./test.sh
152
- ```
153
-
154
- ### Test Results
155
- - ✅ **91% Test Coverage** on Android implementation
156
- - ✅ **67/73 tests passing**
157
- - ✅ **All core functionality tested**
76
+ - `PianoComposer.create(aid: string)` - Creates and initializes a new PianoComposer instance
77
+ - `composer.executeExperience()` - Executes the Piano experience with the current configuration
78
+ - `composer.signIn()` - Initiates the user sign-in flow
79
+ - `composer.signOut()` - Signs out the current user
80
+
81
+ ### Configuration Methods
82
+
83
+ - `addTag(tag: string)`
84
+ - `addTags(tags: string[])`
85
+ - `setZoneId(zoneId: string)`
86
+ - `setReferrer(referrer: string)`
87
+ - `setUrl(url: string)`
88
+ - `setUserToken(token: string)`
89
+ - `addCustomVariable(key: string, value: string)`
90
+ - `setCustomVariables(variables: { [key: string]: string })`
91
+
92
+ ### Utility Methods
93
+
94
+ - `getCurrentUser()`
95
+ - `isAuthenticated()`
96
+ - `getStatus()`
97
+ - `clearConfiguration()`
98
+ - `removeTag(tag: string)`
99
+ - `removeCustomVariable(key: string)`
100
+ - `clearTags()`
101
+ - `clearCustomVariables()`
158
102
 
159
103
  ## 📱 Platform Status
160
104
 
161
- ### Android
162
- - **Status**: Fully implemented and tested
163
- - **Coverage**: 91% test coverage
164
- - **Features**: All core features implemented
165
- - **Dependencies**: React Native 0.78.1 compatible
166
-
167
- ### iOS 🚧
168
- - **Status**: Basic implementation
169
- - **Coverage**: Needs feature parity with Android
170
- - **Features**: Core methods implemented
171
- - **Next Steps**: Implement advanced features and authentication
105
+ - ✅ **Android**: Fully implemented and aligned with the official Piano Android SDK
106
+ - **iOS**: Fully implemented and aligned with the official Piano iOS SDK
172
107
 
173
108
  ## 🔧 Development
174
109
 
175
110
  ### Prerequisites
111
+
176
112
  - Node.js 18+
177
- - React Native 0.78.1
113
+ - React Native
178
114
  - Android Studio (for Android development)
179
- - Xcode (for iOS development)
115
+ - Xcode & CocoaPods (for iOS development)
180
116
 
181
- ### Setup Development Environment
117
+ ### Setup
182
118
 
183
119
  ```bash
184
120
  # Clone the repository
@@ -187,67 +123,60 @@ git clone https://github.com/HexagonSwiss/hex-react-native-sdk-pianoio.git
187
123
  # Install dependencies
188
124
  npm install
189
125
 
190
- # Run tests
191
- npm test
192
-
193
126
  # Build the library
194
127
  npm run build
195
128
  ```
196
129
 
197
130
  ### Project Structure
131
+
198
132
  ```
199
- ├── android/ # Android native implementation
200
- ├── src/main/java/ # Kotlin source files
201
- │ └── src/test/java/ # Android tests
202
- ├── ios/ # iOS native implementation
203
- ├── src/ # TypeScript source
204
- │ ├── index.tsx # Main entry point
205
- │ ├── PianoComposer.tsx # Main SDK class
206
- │ └── NativeSdkPianoio.ts # Native module interface
207
- ├── example/ # Example React Native app
208
- └── lib/ # Built library files
133
+ ├── android/ # Android native implementation
134
+ ├── ios/ # iOS native implementation
135
+ ├── src/ # TypeScript source (JS bridge)
136
+ └── ...
209
137
  ```
210
138
 
211
- ## 🎯 Example App
212
-
213
- The repository includes a comprehensive example app demonstrating all SDK features:
139
+ ## 🎯 How to install
214
140
 
215
- ```bash
216
- # Navigate to example directory
217
- cd example
141
+ ```
142
+ # In your expo projet's app.json file, make sure to have:
143
+
144
+ "plugins": [
145
+ [
146
+ "expo-build-properties",
147
+ {
148
+ "android": {
149
+ "buildToolsVersion": "35.0.0",
150
+ "compileSdkVersion": 34,
151
+ "minSdkVersion": 24,
152
+ "targetSdkVersion": 34
153
+ },
154
+ "ios": {
155
+ "deploymentTarget": "15.1",
156
+ "useFrameworks": "static"
157
+ }
158
+ }
159
+ ]
160
+ ...other plugins...
161
+ ],
218
162
 
219
163
  # Install dependencies
220
- npm install
164
+ npm install react-native-sdk-pianoio
221
165
 
222
166
  # Run on Android
223
- npx react-native run-android
167
+ npx expo run:android
224
168
 
225
169
  # Run on iOS
226
- npx react-native run-ios
170
+ npx expo run:ios
227
171
  ```
228
172
 
229
- The example app includes:
230
- - ✅ Basic configuration testing
231
- - ✅ Authentication flow testing
232
- - ✅ Advanced configuration options
233
- - ✅ Experience execution
234
- - ✅ Real-time logging
235
-
236
173
  ## 🤝 Contributing
237
174
 
238
- We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
239
-
240
- ### Development Workflow
241
- 1. Fork the repository
242
- 2. Create a feature branch
243
- 3. Make your changes
244
- 4. Add tests for new functionality
245
- 5. Ensure all tests pass
246
- 6. Submit a pull request
175
+ We welcome contributions! Please see our Contributing Guide for details.
247
176
 
248
177
  ## 📄 License
249
178
 
250
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
179
+ This project is licensed under the MIT License - see the LICENSE file for details.
251
180
 
252
181
  ## 🆘 Support
253
182
 
@@ -255,10 +184,6 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
255
184
  - 🐛 **Issues**: [GitHub Issues](https://github.com/HexagonSwiss/hex-react-native-sdk-pianoio/issues)
256
185
  - 📖 **Documentation**: [Piano.io Documentation](https://docs.piano.io/)
257
186
 
258
- ## 🔄 Changelog
259
-
260
- See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes.
261
-
262
187
  ---
263
188
 
264
- **Made with ❤️ by [HexagonSwiss](https://hexagonswiss.ch)**
189
+ Made with ❤️ by HexagonSwiss
@@ -26,40 +26,24 @@ class ComposerPianoImpl {
26
26
 
27
27
  // MARK: - Properties
28
28
 
29
- /** The Piano SDK's Composer instance */
30
29
  private var composer: Composer? = null
31
-
32
- /** The Piano ID Token Service instance */
33
30
  internal var tokenService: TokenService? = null
34
31
 
35
- /** The Piano Application ID */
36
32
  companion object {
37
33
  var aid: String = ""
38
34
  }
39
35
 
40
36
  // MARK: - Configuration Properties
41
37
 
42
- /** Configured tags for the composer */
43
38
  private val tags = mutableListOf<String>()
44
-
45
- /** Configured Zone ID */
46
39
  private var zoneId: String? = null
47
-
48
- /** Configured referrer */
49
40
  private var referrer: String? = null
50
-
51
- /** Configured URL */
52
41
  private var url: String? = null
53
-
54
- /** Configured user token */
55
42
  private var userToken: String? = null
56
-
57
- /** Configured custom variables */
58
43
  private val customVariables = mutableMapOf<String, String>()
59
44
 
60
45
  // MARK: - Initialization
61
46
 
62
- /** Public class constructor Initializes the instance with default values */
63
47
  constructor() {
64
48
  println("ComposerPianoImpl: Constructor initialized")
65
49
  }
@@ -103,24 +87,48 @@ class ComposerPianoImpl {
103
87
  }
104
88
  }
105
89
 
106
- // MARK: - Configuration Methods
90
+ // MARK: - State Methods (Getters)
91
+
92
+ fun getAid(): String {
93
+ return ComposerPianoImpl.aid
94
+ }
95
+
96
+ fun getTags(): List<String> {
97
+ return this.tags.toList()
98
+ }
99
+
100
+ fun getZoneId(): String {
101
+ return this.zoneId ?: ""
102
+ }
103
+
104
+ fun getReferrer(): String {
105
+ return referrer ?: ""
106
+ }
107
+
108
+ fun getUrl(): String {
109
+ return url ?: ""
110
+ }
111
+
112
+ fun getUserToken(): String {
113
+ return userToken ?: ""
114
+ }
115
+
116
+ fun getComposer(): Composer? {
117
+ return composer
118
+ }
119
+
120
+ fun getCustomVariables(): Map<String, String> {
121
+ return customVariables.toMap()
122
+ }
123
+
124
+ // MARK: - Configuration Methods (Setters)
107
125
 
108
- /**
109
- * Adds a tag to the composer
110
- *
111
- * @param tag The tag to be added
112
- */
113
126
  fun addTag(tag: String) {
114
127
  if (!this.tags.contains(tag)) {
115
128
  this.tags.add(tag)
116
129
  }
117
130
  }
118
131
 
119
- /**
120
- * Adds multiple tags to the composer
121
- *
122
- * @param tags The list of tags to be added
123
- */
124
132
  fun addTags(tags: List<String>) {
125
133
  for (tag in tags) {
126
134
  if (!this.tags.contains(tag)) {
@@ -129,166 +137,57 @@ class ComposerPianoImpl {
129
137
  }
130
138
  }
131
139
 
132
- /**
133
- * Sets the Zone ID for the composer
134
- *
135
- * @param zoneId The Zone ID to be configured
136
- */
137
140
  fun setZoneId(zoneId: String) {
138
141
  this.zoneId = zoneId
139
142
  }
140
143
 
141
- /**
142
- * Sets the referrer for the composer
143
- *
144
- * @param referrer The referrer to be configured
145
- */
146
144
  fun setReferrer(referrer: String) {
147
145
  this.referrer = referrer
148
146
  }
149
147
 
150
- /**
151
- * Sets the URL for the composer
152
- *
153
- * @param url The URL to be configured
154
- */
155
148
  fun setUrl(url: String) {
156
149
  this.url = url
157
150
  }
158
151
 
159
- /**
160
- * Sets the user token on the Composer instance.
161
- *
162
- * @param token The user's access token.
163
- */
164
152
  fun setUserToken(token: String) {
165
153
  this.userToken = token
166
- // Call the official SDK method to set the token
167
154
  composer?.userToken(token)
168
155
  }
169
156
 
170
- /**
171
- * Adds a custom variable.
172
- *
173
- * @param key The variable's key
174
- * @param value The variable's value
175
- */
176
157
  fun addCustomVariable(key: String, value: String) {
177
158
  this.customVariables[key] = value
178
159
  }
179
160
 
180
- // MARK: - Advanced Configuration Methods
181
-
182
- /**
183
- * Sets multiple custom variables at once.
184
- *
185
- * @param variables A map of custom variables.
186
- */
187
161
  fun setCustomVariables(variables: Map<String, String>) {
188
162
  this.customVariables.clear()
189
163
  this.customVariables.putAll(variables)
190
164
  }
191
165
 
192
- /** Removes all configured tags. */
166
+ // MARK: - Cleanup Methods
167
+
193
168
  fun clearTags() {
194
169
  this.tags.clear()
195
170
  }
196
171
 
197
- /** Removes all custom variables. */
198
172
  fun clearCustomVariables() {
199
173
  this.customVariables.clear()
200
174
  }
201
175
 
202
- /**
203
- * Removes a specific tag.
204
- *
205
- * @param tag The tag to be removed.
206
- */
207
176
  fun removeTag(tag: String) {
208
177
  this.tags.remove(tag)
209
178
  }
210
179
 
211
- /**
212
- * Removes a specific custom variable.
213
- *
214
- * @param key The key of the variable to be removed.
215
- */
216
180
  fun removeCustomVariable(key: String) {
217
181
  this.customVariables.remove(key)
218
182
  }
219
183
 
220
- // MARK: - State Methods (Getters)
221
-
222
- /**
223
- * Gets the Application ID.
224
- *
225
- * @return The current Application ID.
226
- */
227
- fun getAid(): String {
228
- return ComposerPianoImpl.aid
229
- }
230
-
231
- /**
232
- * Gets the configured tags.
233
- *
234
- * @return A list of configured tags.
235
- */
236
- fun getTags(): List<String> {
237
- return this.tags.toList()
238
- }
239
-
240
- /**
241
- * Gets the configured Zone ID.
242
- *
243
- * @return The current Zone ID.
244
- */
245
- fun getZoneId(): String {
246
- return this.zoneId ?: ""
247
- }
248
-
249
- /**
250
- * Gets the configured referrer.
251
- *
252
- * @return The current referrer.
253
- */
254
- fun getReferrer(): String {
255
- return referrer ?: ""
256
- }
257
-
258
- /**
259
- * Gets the configured URL.
260
- *
261
- * @return The current URL.
262
- */
263
- fun getUrl(): String {
264
- return url ?: ""
265
- }
266
-
267
- /**
268
- * Gets the user token.
269
- *
270
- * @return The current user token.
271
- */
272
- fun getUserToken(): String {
273
- return userToken ?: ""
274
- }
275
-
276
- /**
277
- * Gets the composer instance.
278
- *
279
- * @return The Composer instance, or null if not initialized.
280
- */
281
- fun getComposer(): Composer? {
282
- return composer
283
- }
284
-
285
- /**
286
- * Gets the configured custom variables.
287
- *
288
- * @return A map of the custom variables.
289
- */
290
- fun getCustomVariables(): Map<String, String> {
291
- return customVariables.toMap()
184
+ fun clearConfiguration() {
185
+ this.clearTags()
186
+ this.clearCustomVariables()
187
+ this.zoneId = null
188
+ this.referrer = null
189
+ this.url = null
190
+ this.userToken = null
292
191
  }
293
192
 
294
193
  // MARK: - Execution Methods
@@ -54,20 +54,10 @@ class TokenService {
54
54
 
55
55
  // MARK: - Authentication Methods
56
56
 
57
- /**
58
- * Caches the token received from a successful sign-in.
59
- *
60
- * @param token The token to cache. Can be null to clear it.
61
- */
62
57
  fun setToken(token: PianoIdToken?) {
63
58
  this.cachedToken = token
64
59
  }
65
60
 
66
- /**
67
- * Launches the Piano ID sign-in flow.
68
- *
69
- * @param authResultLauncher The ActivityResultLauncher from the calling Activity/Fragment.
70
- */
71
61
  fun signIn(authResultLauncher: ActivityResultLauncher<PianoIdClient.SignInContext>) {
72
62
  val localClient = client
73
63
  if (localClient == null) {
@@ -79,11 +69,6 @@ class TokenService {
79
69
  authResultLauncher.launch(request)
80
70
  }
81
71
 
82
- /**
83
- * Signs the user out.
84
- *
85
- * @param callback The callback to be invoked with the result (true for success, false for failure).
86
- */
87
72
  fun signOut(callback: (Boolean) -> Unit) {
88
73
  val localClient = client
89
74
  if (localClient == null) {
@@ -113,11 +98,6 @@ class TokenService {
113
98
 
114
99
  // MARK: - User Information Methods
115
100
 
116
- /**
117
- * Gets the current user's information.
118
- *
119
- * @return A User object if authenticated, otherwise null.
120
- */
121
101
  fun getCurrentUser(): User? {
122
102
  val token = this.cachedToken ?: return null
123
103
  // Construct a user from the token information using the getInfoField method.
@@ -128,11 +108,6 @@ class TokenService {
128
108
  )
129
109
  }
130
110
 
131
- /**
132
- * Checks if a user is currently authenticated.
133
- *
134
- * @return true if a valid token exists, false otherwise.
135
- */
136
111
  fun isAuthenticated(): Boolean {
137
112
  return this.cachedToken != null
138
113
  }
@@ -3,15 +3,13 @@ import PianoComposer
3
3
  import PianoOAuth
4
4
  import React
5
5
 
6
- /**
7
- * ComposerPianoImpl - Main implementation class for the Piano SDK on iOS.
8
- *
9
- * This class is responsible for:
10
- * - Managing the Piano SDK's Composer instance.
11
- * - Configuring the experience request using a fluent builder pattern.
12
- * - Executing Piano experiences and handling results via a delegate.
13
- * - Managing React Native promises across asynchronous callbacks.
14
- */
6
+ /// ComposerPianoImpl - Main implementation class for the Piano SDK on iOS.
7
+ ///
8
+ /// This class is responsible for:
9
+ /// - Managing the Piano SDK's Composer instance.
10
+ /// - Configuring the experience request using a fluent builder pattern.
11
+ /// - Executing Piano experiences and handling results via a delegate.
12
+ /// - Managing React Native promises across asynchronous callbacks.
15
13
  @objcMembers public class ComposerPianoImpl: NSObject {
16
14
 
17
15
  // MARK: - Properties
@@ -20,15 +18,14 @@ import React
20
18
  private var tokenService: TokenService?
21
19
  private var delegate: MyComposerDelegate?
22
20
 
23
- // Promises to communicate results of async operations back to React Native
24
21
  var experienceResolver: RCTPromiseResolveBlock?
25
22
  var experienceRejecter: RCTPromiseRejectBlock?
26
23
 
27
- // Stored configuration properties
28
24
  private var tags: [String] = []
29
25
  private var zoneId: String?
30
26
  private var referrer: String?
31
27
  private var url: String?
28
+ private var userToken: String?
32
29
  private var customVariables: [String: String] = [:]
33
30
 
34
31
  // MARK: - Initialization
@@ -56,7 +53,33 @@ import React
56
53
  print("ComposerPianoImpl: Delegate initialized and set")
57
54
  }
58
55
 
59
- // MARK: - Configuration Methods
56
+ // MARK: - State Methods (Getters)
57
+
58
+ public func getTags() -> [String] {
59
+ return self.tags
60
+ }
61
+
62
+ public func getZoneId() -> String {
63
+ return self.zoneId ?? ""
64
+ }
65
+
66
+ public func getReferrer() -> String {
67
+ return self.referrer ?? ""
68
+ }
69
+
70
+ public func getUrl() -> String {
71
+ return self.url ?? ""
72
+ }
73
+
74
+ public func getUserToken() -> String {
75
+ return self.composer?.userToken ?? ""
76
+ }
77
+
78
+ public func getCustomVariables() -> [String: String] {
79
+ return self.customVariables
80
+ }
81
+
82
+ // MARK: - Configuration Methods (Setters)
60
83
 
61
84
  public func addTag(_ tag: String) {
62
85
  self.tags.append(tag)
@@ -78,23 +101,47 @@ import React
78
101
  self.url = url
79
102
  }
80
103
 
81
- public func setCustomVariable(_ name: String, value: String) {
104
+ public func setCustomVariables(_ variables: [String: String]) {
105
+ self.customVariables = variables
106
+ }
107
+
108
+ public func addCustomVariable(_ name: String, value: String) {
82
109
  self.customVariables[name] = value
83
110
  }
84
111
 
85
112
  public func setUserToken(_ token: String) {
86
- // The iOS SDK requires setting the user token on the composer instance directly
87
113
  _ = self.composer?.userToken(token)
88
114
  }
89
115
 
116
+ // MARK: - Cleanup Methods
117
+
118
+ public func clearTags() {
119
+ self.tags.removeAll()
120
+ }
121
+
122
+ public func clearCustomVariables() {
123
+ self.customVariables.removeAll()
124
+ }
125
+
126
+ public func removeTag(_ tag: String) {
127
+ self.tags.removeAll { $0 == tag }
128
+ }
129
+
130
+ public func removeCustomVariable(key: String) {
131
+ self.customVariables.removeValue(forKey: key)
132
+ }
133
+
134
+ public func clearConfiguration() {
135
+ self.clearTags()
136
+ self.clearCustomVariables()
137
+ self.zoneId = nil
138
+ self.referrer = nil
139
+ self.url = nil
140
+ self.userToken = nil
141
+ }
142
+
90
143
  // MARK: - Execution Method
91
144
 
92
- /**
93
- * Executes the Piano experience with the current configuration.
94
- *
95
- * @param resolver The promise resolver from React Native.
96
- * @param rejecter The promise rejecter from React Native.
97
- */
98
145
  public func executeExperience(
99
146
  resolver: @escaping RCTPromiseResolveBlock,
100
147
  rejecter: @escaping RCTPromiseRejectBlock
@@ -104,47 +151,20 @@ import React
104
151
  return
105
152
  }
106
153
 
107
- print("ComposerPianoImpl: Executing experience")
108
-
109
- // Store the promise functions to be called by the delegate later
110
154
  self.experienceResolver = resolver
111
155
  self.experienceRejecter = rejecter
112
156
 
113
- // Configure the composer instance using the fluent interface
114
- _ = composer
157
+ _ =
158
+ composer
115
159
  .tags(self.tags)
116
- .zoneId(self.zoneId ?? "") // Safely unwrap optionals
117
- .referrer(self.referrer ?? "") // Safely unwrap optionals
118
- .url(self.url ?? "") // Safely unwrap optionals
160
+ .zoneId(self.zoneId ?? "")
161
+ .referrer(self.referrer ?? "")
162
+ .url(self.url ?? "")
119
163
 
120
164
  for (key, value) in self.customVariables {
121
165
  _ = composer.customVariable(name: key, value: value)
122
166
  }
123
167
 
124
- // Execute the experience. The result will be handled by the delegate.
125
168
  composer.execute()
126
169
  }
127
-
128
- // MARK: - State Methods (Getters)
129
-
130
- public func getTags() -> [String] {
131
- return self.tags
132
- }
133
-
134
- public func getZoneId() -> String {
135
- return self.zoneId ?? ""
136
- }
137
-
138
- public func getReferrer() -> String {
139
- return self.referrer ?? ""
140
- }
141
-
142
- public func getUrl() -> String {
143
- return self.url ?? ""
144
- }
145
-
146
- public func getUserToken() -> String {
147
- // User token is write-only to the composer instance, so we return the stored value if needed.
148
- return self.composer?.userToken ?? ""
149
- }
150
170
  }
@@ -1,11 +1,9 @@
1
1
  import Foundation
2
2
  import React
3
3
 
4
- /**
5
- * SdkPianoio - The main React Native bridge module for the Piano SDK.
6
- *
7
- * This class exposes the functionality of the ComposerPianoImpl to JavaScript.
8
- */
4
+ /// SdkPianoio - The main React Native bridge module for the Piano SDK.
5
+ ///
6
+ /// This class exposes the functionality of the ComposerPianoImpl to JavaScript.
9
7
  @objc(SdkPianoio)
10
8
  class SdkPianoio: NSObject {
11
9
 
@@ -18,7 +16,10 @@ class SdkPianoio: NSObject {
18
16
  }
19
17
 
20
18
  @objc(initialize:resolver:rejecter:)
21
- func initialize(aid: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
19
+ func initialize(
20
+ aid: String, resolver: @escaping RCTPromiseResolveBlock,
21
+ rejecter: @escaping RCTPromiseRejectBlock
22
+ ) {
22
23
  moduleImpl?.initialize(aid: aid)
23
24
  resolver(true)
24
25
  }
@@ -26,51 +27,123 @@ class SdkPianoio: NSObject {
26
27
  // MARK: - Configuration Methods
27
28
 
28
29
  @objc(addTag:resolver:rejecter:)
29
- func addTag(tag: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
30
+ func addTag(
31
+ tag: String, resolver: @escaping RCTPromiseResolveBlock,
32
+ rejecter: @escaping RCTPromiseRejectBlock
33
+ ) {
30
34
  moduleImpl?.addTag(tag)
31
35
  resolver(true)
32
36
  }
33
37
 
34
38
  @objc(addTags:resolver:rejecter:)
35
- func addTags(tags: [String], resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
39
+ func addTags(
40
+ tags: [String], resolver: @escaping RCTPromiseResolveBlock,
41
+ rejecter: @escaping RCTPromiseRejectBlock
42
+ ) {
36
43
  moduleImpl?.addTags(tags)
37
44
  resolver(true)
38
45
  }
39
46
 
40
47
  @objc(setZoneId:resolver:rejecter:)
41
- func setZoneId(zoneId: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
48
+ func setZoneId(
49
+ zoneId: String, resolver: @escaping RCTPromiseResolveBlock,
50
+ rejecter: @escaping RCTPromiseRejectBlock
51
+ ) {
42
52
  moduleImpl?.setZoneId(zoneId)
43
53
  resolver(true)
44
54
  }
45
55
 
46
56
  @objc(setReferrer:resolver:rejecter:)
47
- func setReferrer(referrer: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
57
+ func setReferrer(
58
+ referrer: String, resolver: @escaping RCTPromiseResolveBlock,
59
+ rejecter: @escaping RCTPromiseRejectBlock
60
+ ) {
48
61
  moduleImpl?.setReferrer(referrer)
49
62
  resolver(true)
50
63
  }
51
64
 
52
65
  @objc(setUrl:resolver:rejecter:)
53
- func setUrl(url: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
66
+ func setUrl(
67
+ url: String, resolver: @escaping RCTPromiseResolveBlock,
68
+ rejecter: @escaping RCTPromiseRejectBlock
69
+ ) {
54
70
  moduleImpl?.setUrl(url)
55
71
  resolver(true)
56
72
  }
57
73
 
58
74
  @objc(setUserToken:resolver:rejecter:)
59
- func setUserToken(token: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
75
+ func setUserToken(
76
+ token: String, resolver: @escaping RCTPromiseResolveBlock,
77
+ rejecter: @escaping RCTPromiseRejectBlock
78
+ ) {
60
79
  moduleImpl?.setUserToken(token)
61
80
  resolver(true)
62
81
  }
63
82
 
64
- @objc(setCustomVariable:value:resolver:rejecter:)
65
- func setCustomVariable(name: String, value: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
66
- moduleImpl?.setCustomVariable(name, value: value)
83
+ @objc(addCustomVariable:value:resolver:rejecter:)
84
+ func addCustomVariable(
85
+ name: String, value: String, resolver: @escaping RCTPromiseResolveBlock,
86
+ rejecter: @escaping RCTPromiseRejectBlock
87
+ ) {
88
+ moduleImpl?.addCustomVariable(name, value: value)
89
+ resolver(true)
90
+ }
91
+
92
+ @objc(setCustomVariables:resolver:rejecter:)
93
+ func setCustomVariables(
94
+ variables: [String: String], resolver: @escaping RCTPromiseResolveBlock,
95
+ rejecter: @escaping RCTPromiseRejectBlock
96
+ ) {
97
+ moduleImpl.setCustomVariables(variables)
67
98
  resolver(true)
68
99
  }
69
100
 
70
101
  // MARK: - Execution Method
71
102
 
72
103
  @objc(executeExperience:rejecter:)
73
- func executeExperience(resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
104
+ func executeExperience(
105
+ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
106
+ ) {
74
107
  moduleImpl?.executeExperience(resolver: resolver, rejecter: rejecter)
75
108
  }
109
+
110
+ // MARK: - Authentication Methods
111
+
112
+ @objc(signIn:rejecter:)
113
+ func signIn(
114
+ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
115
+ ) {
116
+ moduleImpl.signIn(resolver: resolver, rejecter: rejecter)
117
+ }
118
+
119
+ @objc(signOut:rejecter:)
120
+ func signOut(
121
+ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
122
+ ) {
123
+ moduleImpl.signOut(resolver: resolver, rejecter: rejecter)
124
+ }
125
+
126
+ @objc(getCurrentUser:rejecter:)
127
+ func getCurrentUser(
128
+ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
129
+ ) {
130
+ moduleImpl.getCurrentUser(resolver: resolver, rejecter: rejecter)
131
+ }
132
+
133
+ @objc(isAuthenticated:rejecter:)
134
+ func isAuthenticated(
135
+ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
136
+ ) {
137
+ moduleImpl.isAuthenticated(resolver: resolver, rejecter: rejecter)
138
+ }
139
+
140
+ // MARK: - Helper and Cleanup Methods
141
+
142
+ @objc(clearConfiguration:rejecter:)
143
+ func clearConfiguration(
144
+ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
145
+ ) {
146
+ moduleImpl.clearConfiguration()
147
+ resolver(true)
148
+ }
76
149
  }
@@ -35,19 +35,37 @@ RCT_EXTERN_METHOD(setUserToken:(NSString *)token
35
35
  resolver:(RCTPromiseResolveBlock)resolve
36
36
  rejecter:(RCTPromiseRejectBlock)reject)
37
37
 
38
- RCT_EXTERN_METHOD(setCustomVariable:(NSString *)name
38
+ RCT_EXTERN_METHOD(addCustomVariable:(NSString *)name
39
39
  value:(NSString *)value
40
40
  resolver:(RCTPromiseResolveBlock)resolve
41
41
  rejecter:(RCTPromiseRejectBlock)reject)
42
42
 
43
+ RCT_EXTERN_METHOD(setCustomVariables:(NSDictionary *)variables
44
+ resolver:(RCTPromiseResolveBlock)resolve
45
+ rejecter:(RCTPromiseRejectBlock)reject)
46
+
43
47
  // MARK: - Execution Method
44
48
 
45
49
  RCT_EXTERN_METHOD(executeExperience:(RCTPromiseResolveBlock)resolve
46
50
  rejecter:(RCTPromiseRejectBlock)reject)
47
51
 
48
- // Note: Authentication methods (signIn, signOut, etc.) would be added here
49
- // if they were exposed from SdkPianoio.swift. Since they are handled internally
50
- // by the Composer/TokenService interaction, they don't need to be exposed directly
51
- // unless you add them to the SdkPianoio.swift class.
52
+ // MARK: - Authentication Methods
53
+
54
+ RCT_EXTERN_METHOD(signIn:(RCTPromiseResolveBlock)resolve
55
+ rejecter:(RCTPromiseRejectBlock)reject)
56
+
57
+ RCT_EXTERN_METHOD(signOut:(RCTPromiseResolveBlock)resolve
58
+ rejecter:(RCTPromiseRejectBlock)reject)
59
+
60
+ RCT_EXTERN_METHOD(getCurrentUser:(RCTPromiseResolveBlock)resolve
61
+ rejecter:(RCTPromiseRejectBlock)reject)
62
+
63
+ RCT_EXTERN_METHOD(isAuthenticated:(RCTPromiseResolveBlock)resolve
64
+ rejecter:(RCTPromiseRejectBlock)reject)
65
+
66
+ // MARK: - Helper and Cleanup Methods
67
+
68
+ RCT_EXTERN_METHOD(clearConfiguration:(RCTPromiseResolveBlock)resolve
69
+ rejecter:(RCTPromiseRejectBlock)reject)
52
70
 
53
71
  @end
@@ -16,7 +16,7 @@ public class User {
16
16
  self.accessToken = accessToken
17
17
  }
18
18
  }
19
-
19
+
20
20
  /**
21
21
  * TokenService - Manages OAuth tokens and authentication with the Piano ID SDK.
22
22
  *
@@ -40,11 +40,6 @@ public class TokenService: NSObject, PianoIDDelegate {
40
40
 
41
41
  // MARK: - Initialization
42
42
 
43
- /**
44
- * Initializes the TokenService and configures the PianoID singleton.
45
- *
46
- * @param aid The Piano Application ID.
47
- */
48
43
  public func initialize(aid: String) {
49
44
  if isInitialized {
50
45
  return
@@ -61,12 +56,8 @@ public class TokenService: NSObject, PianoIDDelegate {
61
56
 
62
57
  // MARK: - Authentication Methods
63
58
 
64
- /**
65
- * Starts the sign-in process.
66
- *
67
- * @param resolver The promise resolver from React Native.
68
- * @param rejecter The promise rejecter from React Native.
69
- */
59
+ // Missing set tokens no?
60
+
70
61
  public func signIn(resolver: @escaping (Any?) -> Void, rejecter: @escaping (String?, String?, Error?) -> Void) {
71
62
  if !isInitialized {
72
63
  print("TokenService: Not initialized. Call initialize() first.")
@@ -79,12 +70,7 @@ public class TokenService: NSObject, PianoIDDelegate {
79
70
  PianoID.shared.signIn()
80
71
  }
81
72
 
82
- /**
83
- * Starts the sign-out process.
84
- *
85
- * @param resolver The promise resolver from React Native.
86
- * @param rejecter The promise rejecter from React Native.
87
- */
73
+
88
74
  public func signOut(resolver: @escaping (Any?) -> Void, rejecter: @escaping (String?, String?, Error?) -> Void) {
89
75
  if !isInitialized {
90
76
  print("TokenService: Not initialized.")
@@ -105,11 +91,6 @@ public class TokenService: NSObject, PianoIDDelegate {
105
91
 
106
92
  // MARK: - User Information Methods
107
93
 
108
- /**
109
- * Gets the current user's information.
110
- *
111
- * @return A User object if authenticated, otherwise null.
112
- */
113
94
  public func getCurrentUser() -> User? {
114
95
  guard let token = self.cachedToken else {
115
96
  return nil
@@ -129,11 +110,6 @@ public class TokenService: NSObject, PianoIDDelegate {
129
110
  )
130
111
  }
131
112
 
132
- /**
133
- * Checks if a user is currently authenticated.
134
- *
135
- * @return true if a valid token exists, false otherwise.
136
- */
137
113
  public func isAuthenticated() -> Bool {
138
114
  return self.cachedToken != nil
139
115
  }
@@ -157,7 +133,7 @@ public class TokenService: NSObject, PianoIDDelegate {
157
133
  print("TokenService: Sign in failed: \(e.localizedDescription)")
158
134
  self.signInRejecter?("SIGNIN_ERROR", e.localizedDescription, e)
159
135
  }
160
- // Clean up promises
136
+
161
137
  self.signInResolver = nil
162
138
  self.signInRejecter = nil
163
139
  }
@@ -188,12 +164,6 @@ public class TokenService: NSObject, PianoIDDelegate {
188
164
 
189
165
  // MARK: - Helper Methods
190
166
 
191
- /**
192
- * Decodes the payload of a JWT.
193
- *
194
- * @param jwt The JSON Web Token string.
195
- * @return A dictionary of claims, or nil if decoding fails.
196
- */
197
167
  private func decode(jwtToken jwt: String) -> [String: Any]? {
198
168
  let segments = jwt.components(separatedBy: ".")
199
169
  guard segments.count > 1 else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-sdk-pianoio",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Piano io sdk integration",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/commonjs/index.js",