@thelacanians/vue-native-cli 0.4.2 → 0.4.4

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 (172) hide show
  1. package/dist/cli.js +43 -23
  2. package/native/android/README.md +205 -0
  3. package/native/android/VueNativeCore/build.gradle.kts +100 -0
  4. package/native/android/VueNativeCore/consumer-rules.pro +12 -0
  5. package/native/android/VueNativeCore/proguard-rules.pro +33 -0
  6. package/native/android/VueNativeCore/src/main/AndroidManifest.xml +17 -0
  7. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/ErrorOverlayView.kt +94 -0
  8. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/HotReloadManager.kt +105 -0
  9. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSPolyfills.kt +652 -0
  10. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSRuntime.kt +207 -0
  11. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +417 -0
  12. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/ComponentRegistry.kt +76 -0
  13. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActionSheetFactory.kt +78 -0
  14. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActivityIndicatorFactory.kt +46 -0
  15. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VAlertDialogFactory.kt +84 -0
  16. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VButtonFactory.kt +73 -0
  17. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VCheckboxFactory.kt +93 -0
  18. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VDropdownFactory.kt +125 -0
  19. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VImageFactory.kt +75 -0
  20. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VInputFactory.kt +210 -0
  21. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VKeyboardAvoidingFactory.kt +31 -0
  22. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +183 -0
  23. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VModalFactory.kt +105 -0
  24. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPickerFactory.kt +57 -0
  25. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPressableFactory.kt +109 -0
  26. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VProgressBarFactory.kt +43 -0
  27. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRadioFactory.kt +103 -0
  28. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRefreshControlFactory.kt +73 -0
  29. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRootFactory.kt +39 -0
  30. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSafeAreaFactory.kt +48 -0
  31. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +105 -0
  32. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSectionListFactory.kt +144 -0
  33. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSegmentedControlFactory.kt +77 -0
  34. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +74 -0
  35. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VStatusBarFactory.kt +52 -0
  36. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSwitchFactory.kt +62 -0
  37. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VTextFactory.kt +53 -0
  38. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VVideoFactory.kt +191 -0
  39. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +48 -0
  40. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VWebViewFactory.kt +90 -0
  41. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/NativeComponentFactory.kt +40 -0
  42. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/VTextNodeView.kt +23 -0
  43. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/GestureHelper.kt +16 -0
  44. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/TouchableView.kt +105 -0
  45. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AnimationModule.kt +292 -0
  46. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AppStateModule.kt +41 -0
  47. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AsyncStorageModule.kt +59 -0
  48. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AudioModule.kt +331 -0
  49. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BackgroundTaskModule.kt +166 -0
  50. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BiometryModule.kt +56 -0
  51. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BluetoothModule.kt +302 -0
  52. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CalendarModule.kt +198 -0
  53. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CameraModule.kt +64 -0
  54. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ClipboardModule.kt +36 -0
  55. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ContactsModule.kt +288 -0
  56. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DatabaseModule.kt +229 -0
  57. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DeviceInfoModule.kt +39 -0
  58. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/FileSystemModule.kt +193 -0
  59. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeolocationModule.kt +68 -0
  60. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HapticsModule.kt +61 -0
  61. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HttpModule.kt +111 -0
  62. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/IAPModule.kt +302 -0
  63. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/KeyboardModule.kt +26 -0
  64. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/LinkingModule.kt +43 -0
  65. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModule.kt +27 -0
  66. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +92 -0
  67. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NetworkModule.kt +75 -0
  68. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NotificationsModule.kt +181 -0
  69. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/OTAModule.kt +255 -0
  70. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PerformanceModule.kt +147 -0
  71. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PermissionsModule.kt +126 -0
  72. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SecureStorageModule.kt +51 -0
  73. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SensorsModule.kt +134 -0
  74. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ShareModule.kt +36 -0
  75. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SocialAuthModule.kt +160 -0
  76. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/WebSocketModule.kt +155 -0
  77. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Styling/StyleEngine.kt +802 -0
  78. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Tags.kt +43 -0
  79. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/VueNativeActivity.kt +169 -0
  80. package/native/android/VueNativeCore/src/main/res/values/ids.xml +8 -0
  81. package/native/android/app/build.gradle.kts +45 -0
  82. package/native/android/app/proguard-rules.pro +5 -0
  83. package/native/android/app/src/main/AndroidManifest.xml +25 -0
  84. package/native/android/app/src/main/assets/.gitkeep +0 -0
  85. package/native/android/app/src/main/kotlin/com/vuenative/example/counter/MainActivity.kt +14 -0
  86. package/native/android/app/src/main/res/layout/activity_main.xml +6 -0
  87. package/native/android/app/src/main/res/values/strings.xml +3 -0
  88. package/native/android/app/src/main/res/values/themes.xml +9 -0
  89. package/native/android/app/src/main/res/xml/network_security_config.xml +8 -0
  90. package/native/android/build.gradle.kts +6 -0
  91. package/native/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  92. package/native/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  93. package/native/android/gradle.properties +4 -0
  94. package/native/android/gradlew +87 -0
  95. package/native/android/gradlew.bat +48 -0
  96. package/native/android/settings.gradle.kts +20 -0
  97. package/native/ios/VueNativeCore/Package.resolved +23 -0
  98. package/native/ios/VueNativeCore/Package.swift +32 -0
  99. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/CertificatePinning.swift +132 -0
  100. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/ErrorOverlayView.swift +92 -0
  101. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/HotReloadManager.swift +147 -0
  102. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSPolyfills.swift +711 -0
  103. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSRuntime.swift +421 -0
  104. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +891 -0
  105. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/VueNativeViewController.swift +88 -0
  106. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/ComponentRegistry.swift +193 -0
  107. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActionSheetFactory.swift +91 -0
  108. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActivityIndicatorFactory.swift +74 -0
  109. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VAlertDialogFactory.swift +150 -0
  110. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VButtonFactory.swift +93 -0
  111. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VCheckboxFactory.swift +114 -0
  112. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VDropdownFactory.swift +112 -0
  113. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VImageFactory.swift +172 -0
  114. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VInputFactory.swift +357 -0
  115. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VKeyboardAvoidingFactory.swift +99 -0
  116. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +250 -0
  117. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VModalFactory.swift +112 -0
  118. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPickerFactory.swift +96 -0
  119. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPressableFactory.swift +168 -0
  120. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VProgressBarFactory.swift +39 -0
  121. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRadioFactory.swift +167 -0
  122. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRefreshControlFactory.swift +153 -0
  123. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSafeAreaFactory.swift +56 -0
  124. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +240 -0
  125. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSectionListFactory.swift +248 -0
  126. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSegmentedControlFactory.swift +73 -0
  127. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +63 -0
  128. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VStatusBarFactory.swift +50 -0
  129. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSwitchFactory.swift +108 -0
  130. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +290 -0
  131. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VVideoFactory.swift +246 -0
  132. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +157 -0
  133. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VWebViewFactory.swift +172 -0
  134. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/NativeComponentFactory.swift +53 -0
  135. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +107 -0
  136. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/TouchableView.swift +136 -0
  137. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/UIColor+Hex.swift +80 -0
  138. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AnimationModule.swift +291 -0
  139. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AppStateModule.swift +65 -0
  140. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AsyncStorageModule.swift +68 -0
  141. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AudioModule.swift +366 -0
  142. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BackgroundTaskModule.swift +135 -0
  143. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BiometryModule.swift +61 -0
  144. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BluetoothModule.swift +387 -0
  145. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CalendarModule.swift +161 -0
  146. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CameraModule.swift +318 -0
  147. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ClipboardModule.swift +33 -0
  148. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ContactsModule.swift +173 -0
  149. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DatabaseModule.swift +259 -0
  150. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DeviceInfoModule.swift +34 -0
  151. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/FileSystemModule.swift +233 -0
  152. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeolocationModule.swift +147 -0
  153. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/HapticsModule.swift +50 -0
  154. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/IAPModule.swift +194 -0
  155. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/KeyboardModule.swift +31 -0
  156. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/LinkingModule.swift +42 -0
  157. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModule.swift +28 -0
  158. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +78 -0
  159. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NetworkModule.swift +62 -0
  160. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NotificationsModule.swift +215 -0
  161. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/OTAModule.swift +281 -0
  162. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PerformanceModule.swift +138 -0
  163. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PermissionsModule.swift +190 -0
  164. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SecureStorageModule.swift +118 -0
  165. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SensorsModule.swift +103 -0
  166. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ShareModule.swift +49 -0
  167. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SocialAuthModule.swift +240 -0
  168. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/WebSocketModule.swift +213 -0
  169. package/native/ios/VueNativeCore/Sources/VueNativeCore/Resources/vue-native-placeholder.js +8 -0
  170. package/native/ios/VueNativeCore/Sources/VueNativeCore/Styling/StyleEngine.swift +885 -0
  171. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSRuntimeTests.swift +362 -0
  172. package/package.json +3 -2
@@ -0,0 +1,132 @@
1
+ #if canImport(UIKit)
2
+ import Foundation
3
+ import CommonCrypto
4
+
5
+ /// Manages certificate pinning for network requests.
6
+ /// Stores SHA-256 pin hashes per domain and provides a URLSession with
7
+ /// a delegate that validates server certificates against the pinned hashes.
8
+ ///
9
+ /// Usage from JS (via the bridge):
10
+ /// __VN_configurePins({ "api.example.com": ["sha256/BBBBBBB..."] })
11
+ ///
12
+ /// The fetch polyfill uses `CertificatePinning.shared.session` instead of
13
+ /// `URLSession.shared` when pins are configured for the request's host.
14
+ public final class CertificatePinning: NSObject, URLSessionDelegate {
15
+
16
+ public static let shared = CertificatePinning()
17
+
18
+ /// Maps lowercase domain to an array of base64-encoded SHA-256 hashes of the
19
+ /// Subject Public Key Info (SPKI).
20
+ private var pins: [String: [String]] = [:]
21
+
22
+ /// A URLSession configured with this object as its delegate for TLS validation.
23
+ /// Lazily created so we don't pay the cost if pinning is never configured.
24
+ public private(set) lazy var session: URLSession = {
25
+ let config = URLSessionConfiguration.default
26
+ config.timeoutIntervalForRequest = 30
27
+ config.timeoutIntervalForResource = 60
28
+ return URLSession(configuration: config, delegate: self, delegateQueue: nil)
29
+ }()
30
+
31
+ private override init() {
32
+ super.init()
33
+ }
34
+
35
+ // MARK: - Configuration
36
+
37
+ /// Configure certificate pins for one or more domains.
38
+ /// Each pin string must be in the format "sha256/<base64-encoded-hash>".
39
+ ///
40
+ /// - Parameter domainPins: Dictionary mapping domain names to arrays of pin strings.
41
+ public func configurePins(_ domainPins: [String: [String]]) {
42
+ for (domain, pinList) in domainPins {
43
+ let hashes = pinList.compactMap { pin -> String? in
44
+ // Accept "sha256/XXXXX" format — strip the prefix
45
+ if pin.hasPrefix("sha256/") {
46
+ return String(pin.dropFirst(7))
47
+ }
48
+ return nil
49
+ }
50
+ if !hashes.isEmpty {
51
+ pins[domain.lowercased()] = hashes
52
+ }
53
+ }
54
+ }
55
+
56
+ /// Returns true if there are pins configured for the given host.
57
+ public func hasPins(for host: String) -> Bool {
58
+ return pins[host.lowercased()] != nil
59
+ }
60
+
61
+ /// Remove all configured pins.
62
+ public func clearPins() {
63
+ pins.removeAll()
64
+ }
65
+
66
+ // MARK: - URLSessionDelegate
67
+
68
+ public func urlSession(
69
+ _ session: URLSession,
70
+ didReceive challenge: URLAuthenticationChallenge,
71
+ completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
72
+ ) {
73
+ guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
74
+ let serverTrust = challenge.protectionSpace.serverTrust else {
75
+ completionHandler(.performDefaultHandling, nil)
76
+ return
77
+ }
78
+
79
+ let host = challenge.protectionSpace.host.lowercased()
80
+
81
+ // If no pins configured for this host, use default handling
82
+ guard let expectedPins = pins[host] else {
83
+ completionHandler(.performDefaultHandling, nil)
84
+ return
85
+ }
86
+
87
+ // Evaluate the server trust
88
+ var error: CFError?
89
+ guard SecTrustEvaluateWithError(serverTrust, &error) else {
90
+ NSLog("[VueNative CertPin] Trust evaluation failed for %@: %@", host, error?.localizedDescription ?? "unknown")
91
+ completionHandler(.cancelAuthenticationChallenge, nil)
92
+ return
93
+ }
94
+
95
+ // Check each certificate in the chain against our pins
96
+ let certCount = SecTrustGetCertificateCount(serverTrust)
97
+ for i in 0..<certCount {
98
+ guard let cert = SecTrustCopyCertificateChain(serverTrust)?[i] else { continue }
99
+ guard let certificate = cert as? SecCertificate else { continue }
100
+ let spkiHash = sha256OfSPKI(for: certificate)
101
+ if expectedPins.contains(spkiHash) {
102
+ completionHandler(.useCredential, URLCredential(trust: serverTrust))
103
+ return
104
+ }
105
+ }
106
+
107
+ // No pin matched — reject the connection
108
+ NSLog("[VueNative CertPin] Pin validation failed for %@. No matching pin found.", host)
109
+ completionHandler(.cancelAuthenticationChallenge, nil)
110
+ }
111
+
112
+ // MARK: - SPKI Hashing
113
+
114
+ /// Compute the base64-encoded SHA-256 hash of a certificate's Subject Public Key Info.
115
+ private func sha256OfSPKI(for certificate: SecCertificate) -> String {
116
+ guard let publicKey = SecCertificateCopyKey(certificate) else { return "" }
117
+
118
+ var error: Unmanaged<CFError>?
119
+ guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
120
+ return ""
121
+ }
122
+
123
+ // Hash the raw public key data with SHA-256
124
+ var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
125
+ publicKeyData.withUnsafeBytes { bytes in
126
+ _ = CC_SHA256(bytes.baseAddress, CC_LONG(publicKeyData.count), &hash)
127
+ }
128
+
129
+ return Data(hash).base64EncodedString()
130
+ }
131
+ }
132
+ #endif
@@ -0,0 +1,92 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+
4
+ /// Full-screen red error overlay shown in dev mode when a JS exception occurs.
5
+ @MainActor
6
+ final class ErrorOverlayView: UIView {
7
+
8
+ private let containerView = UIView()
9
+ private let titleLabel = UILabel()
10
+ private let messageLabel = UILabel()
11
+ private let dismissButton = UIButton(type: .system)
12
+ private let scrollView = UIScrollView()
13
+
14
+ override init(frame: CGRect) {
15
+ super.init(frame: frame)
16
+ setupUI()
17
+ }
18
+
19
+ required init?(coder: NSCoder) { fatalError() }
20
+
21
+ private func setupUI() {
22
+ backgroundColor = UIColor(red: 0.8, green: 0.1, blue: 0.1, alpha: 0.95)
23
+
24
+ titleLabel.text = "JavaScript Error"
25
+ titleLabel.textColor = .white
26
+ titleLabel.font = .systemFont(ofSize: 20, weight: .bold)
27
+ titleLabel.textAlignment = .center
28
+
29
+ messageLabel.textColor = .white
30
+ messageLabel.font = .monospacedSystemFont(ofSize: 13, weight: .regular)
31
+ messageLabel.numberOfLines = 0
32
+ messageLabel.textAlignment = .left
33
+
34
+ dismissButton.setTitle("Dismiss", for: .normal)
35
+ dismissButton.setTitleColor(.white, for: .normal)
36
+ dismissButton.backgroundColor = UIColor(white: 1, alpha: 0.2)
37
+ dismissButton.layer.cornerRadius = 8
38
+ dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
39
+
40
+ scrollView.addSubview(messageLabel)
41
+ addSubview(titleLabel)
42
+ addSubview(scrollView)
43
+ addSubview(dismissButton)
44
+ }
45
+
46
+ func show(error: String, in window: UIWindow) {
47
+ messageLabel.text = error
48
+ frame = window.bounds
49
+
50
+ let padding: CGFloat = 20
51
+ let topPadding = window.safeAreaInsets.top + 20
52
+
53
+ titleLabel.frame = CGRect(x: padding, y: topPadding, width: bounds.width - padding * 2, height: 30)
54
+ dismissButton.frame = CGRect(
55
+ x: padding,
56
+ y: bounds.height - 60 - window.safeAreaInsets.bottom,
57
+ width: bounds.width - padding * 2,
58
+ height: 44
59
+ )
60
+ scrollView.frame = CGRect(
61
+ x: padding,
62
+ y: topPadding + 40,
63
+ width: bounds.width - padding * 2,
64
+ height: dismissButton.frame.minY - topPadding - 50
65
+ )
66
+ messageLabel.frame = CGRect(x: 0, y: 0, width: scrollView.bounds.width, height: 0)
67
+ messageLabel.sizeToFit()
68
+ scrollView.contentSize = CGSize(width: scrollView.bounds.width, height: messageLabel.bounds.height)
69
+
70
+ window.addSubview(self)
71
+ }
72
+
73
+ @objc private func dismiss() {
74
+ removeFromSuperview()
75
+ }
76
+
77
+ static func show(error: String) {
78
+ DispatchQueue.main.async {
79
+ guard let window = UIApplication.shared.connectedScenes
80
+ .compactMap({ $0 as? UIWindowScene })
81
+ .flatMap({ $0.windows })
82
+ .first(where: { $0.isKeyWindow }) else { return }
83
+
84
+ // Remove any existing overlay
85
+ window.subviews.compactMap { $0 as? ErrorOverlayView }.forEach { $0.removeFromSuperview() }
86
+
87
+ let overlay = ErrorOverlayView(frame: window.bounds)
88
+ overlay.show(error: error, in: window)
89
+ }
90
+ }
91
+ }
92
+ #endif
@@ -0,0 +1,147 @@
1
+ #if canImport(UIKit)
2
+ import Foundation
3
+ import UIKit
4
+
5
+ /// Manages a WebSocket connection to the Vue Native dev server for hot reload.
6
+ /// When a new bundle is broadcast, triggers a full app reload via NativeBridge.
7
+ ///
8
+ /// Usage in your app's root ViewController (debug builds only):
9
+ /// ```swift
10
+ /// #if DEBUG
11
+ /// HotReloadManager.shared.connect(to: URL(string: "ws://localhost:8174")!)
12
+ /// #endif
13
+ /// ```
14
+ public final class HotReloadManager: NSObject, URLSessionWebSocketDelegate {
15
+
16
+ public static let shared = HotReloadManager()
17
+
18
+ private var webSocketTask: URLSessionWebSocketTask?
19
+ private var session: URLSession?
20
+ private var serverURL: URL?
21
+ private var isConnecting = false
22
+
23
+ private override init() {
24
+ super.init()
25
+ }
26
+
27
+ // MARK: - Public API
28
+
29
+ /// Connect to the dev server. Safe to call multiple times.
30
+ public func connect(to url: URL) {
31
+ serverURL = url
32
+ scheduleConnect(delay: 0)
33
+ }
34
+
35
+ /// Disconnect and stop reconnecting.
36
+ public func disconnect() {
37
+ serverURL = nil
38
+ webSocketTask?.cancel(with: .goingAway, reason: nil)
39
+ webSocketTask = nil
40
+ session?.invalidateAndCancel()
41
+ session = nil
42
+ NSLog("[VueNative HotReload] Disconnected")
43
+ }
44
+
45
+ // MARK: - Connection
46
+
47
+ private func scheduleConnect(delay: TimeInterval) {
48
+ guard serverURL != nil, !isConnecting else { return }
49
+ isConnecting = true
50
+ DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
51
+ self?.openConnection()
52
+ }
53
+ }
54
+
55
+ private func openConnection() {
56
+ guard let url = serverURL else {
57
+ isConnecting = false
58
+ return
59
+ }
60
+
61
+ // Create a fresh session each time to avoid stale state
62
+ session?.invalidateAndCancel()
63
+ let config = URLSessionConfiguration.default
64
+ config.timeoutIntervalForRequest = 5
65
+ session = URLSession(configuration: config, delegate: self, delegateQueue: .main)
66
+
67
+ webSocketTask = session?.webSocketTask(with: url)
68
+ webSocketTask?.resume()
69
+ NSLog("[VueNative HotReload] Connecting to \(url)...")
70
+ receiveNextMessage()
71
+ }
72
+
73
+ // MARK: - Message Handling
74
+
75
+ private func receiveNextMessage() {
76
+ webSocketTask?.receive { [weak self] result in
77
+ guard let self = self else { return }
78
+ switch result {
79
+ case .success(let message):
80
+ self.handleMessage(message)
81
+ self.receiveNextMessage()
82
+ case .failure(let error):
83
+ NSLog("[VueNative HotReload] Receive error: \(error.localizedDescription)")
84
+ self.scheduleReconnect()
85
+ }
86
+ }
87
+ }
88
+
89
+ private func handleMessage(_ message: URLSessionWebSocketTask.Message) {
90
+ let text: String
91
+ switch message {
92
+ case .string(let s): text = s
93
+ case .data(let d): text = String(data: d, encoding: .utf8) ?? ""
94
+ @unknown default: return
95
+ }
96
+
97
+ guard let data = text.data(using: .utf8),
98
+ let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
99
+ let type = json["type"] as? String else {
100
+ return
101
+ }
102
+
103
+ switch type {
104
+ case "connected":
105
+ isConnecting = false
106
+ NSLog("[VueNative HotReload] Connected — hot reload active")
107
+
108
+ case "bundle":
109
+ guard let bundle = json["bundle"] as? String else { return }
110
+ NSLog("[VueNative HotReload] Received bundle (\(bundle.count) bytes) — reloading...")
111
+ DispatchQueue.main.async {
112
+ NativeBridge.shared.reloadWithBundle(bundle)
113
+ }
114
+
115
+ case "ping":
116
+ // Respond to keep-alive pings
117
+ let pong = "{\"type\":\"pong\"}"
118
+ webSocketTask?.send(.string(pong)) { _ in }
119
+
120
+ default:
121
+ break
122
+ }
123
+ }
124
+
125
+ // MARK: - Reconnection
126
+
127
+ private func scheduleReconnect() {
128
+ guard serverURL != nil else { return }
129
+ isConnecting = false
130
+ NSLog("[VueNative HotReload] Reconnecting in 2s...")
131
+ scheduleConnect(delay: 2.0)
132
+ }
133
+
134
+ // MARK: - URLSessionWebSocketDelegate
135
+
136
+ public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask,
137
+ didOpenWithProtocol protocol: String?) {
138
+ NSLog("[VueNative HotReload] WebSocket opened")
139
+ }
140
+
141
+ public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask,
142
+ didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
143
+ NSLog("[VueNative HotReload] WebSocket closed (code: \(closeCode.rawValue))")
144
+ scheduleReconnect()
145
+ }
146
+ }
147
+ #endif