react-native-spike-sdk 0.2.9 → 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 (198) hide show
  1. package/README.md +284 -143
  2. package/android/build.gradle +14 -1
  3. package/android/gradle.properties +2 -1
  4. package/android/src/main/java/com/spikesdk/SpikeConnectionLogger.kt +37 -0
  5. package/android/src/main/java/com/spikesdk/SpikeMappers.kt +61 -0
  6. package/android/src/main/java/com/spikesdk/SpikeSdkModule.kt +413 -8
  7. package/ios/SpikeConnectionListener.swift +17 -0
  8. package/ios/SpikeConnectionLogger.swift +43 -0
  9. package/ios/SpikeDataTypeMapper.swift +207 -0
  10. package/ios/SpikeExceptionMapper.swift +34 -0
  11. package/ios/SpikeSdk.m +82 -17
  12. package/ios/SpikeSdk.swift +460 -134
  13. package/lib/commonjs/DataModels/SpikeActivitiesStreamDataEntry.js +2 -0
  14. package/lib/commonjs/DataModels/SpikeActivitiesStreamDataEntry.js.map +1 -0
  15. package/lib/commonjs/DataModels/SpikeActivitiesSummaryDataEntry.js +2 -0
  16. package/lib/commonjs/DataModels/SpikeActivitiesSummaryDataEntry.js.map +1 -0
  17. package/lib/commonjs/DataModels/SpikeBreathingDataEntry.js +2 -0
  18. package/lib/commonjs/DataModels/SpikeBreathingDataEntry.js.map +1 -0
  19. package/lib/commonjs/DataModels/SpikeCaloriesDataEntry.js +2 -0
  20. package/lib/commonjs/DataModels/SpikeCaloriesDataEntry.js.map +1 -0
  21. package/lib/commonjs/{SpikeInterface.js → DataModels/SpikeData.js} +1 -1
  22. package/lib/commonjs/DataModels/SpikeData.js.map +1 -0
  23. package/lib/commonjs/DataModels/SpikeDataTypes.js +22 -0
  24. package/lib/commonjs/DataModels/SpikeDataTypes.js.map +1 -0
  25. package/lib/commonjs/DataModels/SpikeDistanceDataEntry.js +2 -0
  26. package/lib/commonjs/DataModels/SpikeDistanceDataEntry.js.map +1 -0
  27. package/lib/commonjs/DataModels/SpikeGlucoseDataEntry.js +2 -0
  28. package/lib/commonjs/DataModels/SpikeGlucoseDataEntry.js.map +1 -0
  29. package/lib/commonjs/DataModels/SpikeHeartDataEntry.js +2 -0
  30. package/lib/commonjs/DataModels/SpikeHeartDataEntry.js.map +1 -0
  31. package/lib/commonjs/DataModels/SpikeOxygenSaturationDataEntry.js +2 -0
  32. package/lib/commonjs/DataModels/SpikeOxygenSaturationDataEntry.js.map +1 -0
  33. package/lib/commonjs/DataModels/SpikeSleepDataEntry.js +2 -0
  34. package/lib/commonjs/DataModels/SpikeSleepDataEntry.js.map +1 -0
  35. package/lib/commonjs/DataModels/SpikeStepsDataEntry.js +2 -0
  36. package/lib/commonjs/DataModels/SpikeStepsDataEntry.js.map +1 -0
  37. package/lib/commonjs/DataModels/SpikeWebhookJob.js +2 -0
  38. package/lib/commonjs/DataModels/SpikeWebhookJob.js.map +1 -0
  39. package/lib/commonjs/DataTypes/SpikeDataType.js +53 -0
  40. package/lib/commonjs/DataTypes/SpikeDataType.js.map +1 -0
  41. package/lib/commonjs/Spike.js +61 -50
  42. package/lib/commonjs/Spike.js.map +1 -1
  43. package/lib/commonjs/SpikeConnection.js +104 -0
  44. package/lib/commonjs/SpikeConnection.js.map +1 -0
  45. package/lib/commonjs/SpikeException.js +27 -0
  46. package/lib/commonjs/SpikeException.js.map +1 -0
  47. package/lib/commonjs/SpikeLogger.js +6 -0
  48. package/lib/commonjs/{SpikeDataType.js.map → SpikeLogger.js.map} +1 -1
  49. package/lib/commonjs/SpikeSdk.js +1 -1
  50. package/lib/commonjs/SpikeSdk.js.map +1 -1
  51. package/lib/commonjs/SpikeWebhookConnection.js +119 -0
  52. package/lib/commonjs/SpikeWebhookConnection.js.map +1 -0
  53. package/lib/commonjs/SpikeWebhookConnectionListener.js +6 -0
  54. package/lib/commonjs/{SpikeResultData.js.map → SpikeWebhookConnectionListener.js.map} +1 -1
  55. package/lib/commonjs/index.js +26 -7
  56. package/lib/commonjs/index.js.map +1 -1
  57. package/lib/module/DataModels/SpikeActivitiesStreamDataEntry.js +2 -0
  58. package/lib/module/DataModels/SpikeActivitiesStreamDataEntry.js.map +1 -0
  59. package/lib/module/DataModels/SpikeActivitiesSummaryDataEntry.js +2 -0
  60. package/lib/module/DataModels/SpikeActivitiesSummaryDataEntry.js.map +1 -0
  61. package/lib/module/DataModels/SpikeBreathingDataEntry.js +2 -0
  62. package/lib/module/DataModels/SpikeBreathingDataEntry.js.map +1 -0
  63. package/lib/module/DataModels/SpikeCaloriesDataEntry.js +2 -0
  64. package/lib/module/DataModels/SpikeCaloriesDataEntry.js.map +1 -0
  65. package/lib/module/DataModels/SpikeData.js +2 -0
  66. package/lib/module/DataModels/SpikeData.js.map +1 -0
  67. package/lib/module/DataModels/SpikeDataTypes.js +15 -0
  68. package/lib/module/DataModels/SpikeDataTypes.js.map +1 -0
  69. package/lib/module/DataModels/SpikeDistanceDataEntry.js +2 -0
  70. package/lib/module/DataModels/SpikeDistanceDataEntry.js.map +1 -0
  71. package/lib/module/DataModels/SpikeGlucoseDataEntry.js +2 -0
  72. package/lib/module/DataModels/SpikeGlucoseDataEntry.js.map +1 -0
  73. package/lib/module/DataModels/SpikeHeartDataEntry.js +2 -0
  74. package/lib/module/DataModels/SpikeHeartDataEntry.js.map +1 -0
  75. package/lib/module/DataModels/SpikeOxygenSaturationDataEntry.js +2 -0
  76. package/lib/module/DataModels/SpikeOxygenSaturationDataEntry.js.map +1 -0
  77. package/lib/module/DataModels/SpikeSleepDataEntry.js +2 -0
  78. package/lib/module/DataModels/SpikeSleepDataEntry.js.map +1 -0
  79. package/lib/module/DataModels/SpikeStepsDataEntry.js +2 -0
  80. package/lib/module/DataModels/SpikeStepsDataEntry.js.map +1 -0
  81. package/lib/module/DataModels/SpikeWebhookJob.js +2 -0
  82. package/lib/module/DataModels/SpikeWebhookJob.js.map +1 -0
  83. package/lib/module/DataTypes/SpikeDataType.js +36 -0
  84. package/lib/module/DataTypes/SpikeDataType.js.map +1 -0
  85. package/lib/module/Spike.js +56 -49
  86. package/lib/module/Spike.js.map +1 -1
  87. package/lib/module/SpikeConnection.js +97 -0
  88. package/lib/module/SpikeConnection.js.map +1 -0
  89. package/lib/module/SpikeException.js +11 -0
  90. package/lib/module/SpikeException.js.map +1 -0
  91. package/lib/module/SpikeLogger.js +2 -0
  92. package/lib/module/{SpikeDataType.js.map → SpikeLogger.js.map} +1 -1
  93. package/lib/module/SpikeSdk.js +1 -2
  94. package/lib/module/SpikeSdk.js.map +1 -1
  95. package/lib/module/SpikeWebhookConnection.js +112 -0
  96. package/lib/module/SpikeWebhookConnection.js.map +1 -0
  97. package/lib/module/SpikeWebhookConnectionListener.js +2 -0
  98. package/lib/{commonjs/SpikeSleepAnalysisResultData.js.map → module/SpikeWebhookConnectionListener.js.map} +1 -1
  99. package/lib/module/index.js +13 -5
  100. package/lib/module/index.js.map +1 -1
  101. package/lib/typescript/{SpikeWorkoutResultData.d.ts → DataModels/SpikeActivitiesStreamDataEntry.d.ts} +15 -14
  102. package/lib/typescript/DataModels/SpikeActivitiesStreamDataEntry.d.ts.map +1 -0
  103. package/lib/typescript/{SpikeResultData.d.ts → DataModels/SpikeActivitiesSummaryDataEntry.d.ts} +5 -8
  104. package/lib/typescript/DataModels/SpikeActivitiesSummaryDataEntry.d.ts.map +1 -0
  105. package/lib/typescript/DataModels/SpikeBreathingDataEntry.d.ts +13 -0
  106. package/lib/typescript/DataModels/SpikeBreathingDataEntry.d.ts.map +1 -0
  107. package/lib/typescript/DataModels/SpikeCaloriesDataEntry.d.ts +15 -0
  108. package/lib/typescript/DataModels/SpikeCaloriesDataEntry.d.ts.map +1 -0
  109. package/lib/typescript/DataModels/SpikeData.d.ts +25 -0
  110. package/lib/typescript/DataModels/SpikeData.d.ts.map +1 -0
  111. package/lib/typescript/DataModels/SpikeDataTypes.d.ts +15 -0
  112. package/lib/typescript/DataModels/SpikeDataTypes.d.ts.map +1 -0
  113. package/lib/typescript/DataModels/SpikeDistanceDataEntry.d.ts +13 -0
  114. package/lib/typescript/DataModels/SpikeDistanceDataEntry.d.ts.map +1 -0
  115. package/lib/typescript/DataModels/SpikeGlucoseDataEntry.d.ts +4 -0
  116. package/lib/typescript/DataModels/SpikeGlucoseDataEntry.d.ts.map +1 -0
  117. package/lib/typescript/DataModels/SpikeHeartDataEntry.d.ts +32 -0
  118. package/lib/typescript/DataModels/SpikeHeartDataEntry.d.ts.map +1 -0
  119. package/lib/typescript/DataModels/SpikeOxygenSaturationDataEntry.d.ts +15 -0
  120. package/lib/typescript/DataModels/SpikeOxygenSaturationDataEntry.d.ts.map +1 -0
  121. package/lib/typescript/{SpikeSleepAnalysisResultData.d.ts → DataModels/SpikeSleepDataEntry.d.ts} +10 -13
  122. package/lib/typescript/DataModels/SpikeSleepDataEntry.d.ts.map +1 -0
  123. package/lib/typescript/DataModels/SpikeStepsDataEntry.d.ts +13 -0
  124. package/lib/typescript/DataModels/SpikeStepsDataEntry.d.ts.map +1 -0
  125. package/lib/typescript/DataModels/SpikeWebhookJob.d.ts +11 -0
  126. package/lib/typescript/DataModels/SpikeWebhookJob.d.ts.map +1 -0
  127. package/lib/typescript/DataTypes/SpikeDataType.d.ts +50 -0
  128. package/lib/typescript/DataTypes/SpikeDataType.d.ts.map +1 -0
  129. package/lib/typescript/Spike.d.ts +12 -14
  130. package/lib/typescript/Spike.d.ts.map +1 -1
  131. package/lib/typescript/SpikeConnection.d.ts +23 -0
  132. package/lib/typescript/SpikeConnection.d.ts.map +1 -0
  133. package/lib/typescript/SpikeException.d.ts +21 -0
  134. package/lib/typescript/SpikeException.d.ts.map +1 -0
  135. package/lib/typescript/SpikeLogger.d.ts +10 -0
  136. package/lib/typescript/SpikeLogger.d.ts.map +1 -0
  137. package/lib/typescript/SpikeSdk.d.ts.map +1 -1
  138. package/lib/typescript/SpikeWebhookConnection.d.ts +21 -0
  139. package/lib/typescript/SpikeWebhookConnection.d.ts.map +1 -0
  140. package/lib/typescript/SpikeWebhookConnectionListener.d.ts +6 -0
  141. package/lib/typescript/SpikeWebhookConnectionListener.d.ts.map +1 -0
  142. package/lib/typescript/index.d.ts +16 -7
  143. package/lib/typescript/index.d.ts.map +1 -1
  144. package/package.json +1 -1
  145. package/react-native-spike-sdk.podspec +2 -2
  146. package/src/{SpikeWorkoutResultData.ts → DataModels/SpikeActivitiesStreamDataEntry.ts} +14 -12
  147. package/src/{SpikeResultData.ts → DataModels/SpikeActivitiesSummaryDataEntry.ts} +4 -4
  148. package/src/DataModels/SpikeBreathingDataEntry.ts +12 -0
  149. package/src/DataModels/SpikeCaloriesDataEntry.ts +13 -0
  150. package/src/DataModels/SpikeData.ts +35 -0
  151. package/src/DataModels/SpikeDataTypes.ts +27 -0
  152. package/src/DataModels/SpikeDistanceDataEntry.ts +12 -0
  153. package/src/DataModels/SpikeGlucoseDataEntry.ts +3 -0
  154. package/src/DataModels/SpikeHeartDataEntry.ts +34 -0
  155. package/src/DataModels/SpikeOxygenSaturationDataEntry.ts +14 -0
  156. package/src/{SpikeSleepAnalysisResultData.ts → DataModels/SpikeSleepDataEntry.ts} +9 -7
  157. package/src/DataModels/SpikeStepsDataEntry.ts +11 -0
  158. package/src/DataModels/SpikeWebhookJob.ts +10 -0
  159. package/src/DataTypes/SpikeDataType.ts +87 -0
  160. package/src/Spike.ts +132 -79
  161. package/src/SpikeConnection.ts +151 -0
  162. package/src/SpikeException.ts +11 -0
  163. package/src/SpikeLogger.ts +11 -0
  164. package/src/SpikeSdk.ts +1 -3
  165. package/src/SpikeWebhookConnection.ts +201 -0
  166. package/src/SpikeWebhookConnectionListener.ts +9 -0
  167. package/src/index.ts +32 -20
  168. package/lib/commonjs/SpikeDataType.js +0 -2
  169. package/lib/commonjs/SpikeInterface.js.map +0 -1
  170. package/lib/commonjs/SpikeResultData.js +0 -2
  171. package/lib/commonjs/SpikeSleepAnalysisResultData.js +0 -2
  172. package/lib/commonjs/SpikeWorkoutResultData.js +0 -2
  173. package/lib/commonjs/SpikeWorkoutResultData.js.map +0 -1
  174. package/lib/commonjs/useSpikeEvents.js +0 -69
  175. package/lib/commonjs/useSpikeEvents.js.map +0 -1
  176. package/lib/module/SpikeDataType.js +0 -2
  177. package/lib/module/SpikeInterface.js +0 -2
  178. package/lib/module/SpikeInterface.js.map +0 -1
  179. package/lib/module/SpikeResultData.js +0 -2
  180. package/lib/module/SpikeResultData.js.map +0 -1
  181. package/lib/module/SpikeSleepAnalysisResultData.js +0 -2
  182. package/lib/module/SpikeSleepAnalysisResultData.js.map +0 -1
  183. package/lib/module/SpikeWorkoutResultData.js +0 -2
  184. package/lib/module/SpikeWorkoutResultData.js.map +0 -1
  185. package/lib/module/useSpikeEvents.js +0 -62
  186. package/lib/module/useSpikeEvents.js.map +0 -1
  187. package/lib/typescript/SpikeDataType.d.ts +0 -2
  188. package/lib/typescript/SpikeDataType.d.ts.map +0 -1
  189. package/lib/typescript/SpikeInterface.d.ts +0 -14
  190. package/lib/typescript/SpikeInterface.d.ts.map +0 -1
  191. package/lib/typescript/SpikeResultData.d.ts.map +0 -1
  192. package/lib/typescript/SpikeSleepAnalysisResultData.d.ts.map +0 -1
  193. package/lib/typescript/SpikeWorkoutResultData.d.ts.map +0 -1
  194. package/lib/typescript/useSpikeEvents.d.ts +0 -17
  195. package/lib/typescript/useSpikeEvents.d.ts.map +0 -1
  196. package/src/SpikeDataType.ts +0 -12
  197. package/src/SpikeInterface.ts +0 -32
  198. package/src/useSpikeEvents.ts +0 -89
@@ -1,18 +1,423 @@
1
1
  package com.spikesdk
2
2
 
3
+ import com.facebook.react.bridge.Promise
3
4
  import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.ReactContext
4
6
  import com.facebook.react.bridge.ReactContextBaseJavaModule
5
7
  import com.facebook.react.bridge.ReactMethod
6
- import com.facebook.react.bridge.Promise
8
+ import com.facebook.react.bridge.WritableMap
9
+ import com.facebook.react.bridge.WritableNativeMap
10
+ import com.facebook.react.modules.core.DeviceEventManagerModule
11
+ import com.google.gson.GsonBuilder
12
+ import com.google.gson.JsonDeserializer
13
+ import com.spikeapi.SpikeConnection
14
+ import com.spikeapi.SpikeExceptions
15
+ import com.spikeapi.SpikeLogger
16
+ import com.spikeapi.SpikeWebhookConnection
17
+ import kotlinx.coroutines.CoroutineScope
18
+ import kotlinx.coroutines.Dispatchers
19
+ import kotlinx.coroutines.SupervisorJob
20
+ import kotlinx.coroutines.launch
21
+ import java.time.OffsetDateTime
7
22
 
8
23
  class SpikeSdkModule(reactContext: ReactApplicationContext) :
9
- ReactContextBaseJavaModule(reactContext) {
24
+ ReactContextBaseJavaModule(reactContext) {
25
+
26
+ private val connections = mutableMapOf<String, SpikeConnection>()
27
+
28
+ private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
29
+
30
+ private val gson = GsonBuilder().setPrettyPrinting().registerTypeAdapter(
31
+ OffsetDateTime::class.java,
32
+ JsonDeserializer { json, _, _ ->
33
+ OffsetDateTime.parse(json.asJsonPrimitive.asString)
34
+ }
35
+ ).create()
36
+
37
+ override fun getName(): String {
38
+ return NAME
39
+ }
40
+
41
+ @ReactMethod
42
+ fun createConnection(
43
+ uuid: String,
44
+ appId: String,
45
+ authToken: String,
46
+ customerEndUserId: String,
47
+ useLogger: Boolean,
48
+ promise: Promise
49
+ ) {
50
+ scope.launch {
51
+ try {
52
+ val logger = if (useLogger) {
53
+ createLogger(uuid)
54
+ } else {
55
+ null
56
+ }
57
+ connections[uuid] = SpikeConnection.createConnection(
58
+ context = reactApplicationContext,
59
+ authToken = authToken,
60
+ customerEndUserId = customerEndUserId,
61
+ appId = appId,
62
+ logger = logger,
63
+ )
64
+ promise.resolve(uuid)
65
+ } catch (e: SpikeExceptions) {
66
+ promise.reject(e.mapException(), e.message)
67
+ }
68
+ }
69
+ }
70
+
71
+ @ReactMethod
72
+ fun getAppId(uuid: String, promise: Promise) {
73
+ try {
74
+ val connection = connections[uuid] ?: return promise.reject(
75
+ SpikeExceptions.SpikeException(
76
+ "Connection not found"
77
+ ).mapException(), "Connection not found"
78
+ )
79
+ val appId = connection.getAppId()
80
+ promise.resolve(appId)
81
+ } catch (e: SpikeExceptions) {
82
+ promise.reject(e.mapException(), e.message)
83
+ }
84
+ }
85
+
86
+ @ReactMethod
87
+ fun getSpikeEndUserId(uuid: String, promise: Promise) {
88
+ try {
89
+ val connection = connections[uuid] ?: return promise.reject(
90
+ SpikeExceptions.SpikeException(
91
+ "Connection not found"
92
+ ).mapException(), "Connection not found"
93
+ )
94
+ val spikeEndUserId = connection.getSpikeUserId()
95
+ promise.resolve(spikeEndUserId)
96
+ } catch (e: SpikeExceptions) {
97
+ promise.reject(e.mapException(), e.message)
98
+ }
99
+ }
100
+
101
+ @ReactMethod
102
+ fun getCustomerEndUserId(uuid: String, promise: Promise) {
103
+ try {
104
+ val connection = connections[uuid] ?: return promise.reject(
105
+ SpikeExceptions.SpikeException(
106
+ "Connection not found"
107
+ ).mapException(), "Connection not found"
108
+ )
109
+ val customerEndUserId = connection.getCustomerUserId()
110
+ promise.resolve(customerEndUserId)
111
+ } catch (e: SpikeExceptions) {
112
+ promise.reject(e.mapException(), e.message)
113
+ }
114
+ }
115
+
116
+ @ReactMethod
117
+ fun getCallbackUrl(uuid: String, promise: Promise) {
118
+ try {
119
+ val connection = (connections[uuid] as? SpikeWebhookConnection) ?: return promise.reject(
120
+ SpikeExceptions.SpikeException(
121
+ "Connection not found"
122
+ ).mapException(), "Connection not found"
123
+ )
124
+ val callbackUrl = connection.getPostbackUrl()
125
+ promise.resolve(callbackUrl)
126
+ } catch (e: SpikeExceptions) {
127
+ promise.reject(e.mapException(), e.message)
128
+ }
129
+ }
130
+
131
+
132
+
133
+ @ReactMethod
134
+ fun close(uuid: String, promise: Promise) {
135
+ scope.launch {
136
+ try {
137
+ val connection = connections[uuid] ?: return@launch promise.reject(
138
+ SpikeExceptions.SpikeException(
139
+ "Connection not found"
140
+ ).mapException(), "Connection not found"
141
+ )
142
+ connection.close()
143
+ promise.resolve(true)
144
+ } catch (e: SpikeExceptions) {
145
+ promise.reject(e.mapException(), e.message)
146
+ }
147
+ }
148
+ }
149
+
150
+ @ReactMethod
151
+ fun pack(uuid: String, promise: Promise) {
152
+ scope.launch {
153
+ try {
154
+ val connection = connections[uuid] ?: return@launch promise.reject(
155
+ SpikeExceptions.SpikeException(
156
+ "Connection not found"
157
+ ).mapException(), "Connection not found"
158
+ )
159
+ val serializedConnection = connection.pack()
160
+ promise.resolve(serializedConnection)
161
+ } catch (e: SpikeExceptions) {
162
+ promise.reject(e.mapException(), e.message)
163
+ }
164
+ }
165
+ }
166
+
167
+ @ReactMethod
168
+ fun unpackConnection(
169
+ uuid: String,
170
+ connection: String,
171
+ useLogger: Boolean,
172
+ promise: Promise
173
+ ) {
174
+ scope.launch {
175
+ try {
176
+ val logger = if (useLogger) {
177
+ createLogger(uuid)
178
+ } else {
179
+ null
180
+ }
181
+ connections[uuid] =
182
+ SpikeConnection.unpackConnection(
183
+ context = reactApplicationContext,
184
+ connection = connection,
185
+ logger = logger
186
+ )
187
+ promise.resolve(uuid)
188
+ } catch (e: SpikeExceptions) {
189
+ promise.reject(e.mapException(), e.message)
190
+ }
191
+ }
192
+ }
193
+
194
+ @ReactMethod
195
+ fun extractDataInRange(
196
+ connectionUUID: String,
197
+ dataType: String,
198
+ fromDateMillis: Double,
199
+ toDateMillis: Double,
200
+ promise: Promise
201
+ ) {
202
+ scope.launch {
203
+ try {
204
+ val result = connections[connectionUUID]?.extractData(
205
+ dataType = dataType.toSpikeDataType(),
206
+ from = fromDateMillis.toLong().millisToOffsetDataTime(),
207
+ to = toDateMillis.toLong().millisToOffsetDataTime()
208
+ )
209
+ promise.resolve(gson.toJson(result))
210
+ } catch (e: SpikeExceptions) {
211
+ promise.reject(e.mapException(), e.message)
212
+ }
213
+ }
214
+ }
215
+
216
+ @ReactMethod
217
+ fun extractAndPostDataInRange(
218
+ connectionUUID: String,
219
+ dataType: String,
220
+ fromDateMillis: Double,
221
+ toDateMillis: Double,
222
+ promise: Promise
223
+ ) {
224
+ scope.launch {
225
+ try {
226
+ val result =
227
+ (connections[connectionUUID] as? SpikeWebhookConnection)?.extractAndPostData(
228
+ dataType = dataType.toSpikeDataType(),
229
+ from = fromDateMillis.toLong().millisToOffsetDataTime(),
230
+ to = toDateMillis.toLong().millisToOffsetDataTime()
231
+ )
232
+ promise.resolve(gson.toJson(result))
233
+ } catch (e: SpikeExceptions) {
234
+ promise.reject(e.mapException(), e.message)
235
+ }
236
+ }
237
+ }
238
+
239
+ @ReactMethod
240
+ fun extractData(
241
+ connectionUUID: String,
242
+ dataType: String,
243
+ promise: Promise
244
+ ) {
245
+ scope.launch {
246
+ try {
247
+ val result = connections[connectionUUID]?.extractData(
248
+ dataType = dataType.toSpikeDataType()
249
+ )
250
+ promise.resolve(gson.toJson(result))
251
+ } catch (e: SpikeExceptions) {
252
+ promise.reject(e.mapException(), e.message)
253
+ }
254
+ }
255
+ }
256
+
257
+ @ReactMethod
258
+ fun extractAndPostData(
259
+ connectionUUID: String,
260
+ dataType: String,
261
+ promise: Promise
262
+ ) {
263
+ scope.launch {
264
+ try {
265
+ val result =
266
+ (connections[connectionUUID] as? SpikeWebhookConnection)?.extractAndPostData(
267
+ dataType = dataType.toSpikeDataType()
268
+ )
269
+ promise.resolve(gson.toJson(result))
270
+ } catch (e: SpikeExceptions) {
271
+ promise.reject(e.mapException(), e.message)
272
+ }
273
+ }
274
+ }
275
+
276
+ @ReactMethod
277
+ fun createWebhookConnection(
278
+ uuid: String,
279
+ appId: String,
280
+ authToken: String,
281
+ customerEndUserId: String,
282
+ callbackUrl: String,
283
+ useLogger: Boolean,
284
+ promise: Promise
285
+ ) {
286
+ scope.launch {
287
+ try {
288
+ val logger = if (useLogger) {
289
+ createLogger(uuid)
290
+ } else {
291
+ null
292
+ }
293
+ connections[uuid] = SpikeWebhookConnection.createConnection(
294
+ context = reactApplicationContext,
295
+ authToken = authToken,
296
+ customerEndUserId = customerEndUserId,
297
+ appId = appId,
298
+ logger = logger,
299
+ callbackUrl = callbackUrl
300
+ )
301
+ promise.resolve(uuid)
302
+ } catch (e: SpikeExceptions) {
303
+ promise.reject(e.mapException(), e.message)
304
+ }
305
+ }
306
+ }
307
+
308
+ @ReactMethod
309
+ fun manageHealthConnect(connectionUUID: String, promise: Promise) {
310
+ try {
311
+ val connection = connections[connectionUUID] ?: return promise.reject(
312
+ SpikeExceptions.SpikeException(
313
+ "Connection not found"
314
+ ).mapException(), "Connection not found"
315
+ )
316
+ connection.manageHealthConnect()
317
+ promise.resolve(true)
318
+ } catch (e: SpikeExceptions) {
319
+ promise.reject(e.mapException(), e.message)
320
+ }
321
+ }
322
+
323
+ @ReactMethod
324
+ fun checkPermissionsGranted(connectionUUID: String, promise: Promise) {
325
+ scope.launch {
326
+ try {
327
+ val permissionsGranted: Boolean =
328
+ connections[connectionUUID]?.hasHealthPermissionsGranted()
329
+ ?: return@launch promise.resolve(true)
330
+ promise.resolve(permissionsGranted)
331
+ } catch (e: SpikeExceptions) {
332
+ promise.reject(e.mapException(), e.message)
333
+ }
334
+ }
335
+ }
336
+
337
+ @ReactMethod
338
+ fun getHealthConnectAvailability(connectionUUID: String, promise: Promise) {
339
+ scope.launch {
340
+ try {
341
+ val availability = connections[connectionUUID]?.getHealthConnectAvailability()
342
+ ?: return@launch promise.resolve(true)
343
+ promise.resolve(availability.toStringType())
344
+ } catch (e: SpikeExceptions) {
345
+ promise.reject(e.mapException(), e.message)
346
+ }
347
+ }
348
+ }
349
+
350
+ @ReactMethod
351
+ fun revokeAllPermissions(connectionUUID: String, promise: Promise) {
352
+ scope.launch {
353
+ try {
354
+ connections[connectionUUID]?.revokeAllPermissions()
355
+ promise.resolve(true)
356
+ } catch (e: SpikeExceptions) {
357
+ promise.reject(e.mapException(), e.message)
358
+ }
359
+ }
360
+ }
361
+
362
+ @ReactMethod
363
+ fun requestHealthPermissions(connectionUUID: String, promise: Promise) {
364
+ val connection = connections[connectionUUID] ?: return promise.reject(
365
+ SpikeExceptions.SpikeException(
366
+ "Connection not found"
367
+ ).mapException(), "Connection not found"
368
+ )
369
+
370
+ val permissions = connection.getRequiredHealthPermissionsMetadata()
371
+
372
+ val intent = connection.requestReadAuthorization().createIntent(
373
+ context = reactApplicationContext, permissions
374
+ )
375
+
376
+ reactApplicationContext.currentActivity?.startActivityForResult(
377
+ intent,
378
+ REQUEST_CODE
379
+ )
380
+ promise.resolve(true)
381
+ }
382
+
383
+ private fun createLogger(connectionUUID: String): SpikeLogger {
384
+ return SpikeConnectionLogger(connectionUUID) { _, logLevel, message ->
385
+ val body = WritableNativeMap().apply {
386
+ putString("connectionUUID", connectionUUID)
387
+ putString("message", message)
388
+ }
389
+
390
+ when (logLevel) {
391
+ SpikeLogLevel.DEBUG -> sendEvent(
392
+ reactContext = reactApplicationContext,
393
+ eventName = logLevel.jsEventName,
394
+ params = body
395
+ )
396
+
397
+ SpikeLogLevel.ERROR -> sendEvent(
398
+ reactContext = reactApplicationContext,
399
+ eventName = logLevel.jsEventName,
400
+ params = body
401
+ )
402
+
403
+ SpikeLogLevel.INFO -> sendEvent(
404
+ reactContext = reactApplicationContext,
405
+ eventName = logLevel.jsEventName,
406
+ params = body
407
+ )
408
+ }
409
+ }
410
+ }
411
+
412
+ private fun sendEvent(reactContext: ReactContext, eventName: String, params: WritableMap?) {
413
+ reactContext
414
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
415
+ .emit(eventName, params)
416
+ }
10
417
 
11
- override fun getName(): String {
12
- return NAME
13
- }
418
+ companion object {
419
+ const val NAME = "SpikeSdk"
420
+ const val REQUEST_CODE = 4200
421
+ }
14
422
 
15
- companion object {
16
- const val NAME = "SpikeSdk"
17
- }
18
423
  }
@@ -0,0 +1,17 @@
1
+ import Foundation
2
+ import SpikeSDK
3
+
4
+ class SpikeConnectionListener: SpikeWebhookConnectionListener {
5
+
6
+ private let connectionUUID: String
7
+ private var onFailure: (String, SpikeWebhookJob, SpikeException) -> Void
8
+
9
+ init(connectionUUID: String, onFailure: @escaping (String, SpikeWebhookJob, SpikeException) -> Void) {
10
+ self.connectionUUID = connectionUUID
11
+ self.onFailure = onFailure
12
+ }
13
+
14
+ func onSubmissionFailure(webhookJob: SpikeWebhookJob, exception: SpikeException) {
15
+ onFailure(connectionUUID, webhookJob, exception)
16
+ }
17
+ }
@@ -0,0 +1,43 @@
1
+ import Foundation
2
+ import SpikeSDK
3
+
4
+ enum SpikeLogLevel {
5
+ case debug
6
+ case info
7
+ case error
8
+ }
9
+
10
+ class SpikeConnectionLogger: SpikeLogger {
11
+
12
+ private let connectionUUID: String
13
+ private var onLog: (String, SpikeLogLevel, String) -> Void
14
+
15
+ init(connectionUUID: String, onLog: @escaping (String, SpikeLogLevel, String) -> Void) {
16
+ self.connectionUUID = connectionUUID
17
+ self.onLog = onLog
18
+ }
19
+
20
+ func isDebugEnabled() -> Bool {
21
+ return true
22
+ }
23
+
24
+ func isInfoEnabled() -> Bool {
25
+ return true
26
+ }
27
+
28
+ func isErrorEnabled() -> Bool {
29
+ return true
30
+ }
31
+
32
+ func debug(connection: SpikeConnection, message: String) {
33
+ onLog(connectionUUID, .debug, message)
34
+ }
35
+
36
+ func info(connection: SpikeConnection, message: String) {
37
+ onLog(connectionUUID, .debug, message)
38
+ }
39
+
40
+ func error(connection: SpikeConnection, message: String) {
41
+ onLog(connectionUUID, .debug, message)
42
+ }
43
+ }
@@ -0,0 +1,207 @@
1
+ import Foundation
2
+ import SpikeSDK
3
+
4
+ class SpikeDataTypeMapper {
5
+
6
+ static func mapDataType(_ dataType: String) -> any SpikeDataType {
7
+ switch dataType {
8
+ case "activities_summary":
9
+ return SpikeDataTypes.activitiesSummary
10
+ case "activities_stream":
11
+ return SpikeDataTypes.activitiesStream
12
+ case "breathing":
13
+ return SpikeDataTypes.breathing
14
+ case "calories":
15
+ return SpikeDataTypes.calories
16
+ case "distance":
17
+ return SpikeDataTypes.distance
18
+ case "glucose":
19
+ return SpikeDataTypes.glucose
20
+ case "heart":
21
+ return SpikeDataTypes.heart
22
+ case "oxygen_saturation":
23
+ return SpikeDataTypes.oxygenSaturation
24
+ case "sleep":
25
+ return SpikeDataTypes.sleep
26
+ case "steps":
27
+ return SpikeDataTypes.steps
28
+ default:
29
+ return SpikeDataTypes.activitiesSummary
30
+ }
31
+ }
32
+
33
+ static func mapDataTypeToString(_ dataType: any SpikeDataType) -> String {
34
+ switch dataType {
35
+ case is SpikeActivitiesSummaryDataType:
36
+ return "activities_summary"
37
+ case is SpikeActivitiesStreamDataType:
38
+ return "activities_stream"
39
+ case is SpikeBreathingDataType:
40
+ return "breathing"
41
+ case is SpikeCaloriesDataType:
42
+ return "calories"
43
+ case is SpikeDistanceDataType:
44
+ return "distance"
45
+ case is SpikeGlucoseDataType:
46
+ return "glucose"
47
+ case is SpikeHeartDataType:
48
+ return "heart"
49
+ case is SpikeOxygenSaturationDataType:
50
+ return "oxygen_saturation"
51
+ case is SpikeSleepDataType:
52
+ return "sleep"
53
+ case is SpikeStepsDataType:
54
+ return "steps"
55
+ default:
56
+ return "activities_summary"
57
+ }
58
+ }
59
+
60
+ static func extractData(_ dataType: String, connection: SpikeConnection) async throws -> String? {
61
+ switch dataType {
62
+ case "activities_summary":
63
+ let value = try await connection.extractData(SpikeDataTypes.activitiesSummary)
64
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
65
+ case "activities_stream":
66
+ let value = try await connection.extractData(SpikeDataTypes.activitiesStream)
67
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
68
+ case "breathing":
69
+ let value = try await connection.extractData(SpikeDataTypes.breathing)
70
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
71
+ case "calories":
72
+ let value = try await connection.extractData(SpikeDataTypes.calories)
73
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
74
+ case "distance":
75
+ let value = try await connection.extractData(SpikeDataTypes.distance)
76
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
77
+ case "glucose":
78
+ let value = try await connection.extractData(SpikeDataTypes.glucose)
79
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
80
+ case "heart":
81
+ let value = try await connection.extractData(SpikeDataTypes.heart)
82
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
83
+ case "oxygen_saturation":
84
+ let value = try await connection.extractData(SpikeDataTypes.oxygenSaturation)
85
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
86
+ case "sleep":
87
+ let value = try await connection.extractData(SpikeDataTypes.sleep)
88
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
89
+ case "steps":
90
+ let value = try await connection.extractData(SpikeDataTypes.steps)
91
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
92
+ default:
93
+ return nil
94
+ }
95
+ }
96
+
97
+ static func extractDataInRange(_ dataType: String, connection: SpikeConnection, from: Date, to: Date) async throws -> String? {
98
+ switch dataType {
99
+ case "activities_summary":
100
+ let value = try await connection.extractData(SpikeDataTypes.activitiesSummary, from: from, to: to)
101
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
102
+ case "activities_stream":
103
+ let value = try await connection.extractData(SpikeDataTypes.activitiesStream, from: from, to: to)
104
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
105
+ case "breathing":
106
+ let value = try await connection.extractData(SpikeDataTypes.breathing, from: from, to: to)
107
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
108
+ case "calories":
109
+ let value = try await connection.extractData(SpikeDataTypes.calories, from: from, to: to)
110
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
111
+ case "distance":
112
+ let value = try await connection.extractData(SpikeDataTypes.distance, from: from, to: to)
113
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
114
+ case "glucose":
115
+ let value = try await connection.extractData(SpikeDataTypes.glucose, from: from, to: to)
116
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
117
+ case "heart":
118
+ let value = try await connection.extractData(SpikeDataTypes.heart, from: from, to: to)
119
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
120
+ case "oxygen_saturation":
121
+ let value = try await connection.extractData(SpikeDataTypes.oxygenSaturation, from: from, to: to)
122
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
123
+ case "sleep":
124
+ let value = try await connection.extractData(SpikeDataTypes.sleep, from: from, to: to)
125
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
126
+ case "steps":
127
+ let value = try await connection.extractData(SpikeDataTypes.steps, from: from, to: to)
128
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
129
+ default:
130
+ return nil
131
+ }
132
+ }
133
+
134
+ static func extractAndPostData(_ dataType: String, connection: SpikeWebhookConnection) async throws -> String? {
135
+ switch dataType {
136
+ case "activities_summary":
137
+ let value = try await connection.extractAndPostData(SpikeDataTypes.activitiesSummary)
138
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
139
+ case "activities_stream":
140
+ let value = try await connection.extractAndPostData(SpikeDataTypes.activitiesStream)
141
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
142
+ case "breathing":
143
+ let value = try await connection.extractAndPostData(SpikeDataTypes.breathing)
144
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
145
+ case "calories":
146
+ let value = try await connection.extractAndPostData(SpikeDataTypes.calories)
147
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
148
+ case "distance":
149
+ let value = try await connection.extractAndPostData(SpikeDataTypes.distance)
150
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
151
+ case "glucose":
152
+ let value = try await connection.extractAndPostData(SpikeDataTypes.glucose)
153
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
154
+ case "heart":
155
+ let value = try await connection.extractAndPostData(SpikeDataTypes.heart)
156
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
157
+ case "oxygen_saturation":
158
+ let value = try await connection.extractAndPostData(SpikeDataTypes.oxygenSaturation)
159
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
160
+ case "sleep":
161
+ let value = try await connection.extractAndPostData(SpikeDataTypes.sleep)
162
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
163
+ case "steps":
164
+ let value = try await connection.extractAndPostData(SpikeDataTypes.steps)
165
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
166
+ default:
167
+ return nil
168
+ }
169
+ }
170
+
171
+ static func extractAndPostDataInRange(_ dataType: String, connection: SpikeWebhookConnection, from: Date, to: Date) async throws -> String? {
172
+ switch dataType {
173
+ case "activities_summary":
174
+ let value = try await connection.extractAndPostData(SpikeDataTypes.activitiesSummary, from: from, to: to)
175
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
176
+ case "activities_stream":
177
+ let value = try await connection.extractAndPostData(SpikeDataTypes.activitiesStream, from: from, to: to)
178
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
179
+ case "breathing":
180
+ let value = try await connection.extractAndPostData(SpikeDataTypes.breathing, from: from, to: to)
181
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
182
+ case "calories":
183
+ let value = try await connection.extractAndPostData(SpikeDataTypes.calories, from: from, to: to)
184
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
185
+ case "distance":
186
+ let value = try await connection.extractAndPostData(SpikeDataTypes.distance, from: from, to: to)
187
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
188
+ case "glucose":
189
+ let value = try await connection.extractAndPostData(SpikeDataTypes.glucose, from: from, to: to)
190
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
191
+ case "heart":
192
+ let value = try await connection.extractAndPostData(SpikeDataTypes.heart, from: from, to: to)
193
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
194
+ case "oxygen_saturation":
195
+ let value = try await connection.extractAndPostData(SpikeDataTypes.oxygenSaturation, from: from, to: to)
196
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
197
+ case "sleep":
198
+ let value = try await connection.extractAndPostData(SpikeDataTypes.sleep, from: from, to: to)
199
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
200
+ case "steps":
201
+ let value = try await connection.extractAndPostData(SpikeDataTypes.steps, from: from, to: to)
202
+ return try? String(data: JSONEncoder().encode(value), encoding: .utf8)
203
+ default:
204
+ return nil
205
+ }
206
+ }
207
+ }