@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,240 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+ import AuthenticationServices
4
+
5
+ /// Native module for social authentication (Apple Sign In, Google Sign In).
6
+ ///
7
+ /// Methods:
8
+ /// - signInWithApple() -- present Apple Sign In sheet
9
+ /// - signInWithGoogle(clientId: String) -- present Google OAuth web flow
10
+ /// - signOut(provider: String) -- clear cached credentials
11
+ /// - getCurrentUser(provider: String) -- check for existing session
12
+ ///
13
+ /// Events:
14
+ /// - auth:appleCredentialRevoked -- fired when Apple credential is revoked
15
+ final class SocialAuthModule: NSObject, NativeModule, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
16
+ let moduleName = "SocialAuth"
17
+ private weak var bridge: NativeBridge?
18
+ private var appleSignInCallback: ((Any?, String?) -> Void)?
19
+ private var credentialObserver: NSObjectProtocol?
20
+
21
+ init(bridge: NativeBridge? = nil) {
22
+ self.bridge = bridge
23
+ super.init()
24
+ observeAppleCredentialRevocation()
25
+ }
26
+
27
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
28
+ switch method {
29
+ case "signInWithApple":
30
+ handleAppleSignIn(callback: callback)
31
+
32
+ case "signInWithGoogle":
33
+ guard let clientId = args.first as? String else {
34
+ callback(nil, "signInWithGoogle: expected clientId string")
35
+ return
36
+ }
37
+ handleGoogleSignIn(clientId: clientId, callback: callback)
38
+
39
+ case "signOut":
40
+ let provider = args.first as? String ?? "apple"
41
+ handleSignOut(provider: provider, callback: callback)
42
+
43
+ case "getCurrentUser":
44
+ let provider = args.first as? String ?? "apple"
45
+ handleGetCurrentUser(provider: provider, callback: callback)
46
+
47
+ default:
48
+ callback(nil, "SocialAuthModule: unknown method '\(method)'")
49
+ }
50
+ }
51
+
52
+ // MARK: - Apple Sign In
53
+
54
+ private func handleAppleSignIn(callback: @escaping (Any?, String?) -> Void) {
55
+ appleSignInCallback = callback
56
+
57
+ let request = ASAuthorizationAppleIDProvider().createRequest()
58
+ request.requestedScopes = [.fullName, .email]
59
+
60
+ let controller = ASAuthorizationController(authorizationRequests: [request])
61
+ controller.delegate = self
62
+ controller.presentationContextProvider = self
63
+ controller.performRequests()
64
+ }
65
+
66
+ // ASAuthorizationControllerDelegate
67
+ func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
68
+ guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential else {
69
+ appleSignInCallback?(nil, "signInWithApple: unexpected credential type")
70
+ appleSignInCallback = nil
71
+ return
72
+ }
73
+
74
+ var result: [String: Any] = [
75
+ "userId": credential.user,
76
+ ]
77
+
78
+ if let email = credential.email {
79
+ result["email"] = email
80
+ }
81
+
82
+ if let fullName = credential.fullName {
83
+ let name = [fullName.givenName, fullName.familyName]
84
+ .compactMap { $0 }
85
+ .joined(separator: " ")
86
+ if !name.isEmpty {
87
+ result["fullName"] = name
88
+ }
89
+ }
90
+
91
+ if let tokenData = credential.identityToken, let token = String(data: tokenData, encoding: .utf8) {
92
+ result["identityToken"] = token
93
+ }
94
+
95
+ if let codeData = credential.authorizationCode, let code = String(data: codeData, encoding: .utf8) {
96
+ result["authorizationCode"] = code
97
+ }
98
+
99
+ // Persist user ID for session check
100
+ UserDefaults.standard.set(credential.user, forKey: "vn_apple_userId")
101
+
102
+ appleSignInCallback?(result, nil)
103
+ appleSignInCallback = nil
104
+ }
105
+
106
+ func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
107
+ let nsError = error as NSError
108
+ if nsError.domain == ASAuthorizationError.errorDomain && nsError.code == ASAuthorizationError.canceled.rawValue {
109
+ appleSignInCallback?(nil, "signInWithApple: user cancelled")
110
+ } else {
111
+ appleSignInCallback?(nil, "signInWithApple: \(error.localizedDescription)")
112
+ }
113
+ appleSignInCallback = nil
114
+ }
115
+
116
+ func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
117
+ return UIApplication.shared.connectedScenes
118
+ .compactMap { $0 as? UIWindowScene }
119
+ .first?.windows.first { $0.isKeyWindow } ?? UIWindow()
120
+ }
121
+
122
+ // MARK: - Google Sign In (URL-based OAuth)
123
+
124
+ private func handleGoogleSignIn(clientId: String, callback: @escaping (Any?, String?) -> Void) {
125
+ // URL-based OAuth flow using ASWebAuthenticationSession for zero dependencies
126
+ let redirectURI = "com.googleusercontent.apps.\(clientId.components(separatedBy: ".").first ?? clientId):/oauthredirect"
127
+ let scope = "openid email profile"
128
+ let urlString = "https://accounts.google.com/o/oauth2/v2/auth?client_id=\(clientId)&redirect_uri=\(redirectURI)&response_type=code&scope=\(scope.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? scope)"
129
+
130
+ guard let url = URL(string: urlString) else {
131
+ callback(nil, "signInWithGoogle: invalid OAuth URL")
132
+ return
133
+ }
134
+
135
+ DispatchQueue.main.async {
136
+ let scheme = redirectURI.components(separatedBy: ":").first
137
+ let session = ASWebAuthenticationSession(url: url, callbackURLScheme: scheme) { callbackURL, error in
138
+ if let error = error {
139
+ let nsError = error as NSError
140
+ if nsError.domain == ASWebAuthenticationSessionError.errorDomain &&
141
+ nsError.code == ASWebAuthenticationSessionError.canceledLogin.rawValue {
142
+ callback(nil, "signInWithGoogle: user cancelled")
143
+ } else {
144
+ callback(nil, "signInWithGoogle: \(error.localizedDescription)")
145
+ }
146
+ return
147
+ }
148
+
149
+ guard let callbackURL = callbackURL,
150
+ let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false),
151
+ let code = components.queryItems?.first(where: { $0.name == "code" })?.value else {
152
+ callback(nil, "signInWithGoogle: no authorization code received")
153
+ return
154
+ }
155
+
156
+ let result: [String: Any] = [
157
+ "userId": code, // The auth code — exchange server-side for tokens
158
+ "authorizationCode": code,
159
+ ]
160
+
161
+ UserDefaults.standard.set(code, forKey: "vn_google_authCode")
162
+ callback(result, nil)
163
+ }
164
+
165
+ session.prefersEphemeralWebBrowserSession = false
166
+
167
+ // Find the presentation anchor
168
+ if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
169
+ let window = windowScene.windows.first {
170
+ session.presentationContextProvider = window.rootViewController as? ASWebAuthenticationPresentationContextProviding
171
+ }
172
+
173
+ session.start()
174
+ }
175
+ }
176
+
177
+ // MARK: - Sign Out
178
+
179
+ private func handleSignOut(provider: String, callback: @escaping (Any?, String?) -> Void) {
180
+ switch provider {
181
+ case "apple":
182
+ UserDefaults.standard.removeObject(forKey: "vn_apple_userId")
183
+ case "google":
184
+ UserDefaults.standard.removeObject(forKey: "vn_google_authCode")
185
+ default:
186
+ break
187
+ }
188
+ callback(nil, nil)
189
+ }
190
+
191
+ // MARK: - Get Current User
192
+
193
+ private func handleGetCurrentUser(provider: String, callback: @escaping (Any?, String?) -> Void) {
194
+ switch provider {
195
+ case "apple":
196
+ guard let userId = UserDefaults.standard.string(forKey: "vn_apple_userId") else {
197
+ callback(nil, nil)
198
+ return
199
+ }
200
+ // Verify the credential is still valid
201
+ ASAuthorizationAppleIDProvider().getCredentialState(forUserID: userId) { state, _ in
202
+ switch state {
203
+ case .authorized:
204
+ callback(["userId": userId], nil)
205
+ default:
206
+ UserDefaults.standard.removeObject(forKey: "vn_apple_userId")
207
+ callback(nil, nil)
208
+ }
209
+ }
210
+ case "google":
211
+ if let code = UserDefaults.standard.string(forKey: "vn_google_authCode") {
212
+ callback(["userId": code], nil)
213
+ } else {
214
+ callback(nil, nil)
215
+ }
216
+ default:
217
+ callback(nil, nil)
218
+ }
219
+ }
220
+
221
+ // MARK: - Credential Revocation Observer
222
+
223
+ private func observeAppleCredentialRevocation() {
224
+ credentialObserver = NotificationCenter.default.addObserver(
225
+ forName: ASAuthorizationAppleIDProvider.credentialRevokedNotification,
226
+ object: nil,
227
+ queue: .main
228
+ ) { [weak self] _ in
229
+ UserDefaults.standard.removeObject(forKey: "vn_apple_userId")
230
+ self?.bridge?.emitGlobalEvent("auth:appleCredentialRevoked", payload: [:])
231
+ }
232
+ }
233
+
234
+ deinit {
235
+ if let observer = credentialObserver {
236
+ NotificationCenter.default.removeObserver(observer)
237
+ }
238
+ }
239
+ }
240
+ #endif
@@ -0,0 +1,213 @@
1
+ #if canImport(UIKit)
2
+ import Foundation
3
+
4
+ /// Native module for WebSocket connections.
5
+ ///
6
+ /// Supports multiple simultaneous connections keyed by connection ID.
7
+ ///
8
+ /// Methods:
9
+ /// - connect(url: String, connectionId: String)
10
+ /// - send(connectionId: String, data: String)
11
+ /// - close(connectionId: String, code: Int?, reason: String?)
12
+ ///
13
+ /// Global events dispatched on bridge:
14
+ /// "websocket:open" { connectionId }
15
+ /// "websocket:message" { connectionId, data }
16
+ /// "websocket:close" { connectionId, code, reason }
17
+ /// "websocket:error" { connectionId, message }
18
+ final class WebSocketModule: NativeModule {
19
+ var moduleName: String { "WebSocket" }
20
+ private weak var bridge: NativeBridge?
21
+
22
+ /// Active WebSocket tasks keyed by connectionId
23
+ private var connections: [String: URLSessionWebSocketTask] = [:]
24
+ private var sessions: [String: URLSession] = [:]
25
+
26
+ init(bridge: NativeBridge) {
27
+ self.bridge = bridge
28
+ }
29
+
30
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
31
+ switch method {
32
+ case "connect":
33
+ guard let url = args.first as? String,
34
+ let connectionId = args.count > 1 ? args[1] as? String : nil else {
35
+ callback(nil, "WebSocketModule: expected (url, connectionId)")
36
+ return
37
+ }
38
+ connect(url: url, connectionId: connectionId, callback: callback)
39
+
40
+ case "send":
41
+ guard let connectionId = args.first as? String,
42
+ let data = args.count > 1 ? args[1] as? String : nil else {
43
+ callback(nil, "WebSocketModule: expected (connectionId, data)")
44
+ return
45
+ }
46
+ send(connectionId: connectionId, data: data, callback: callback)
47
+
48
+ case "close":
49
+ guard let connectionId = args.first as? String else {
50
+ callback(nil, "WebSocketModule: expected (connectionId)")
51
+ return
52
+ }
53
+ let code = args.count > 1 ? args[1] as? Int : nil
54
+ let reason = args.count > 2 ? args[2] as? String : nil
55
+ close(connectionId: connectionId, code: code, reason: reason, callback: callback)
56
+
57
+ default:
58
+ callback(nil, "WebSocketModule: Unknown method '\(method)'")
59
+ }
60
+ }
61
+
62
+ // MARK: - Connect
63
+
64
+ private func connect(url: String, connectionId: String, callback: @escaping (Any?, String?) -> Void) {
65
+ guard let wsURL = URL(string: url) else {
66
+ callback(nil, "WebSocketModule: invalid URL '\(url)'")
67
+ return
68
+ }
69
+
70
+ // Clean up existing connection with same ID if any
71
+ closeConnection(connectionId)
72
+
73
+ let session = URLSession(configuration: .default)
74
+ let task = session.webSocketTask(with: wsURL)
75
+ connections[connectionId] = task
76
+ sessions[connectionId] = session
77
+
78
+ task.resume()
79
+
80
+ // Dispatch open event once resumed
81
+ let weakBridge = bridge
82
+ DispatchQueue.main.async {
83
+ weakBridge?.dispatchGlobalEvent("websocket:open", payload: [
84
+ "connectionId": connectionId
85
+ ])
86
+ }
87
+
88
+ // Start receive loop
89
+ receiveLoop(connectionId: connectionId, task: task)
90
+
91
+ callback(true, nil)
92
+ }
93
+
94
+ // MARK: - Receive loop
95
+
96
+ private func receiveLoop(connectionId: String, task: URLSessionWebSocketTask) {
97
+ task.receive { [weak self] result in
98
+ guard let self = self else { return }
99
+ // Check if connection still exists (may have been closed)
100
+ guard self.connections[connectionId] != nil else { return }
101
+
102
+ switch result {
103
+ case .success(let message):
104
+ let data: String
105
+ switch message {
106
+ case .string(let text):
107
+ data = text
108
+ case .data(let bytes):
109
+ data = String(data: bytes, encoding: .utf8) ?? ""
110
+ @unknown default:
111
+ data = ""
112
+ }
113
+
114
+ let weakBridge = self.bridge
115
+ DispatchQueue.main.async {
116
+ weakBridge?.dispatchGlobalEvent("websocket:message", payload: [
117
+ "connectionId": connectionId,
118
+ "data": data
119
+ ])
120
+ }
121
+
122
+ // Continue receiving
123
+ self.receiveLoop(connectionId: connectionId, task: task)
124
+
125
+ case .failure(let error):
126
+ let weakBridge = self.bridge
127
+ let errorMessage = error.localizedDescription
128
+ DispatchQueue.main.async {
129
+ // Check if this is a normal close or an actual error
130
+ let nsError = error as NSError
131
+ if nsError.domain == NSPOSIXErrorDomain && nsError.code == 57 {
132
+ // Socket not connected — normal close, dispatch close event
133
+ weakBridge?.dispatchGlobalEvent("websocket:close", payload: [
134
+ "connectionId": connectionId,
135
+ "code": 1000,
136
+ "reason": ""
137
+ ])
138
+ } else {
139
+ weakBridge?.dispatchGlobalEvent("websocket:error", payload: [
140
+ "connectionId": connectionId,
141
+ "message": errorMessage
142
+ ])
143
+ weakBridge?.dispatchGlobalEvent("websocket:close", payload: [
144
+ "connectionId": connectionId,
145
+ "code": 1006,
146
+ "reason": errorMessage
147
+ ])
148
+ }
149
+ }
150
+ self.connections.removeValue(forKey: connectionId)
151
+ self.sessions[connectionId]?.invalidateAndCancel()
152
+ self.sessions.removeValue(forKey: connectionId)
153
+ }
154
+ }
155
+ }
156
+
157
+ // MARK: - Send
158
+
159
+ private func send(connectionId: String, data: String, callback: @escaping (Any?, String?) -> Void) {
160
+ guard let task = connections[connectionId] else {
161
+ callback(nil, "WebSocketModule: no connection '\(connectionId)'")
162
+ return
163
+ }
164
+ task.send(.string(data)) { error in
165
+ if let error = error {
166
+ callback(nil, error.localizedDescription)
167
+ } else {
168
+ callback(true, nil)
169
+ }
170
+ }
171
+ }
172
+
173
+ // MARK: - Close
174
+
175
+ private func close(connectionId: String, code: Int?, reason: String?, callback: @escaping (Any?, String?) -> Void) {
176
+ guard let task = connections[connectionId] else {
177
+ callback(nil, nil) // Already closed, not an error
178
+ return
179
+ }
180
+
181
+ let closeCode = URLSessionWebSocketTask.CloseCode(rawValue: code ?? 1000) ?? .normalClosure
182
+ let reasonData = reason?.data(using: .utf8)
183
+ task.cancel(with: closeCode, reason: reasonData)
184
+
185
+ let weakBridge = bridge
186
+ DispatchQueue.main.async {
187
+ weakBridge?.dispatchGlobalEvent("websocket:close", payload: [
188
+ "connectionId": connectionId,
189
+ "code": code ?? 1000,
190
+ "reason": reason ?? ""
191
+ ])
192
+ }
193
+
194
+ connections.removeValue(forKey: connectionId)
195
+ sessions[connectionId]?.invalidateAndCancel()
196
+ sessions.removeValue(forKey: connectionId)
197
+
198
+ callback(true, nil)
199
+ }
200
+
201
+ // MARK: - Helpers
202
+
203
+ private func closeConnection(_ connectionId: String) {
204
+ guard let task = connections[connectionId] else { return }
205
+ task.cancel(with: .normalClosure, reason: nil)
206
+ connections.removeValue(forKey: connectionId)
207
+ sessions[connectionId]?.invalidateAndCancel()
208
+ sessions.removeValue(forKey: connectionId)
209
+ }
210
+
211
+ func invokeSync(method: String, args: [Any]) -> Any? { nil }
212
+ }
213
+ #endif
@@ -0,0 +1,8 @@
1
+ // Placeholder: Vue Native JS bundle will be generated by Vite build pipeline.
2
+ // This file is included as an SPM resource so the package structure is valid.
3
+ // Replace with the actual IIFE bundle from: pnpm build (in the app project).
4
+ (function() {
5
+ if (typeof __VN_log === 'function') {
6
+ __VN_log('vue-native-bundle.js placeholder loaded');
7
+ }
8
+ })();