@velocitycareerlabs/vcl-react-native 2.9.0 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/VclReactNative.podspec +1 -1
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/io/velocitycareerlabs/reactnative/VclReactNativeModule.kt +58 -74
  4. package/android/src/main/java/io/velocitycareerlabs/reactnative/extensions/VCLErrorExtensions.kt +62 -2
  5. package/ios/VCLErrorBridge.swift +89 -0
  6. package/ios/VclReactNativeImpl.swift +29 -23
  7. package/lib/module/api/VCLApi.js +44 -18
  8. package/lib/module/api/VCLApi.js.map +1 -1
  9. package/lib/module/api/entities/error/VCLError.js +9 -13
  10. package/lib/module/api/entities/error/VCLError.js.map +1 -1
  11. package/lib/module/api/entities/error/VCLErrorDeserializer.js +98 -0
  12. package/lib/module/api/entities/error/VCLErrorDeserializer.js.map +1 -0
  13. package/lib/module/index.js.map +1 -1
  14. package/lib/typescript/src/api/VCLApi.d.ts.map +1 -1
  15. package/lib/typescript/src/api/entities/error/VCLError.d.ts +22 -1
  16. package/lib/typescript/src/api/entities/error/VCLError.d.ts.map +1 -1
  17. package/lib/typescript/src/api/entities/error/VCLErrorDeserializer.d.ts +19 -0
  18. package/lib/typescript/src/api/entities/error/VCLErrorDeserializer.d.ts.map +1 -0
  19. package/lib/typescript/src/api/entities/initialization/VCLInitializationDescriptor.d.ts +6 -0
  20. package/lib/typescript/src/api/entities/initialization/VCLInitializationDescriptor.d.ts.map +1 -1
  21. package/lib/typescript/src/index.d.ts +2 -1
  22. package/lib/typescript/src/index.d.ts.map +1 -1
  23. package/package.json +1 -1
  24. package/src/api/VCLApi.ts +58 -18
  25. package/src/api/entities/error/VCLError.ts +33 -13
  26. package/src/api/entities/error/VCLErrorDeserializer.ts +151 -0
  27. package/src/api/entities/initialization/VCLInitializationDescriptor.ts +6 -0
  28. package/src/index.tsx +8 -0
@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
18
18
 
19
19
  s.swift_version = "5.0"
20
20
 
21
- s.dependency "VCL", "2.9.0"
21
+ s.dependency "VCL", "2.9.3"
22
22
 
23
23
  install_modules_dependencies(s)
24
24
  end
@@ -76,7 +76,7 @@ dependencies {
76
76
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
77
77
 
78
78
  //--------- Must: be added:
79
- implementation "io.velocitycareerlabs:vcl:2.9.0"
79
+ implementation "io.velocitycareerlabs:vcl:2.9.2"
80
80
  implementation 'com.nimbusds:nimbus-jose-jwt:10.5'
81
81
  implementation "androidx.security:security-crypto:1.1.0"
82
82
  //-------------------------
@@ -38,7 +38,9 @@ import io.velocitycareerlabs.reactnative.utlis.Converter.verifiedProfileToMap
38
38
  import io.velocitycareerlabs.api.VCLProvider
39
39
  import io.velocitycareerlabs.api.entities.error.VCLError
40
40
  import io.velocitycareerlabs.api.entities.initialization.VCLInitializationDescriptor
41
- import io.velocitycareerlabs.reactnative.extensions.toThrowable
41
+ import io.velocitycareerlabs.reactnative.extensions.VCLErrorBridgeConfig
42
+ import io.velocitycareerlabs.reactnative.extensions.getIntOpt
43
+ import io.velocitycareerlabs.reactnative.extensions.rejectBridgedVCLError
42
44
  import io.velocitycareerlabs.reactnative.utlis.Converter.authTokenToMap
43
45
  import io.velocitycareerlabs.reactnative.utlis.Converter.didJwkToMap
44
46
  import io.velocitycareerlabs.reactnative.utlis.Converter.mapToAuthToken
@@ -72,11 +74,25 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
72
74
  GlobalConfig.IsDebugOn = initializationDescriptor.isDebugOn
73
75
  }
74
76
 
77
+ private inline fun withBridgedLocalExceptions(
78
+ promise: Promise,
79
+ block: () -> Unit
80
+ ) {
81
+ try {
82
+ block()
83
+ } catch (ex: Exception) {
84
+ promise.rejectBridgedVCLError(VCLError(ex))
85
+ }
86
+ }
87
+
75
88
  override fun initialize(
76
89
  initializationDescriptorMap: ReadableMap,
77
90
  promise: Promise
78
91
  ) {
79
- try {
92
+ withBridgedLocalExceptions(promise) {
93
+ VCLErrorBridgeConfig.updateNativeErrorStackFrameLimit(
94
+ initializationDescriptorMap.getIntOpt("nativeErrorStackFrameLimit")
95
+ )
80
96
  val initializationDescriptor = mapToInitializationDescriptor(
81
97
  initializationDescriptorMap
82
98
  )
@@ -88,37 +104,29 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
88
104
  promise.resolve("VCL initialization succeed!")
89
105
  },
90
106
  errorHandler = {
91
- promise.reject(it.toThrowable())
107
+ promise.rejectBridgedVCLError(it)
92
108
  })
93
- } catch (ex: Exception) {
94
- promise.reject(VCLError(ex).toThrowable())
95
109
  }
96
110
  }
97
111
 
98
112
  override fun getCountries(promise: Promise) {
99
- try {
113
+ withBridgedLocalExceptions(promise) {
100
114
  vcl.countries?.let { promise.resolve(countriesToMap(it)) }
101
- ?: promise.reject(VCLError(message = "Countries not found").toThrowable())
102
- } catch (ex: Exception) {
103
- promise.reject(VCLError(ex).toThrowable())
115
+ ?: promise.rejectBridgedVCLError(VCLError(message = "Countries not found"))
104
116
  }
105
117
  }
106
118
 
107
119
  override fun getCredentialTypeSchemas(promise: Promise) {
108
- try {
120
+ withBridgedLocalExceptions(promise) {
109
121
  vcl.credentialTypeSchemas?.let { promise.resolve(credentialTypeSchemasToMap(it)) }
110
- ?: promise.reject(VCLError(message = "Credential Types not found").toThrowable())
111
- } catch (ex: Exception) {
112
- promise.reject(VCLError(ex).toThrowable())
122
+ ?: promise.rejectBridgedVCLError(VCLError(message = "Credential Type Schemas not found"))
113
123
  }
114
124
  }
115
125
 
116
126
  override fun getCredentialTypes(promise: Promise) {
117
- try {
127
+ withBridgedLocalExceptions(promise) {
118
128
  vcl.credentialTypes?.let { promise.resolve(credentialTypesToMap(it)) }
119
- ?: promise.reject(VCLError(message = "Credential Types not found").toThrowable())
120
- } catch (ex: Exception) {
121
- promise.reject(VCLError(ex).toThrowable())
129
+ ?: promise.rejectBridgedVCLError(VCLError(message = "Credential Types not found"))
122
130
  }
123
131
  }
124
132
 
@@ -126,7 +134,7 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
126
134
  presentationRequestDescriptorMap: ReadableMap,
127
135
  promise: Promise
128
136
  ) {
129
- try {
137
+ withBridgedLocalExceptions(promise) {
130
138
  vcl.getPresentationRequest(
131
139
  presentationRequestDescriptor = mapTopPresentationRequestDescriptor(
132
140
  presentationRequestDescriptorMap
@@ -135,10 +143,8 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
135
143
  promise.resolve(presentationRequestToMap(it))
136
144
  },
137
145
  errorHandler = {
138
- promise.reject(it.toThrowable())
146
+ promise.rejectBridgedVCLError(it)
139
147
  })
140
- } catch (ex: Exception) {
141
- promise.reject(VCLError(ex).toThrowable())
142
148
  }
143
149
  }
144
150
 
@@ -147,7 +153,7 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
147
153
  authTokenMap: ReadableMap?,
148
154
  promise: Promise
149
155
  ) {
150
- try {
156
+ withBridgedLocalExceptions(promise) {
151
157
  vcl.submitPresentation(
152
158
  presentationSubmission = mapToPresentationSubmission(presentationSubmissionMap),
153
159
  authToken = mapToAuthToken(authTokenMap),
@@ -155,10 +161,8 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
155
161
  promise.resolve(presentationSubmissionResultToMap(it))
156
162
  },
157
163
  errorHandler = {
158
- promise.reject(it.toThrowable())
164
+ promise.rejectBridgedVCLError(it)
159
165
  })
160
- } catch (ex: Exception) {
161
- promise.reject(VCLError(ex).toThrowable())
162
166
  }
163
167
  }
164
168
 
@@ -166,16 +170,14 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
166
170
  exchangeDescriptorMap: ReadableMap,
167
171
  promise: Promise
168
172
  ) {
169
- try {
173
+ withBridgedLocalExceptions(promise) {
170
174
  vcl.getExchangeProgress(mapToExchangeDescriptor(exchangeDescriptorMap),
171
175
  {
172
176
  promise.resolve(exchangeToMap(it))
173
177
  },
174
178
  {
175
- promise.reject(it.toThrowable())
179
+ promise.rejectBridgedVCLError(it)
176
180
  })
177
- } catch (ex: Exception) {
178
- promise.reject(VCLError(ex).toThrowable())
179
181
  }
180
182
  }
181
183
 
@@ -183,17 +185,15 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
183
185
  organizationsSearchDescriptorMap: ReadableMap,
184
186
  promise: Promise
185
187
  ) {
186
- try {
188
+ withBridgedLocalExceptions(promise) {
187
189
  vcl.searchForOrganizations(
188
190
  mapToOrganizationsSearchDescriptor(organizationsSearchDescriptorMap),
189
191
  {
190
192
  promise.resolve(organizationsToMap(it))
191
193
  },
192
194
  {
193
- promise.reject(it.toThrowable())
195
+ promise.rejectBridgedVCLError(it)
194
196
  })
195
- } catch (ex: Exception) {
196
- promise.reject(VCLError(ex).toThrowable())
197
197
  }
198
198
  }
199
199
 
@@ -201,7 +201,7 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
201
201
  credentialManifestDescriptorMap: ReadableMap,
202
202
  promise: Promise
203
203
  ) {
204
- try {
204
+ withBridgedLocalExceptions(promise) {
205
205
  VCLLog.d(TAG, "credentialManifestDescriptorMap map: $credentialManifestDescriptorMap")
206
206
  mapToCredentialManifestDescriptor(credentialManifestDescriptorMap)?.let { credentialManifestDescriptor ->
207
207
  VCLLog.d(
@@ -214,13 +214,15 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
214
214
  promise.resolve(credentialManifestToMap(it))
215
215
  },
216
216
  errorHandler = {
217
- promise.reject(it.toThrowable())
217
+ promise.rejectBridgedVCLError(it)
218
218
  })
219
219
  } ?: run {
220
- promise.reject(VCLError("Unexpected Credential Credential Manifest Descriptor: $credentialManifestDescriptorMap").toThrowable())
220
+ promise.rejectBridgedVCLError(
221
+ VCLError(
222
+ message = "Unexpected Credential Manifest Descriptor"
223
+ )
224
+ )
221
225
  }
222
- } catch (ex: Exception) {
223
- promise.reject(VCLError(ex).toThrowable())
224
226
  }
225
227
  }
226
228
 
@@ -228,17 +230,15 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
228
230
  generateOffersDescriptorMap: ReadableMap,
229
231
  promise: Promise
230
232
  ) {
231
- try {
233
+ withBridgedLocalExceptions(promise) {
232
234
  vcl.generateOffers(
233
235
  generateOffersDescriptor = mapToGenerateOffersDescriptor(generateOffersDescriptorMap),
234
236
  successHandler = {
235
237
  promise.resolve(offersToMap(it))
236
238
  },
237
239
  errorHandler = {
238
- promise.reject(it.toThrowable())
240
+ promise.rejectBridgedVCLError(it)
239
241
  })
240
- } catch (ex: Exception) {
241
- promise.reject(VCLError(ex).toThrowable())
242
242
  }
243
243
  }
244
244
 
@@ -247,7 +247,7 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
247
247
  sessionTokenMap: ReadableMap,
248
248
  promise: Promise
249
249
  ) {
250
- try {
250
+ withBridgedLocalExceptions(promise) {
251
251
  vcl.checkForOffers(
252
252
  mapToGenerateOffersDescriptor(generateOffersDescriptorMap),
253
253
  mapToToken(sessionTokenMap),
@@ -255,10 +255,8 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
255
255
  promise.resolve(offersToMap(it))
256
256
  },
257
257
  {
258
- promise.reject(it.toThrowable())
258
+ promise.rejectBridgedVCLError(it)
259
259
  })
260
- } catch (ex: Exception) {
261
- promise.reject(VCLError(ex).toThrowable())
262
260
  }
263
261
  }
264
262
 
@@ -267,7 +265,7 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
267
265
  sessionTokenMap: ReadableMap,
268
266
  promise: Promise
269
267
  ) {
270
- try {
268
+ withBridgedLocalExceptions(promise) {
271
269
  vcl.finalizeOffers(
272
270
  finalizeOffersDescriptor = mapToFinalizedOffersDescriptor(finalizeOffersDescriptorMap),
273
271
  sessionToken = mapToToken(sessionTokenMap),
@@ -275,10 +273,8 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
275
273
  promise.resolve(jwtVerifiableCredentialsToMap(it))
276
274
  },
277
275
  errorHandler = {
278
- promise.reject(it.toThrowable())
276
+ promise.rejectBridgedVCLError(it)
279
277
  })
280
- } catch (ex: Exception) {
281
- promise.reject(VCLError(ex).toThrowable())
282
278
  }
283
279
  }
284
280
 
@@ -286,17 +282,15 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
286
282
  authTokenDescriptorMap: ReadableMap,
287
283
  promise: Promise
288
284
  ) {
289
- try {
285
+ withBridgedLocalExceptions(promise) {
290
286
  vcl.getAuthToken(
291
287
  authTokenDescriptor = mapToAuthTokenDescriptor(authTokenDescriptorMap),
292
288
  successHandler = {
293
289
  promise.resolve(authTokenToMap(it))
294
290
  },
295
291
  errorHandler = {
296
- promise.reject(it.toThrowable())
292
+ promise.rejectBridgedVCLError(it)
297
293
  })
298
- } catch (ex: Exception) {
299
- promise.reject(VCLError(ex).toThrowable())
300
294
  }
301
295
  }
302
296
 
@@ -304,18 +298,16 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
304
298
  credentialTypesUIFormSchemaDescriptorMap: ReadableMap,
305
299
  promise: Promise
306
300
  ) {
307
- try {
301
+ withBridgedLocalExceptions(promise) {
308
302
  vcl.getCredentialTypesUIFormSchema(
309
303
  mapToCredentialTypesUIFormSchemaDescriptor(credentialTypesUIFormSchemaDescriptorMap),
310
304
  {
311
305
  promise.resolve(credentialTypesFormSchemaToMap(it))
312
306
  },
313
307
  {
314
- promise.reject(it.toThrowable())
308
+ promise.rejectBridgedVCLError(it)
315
309
  }
316
310
  )
317
- } catch (ex: Exception) {
318
- promise.reject(VCLError(ex).toThrowable())
319
311
  }
320
312
  }
321
313
 
@@ -323,16 +315,14 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
323
315
  verifiedProfileDescriptorMap: ReadableMap,
324
316
  promise: Promise
325
317
  ) {
326
- try {
318
+ withBridgedLocalExceptions(promise) {
327
319
  vcl.getVerifiedProfile(mapToVerifiedProfileDescriptor(verifiedProfileDescriptorMap),
328
320
  {
329
321
  promise.resolve(verifiedProfileToMap(it))
330
322
  },
331
323
  {
332
- promise.reject(it.toThrowable())
324
+ promise.rejectBridgedVCLError(it)
333
325
  })
334
- } catch (ex: Exception) {
335
- promise.reject(VCLError(ex).toThrowable())
336
326
  }
337
327
  }
338
328
 
@@ -342,7 +332,7 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
342
332
  remoteCryptoServicesTokenMap: ReadableMap?,
343
333
  promise: Promise
344
334
  ) {
345
- try {
335
+ withBridgedLocalExceptions(promise) {
346
336
  vcl.verifyJwt(
347
337
  jwt = mapToJwt(jwtMap),
348
338
  publicJwk = mapToPublicJwk(publicJwkMap),
@@ -351,10 +341,8 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
351
341
  promise.resolve(it)
352
342
  },
353
343
  errorHandler = {
354
- promise.reject(it.toThrowable())
344
+ promise.rejectBridgedVCLError(it)
355
345
  })
356
- } catch (ex: Exception) {
357
- promise.reject(VCLError(ex).toThrowable())
358
346
  }
359
347
  }
360
348
 
@@ -364,7 +352,7 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
364
352
  remoteCryptoServicesTokenMap: ReadableMap?,
365
353
  promise: Promise
366
354
  ) {
367
- try {
355
+ withBridgedLocalExceptions(promise) {
368
356
  vcl.generateSignedJwt(
369
357
  jwtDescriptor = mapToJwtDescriptor(jwtDescriptorMap),
370
358
  didJwk = mapToDidJwk(didJwkMap),
@@ -373,10 +361,8 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
373
361
  promise.resolve(Converter.jwtToMap(it))
374
362
  },
375
363
  errorHandler = {
376
- promise.reject(it.toThrowable())
364
+ promise.rejectBridgedVCLError(it)
377
365
  })
378
- } catch (ex: Exception) {
379
- promise.reject(VCLError(ex).toThrowable())
380
366
  }
381
367
  }
382
368
 
@@ -384,17 +370,15 @@ class VclReactNativeModule(val reactContext: ReactApplicationContext) :
384
370
  didJwkDescriptorMap: ReadableMap?,
385
371
  promise: Promise
386
372
  ) {
387
- try {
373
+ withBridgedLocalExceptions(promise) {
388
374
  vcl.generateDidJwk(
389
375
  didJwkDescriptor = mapToDidJwkDescriptor(didJwkDescriptorMap),
390
376
  successHandler = {
391
377
  promise.resolve(didJwkToMap(it))
392
378
  },
393
379
  errorHandler = {
394
- promise.reject(it.toThrowable())
380
+ promise.rejectBridgedVCLError(it)
395
381
  })
396
- } catch (ex: Exception) {
397
- promise.reject(VCLError(ex).toThrowable())
398
382
  }
399
383
  }
400
384
  }
@@ -7,7 +7,67 @@
7
7
 
8
8
  package io.velocitycareerlabs.reactnative.extensions
9
9
 
10
+ import com.facebook.react.bridge.Promise
10
11
  import io.velocitycareerlabs.api.entities.error.VCLError
12
+ import org.json.JSONArray
13
+ import org.json.JSONObject
11
14
 
12
- fun VCLError.toThrowable() =
13
- Throwable(this.toJsonObject().toString())
15
+ const val BRIDGED_VCL_ERROR_CODE = "VCL_BRIDGED_ERROR_V1"
16
+ private const val DEFAULT_NATIVE_ERROR_STACK_FRAME_LIMIT = 5
17
+ private const val MAX_NATIVE_ERROR_STACK_FRAME_LIMIT = 20
18
+
19
+ object VCLErrorBridgeConfig {
20
+ var nativeErrorStackFrameLimit = DEFAULT_NATIVE_ERROR_STACK_FRAME_LIMIT
21
+ private set
22
+
23
+ fun updateNativeErrorStackFrameLimit(nativeErrorStackFrameLimit: Int?) {
24
+ this.nativeErrorStackFrameLimit =
25
+ nativeErrorStackFrameLimit
26
+ ?.coerceIn(0, MAX_NATIVE_ERROR_STACK_FRAME_LIMIT)
27
+ ?: DEFAULT_NATIVE_ERROR_STACK_FRAME_LIMIT
28
+ }
29
+ }
30
+
31
+ fun Promise.rejectBridgedVCLError(error: VCLError) {
32
+ val serializedError =
33
+ error.toBridgedJsonObject(VCLErrorBridgeConfig.nativeErrorStackFrameLimit).toString()
34
+ reject(BRIDGED_VCL_ERROR_CODE, serializedError, error)
35
+ }
36
+
37
+ private fun VCLError.toBridgedJsonObject(
38
+ nativeErrorStackFrameLimit: Int
39
+ ) = JSONObject().apply {
40
+ putOpt("payload", payload)
41
+ putOpt("error", error)
42
+ putOpt("errorCode", errorCode)
43
+ putOpt("requestId", requestId)
44
+ putOpt("message", message)
45
+ putOpt("statusCode", statusCode)
46
+ put("diagnostics", toDiagnosticsJsonObject(nativeErrorStackFrameLimit))
47
+ }
48
+
49
+ private fun VCLError.toDiagnosticsJsonObject(
50
+ nativeErrorStackFrameLimit: Int
51
+ ) = JSONObject().apply {
52
+ put("nativePlatform", "android")
53
+ put("nativeType", this@toDiagnosticsJsonObject::class.java.name)
54
+ putOpt("nativeStackFrames", stackTrace.toStackFramesJsonArray(nativeErrorStackFrameLimit))
55
+ cause?.let { put("nativeCause", it.toNativeCauseJsonObject(nativeErrorStackFrameLimit)) }
56
+ }
57
+
58
+ private fun Throwable.toNativeCauseJsonObject(
59
+ nativeErrorStackFrameLimit: Int
60
+ ) = JSONObject().apply {
61
+ put("type", javaClass.name)
62
+ put("message", message ?: toString())
63
+ putOpt("stackFrames", stackTrace.toStackFramesJsonArray(nativeErrorStackFrameLimit))
64
+ }
65
+
66
+ private fun Array<StackTraceElement>.toStackFramesJsonArray(
67
+ nativeErrorStackFrameLimit: Int
68
+ ): JSONArray? =
69
+ takeIf { nativeErrorStackFrameLimit > 0 }
70
+ ?.take(nativeErrorStackFrameLimit)
71
+ ?.map { it.toString() }
72
+ ?.takeIf { it.isNotEmpty() }
73
+ ?.let { JSONArray(it) }
@@ -0,0 +1,89 @@
1
+ //
2
+ // VCLErrorBridge.swift
3
+ // vcl-react-native
4
+ //
5
+ // Copyright 2022 Velocity Career Labs inc.
6
+ // SPDX-License-Identifier: Apache-2.0
7
+ //
8
+
9
+ import Foundation
10
+ import React
11
+ import VCL
12
+
13
+ final class VCLErrorBridge {
14
+
15
+ private static let bridgedVCLErrorCode = "VCL_BRIDGED_ERROR_V1"
16
+ private static let defaultNativeErrorStackFrameLimit = 5
17
+ private static let maxNativeErrorStackFrameLimit = 20
18
+ private static let nativeStackFramesDictionaryKey = "callStackSymbols"
19
+
20
+ private var nativeErrorStackFrameLimit = VCLErrorBridge.defaultNativeErrorStackFrameLimit
21
+
22
+ func updateConfiguration(_ initializationDescriptorDictionary: [String: Any]) {
23
+ let stackFrameLimit = initializationDescriptorDictionary["nativeErrorStackFrameLimit"] as? Int
24
+ nativeErrorStackFrameLimit =
25
+ stackFrameLimit.map { min(max($0, 0), Self.maxNativeErrorStackFrameLimit) }
26
+ ?? Self.defaultNativeErrorStackFrameLimit
27
+ }
28
+
29
+ func rejectBridgedVCLError(
30
+ _ reject: @escaping RCTPromiseRejectBlock,
31
+ error: VCLError
32
+ ) {
33
+ let serializedError =
34
+ bridgedVCLErrorPayload(error).toJsonString()
35
+ ?? error.message
36
+ ?? "Unexpected VCLError"
37
+ reject(Self.bridgedVCLErrorCode, serializedError, error)
38
+ }
39
+
40
+ private func bridgedVCLErrorPayload(_ error: VCLError) -> [String: Any] {
41
+ var payload = error.toDictionary().compactMapValues { $0 }
42
+ payload.removeValue(forKey: Self.nativeStackFramesDictionaryKey)
43
+ payload["diagnostics"] = bridgedDiagnostics(error)
44
+ return payload
45
+ }
46
+
47
+ private func bridgedDiagnostics(_ error: VCLError) -> [String: Any] {
48
+ var diagnostics: [String: Any] = [
49
+ "nativePlatform": "ios",
50
+ "nativeType": String(describing: type(of: error)),
51
+ ]
52
+
53
+ if let nativeStackFrames =
54
+ limitedStackFrames(
55
+ error.toDictionary()[Self.nativeStackFramesDictionaryKey] as? [String]
56
+ )
57
+ {
58
+ diagnostics["nativeStackFrames"] = nativeStackFrames
59
+ }
60
+
61
+ if let cause = error.cause {
62
+ var nativeCause: [String: Any] = [
63
+ "type": String(describing: type(of: cause)),
64
+ "message": String(describing: cause),
65
+ ]
66
+
67
+ if let stackFrames =
68
+ limitedStackFrames(
69
+ (cause as? VCLError)?.toDictionary()[Self.nativeStackFramesDictionaryKey] as? [String]
70
+ )
71
+ {
72
+ nativeCause["stackFrames"] = stackFrames
73
+ }
74
+
75
+ diagnostics["nativeCause"] = nativeCause
76
+ }
77
+
78
+ return diagnostics
79
+ }
80
+
81
+ private func limitedStackFrames(_ stackFrames: [String]?) -> [String]? {
82
+ guard nativeErrorStackFrameLimit > 0, let stackFrames else {
83
+ return nil
84
+ }
85
+
86
+ let trimmedStackFrames = Array(stackFrames.prefix(nativeErrorStackFrameLimit))
87
+ return trimmedStackFrames.isEmpty ? nil : trimmedStackFrames
88
+ }
89
+ }