@dynamic-labs-sdk/client 1.6.0 → 1.8.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 (135) hide show
  1. package/android/build.gradle +231 -0
  2. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  3. package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  4. package/android/gradle.properties +8 -0
  5. package/android/gradlew +251 -0
  6. package/android/gradlew.bat +94 -0
  7. package/android/settings.gradle +30 -0
  8. package/android/src/main/java/xyz/dynamic/client/DynamicClientPackage.kt +52 -0
  9. package/android/src/main/java/xyz/dynamic/client/keychain/KeyStoreKeyManager.kt +147 -0
  10. package/android/src/main/java/xyz/dynamic/client/keychain/KeychainModule.kt +85 -0
  11. package/android/src/main/java/xyz/dynamic/client/manifest/ReactNativeManifestModule.kt +25 -0
  12. package/android/src/main/java/xyz/dynamic/client/webview/DynamicWebViewClient.kt +83 -0
  13. package/android/src/main/java/xyz/dynamic/client/webview/DynamicWebViewHost.kt +518 -0
  14. package/android/src/main/java/xyz/dynamic/client/webview/DynamicWebViewModule.kt +147 -0
  15. package/android/src/test/java/xyz/dynamic/client/keychain/KeyStoreKeyManagerTest.kt +288 -0
  16. package/android/src/test/java/xyz/dynamic/client/webview/DynamicWebViewClientTest.kt +196 -0
  17. package/android/src/test/java/xyz/dynamic/client/webview/DynamicWebViewHostOpenTest.kt +347 -0
  18. package/android/src/test/java/xyz/dynamic/client/webview/DynamicWebViewHostTest.kt +171 -0
  19. package/android/src/test/java/xyz/dynamic/client/webview/DynamicWebViewModuleTest.kt +191 -0
  20. package/dist/{InvalidParamError-BIptAjbC.native.esm.js → InvalidParamError-Bc6OZBog.native.esm.js} +91 -829
  21. package/dist/InvalidParamError-Bc6OZBog.native.esm.js.map +1 -0
  22. package/dist/{InvalidParamError-BZ0LHaml.esm.js → InvalidParamError-IHYLdzFd.esm.js} +108 -381
  23. package/dist/InvalidParamError-IHYLdzFd.esm.js.map +1 -0
  24. package/dist/{InvalidParamError-DyXEKMWn.cjs → InvalidParamError-S56rFFDP.cjs} +108 -450
  25. package/dist/InvalidParamError-S56rFFDP.cjs.map +1 -0
  26. package/dist/{NotWaasWalletAccountError-nT4jrLbp.esm.js → NotWaasWalletAccountError-BP-bODbJ.native.esm.js} +4 -4
  27. package/dist/NotWaasWalletAccountError-BP-bODbJ.native.esm.js.map +1 -0
  28. package/dist/{NotWaasWalletAccountError-BbOA5rPd.native.esm.js → NotWaasWalletAccountError-BYEL2l-W.esm.js} +4 -4
  29. package/dist/NotWaasWalletAccountError-BYEL2l-W.esm.js.map +1 -0
  30. package/dist/{NotWaasWalletAccountError-CElqwdQO.cjs → NotWaasWalletAccountError-CbhIKUDM.cjs} +4 -4
  31. package/dist/NotWaasWalletAccountError-CbhIKUDM.cjs.map +1 -0
  32. package/dist/core.cjs +11 -11
  33. package/dist/core.cjs.map +1 -1
  34. package/dist/core.esm.js +5 -5
  35. package/dist/core.native.esm.js +7 -7
  36. package/dist/core.native.esm.js.map +1 -1
  37. package/dist/errors/WebViewLoadFailedError.d.ts +1 -1
  38. package/dist/errors/WebViewLoadFailedError.d.ts.map +1 -1
  39. package/dist/exports/index.d.ts +2 -0
  40. package/dist/exports/index.d.ts.map +1 -1
  41. package/dist/{getNetworkProviderFromNetworkId-DbI5MZhq.cjs → getNetworkProviderFromNetworkId-BDdcpGHH.cjs} +56 -55
  42. package/dist/{getNetworkProviderFromNetworkId-DbI5MZhq.cjs.map → getNetworkProviderFromNetworkId-BDdcpGHH.cjs.map} +1 -1
  43. package/dist/{getNetworkProviderFromNetworkId-BkAPIdRC.esm.js → getNetworkProviderFromNetworkId-D8rWYXlT.esm.js} +54 -54
  44. package/dist/{getNetworkProviderFromNetworkId-BkAPIdRC.esm.js.map → getNetworkProviderFromNetworkId-D8rWYXlT.esm.js.map} +1 -1
  45. package/dist/{getNetworkProviderFromNetworkId-B7DIqT2T.native.esm.js → getNetworkProviderFromNetworkId-DVmF7pH2.native.esm.js} +312 -41
  46. package/dist/getNetworkProviderFromNetworkId-DVmF7pH2.native.esm.js.map +1 -0
  47. package/dist/{getSignedSessionId-BF6n8gve.cjs → getSignedSessionId-BBaBCi9S.cjs} +3 -3
  48. package/dist/{getSignedSessionId-BF6n8gve.cjs.map → getSignedSessionId-BBaBCi9S.cjs.map} +1 -1
  49. package/dist/{getSignedSessionId-y3YtxFHZ.esm.js → getSignedSessionId-CND07Eca.esm.js} +3 -3
  50. package/dist/{getSignedSessionId-y3YtxFHZ.esm.js.map → getSignedSessionId-CND07Eca.esm.js.map} +1 -1
  51. package/dist/{getSignedSessionId-1TV-x__C.native.esm.js → getSignedSessionId-RwV7JPn8.native.esm.js} +3 -3
  52. package/dist/{getSignedSessionId-1TV-x__C.native.esm.js.map → getSignedSessionId-RwV7JPn8.native.esm.js.map} +1 -1
  53. package/dist/getVerifiedCredentialForWalletAccount-BVrGV8qf.native.esm.js +701 -0
  54. package/dist/getVerifiedCredentialForWalletAccount-BVrGV8qf.native.esm.js.map +1 -0
  55. package/dist/{getVerifiedCredentialForWalletAccount-etV50QRH.esm.js → getVerifiedCredentialForWalletAccount-BiOS65Tk.esm.js} +2 -2
  56. package/dist/{getVerifiedCredentialForWalletAccount-etV50QRH.esm.js.map → getVerifiedCredentialForWalletAccount-BiOS65Tk.esm.js.map} +1 -1
  57. package/dist/{getVerifiedCredentialForWalletAccount-BfJ29erz.cjs → getVerifiedCredentialForWalletAccount-FrxYWSuD.cjs} +3 -2
  58. package/dist/{getVerifiedCredentialForWalletAccount-BfJ29erz.cjs.map → getVerifiedCredentialForWalletAccount-FrxYWSuD.cjs.map} +1 -1
  59. package/dist/index.cjs +35 -35
  60. package/dist/index.cjs.map +1 -1
  61. package/dist/index.esm.js +14 -14
  62. package/dist/index.esm.js.map +1 -1
  63. package/dist/index.native.esm.js +14 -14
  64. package/dist/index.native.esm.js.map +1 -1
  65. package/dist/isMfaRequiredForAction-BPL_dgIM.esm.js +318 -0
  66. package/dist/isMfaRequiredForAction-BPL_dgIM.esm.js.map +1 -0
  67. package/dist/isMfaRequiredForAction-BolTrtCO.cjs +405 -0
  68. package/dist/isMfaRequiredForAction-BolTrtCO.cjs.map +1 -0
  69. package/dist/{isMfaRequiredForAction-B2vKX31S.native.esm.js → isMfaRequiredForAction-DQDoPsi6.native.esm.js} +2 -2
  70. package/dist/{isMfaRequiredForAction-B2vKX31S.native.esm.js.map → isMfaRequiredForAction-DQDoPsi6.native.esm.js.map} +1 -1
  71. package/dist/modules/apiClient/apiClient.types.d.ts +0 -12
  72. package/dist/modules/apiClient/apiClient.types.d.ts.map +1 -1
  73. package/dist/modules/apiClient/createApiClient.d.ts.map +1 -1
  74. package/dist/modules/auth/logoutReason.d.ts +1 -1
  75. package/dist/modules/auth/logoutReason.d.ts.map +1 -1
  76. package/dist/modules/auth/logoutWithReason/logoutWithReason.d.ts.map +1 -1
  77. package/dist/modules/deviceRegistration/getRegisteredDevices/getRegisteredDevices.d.ts.map +1 -1
  78. package/dist/modules/user/refreshAuth/refreshAuth.d.ts.map +1 -1
  79. package/dist/modules/waas/backupWaasKeySharesToGoogleDrive/backupWaasKeySharesToGoogleDrive.d.ts +12 -1
  80. package/dist/modules/waas/backupWaasKeySharesToGoogleDrive/backupWaasKeySharesToGoogleDrive.d.ts.map +1 -1
  81. package/dist/modules/waas/createWaasClient/createWaasClient.d.ts.map +1 -1
  82. package/dist/modules/waas/createWaasClient/translateNativeOpenError.d.ts.map +1 -1
  83. package/dist/modules/waas/createWaasProvider/createWaasProvider.d.ts.map +1 -1
  84. package/dist/modules/waas/waas.types.d.ts +1 -0
  85. package/dist/modules/waas/waas.types.d.ts.map +1 -1
  86. package/dist/modules/wallets/walletProvider/events/onWalletProviderEvent/onWalletProviderEvent.d.ts +1 -2
  87. package/dist/modules/wallets/walletProvider/events/onWalletProviderEvent/onWalletProviderEvent.d.ts.map +1 -1
  88. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  89. package/dist/waas.cjs +7 -4
  90. package/dist/waas.cjs.map +1 -1
  91. package/dist/waas.esm.js +6 -4
  92. package/dist/waas.esm.js.map +1 -1
  93. package/dist/waas.native.esm.js +6 -4
  94. package/dist/waas.native.esm.js.map +1 -1
  95. package/dist/waasCore.cjs +10 -5
  96. package/dist/waasCore.cjs.map +1 -1
  97. package/dist/waasCore.esm.js +10 -5
  98. package/dist/waasCore.esm.js.map +1 -1
  99. package/dist/waasCore.native.esm.js +10 -8
  100. package/dist/waasCore.native.esm.js.map +1 -1
  101. package/dynamic-labs-sdk-client.podspec +27 -0
  102. package/ios/DynamicClientKeychain.h +4 -0
  103. package/ios/DynamicClientKeychain.mm +101 -0
  104. package/ios/DynamicClientManifest.h +4 -0
  105. package/ios/DynamicClientManifest.mm +45 -0
  106. package/ios/DynamicClientWebView.h +5 -0
  107. package/ios/DynamicClientWebView.mm +143 -0
  108. package/ios/DynamicWebViewImpl.swift +603 -0
  109. package/ios/LiveSecKeyAPI.swift +86 -0
  110. package/ios/ReactNativeManifestImpl.swift +20 -0
  111. package/ios/SecKeyAPI.swift +57 -0
  112. package/ios/SecureEnclaveKeyManager.swift +191 -0
  113. package/package.json +16 -5
  114. package/react-native.config.cjs +14 -0
  115. package/src/turboModules/NativeDynamicWebView.native.spec.ts +61 -0
  116. package/src/turboModules/NativeDynamicWebView.ts +40 -0
  117. package/src/turboModules/NativeKeychain.native.spec.ts +47 -0
  118. package/src/turboModules/NativeKeychain.ts +19 -0
  119. package/src/turboModules/NativeReactNativeManifest.native.spec.ts +55 -0
  120. package/src/turboModules/NativeReactNativeManifest.ts +28 -0
  121. package/dist/InvalidParamError-BIptAjbC.native.esm.js.map +0 -1
  122. package/dist/InvalidParamError-BZ0LHaml.esm.js.map +0 -1
  123. package/dist/InvalidParamError-DyXEKMWn.cjs.map +0 -1
  124. package/dist/NotWaasWalletAccountError-BbOA5rPd.native.esm.js.map +0 -1
  125. package/dist/NotWaasWalletAccountError-CElqwdQO.cjs.map +0 -1
  126. package/dist/NotWaasWalletAccountError-nT4jrLbp.esm.js.map +0 -1
  127. package/dist/getNetworkProviderFromNetworkId-B7DIqT2T.native.esm.js.map +0 -1
  128. package/dist/getVerifiedCredentialForWalletAccount-CLyC2nOl.native.esm.js +0 -269
  129. package/dist/getVerifiedCredentialForWalletAccount-CLyC2nOl.native.esm.js.map +0 -1
  130. package/dist/isMfaRequiredForAction-Dy4-S3mr.esm.js +0 -79
  131. package/dist/isMfaRequiredForAction-Dy4-S3mr.esm.js.map +0 -1
  132. package/dist/isMfaRequiredForAction-K2Jh-3-j.cjs +0 -96
  133. package/dist/isMfaRequiredForAction-K2Jh-3-j.cjs.map +0 -1
  134. package/dist/modules/apiClient/utils/sessionExpiryLogoutMiddleware/createSessionExpiryLogoutMiddleware.d.ts +0 -27
  135. package/dist/modules/apiClient/utils/sessionExpiryLogoutMiddleware/createSessionExpiryLogoutMiddleware.d.ts.map +0 -1
@@ -0,0 +1,191 @@
1
+ package xyz.dynamic.client.webview
2
+
3
+ import android.app.Activity
4
+ import android.net.Uri
5
+ import android.os.Looper
6
+ import android.webkit.WebView
7
+ import androidx.webkit.JavaScriptReplyProxy
8
+ import androidx.webkit.WebMessageCompat
9
+ import androidx.webkit.WebViewCompat
10
+ import androidx.webkit.WebViewFeature
11
+ import com.facebook.react.bridge.Arguments
12
+ import com.facebook.react.bridge.JavaOnlyArray
13
+ import com.facebook.react.bridge.JavaOnlyMap
14
+ import com.facebook.react.bridge.Promise
15
+ import com.facebook.react.bridge.ReactApplicationContext
16
+ import com.facebook.react.bridge.ReadableType
17
+ import com.facebook.react.bridge.WritableMap
18
+ import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
19
+ import io.mockk.CapturingSlot
20
+ import io.mockk.Runs
21
+ import io.mockk.every
22
+ import io.mockk.just
23
+ import io.mockk.mockk
24
+ import io.mockk.mockkStatic
25
+ import io.mockk.slot
26
+ import io.mockk.unmockkAll
27
+ import io.mockk.verify
28
+ import org.junit.After
29
+ import org.junit.Assert.assertEquals
30
+ import org.junit.Before
31
+ import org.junit.Test
32
+ import org.junit.runner.RunWith
33
+ import org.robolectric.Robolectric
34
+ import org.robolectric.RobolectricTestRunner
35
+ import org.robolectric.Shadows.shadowOf
36
+ import org.robolectric.annotation.Config
37
+
38
+ // The androidx.webkit + Arguments statics are mocked (they delegate to the
39
+ // device WebView / JNI). A real Robolectric Activity backs WebView construction
40
+ // so open() reaches the live-host state needed to exercise invalidate().
41
+ @RunWith(RobolectricTestRunner::class)
42
+ @Config(sdk = [35])
43
+ class DynamicWebViewModuleTest {
44
+
45
+ private lateinit var activity: Activity
46
+ private lateinit var reactContext: ReactApplicationContext
47
+ private lateinit var module: DynamicWebViewModule
48
+ private lateinit var eventEmitter: RCTDeviceEventEmitter
49
+ private lateinit var webSlot: CapturingSlot<WebView>
50
+ private lateinit var listenerSlot: CapturingSlot<WebViewCompat.WebMessageListener>
51
+
52
+ @Before
53
+ fun setUp() {
54
+ activity = Robolectric.buildActivity(Activity::class.java).setup().get()
55
+ reactContext = mockk(relaxed = true)
56
+ every { reactContext.currentActivity } returns activity
57
+ every { reactContext.runOnUiQueueThread(any()) } answers { firstArg<Runnable>().run() }
58
+
59
+ eventEmitter = mockk(relaxed = true)
60
+ every {
61
+ reactContext.getJSModule(RCTDeviceEventEmitter::class.java)
62
+ } returns eventEmitter
63
+
64
+ mockkStatic(Arguments::class)
65
+ every { Arguments.createMap() } answers { JavaOnlyMap() }
66
+ every { Arguments.createArray() } answers { JavaOnlyArray() }
67
+
68
+ mockkStatic(WebViewFeature::class)
69
+ every { WebViewFeature.isFeatureSupported(any()) } returns false
70
+ every {
71
+ WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)
72
+ } returns true
73
+
74
+ mockkStatic(WebViewCompat::class)
75
+ webSlot = slot()
76
+ listenerSlot = slot()
77
+ every {
78
+ WebViewCompat.addWebMessageListener(
79
+ capture(webSlot),
80
+ any(),
81
+ any(),
82
+ capture(listenerSlot),
83
+ )
84
+ } just Runs
85
+ every {
86
+ WebViewCompat.addDocumentStartJavaScript(any(), any(), any())
87
+ } returns mockk(relaxed = true)
88
+ every { WebViewCompat.setProfile(any(), any()) } just Runs
89
+
90
+ module = DynamicWebViewModule(reactContext)
91
+ }
92
+
93
+ @After
94
+ fun tearDown() {
95
+ unmockkAll()
96
+ }
97
+
98
+ private fun idleMain() = shadowOf(Looper.getMainLooper()).idle()
99
+
100
+ // region invalidate (#12 — ConcurrentModificationException)
101
+
102
+ @Test
103
+ fun invalidate_closesEveryActiveHostWithoutConcurrentModification() {
104
+ val p1 = mockk<Promise>(relaxed = true)
105
+ val p2 = mockk<Promise>(relaxed = true)
106
+
107
+ module.open("a", "https://app.dynamicauth.com/x", p1)
108
+ module.open("b", "https://app.dynamicauth.com/y", p2)
109
+ idleMain() // run the posted opens → two live hosts
110
+
111
+ module.invalidate()
112
+ idleMain() // run the posted close-all; the .toList() snapshot avoids CME
113
+
114
+ // Both hosts torn down (cancelled) proves the iteration completed across
115
+ // >1 host — without the snapshot this throws ConcurrentModificationException.
116
+ verify { p1.reject("webview_cancelled", any<String>(), any<WritableMap>()) }
117
+ verify { p2.reject("webview_cancelled", any<String>(), any<WritableMap>()) }
118
+ }
119
+
120
+ // endregion
121
+
122
+ // region emitMessage payload mapping (#13 — array payloads)
123
+
124
+ @Test
125
+ fun putBridgeData_mapsArrayPayloadOntoDataField() {
126
+ val target = JavaOnlyMap()
127
+ putBridgeData(target, JavaOnlyArray().apply { pushString("x") })
128
+ assertEquals(ReadableType.Array, target.getType("data"))
129
+ }
130
+
131
+ @Test
132
+ fun putBridgeData_mapsMapStringNullAndUnknownFallthrough() {
133
+ val map = JavaOnlyMap()
134
+
135
+ putBridgeData(map, JavaOnlyMap())
136
+ assertEquals(ReadableType.Map, map.getType("data"))
137
+
138
+ putBridgeData(map, "s")
139
+ assertEquals(ReadableType.String, map.getType("data"))
140
+
141
+ putBridgeData(map, null)
142
+ assertEquals(ReadableType.Null, map.getType("data"))
143
+
144
+ putBridgeData(map, 42)
145
+ assertEquals(ReadableType.Null, map.getType("data"))
146
+ }
147
+
148
+ // endregion
149
+
150
+ // region pre-listener event buffering (F4 — handshake not dropped)
151
+
152
+ // Drives a bridge message into the host's WebMessageListener so it flows
153
+ // through onBridgeMessage -> onMessage -> module.emitMessage.
154
+ private fun deliverBridgeMessage(payload: String) {
155
+ listenerSlot.captured.onPostMessage(
156
+ webSlot.captured,
157
+ mockk<WebMessageCompat> { every { data } returns payload },
158
+ Uri.parse("https://app.dynamicauth.com"),
159
+ true,
160
+ mockk<JavaScriptReplyProxy>(relaxed = true),
161
+ )
162
+ }
163
+
164
+ @Test
165
+ fun emitMessage_buffersBeforeFirstListenerThenFlushesOnSubscribe() {
166
+ module.open("a", "https://app.dynamicauth.com/x", mockk(relaxed = true))
167
+ idleMain()
168
+
169
+ // Handshake arrives before any JS listener subscribed → must be buffered,
170
+ // not emitted (RCTDeviceEventEmitter.emit would otherwise drop it).
171
+ deliverBridgeMessage("{\"type\":\"iframe-ready\"}")
172
+ verify(exactly = 0) { eventEmitter.emit(any(), any()) }
173
+
174
+ // First subscriber attaches → buffered event flushes.
175
+ module.addListener(DynamicWebViewModule.MESSAGE_EVENT_NAME)
176
+ verify { eventEmitter.emit(DynamicWebViewModule.MESSAGE_EVENT_NAME, any()) }
177
+ }
178
+
179
+ @Test
180
+ fun emitMessage_emitsDirectlyAfterListenerAttached() {
181
+ module.open("a", "https://app.dynamicauth.com/x", mockk(relaxed = true))
182
+ idleMain()
183
+ module.addListener(DynamicWebViewModule.MESSAGE_EVENT_NAME)
184
+
185
+ deliverBridgeMessage("{\"type\":\"sign\"}")
186
+
187
+ verify { eventEmitter.emit(DynamicWebViewModule.MESSAGE_EVENT_NAME, any()) }
188
+ }
189
+
190
+ // endregion
191
+ }