react-native-candle 19.0.12-beta → 40.0.8-beta

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 (138) hide show
  1. package/README.md +17 -25
  2. package/android/gradle.properties +5 -0
  3. package/android/src/main/java/com/margelo/nitro/rncandle/BridgeTypes.kt +189 -2
  4. package/android/src/main/java/com/margelo/nitro/rncandle/HybridRNCandle.kt +63 -10
  5. package/ios/Sources/CandleLinkSheetWrapperView.swift +3 -2
  6. package/ios/Sources/CandleLinkViewModel.swift +2 -1
  7. package/ios/Sources/RNCandle.swift +86 -9
  8. package/ios/Sources/Types.swift +199 -5
  9. package/lib/typescript/commonjs/src/context.d.ts +16 -6
  10. package/lib/typescript/commonjs/src/provider.d.ts +1 -2
  11. package/lib/typescript/commonjs/src/specs/RNCandle.nitro.d.ts +76 -6
  12. package/lib/typescript/commonjs/src/types.d.ts +15 -3
  13. package/lib/typescript/module/src/context.d.ts +16 -6
  14. package/lib/typescript/module/src/provider.d.ts +1 -2
  15. package/lib/typescript/module/src/specs/RNCandle.nitro.d.ts +76 -6
  16. package/lib/typescript/module/src/types.d.ts +15 -3
  17. package/nitrogen/generated/android/c++/JAssetAccount.hpp +2 -0
  18. package/nitrogen/generated/android/c++/JAssetAccountsResponse.hpp +2 -0
  19. package/nitrogen/generated/android/c++/JCounterparty.hpp +2 -0
  20. package/nitrogen/generated/android/c++/JCryptoAccount.hpp +3 -0
  21. package/nitrogen/generated/android/c++/JCryptoAsset.hpp +3 -0
  22. package/nitrogen/generated/android/c++/JEventAsset.hpp +3 -0
  23. package/nitrogen/generated/android/c++/JFiatAccount.hpp +2 -0
  24. package/nitrogen/generated/android/c++/JFiatAsset.hpp +2 -0
  25. package/nitrogen/generated/android/c++/JFriendRequestAsset.hpp +86 -0
  26. package/nitrogen/generated/android/c++/JFriendRequestAssetDirection.hpp +58 -0
  27. package/nitrogen/generated/android/c++/JFriendRequestAssetQuoteRequest.hpp +63 -0
  28. package/nitrogen/generated/android/c++/JFriendRequestAssetQuoteRequestAction.hpp +64 -0
  29. package/nitrogen/generated/android/c++/JFriendRequestAssetRef.hpp +66 -0
  30. package/nitrogen/generated/android/c++/JFunc_void_LinkedAccount.hpp +13 -11
  31. package/nitrogen/generated/android/c++/JFunc_void_TradeExecutionResult.hpp +11 -0
  32. package/nitrogen/generated/android/c++/JHostedAuthorizationCallback.hpp +66 -0
  33. package/nitrogen/generated/android/c++/JHostedAuthorizationRequest.hpp +69 -0
  34. package/nitrogen/generated/android/c++/JHybridRNCandleSpec.cpp +78 -15
  35. package/nitrogen/generated/android/c++/JHybridRNCandleSpec.hpp +7 -4
  36. package/nitrogen/generated/android/c++/JLinkedAccount.hpp +2 -0
  37. package/nitrogen/generated/android/c++/JLinkedAccountStatusRef.hpp +3 -0
  38. package/nitrogen/generated/android/c++/JMessageThreadAsset.hpp +99 -0
  39. package/nitrogen/generated/android/c++/JMessageThreadAssetQuoteRequest.hpp +61 -0
  40. package/nitrogen/generated/android/c++/JMessageThreadAssetRef.hpp +65 -0
  41. package/nitrogen/generated/android/c++/JMessageThreadMessage.hpp +78 -0
  42. package/nitrogen/generated/android/c++/JService.hpp +36 -252
  43. package/nitrogen/generated/android/c++/JServiceCounterparty.hpp +3 -0
  44. package/nitrogen/generated/android/c++/JServiceID.hpp +316 -0
  45. package/nitrogen/generated/android/c++/JStockAccount.hpp +3 -0
  46. package/nitrogen/generated/android/c++/JStockAsset.hpp +3 -0
  47. package/nitrogen/generated/android/c++/JTrade.hpp +11 -0
  48. package/nitrogen/generated/android/c++/JTradeAsset.hpp +22 -1
  49. package/nitrogen/generated/android/c++/JTradeAssetKind.hpp +6 -0
  50. package/nitrogen/generated/android/c++/JTradeAssetQuoteRequest.hpp +15 -1
  51. package/nitrogen/generated/android/c++/JTradeAssetRef.hpp +13 -1
  52. package/nitrogen/generated/android/c++/JTradeExecutionResult.hpp +11 -0
  53. package/nitrogen/generated/android/c++/JTradeQuote.hpp +11 -0
  54. package/nitrogen/generated/android/c++/JTradeQuotesRequest.hpp +6 -0
  55. package/nitrogen/generated/android/c++/JTradeQuotesResponse.hpp +10 -0
  56. package/nitrogen/generated/android/c++/JTradeRef.hpp +4 -0
  57. package/nitrogen/generated/android/c++/JTradesResponse.hpp +10 -0
  58. package/nitrogen/generated/android/c++/JTransportAccount.hpp +3 -0
  59. package/nitrogen/generated/android/c++/JTransportAsset.hpp +3 -0
  60. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/FriendRequestAsset.kt +53 -0
  61. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/FriendRequestAssetDirection.kt +23 -0
  62. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/FriendRequestAssetQuoteRequest.kt +41 -0
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/FriendRequestAssetQuoteRequestAction.kt +25 -0
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/FriendRequestAssetRef.kt +44 -0
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/Func_void_LinkedAccount.kt +9 -9
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/HostedAuthorizationCallback.kt +44 -0
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/HostedAuthorizationRequest.kt +47 -0
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/HybridRNCandleSpec.kt +18 -6
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/MessageThreadAsset.kt +50 -0
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/MessageThreadAssetQuoteRequest.kt +41 -0
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/MessageThreadAssetRef.kt +44 -0
  72. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/MessageThreadMessage.kt +53 -0
  73. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/Service.kt +32 -83
  74. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/ServiceID.kt +109 -0
  75. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/TradeAsset.kt +8 -2
  76. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/TradeAssetKind.kt +4 -2
  77. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/TradeAssetQuoteRequest.kt +8 -2
  78. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rncandle/TradeAssetRef.kt +8 -2
  79. package/nitrogen/generated/ios/ReactNativeCandle-Swift-Cxx-Bridge.cpp +3 -3
  80. package/nitrogen/generated/ios/ReactNativeCandle-Swift-Cxx-Bridge.hpp +184 -20
  81. package/nitrogen/generated/ios/ReactNativeCandle-Swift-Cxx-Umbrella.hpp +37 -1
  82. package/nitrogen/generated/ios/c++/HybridRNCandleSpecSwift.hpp +74 -14
  83. package/nitrogen/generated/ios/swift/FriendRequestAsset.swift +67 -0
  84. package/nitrogen/generated/ios/swift/FriendRequestAssetDirection.swift +40 -0
  85. package/nitrogen/generated/ios/swift/FriendRequestAssetQuoteRequest.swift +34 -0
  86. package/nitrogen/generated/ios/swift/FriendRequestAssetQuoteRequestAction.swift +48 -0
  87. package/nitrogen/generated/ios/swift/FriendRequestAssetRef.swift +52 -0
  88. package/nitrogen/generated/ios/swift/Func_void_LinkedAccount.swift +5 -5
  89. package/nitrogen/generated/ios/swift/HostedAuthorizationCallback.swift +52 -0
  90. package/nitrogen/generated/ios/swift/HostedAuthorizationRequest.swift +44 -0
  91. package/nitrogen/generated/ios/swift/HybridRNCandleSpec.swift +7 -4
  92. package/nitrogen/generated/ios/swift/HybridRNCandleSpec_cxx.swift +56 -13
  93. package/nitrogen/generated/ios/swift/MessageThreadAsset.swift +68 -0
  94. package/nitrogen/generated/ios/swift/MessageThreadAssetQuoteRequest.swift +34 -0
  95. package/nitrogen/generated/ios/swift/MessageThreadAssetRef.swift +39 -0
  96. package/nitrogen/generated/ios/swift/MessageThreadMessage.swift +119 -0
  97. package/nitrogen/generated/ios/swift/Service.swift +44 -334
  98. package/nitrogen/generated/ios/swift/ServiceID.swift +384 -0
  99. package/nitrogen/generated/ios/swift/TradeAsset.swift +23 -1
  100. package/nitrogen/generated/ios/swift/TradeAssetKind.swift +8 -0
  101. package/nitrogen/generated/ios/swift/TradeAssetQuoteRequest.swift +23 -1
  102. package/nitrogen/generated/ios/swift/TradeAssetRef.swift +23 -1
  103. package/nitrogen/generated/shared/c++/CryptoAccount.hpp +1 -1
  104. package/nitrogen/generated/shared/c++/CryptoAsset.hpp +1 -1
  105. package/nitrogen/generated/shared/c++/EventAsset.hpp +1 -1
  106. package/nitrogen/generated/shared/c++/FiatAccount.hpp +1 -1
  107. package/nitrogen/generated/shared/c++/FiatAsset.hpp +1 -1
  108. package/nitrogen/generated/shared/c++/FriendRequestAsset.hpp +112 -0
  109. package/nitrogen/generated/shared/c++/FriendRequestAssetDirection.hpp +76 -0
  110. package/nitrogen/generated/shared/c++/FriendRequestAssetQuoteRequest.hpp +89 -0
  111. package/nitrogen/generated/shared/c++/FriendRequestAssetQuoteRequestAction.hpp +84 -0
  112. package/nitrogen/generated/shared/c++/FriendRequestAssetRef.hpp +92 -0
  113. package/nitrogen/generated/shared/c++/HostedAuthorizationCallback.hpp +92 -0
  114. package/nitrogen/generated/shared/c++/HostedAuthorizationRequest.hpp +95 -0
  115. package/nitrogen/generated/shared/c++/HybridRNCandleSpec.cpp +5 -2
  116. package/nitrogen/generated/shared/c++/HybridRNCandleSpec.hpp +16 -7
  117. package/nitrogen/generated/shared/c++/LinkedAccount.hpp +1 -1
  118. package/nitrogen/generated/shared/c++/LinkedAccountStatusRef.hpp +1 -1
  119. package/nitrogen/generated/shared/c++/MessageThreadAsset.hpp +106 -0
  120. package/nitrogen/generated/shared/c++/MessageThreadAssetQuoteRequest.hpp +87 -0
  121. package/nitrogen/generated/shared/c++/MessageThreadAssetRef.hpp +91 -0
  122. package/nitrogen/generated/shared/c++/MessageThreadMessage.hpp +104 -0
  123. package/nitrogen/generated/shared/c++/Service.hpp +60 -346
  124. package/nitrogen/generated/shared/c++/ServiceCounterparty.hpp +1 -1
  125. package/nitrogen/generated/shared/c++/ServiceID.hpp +420 -0
  126. package/nitrogen/generated/shared/c++/StockAccount.hpp +1 -1
  127. package/nitrogen/generated/shared/c++/StockAsset.hpp +1 -1
  128. package/nitrogen/generated/shared/c++/TradeAsset.hpp +15 -1
  129. package/nitrogen/generated/shared/c++/TradeAssetKind.hpp +10 -2
  130. package/nitrogen/generated/shared/c++/TradeAssetQuoteRequest.hpp +15 -1
  131. package/nitrogen/generated/shared/c++/TradeAssetRef.hpp +15 -1
  132. package/nitrogen/generated/shared/c++/TransportAccount.hpp +1 -1
  133. package/nitrogen/generated/shared/c++/TransportAsset.hpp +1 -1
  134. package/package.json +1 -1
  135. package/src/context.ts +21 -5
  136. package/src/provider.tsx +62 -34
  137. package/src/specs/RNCandle.nitro.ts +109 -7
  138. package/src/types.ts +50 -1
package/README.md CHANGED
@@ -1,33 +1,25 @@
1
- # React Native SDK Module
1
+ # Candle React Native Example App(s)
2
2
 
3
- This directory is the workspace source for `react-native-candle`.
3
+ #### Supported Platforms
4
4
 
5
- User-facing installation and API docs live in `web-docs/`. This README only covers the repo-local workflow that is specific to this module.
5
+ <div style="flex-wrap: wrap; display: flex;">
6
6
 
7
- ## What Is Here
7
+ <picture>
8
+ <source media="(prefers-color-scheme: dark)" srcset="Images/ios.svg">
9
+ <source media="(prefers-color-scheme: light)" srcset="Images/ios-active.svg">
10
+ <img alt="ios" src="Images/ios-active.svg" height="24">
11
+ </picture>&nbsp;
8
12
 
9
- - `src/specs/RNCandle.nitro.ts`: Nitro bridge schema and generated native bindings source of truth
10
- - `src/types.ts`: public TypeScript wrapper layer over the Nitro-generated models
11
- - `ios/Sources/`: handwritten Swift bridge code
12
- - `sdk-react-native-example-app/`: the local app used to exercise the package in development
13
+ <picture>
14
+ <source media="(prefers-color-scheme: dark)" srcset="Images/ipados.svg">
15
+ <source media="(prefers-color-scheme: light)" srcset="Images/ipados-active.svg">
16
+ <img alt="ipad" src="Images/ipados-active.svg" height="24">
17
+ </picture>&nbsp;
13
18
 
14
- ## Module-Specific Workflow
19
+ ---
15
20
 
16
- - After changing `src/specs/RNCandle.nitro.ts`, run `pnpm run gen:nitro`.
17
- - After changing the public TS wrapper layer or native bridge code, run:
18
- - `pnpm run lintCheck`
19
- - `pnpm run formatCheck`
20
- - `pnpm run compileCheck`
21
- - Before finishing, run `pnpm turbo check` from the repo root.
21
+ </div>
22
22
 
23
- ## iOS Development Notes
23
+ The Candle React Native SDK is a simple & secure way for developers to connect external services to LLMs, agents, and apps. Visit our [quick start](https://docs.candle.fi) guide to get started.
24
24
 
25
- - The package is currently iOS-only at runtime. The docs and example app assume iOS 17+.
26
- - The example app injects the local Swift SDK pod path in `plugins/withLocalSwiftPod.js`, so native iOS dependency changes usually require `cd ../sdk-react-native-example-app && pnpm prebuild` before rebuilding.
27
- - `ReactNativeCandle.podspec` now pins `Candle` to the same version as this package. If those versions ever stop moving in lockstep, the release wiring will need to change.
28
-
29
- ## Release Notes
30
-
31
- - `publish.sh` prepares the public repo contents.
32
- - `pnpm run script -- apply-public-package-metadata ...` rewrites package metadata for release outputs.
33
- - `public/README.md` is the public-facing README template for this module and should stay aligned with the actual package capabilities.
25
+ ![Candle](Images/sdk-readme.png)
@@ -1,2 +1,7 @@
1
1
  ReactNativeCandle_kotlinVersion=2.1.21
2
2
  org.gradle.caching=true
3
+ org.gradle.daemon=true
4
+ org.gradle.parallel=true
5
+ org.gradle.caching=true
6
+ org.gradle.configureondemand=true
7
+ org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -Dkotlin.daemon.jvm.options=-Xmx2g
@@ -24,6 +24,11 @@ import fi.candle.generated.http.models.FiatAsset as CandleFiatAsset
24
24
  import fi.candle.generated.http.models.FiatAssetQuoteRequest as CandleFiatAssetQuoteRequest
25
25
  import fi.candle.generated.http.models.FiatAssetRef as CandleFiatAssetRef
26
26
  import fi.candle.generated.http.models.FinancialAccountKind as CandleFinancialAccountKind
27
+ import fi.candle.generated.http.models.FriendRequestAsset as CandleFriendRequestAsset
28
+ import fi.candle.generated.http.models.FriendRequestAssetDirection as CandleFriendRequestAssetDirection
29
+ import fi.candle.generated.http.models.FriendRequestAssetQuoteRequest as CandleFriendRequestAssetQuoteRequest
30
+ import fi.candle.generated.http.models.FriendRequestAssetQuoteRequestAction as CandleFriendRequestAssetQuoteRequestAction
31
+ import fi.candle.generated.http.models.FriendRequestAssetRef as CandleFriendRequestAssetRef
27
32
  import fi.candle.generated.http.models.InactiveLinkedAccountDetails as CandleInactiveLinkedAccountDetails
28
33
  import fi.candle.generated.http.models.LinkedAccount as CandleLinkedAccount
29
34
  import fi.candle.generated.http.models.LinkedAccountDetails as CandleLinkedAccountDetails
@@ -32,6 +37,10 @@ import fi.candle.generated.http.models.LinkedAccountStatusRefState as CandleLink
32
37
  import fi.candle.generated.http.models.MerchantCounterparty as CandleMerchantCounterparty
33
38
  import fi.candle.generated.http.models.MerchantCounterpartyQuoteRequest as CandleMerchantCounterpartyQuoteRequest
34
39
  import fi.candle.generated.http.models.MerchantLocation as CandleMerchantLocation
40
+ import fi.candle.generated.http.models.MessageThreadAsset as CandleMessageThreadAsset
41
+ import fi.candle.generated.http.models.MessageThreadAssetQuoteRequest as CandleMessageThreadAssetQuoteRequest
42
+ import fi.candle.generated.http.models.MessageThreadAssetRef as CandleMessageThreadAssetRef
43
+ import fi.candle.generated.http.models.MessageThreadMessage as CandleMessageThreadMessage
35
44
  import fi.candle.generated.http.models.NothingAsset as CandleNothingAsset
36
45
  import fi.candle.generated.http.models.NothingAssetQuoteRequest as CandleNothingAssetQuoteRequest
37
46
  import fi.candle.generated.http.models.OtherAsset as CandleOtherAsset
@@ -39,6 +48,7 @@ import fi.candle.generated.http.models.OtherAssetQuoteRequest as CandleOtherAsse
39
48
  import fi.candle.generated.http.models.Service as CandleService
40
49
  import fi.candle.generated.http.models.ServiceCounterparty as CandleServiceCounterparty
41
50
  import fi.candle.generated.http.models.ServiceCounterpartyQuoteRequest as CandleServiceCounterpartyQuoteRequest
51
+ import fi.candle.generated.http.models.ServiceID as CandleServiceID
42
52
  import fi.candle.generated.http.models.StockAccount as CandleStockAccount
43
53
  import fi.candle.generated.http.models.StockAsset as CandleStockAsset
44
54
  import fi.candle.generated.http.models.StockAssetQuoteRequest as CandleStockAssetQuoteRequest
@@ -65,9 +75,29 @@ import fi.candle.generated.http.models.WireDetails as CandleWireDetails
65
75
  import java.math.BigDecimal
66
76
  import java.util.UUID
67
77
 
68
- internal fun Service.toCandleModel(): CandleService = CandleService.valueOf(name)
78
+ internal fun ServiceID.toCandleModel(): CandleServiceID = CandleServiceID.valueOf(name)
69
79
 
70
- internal fun CandleService.toReactModel(): Service = Service.valueOf(name)
80
+ internal fun CandleServiceID.toReactModel(): ServiceID = ServiceID.valueOf(name)
81
+
82
+ internal fun Service.toCandleModel(): CandleService {
83
+ return CandleService(
84
+ id = id.toCandleModel(),
85
+ displayName = displayName,
86
+ logoURL = logoURL,
87
+ thumbhash = thumbhash,
88
+ accentColor = accentColor,
89
+ )
90
+ }
91
+
92
+ internal fun CandleService.toReactModel(): Service {
93
+ return Service(
94
+ id = id.toReactModel(),
95
+ displayName = displayName,
96
+ logoURL = logoURL,
97
+ thumbhash = thumbhash,
98
+ accentColor = accentColor,
99
+ )
100
+ }
71
101
 
72
102
  internal fun LinkedAccountRef.toGetLinkedAccountRef(): Operations.GetLinkedAccount.Input.Path {
73
103
  return Operations.GetLinkedAccount.Input.Path(
@@ -350,6 +380,8 @@ internal fun CandleTradeAsset.toReactModel(): TradeAsset {
350
380
  stockAsset = null,
351
381
  transportAsset = null,
352
382
  eventAsset = null,
383
+ messageThreadAsset = null,
384
+ friendRequestAsset = null,
353
385
  otherAsset = null,
354
386
  nothingAsset = null,
355
387
  )
@@ -374,6 +406,8 @@ internal fun CandleTradeAsset.toReactModel(): TradeAsset {
374
406
  stockAsset = null,
375
407
  transportAsset = null,
376
408
  eventAsset = null,
409
+ messageThreadAsset = null,
410
+ friendRequestAsset = null,
377
411
  otherAsset = null,
378
412
  nothingAsset = null,
379
413
  )
@@ -398,6 +432,8 @@ internal fun CandleTradeAsset.toReactModel(): TradeAsset {
398
432
  ),
399
433
  transportAsset = null,
400
434
  eventAsset = null,
435
+ messageThreadAsset = null,
436
+ friendRequestAsset = null,
401
437
  otherAsset = null,
402
438
  nothingAsset = null,
403
439
  )
@@ -427,6 +463,8 @@ internal fun CandleTradeAsset.toReactModel(): TradeAsset {
427
463
  service = service.toReactModel(),
428
464
  ),
429
465
  eventAsset = null,
466
+ messageThreadAsset = null,
467
+ friendRequestAsset = null,
430
468
  otherAsset = null,
431
469
  nothingAsset = null,
432
470
  )
@@ -452,6 +490,67 @@ internal fun CandleTradeAsset.toReactModel(): TradeAsset {
452
490
  linkedAccountID = linkedAccountID.toString(),
453
491
  service = service.toReactModel(),
454
492
  ),
493
+ messageThreadAsset = null,
494
+ friendRequestAsset = null,
495
+ otherAsset = null,
496
+ nothingAsset = null,
497
+ )
498
+
499
+ is CandleMessageThreadAsset ->
500
+ TradeAsset(
501
+ fiatAsset = null,
502
+ cryptoAsset = null,
503
+ stockAsset = null,
504
+ transportAsset = null,
505
+ eventAsset = null,
506
+ messageThreadAsset =
507
+ MessageThreadAsset(
508
+ assetKind = "message_thread",
509
+ serviceTradeID = serviceTradeID,
510
+ messages =
511
+ messages
512
+ .map {
513
+ MessageThreadMessage(
514
+ serviceMessageID = it.serviceMessageID,
515
+ senderProfileURN = it.senderProfileURN,
516
+ senderLegalName = it.senderLegalName,
517
+ senderUsername = it.senderUsername,
518
+ text = it.text,
519
+ dateTime = it.dateTime,
520
+ )
521
+ }
522
+ .toTypedArray(),
523
+ linkedAccountID = linkedAccountID.toString(),
524
+ service = service.toReactModel(),
525
+ ),
526
+ friendRequestAsset = null,
527
+ otherAsset = null,
528
+ nothingAsset = null,
529
+ )
530
+
531
+ is CandleFriendRequestAsset ->
532
+ TradeAsset(
533
+ fiatAsset = null,
534
+ cryptoAsset = null,
535
+ stockAsset = null,
536
+ transportAsset = null,
537
+ eventAsset = null,
538
+ messageThreadAsset = null,
539
+ friendRequestAsset =
540
+ FriendRequestAsset(
541
+ assetKind = "friend_request",
542
+ serviceTradeID = serviceTradeID,
543
+ direction = direction.toReactModel(),
544
+ user =
545
+ UserCounterparty(
546
+ kind = "user",
547
+ legalName = user.legalName,
548
+ avatarURL = user.avatarURL,
549
+ username = user.username,
550
+ ),
551
+ linkedAccountID = linkedAccountID.toString(),
552
+ service = service.toReactModel(),
553
+ ),
455
554
  otherAsset = null,
456
555
  nothingAsset = null,
457
556
  )
@@ -463,6 +562,8 @@ internal fun CandleTradeAsset.toReactModel(): TradeAsset {
463
562
  stockAsset = null,
464
563
  transportAsset = null,
465
564
  eventAsset = null,
565
+ messageThreadAsset = null,
566
+ friendRequestAsset = null,
466
567
  otherAsset = OtherAsset(assetKind = "other"),
467
568
  nothingAsset = null,
468
569
  )
@@ -474,6 +575,8 @@ internal fun CandleTradeAsset.toReactModel(): TradeAsset {
474
575
  stockAsset = null,
475
576
  transportAsset = null,
476
577
  eventAsset = null,
578
+ messageThreadAsset = null,
579
+ friendRequestAsset = null,
477
580
  otherAsset = null,
478
581
  nothingAsset = NothingAsset(assetKind = "nothing"),
479
582
  )
@@ -553,6 +656,33 @@ internal fun TradeAsset.toCandleModel(): CandleTradeAsset {
553
656
  service = it.service.toCandleModel(),
554
657
  )
555
658
  }
659
+ messageThreadAsset?.let {
660
+ return CandleMessageThreadAsset(
661
+ serviceTradeID = it.serviceTradeID,
662
+ linkedAccountID = UUID.fromString(it.linkedAccountID),
663
+ messages =
664
+ it.messages.map { message ->
665
+ CandleMessageThreadMessage(
666
+ serviceMessageID = message.serviceMessageID,
667
+ senderProfileURN = message.senderProfileURN,
668
+ senderLegalName = message.senderLegalName,
669
+ senderUsername = message.senderUsername,
670
+ text = message.text,
671
+ dateTime = message.dateTime,
672
+ )
673
+ },
674
+ service = it.service.toCandleModel(),
675
+ )
676
+ }
677
+ friendRequestAsset?.let {
678
+ return CandleFriendRequestAsset(
679
+ serviceTradeID = it.serviceTradeID,
680
+ direction = it.direction.toCandleModel(),
681
+ user = it.user.toCandleModel(),
682
+ linkedAccountID = UUID.fromString(it.linkedAccountID),
683
+ service = it.service.toCandleModel(),
684
+ )
685
+ }
556
686
  if (otherAsset != null) return CandleOtherAsset
557
687
  if (nothingAsset != null) return CandleNothingAsset
558
688
  error("Internal Candle Error: corrupted trade asset.")
@@ -579,6 +709,10 @@ internal fun Counterparty.toCandleModel(): CandleCounterparty {
579
709
  error("Internal Candle Error: corrupted counterparty.")
580
710
  }
581
711
 
712
+ internal fun UserCounterparty.toCandleModel(): CandleUserCounterparty {
713
+ return CandleUserCounterparty(legalName = legalName, avatarURL = avatarURL, username = username)
714
+ }
715
+
582
716
  internal fun CandleMerchantLocation.toReactModel(): MerchantLocation {
583
717
  return MerchantLocation(
584
718
  countryCode = countryCode,
@@ -664,6 +798,12 @@ internal fun TradeAssetQuoteRequest.toCandleModel(): CandleTradeAssetQuoteReques
664
798
  dateTime = it.dateTime,
665
799
  )
666
800
  }
801
+ messageThreadAssetQuoteRequest?.let {
802
+ return CandleMessageThreadAssetQuoteRequest(text = it.text)
803
+ }
804
+ friendRequestAssetQuoteRequest?.let {
805
+ return CandleFriendRequestAssetQuoteRequest(action = it.action.toCandleModel())
806
+ }
667
807
  if (nothingAssetQuoteRequest != null) return CandleNothingAssetQuoteRequest
668
808
  if (otherAssetQuoteRequest != null) return CandleOtherAssetQuoteRequest
669
809
  error("Internal Candle Error: corrupted trade asset quote request.")
@@ -716,6 +856,18 @@ internal fun TradeAssetRef.toCandleModel(): CandleTradeAssetRef {
716
856
  serviceTradeID = it.serviceTradeID,
717
857
  )
718
858
  }
859
+ messageThreadAssetRef?.let {
860
+ return CandleMessageThreadAssetRef(
861
+ linkedAccountID = UUID.fromString(it.linkedAccountID),
862
+ serviceTradeID = it.serviceTradeID,
863
+ )
864
+ }
865
+ friendRequestAssetRef?.let {
866
+ return CandleFriendRequestAssetRef(
867
+ linkedAccountID = UUID.fromString(it.linkedAccountID),
868
+ serviceTradeID = it.serviceTradeID,
869
+ )
870
+ }
719
871
  if (otherAssetRef != null) return CandleOtherAsset
720
872
  if (nothingAssetRef != null) return CandleNothingAsset
721
873
  error("Internal Candle Error: corrupted trade asset ref.")
@@ -737,6 +889,33 @@ internal fun CandleLinkedAccountStatusRefState.toReactModel(): LinkedAccountStat
737
889
  }
738
890
  }
739
891
 
892
+ internal fun CandleFriendRequestAssetDirection.toReactModel(): FriendRequestAssetDirection {
893
+ return when (this) {
894
+ CandleFriendRequestAssetDirection.RECEIVED -> FriendRequestAssetDirection.RECEIVED
895
+ CandleFriendRequestAssetDirection.SENT -> FriendRequestAssetDirection.SENT
896
+ }
897
+ }
898
+
899
+ internal fun FriendRequestAssetDirection.toCandleModel(): CandleFriendRequestAssetDirection {
900
+ return when (this) {
901
+ FriendRequestAssetDirection.RECEIVED -> CandleFriendRequestAssetDirection.RECEIVED
902
+ FriendRequestAssetDirection.SENT -> CandleFriendRequestAssetDirection.SENT
903
+ }
904
+ }
905
+
906
+ internal fun FriendRequestAssetQuoteRequestAction.toCandleModel():
907
+ CandleFriendRequestAssetQuoteRequestAction {
908
+ return when (this) {
909
+ FriendRequestAssetQuoteRequestAction.ACCEPT ->
910
+ CandleFriendRequestAssetQuoteRequestAction.ACCEPT
911
+ FriendRequestAssetQuoteRequestAction.REJECT ->
912
+ CandleFriendRequestAssetQuoteRequestAction.REJECT
913
+ FriendRequestAssetQuoteRequestAction.SEND -> CandleFriendRequestAssetQuoteRequestAction.SEND
914
+ FriendRequestAssetQuoteRequestAction.WITHDRAW ->
915
+ CandleFriendRequestAssetQuoteRequestAction.WITHDRAW
916
+ }
917
+ }
918
+
740
919
  internal fun CandleACHAccountKind.toReactModel(): ACHAccountKind = ACHAccountKind.valueOf(name)
741
920
 
742
921
  internal fun CandleFinancialAccountKind.toReactModel(): FinancialAccountKind {
@@ -783,6 +962,10 @@ internal fun TradeAssetKind.toCandleGainedAssetKind():
783
962
  TradeAssetKind.TRANSPORT ->
784
963
  Operations.GetTrades.Input.Query.GainedAssetKindPayload.TRANSPORT
785
964
  TradeAssetKind.EVENT -> Operations.GetTrades.Input.Query.GainedAssetKindPayload.EVENT
965
+ TradeAssetKind.MESSAGE_THREAD ->
966
+ Operations.GetTrades.Input.Query.GainedAssetKindPayload.MESSAGE_THREAD
967
+ TradeAssetKind.FRIEND_REQUEST ->
968
+ Operations.GetTrades.Input.Query.GainedAssetKindPayload.FRIEND_REQUEST
786
969
  TradeAssetKind.OTHER -> Operations.GetTrades.Input.Query.GainedAssetKindPayload.OTHER
787
970
  TradeAssetKind.NOTHING -> Operations.GetTrades.Input.Query.GainedAssetKindPayload.NOTHING
788
971
  }
@@ -796,6 +979,10 @@ internal fun TradeAssetKind.toCandleLostAssetKind():
796
979
  TradeAssetKind.CRYPTO -> Operations.GetTrades.Input.Query.LostAssetKindPayload.CRYPTO
797
980
  TradeAssetKind.TRANSPORT -> Operations.GetTrades.Input.Query.LostAssetKindPayload.TRANSPORT
798
981
  TradeAssetKind.EVENT -> Operations.GetTrades.Input.Query.LostAssetKindPayload.EVENT
982
+ TradeAssetKind.MESSAGE_THREAD ->
983
+ Operations.GetTrades.Input.Query.LostAssetKindPayload.MESSAGE_THREAD
984
+ TradeAssetKind.FRIEND_REQUEST ->
985
+ Operations.GetTrades.Input.Query.LostAssetKindPayload.FRIEND_REQUEST
799
986
  TradeAssetKind.OTHER -> Operations.GetTrades.Input.Query.LostAssetKindPayload.OTHER
800
987
  TradeAssetKind.NOTHING -> Operations.GetTrades.Input.Query.LostAssetKindPayload.NOTHING
801
988
  }
@@ -10,18 +10,19 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
10
10
  import com.margelo.nitro.NitroModules
11
11
  import com.margelo.nitro.core.Promise
12
12
  import fi.candle.Candle
13
- import fi.candle.client.supportedServices
14
13
  import fi.candle.ui.CandleUiContent
15
14
  import fi.candle.ui.models.PresentationStyle as CandlePresentationStyle
16
15
  import java.util.concurrent.atomic.AtomicBoolean
17
16
 
18
17
  class HybridRNCandle : HybridRNCandleSpec() {
19
18
  private val mainHandler = Handler(Looper.getMainLooper())
19
+ private val hostedAuthorizationRequests =
20
+ mutableMapOf<String, Candle.Client.HostedAuthorizationRequest>()
20
21
 
21
22
  private var linkSheetView: ComposeView? = null
22
23
  private var tradeSheetView: ComposeView? = null
23
24
 
24
- override fun initialize(appKey: String, appSecret: String, accessGroup: String?) {
25
+ override fun initialize(clientID: String, accessGroup: String?) {
25
26
  ReactNativeCandleOnLoad.initializeNative()
26
27
  val context =
27
28
  NitroModules.applicationContext
@@ -31,18 +32,19 @@ class HybridRNCandle : HybridRNCandleSpec() {
31
32
 
32
33
  // Android does not use the iOS keychain access-group concept.
33
34
  accessGroup?.let {}
34
- Candle.Client.initialize(context, appKey, appSecret)
35
+ Candle.Client.initialize(context, clientID)
35
36
  }
36
37
 
37
38
  override fun candleLinkSheet(
38
39
  isPresented: Boolean,
39
- services: Array<Service>?,
40
+ services: Array<ServiceID>?,
41
+ showSandbox: Boolean,
40
42
  cornerRadius: Double,
41
43
  customerName: String?,
42
44
  showDynamicLoading: Boolean,
43
45
  presentationBackground: PresentationBackground,
44
46
  presentationStyle: PresentationStyle,
45
- onSuccess: (account: LinkedAccount) -> Unit,
47
+ onSuccess: (linkedAccount: LinkedAccount) -> Unit,
46
48
  ) {
47
49
  runOnMainThread {
48
50
  if (!isPresented) {
@@ -57,7 +59,8 @@ class HybridRNCandle : HybridRNCandleSpec() {
57
59
  val composeView = createOverlayView(activity)
58
60
  composeView.setContent(
59
61
  CandleUiContent.candleLinkSheet(
60
- services = services?.map { it.toCandleModel() } ?: supportedServices,
62
+ services = services?.map { it.toCandleModel() } ?: emptyList(),
63
+ showSandbox = showSandbox,
61
64
  customerName = customerName,
62
65
  cornerRadiusDp = cornerRadius.toFloat(),
63
66
  showDynamicLoading = showDynamicLoading,
@@ -179,12 +182,62 @@ class HybridRNCandle : HybridRNCandleSpec() {
179
182
  }
180
183
  }
181
184
 
182
- override fun createUser(appUserID: String): Promise<Unit> {
183
- return Promise.async { Candle.Client.shared.createUser(appUserID) }
185
+ override fun hostedAuthorizationUrl(
186
+ redirectUri: String,
187
+ state: String,
188
+ codeChallenge: String,
189
+ grantPackagePublicKey: String,
190
+ ): String {
191
+ return Candle.Client.shared.hostedAuthorizationUrl(
192
+ redirectUri = redirectUri,
193
+ state = state,
194
+ codeChallenge = codeChallenge,
195
+ grantPackagePublicKey = grantPackagePublicKey,
196
+ )
184
197
  }
185
198
 
186
- override fun deleteUser(): Promise<Unit> {
187
- return Promise.async { Candle.Client.shared.deleteUser() }
199
+ override fun makeHostedAuthorizationRequest(
200
+ redirectUri: String,
201
+ state: String?,
202
+ ): HostedAuthorizationRequest {
203
+ val request =
204
+ Candle.Client.shared.makeHostedAuthorizationRequest(
205
+ redirectUri = redirectUri,
206
+ state = state,
207
+ )
208
+ hostedAuthorizationRequests[request.state] = request
209
+ return HostedAuthorizationRequest(
210
+ url = request.url,
211
+ state = request.state,
212
+ codeVerifier = request.codeVerifier,
213
+ grantPackagePublicKey = request.grantPackagePublicKey,
214
+ )
215
+ }
216
+
217
+ override fun parseHostedAuthorizationCallback(
218
+ callbackUrl: String
219
+ ): HostedAuthorizationCallback {
220
+ val callback = Candle.Client.shared.parseHostedAuthorizationCallback(callbackUrl)
221
+ return HostedAuthorizationCallback(
222
+ authorizationCode = callback.authorizationCode,
223
+ encryptedGrantPackage = callback.encryptedGrantPackage,
224
+ state = callback.state,
225
+ )
226
+ }
227
+
228
+ override fun completeHostedAuthorization(callbackUrl: String): Promise<Unit> {
229
+ return Promise.async {
230
+ val callback = Candle.Client.shared.parseHostedAuthorizationCallback(callbackUrl)
231
+ val state = callback.state ?: error("Candle hosted auth callback is missing state.")
232
+ val request =
233
+ hostedAuthorizationRequests.remove(state)
234
+ ?: error("Candle hosted auth state was not started.")
235
+ Candle.Client.shared.completeHostedAuthorization(request, callbackUrl)
236
+ }
237
+ }
238
+
239
+ override fun signOut(): Promise<Unit> {
240
+ return Promise.async { Candle.Client.shared.signOut() }
188
241
  }
189
242
 
190
243
  private fun runOnMainThread(block: () -> Unit) {
@@ -27,7 +27,8 @@ import SwiftUI
27
27
  isPresented: $viewModel.showSheet,
28
28
  customerName: viewModel.customerName,
29
29
  cornerRadius: viewModel.cornerRadius,
30
- services: services.map(Models.Service.init(reactModel:)),
30
+ services: services.map(Models.ServiceID.init(reactModel:)),
31
+ showSandbox: viewModel.showSandbox,
31
32
  showDynamicLoading: viewModel.showDynamicLoading,
32
33
  presentationStyle: viewModel.toCandlePresentationStyle,
33
34
  presentationBackground: viewModel.toCandlePresentationBackground
@@ -39,7 +40,7 @@ import SwiftUI
39
40
  isPresented: $viewModel.showSheet,
40
41
  customerName: viewModel.customerName,
41
42
  cornerRadius: viewModel.cornerRadius,
42
- services: .supported,
43
+ showSandbox: viewModel.showSandbox,
43
44
  showDynamicLoading: viewModel.showDynamicLoading,
44
45
  presentationStyle: viewModel.toCandlePresentationStyle,
45
46
  presentationBackground: viewModel.toCandlePresentationBackground
@@ -6,7 +6,8 @@ import SwiftUI
6
6
  @Published var showSheet = false
7
7
  @Published var linkedAccount: Models.LinkedAccount?
8
8
  @Published var isPresented: Bool = false
9
- @Published var services: [Service]?
9
+ @Published var services: [ServiceID]?
10
+ @Published var showSandbox = false
10
11
  @Published var cornerRadius: Double = 0
11
12
  @Published var customerName: String?
12
13
  @Published var showDynamicLoading: Bool = false
@@ -7,10 +7,13 @@ import UIKit
7
7
 
8
8
  @available(iOS 17.0, *) final class HybridRNCandle: HybridRNCandleSpec {
9
9
  private var rootVC: UIHostingController<CandleLinkSheetWrapper>?
10
+ private var hostedAuthorizationRequests = [String: Candle.HostedAuthorizationRequest]()
10
11
 
11
12
  private var cancellables = Set<AnyCancellable>()
12
13
  private var linkSheetPresentationCancellable: AnyCancellable?
13
14
  private var linkSheetSuccessCancellable: AnyCancellable?
15
+ private var linkSheetSuccessCallback: ((LinkedAccount) -> Void)?
16
+ private var linkSheetSuccessCallbackToken = 0
14
17
 
15
18
  var viewModel: CandleLinkViewModel {
16
19
  get throws {
@@ -21,8 +24,8 @@ import UIKit
21
24
 
22
25
  // MARK: - UI
23
26
 
24
- public func initialize(appKey: String, appSecret: String, accessGroup: String?) throws {
25
- try Client.initialize(appKey: appKey, appSecret: appSecret, accessGroup: accessGroup)
27
+ public func initialize(clientID: String, accessGroup: String?) throws {
28
+ try Client.initialize(clientID: clientID, accessGroup: accessGroup)
26
29
  Task { @MainActor in
27
30
  let wrapperView = CandleLinkSheetWrapper()
28
31
  let hostingVC = UIHostingController(rootView: wrapperView)
@@ -32,7 +35,8 @@ import UIKit
32
35
 
33
36
  public func candleLinkSheet(
34
37
  isPresented: Bool,
35
- services: [Service]?,
38
+ services: [ServiceID]?,
39
+ showSandbox: Bool,
36
40
  cornerRadius: Double,
37
41
  customerName: String?,
38
42
  showDynamicLoading: Bool,
@@ -43,10 +47,14 @@ import UIKit
43
47
  Task { @MainActor in
44
48
  linkSheetPresentationCancellable?.cancel()
45
49
  linkSheetSuccessCancellable?.cancel()
50
+ linkSheetSuccessCallback = onSuccess
51
+ linkSheetSuccessCallbackToken += 1
52
+ let callbackToken = linkSheetSuccessCallbackToken
46
53
 
47
54
  try viewModel.linkedAccount = nil
48
55
  try viewModel.isPresented = isPresented
49
56
  try viewModel.services = services
57
+ try viewModel.showSandbox = showSandbox
50
58
  try viewModel.cornerRadius = cornerRadius
51
59
  try viewModel.customerName = customerName
52
60
  try viewModel.showDynamicLoading = showDynamicLoading
@@ -80,8 +88,15 @@ import UIKit
80
88
  if let rootVC = self?.rootVC, !isPresented { parentVC.removeEmbedded(rootVC) }
81
89
  })
82
90
  linkSheetSuccessCancellable = try viewModel.$linkedAccount.removeDuplicates()
83
- .compactMap(\.?.reactModel).prefix(1).receive(on: RunLoop.main)
84
- .sink(receiveValue: onSuccess)
91
+ .compactMap { $0 }.prefix(1).receive(on: RunLoop.main)
92
+ .sink { [weak self] linkedAccount in
93
+ self?.linkSheetSuccessCallback?(linkedAccount.reactModel)
94
+ DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in
95
+ if self?.linkSheetSuccessCallbackToken == callbackToken {
96
+ self?.linkSheetSuccessCallback = nil
97
+ }
98
+ }
99
+ }
85
100
  }
86
101
  }
87
102
 
@@ -215,13 +230,75 @@ import UIKit
215
230
  }
216
231
  }
217
232
 
218
- public func createUser(appUserID: String) throws -> Promise<Void> {
219
- .async { try await Client.shared.createUser(appUserID: appUserID) }
233
+ public func hostedAuthorizationUrl(
234
+ redirectUri: String,
235
+ state: String,
236
+ codeChallenge: String,
237
+ grantPackagePublicKey: String
238
+ ) throws -> String {
239
+ return Client.shared
240
+ .hostedAuthorizationURL(
241
+ redirectURI: redirectUri,
242
+ state: state,
243
+ codeChallenge: codeChallenge,
244
+ grantPackagePublicKey: grantPackagePublicKey
245
+ )
246
+ .absoluteString
247
+ }
248
+
249
+ public func makeHostedAuthorizationRequest(redirectUri: String, state: String?) throws
250
+ -> HostedAuthorizationRequest
251
+ {
252
+ let request = try Client.shared.makeHostedAuthorizationRequest(
253
+ redirectURI: redirectUri,
254
+ state: state
255
+ )
256
+ hostedAuthorizationRequests[request.state] = request
257
+ return HostedAuthorizationRequest(
258
+ url: request.url.absoluteString,
259
+ state: request.state,
260
+ codeVerifier: request.codeVerifier,
261
+ grantPackagePublicKey: request.grantPackagePublicKey
262
+ )
263
+ }
264
+
265
+ public func parseHostedAuthorizationCallback(callbackUrl: String) throws
266
+ -> HostedAuthorizationCallback
267
+ {
268
+ guard let url = URL(string: callbackUrl),
269
+ let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
270
+ let authorizationCode = components.queryItems?.first(where: { $0.name == "code" })?
271
+ .value
272
+ else { throw CandleError.unexpected(message: "Invalid Candle hosted auth callback.") }
273
+ let encryptedGrantPackage =
274
+ components.queryItems?.first(where: { $0.name == "candle_grant_package" })?.value
275
+ ?? URLComponents(string: "?\(components.fragment ?? "")")?.queryItems?
276
+ .first(where: { $0.name == "candle_grant_package" })?
277
+ .value
278
+ guard let encryptedGrantPackage else {
279
+ throw CandleError.unexpected(message: "Invalid Candle hosted auth callback.")
280
+ }
281
+ return HostedAuthorizationCallback(
282
+ authorizationCode: authorizationCode,
283
+ state: components.queryItems?.first(where: { $0.name == "state" })?.value,
284
+ encryptedGrantPackage: encryptedGrantPackage
285
+ )
220
286
  }
221
287
 
222
- public func deleteUser() throws -> Promise<Void> {
223
- .async { try await Client.shared.deleteUser() }
288
+ public func completeHostedAuthorization(callbackUrl: String) throws -> Promise<Void> {
289
+ guard let url = URL(string: callbackUrl) else {
290
+ throw CandleError.unexpected(message: "Invalid Candle hosted auth callback.")
291
+ }
292
+ let callback = try parseHostedAuthorizationCallback(callbackUrl: callbackUrl)
293
+ guard let state = callback.state,
294
+ let request = hostedAuthorizationRequests.removeValue(forKey: state)
295
+ else { throw CandleError.unexpected(message: "Candle hosted auth state was not started.") }
296
+ return .async {
297
+ try await Client.shared.completeHostedAuthorization(request: request, callbackURL: url)
298
+ }
224
299
  }
300
+
301
+ public func signOut() throws -> Promise<Void> { .async { try await Client.shared.signOut() } }
225
302
  }
226
303
 
227
304
  extension UIViewController {