@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,259 @@
1
+ #if canImport(UIKit)
2
+ import Foundation
3
+ import SQLite3
4
+
5
+ /// Native module for SQLite database access.
6
+ /// Uses the sqlite3 C API (built into iOS, no external dependencies).
7
+ /// Supports multiple named databases, parameterized queries, and transactions.
8
+ final class DatabaseModule: NativeModule {
9
+ let moduleName = "Database"
10
+
11
+ /// Open database handles keyed by database name.
12
+ private var databases: [String: OpaquePointer] = [:]
13
+
14
+ /// Directory for database files.
15
+ private var dbDirectory: URL {
16
+ let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
17
+ .appendingPathComponent("databases", isDirectory: true)
18
+ try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
19
+ return dir
20
+ }
21
+
22
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
23
+ switch method {
24
+ case "open":
25
+ let name = args.first as? String ?? "default"
26
+ open(name: name, callback: callback)
27
+ case "close":
28
+ let name = args.first as? String ?? "default"
29
+ close(name: name, callback: callback)
30
+ case "execute":
31
+ let name = args.count > 0 ? (args[0] as? String ?? "default") : "default"
32
+ let sql = args.count > 1 ? (args[1] as? String ?? "") : ""
33
+ let params = args.count > 2 ? (args[2] as? [Any] ?? []) : []
34
+ execute(name: name, sql: sql, params: params, callback: callback)
35
+ case "query":
36
+ let name = args.count > 0 ? (args[0] as? String ?? "default") : "default"
37
+ let sql = args.count > 1 ? (args[1] as? String ?? "") : ""
38
+ let params = args.count > 2 ? (args[2] as? [Any] ?? []) : []
39
+ query(name: name, sql: sql, params: params, callback: callback)
40
+ case "executeTransaction":
41
+ let name = args.count > 0 ? (args[0] as? String ?? "default") : "default"
42
+ let statements = args.count > 1 ? (args[1] as? [[String: Any]] ?? []) : []
43
+ executeTransaction(name: name, statements: statements, callback: callback)
44
+ default:
45
+ callback(nil, "DatabaseModule: unknown method '\(method)'")
46
+ }
47
+ }
48
+
49
+ // MARK: - Open / Close
50
+
51
+ private func open(name: String, callback: @escaping (Any?, String?) -> Void) {
52
+ if databases[name] != nil {
53
+ callback(true, nil)
54
+ return
55
+ }
56
+
57
+ let path = dbDirectory.appendingPathComponent("\(name).sqlite").path
58
+ var db: OpaquePointer?
59
+
60
+ let flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX
61
+ let result = sqlite3_open_v2(path, &db, flags, nil)
62
+ if result == SQLITE_OK, let db = db {
63
+ // Enable WAL mode for better concurrent read/write performance
64
+ sqlite3_exec(db, "PRAGMA journal_mode=WAL", nil, nil, nil)
65
+ databases[name] = db
66
+ callback(true, nil)
67
+ } else {
68
+ let errorMsg = db != nil ? String(cString: sqlite3_errmsg(db)) : "Unknown error"
69
+ if db != nil { sqlite3_close(db) }
70
+ callback(nil, "Failed to open database '\(name)': \(errorMsg)")
71
+ }
72
+ }
73
+
74
+ private func close(name: String, callback: @escaping (Any?, String?) -> Void) {
75
+ guard let db = databases.removeValue(forKey: name) else {
76
+ callback(nil, nil)
77
+ return
78
+ }
79
+ sqlite3_close(db)
80
+ callback(nil, nil)
81
+ }
82
+
83
+ // MARK: - Execute (INSERT, UPDATE, DELETE, CREATE TABLE, etc.)
84
+
85
+ private func execute(name: String, sql: String, params: [Any], callback: @escaping (Any?, String?) -> Void) {
86
+ guard let db = getOrOpen(name: name, callback: callback) else { return }
87
+
88
+ var stmt: OpaquePointer?
89
+ guard sqlite3_prepare_v2(db, sql, -1, &stmt, nil) == SQLITE_OK else {
90
+ let err = String(cString: sqlite3_errmsg(db))
91
+ callback(nil, "SQL prepare error: \(err)")
92
+ return
93
+ }
94
+ defer { sqlite3_finalize(stmt) }
95
+
96
+ bindParams(stmt: stmt!, params: params)
97
+
98
+ let stepResult = sqlite3_step(stmt)
99
+ if stepResult == SQLITE_DONE || stepResult == SQLITE_ROW {
100
+ let rowsAffected = sqlite3_changes(db)
101
+ let lastInsertId = sqlite3_last_insert_rowid(db)
102
+ var result: [String: Any] = ["rowsAffected": Int(rowsAffected)]
103
+ if lastInsertId > 0 {
104
+ result["insertId"] = Int(lastInsertId)
105
+ }
106
+ callback(result, nil)
107
+ } else {
108
+ let err = String(cString: sqlite3_errmsg(db))
109
+ callback(nil, "SQL execute error: \(err)")
110
+ }
111
+ }
112
+
113
+ // MARK: - Query (SELECT)
114
+
115
+ private func query(name: String, sql: String, params: [Any], callback: @escaping (Any?, String?) -> Void) {
116
+ guard let db = getOrOpen(name: name, callback: callback) else { return }
117
+
118
+ var stmt: OpaquePointer?
119
+ guard sqlite3_prepare_v2(db, sql, -1, &stmt, nil) == SQLITE_OK else {
120
+ let err = String(cString: sqlite3_errmsg(db))
121
+ callback(nil, "SQL prepare error: \(err)")
122
+ return
123
+ }
124
+ defer { sqlite3_finalize(stmt) }
125
+
126
+ bindParams(stmt: stmt!, params: params)
127
+
128
+ var rows: [[String: Any]] = []
129
+ let columnCount = sqlite3_column_count(stmt)
130
+
131
+ while sqlite3_step(stmt) == SQLITE_ROW {
132
+ var row: [String: Any] = [:]
133
+ for i in 0..<columnCount {
134
+ let colName = String(cString: sqlite3_column_name(stmt, i))
135
+ row[colName] = columnValue(stmt: stmt!, index: i)
136
+ }
137
+ rows.append(row)
138
+ }
139
+
140
+ callback(rows, nil)
141
+ }
142
+
143
+ // MARK: - Transaction
144
+
145
+ private func executeTransaction(name: String, statements: [[String: Any]], callback: @escaping (Any?, String?) -> Void) {
146
+ guard let db = getOrOpen(name: name, callback: callback) else { return }
147
+
148
+ sqlite3_exec(db, "BEGIN TRANSACTION", nil, nil, nil)
149
+
150
+ var results: [[String: Any]] = []
151
+
152
+ for stmtData in statements {
153
+ let sql = stmtData["sql"] as? String ?? ""
154
+ let params = stmtData["params"] as? [Any] ?? []
155
+
156
+ var stmt: OpaquePointer?
157
+ guard sqlite3_prepare_v2(db, sql, -1, &stmt, nil) == SQLITE_OK else {
158
+ let err = String(cString: sqlite3_errmsg(db))
159
+ sqlite3_exec(db, "ROLLBACK", nil, nil, nil)
160
+ callback(nil, "Transaction SQL prepare error: \(err)")
161
+ return
162
+ }
163
+
164
+ bindParams(stmt: stmt!, params: params)
165
+
166
+ let stepResult = sqlite3_step(stmt)
167
+ sqlite3_finalize(stmt)
168
+
169
+ if stepResult == SQLITE_DONE || stepResult == SQLITE_ROW {
170
+ let rowsAffected = sqlite3_changes(db)
171
+ let lastInsertId = sqlite3_last_insert_rowid(db)
172
+ var result: [String: Any] = ["rowsAffected": Int(rowsAffected)]
173
+ if lastInsertId > 0 {
174
+ result["insertId"] = Int(lastInsertId)
175
+ }
176
+ results.append(result)
177
+ } else {
178
+ let err = String(cString: sqlite3_errmsg(db))
179
+ sqlite3_exec(db, "ROLLBACK", nil, nil, nil)
180
+ callback(nil, "Transaction execute error: \(err)")
181
+ return
182
+ }
183
+ }
184
+
185
+ sqlite3_exec(db, "COMMIT", nil, nil, nil)
186
+ callback(results, nil)
187
+ }
188
+
189
+ // MARK: - Helpers
190
+
191
+ /// Get an existing database handle or auto-open it.
192
+ private func getOrOpen(name: String, callback: @escaping (Any?, String?) -> Void) -> OpaquePointer? {
193
+ if let db = databases[name] { return db }
194
+
195
+ // Auto-open
196
+ let path = dbDirectory.appendingPathComponent("\(name).sqlite").path
197
+ var db: OpaquePointer?
198
+ let flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX
199
+ let result = sqlite3_open_v2(path, &db, flags, nil)
200
+ if result == SQLITE_OK, let db = db {
201
+ sqlite3_exec(db, "PRAGMA journal_mode=WAL", nil, nil, nil)
202
+ databases[name] = db
203
+ return db
204
+ } else {
205
+ let errorMsg = db != nil ? String(cString: sqlite3_errmsg(db)) : "Unknown error"
206
+ if db != nil { sqlite3_close(db) }
207
+ callback(nil, "Failed to auto-open database '\(name)': \(errorMsg)")
208
+ return nil
209
+ }
210
+ }
211
+
212
+ /// Bind parameter array to a prepared statement. Supports String, Int, Double, Bool, nil/NSNull.
213
+ private func bindParams(stmt: OpaquePointer, params: [Any]) {
214
+ for (i, param) in params.enumerated() {
215
+ let idx = Int32(i + 1)
216
+ if param is NSNull {
217
+ sqlite3_bind_null(stmt, idx)
218
+ } else if let s = param as? String {
219
+ sqlite3_bind_text(stmt, idx, (s as NSString).utf8String, -1, unsafeBitCast(-1, to: sqlite3_destructor_type.self))
220
+ } else if let n = param as? Int {
221
+ sqlite3_bind_int64(stmt, idx, Int64(n))
222
+ } else if let d = param as? Double {
223
+ sqlite3_bind_double(stmt, idx, d)
224
+ } else if let b = param as? Bool {
225
+ sqlite3_bind_int(stmt, idx, b ? 1 : 0)
226
+ } else {
227
+ // Fallback: bind as text
228
+ let str = "\(param)"
229
+ sqlite3_bind_text(stmt, idx, (str as NSString).utf8String, -1, unsafeBitCast(-1, to: sqlite3_destructor_type.self))
230
+ }
231
+ }
232
+ }
233
+
234
+ /// Extract a column value from the current row of a statement.
235
+ private func columnValue(stmt: OpaquePointer, index: Int32) -> Any {
236
+ let type = sqlite3_column_type(stmt, index)
237
+ switch type {
238
+ case SQLITE_INTEGER:
239
+ return Int(sqlite3_column_int64(stmt, index))
240
+ case SQLITE_FLOAT:
241
+ return sqlite3_column_double(stmt, index)
242
+ case SQLITE_TEXT:
243
+ return String(cString: sqlite3_column_text(stmt, index))
244
+ case SQLITE_BLOB:
245
+ // Return blob as base64 string
246
+ if let data = sqlite3_column_blob(stmt, index) {
247
+ let bytes = sqlite3_column_bytes(stmt, index)
248
+ let d = Data(bytes: data, count: Int(bytes))
249
+ return d.base64EncodedString()
250
+ }
251
+ return NSNull()
252
+ case SQLITE_NULL:
253
+ return NSNull()
254
+ default:
255
+ return NSNull()
256
+ }
257
+ }
258
+ }
259
+ #endif
@@ -0,0 +1,34 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+
4
+ /// Native module providing device and screen information.
5
+ ///
6
+ /// Methods:
7
+ /// - getInfo() -> { model, systemVersion, screenWidth, screenHeight, scale }
8
+ final class DeviceInfoModule: NativeModule {
9
+ let moduleName = "DeviceInfo"
10
+
11
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
12
+ DispatchQueue.main.async {
13
+ switch method {
14
+ case "getInfo":
15
+ let device = UIDevice.current
16
+ let screen = UIScreen.main
17
+ let info: [String: Any] = [
18
+ "model": device.model,
19
+ "systemVersion": device.systemVersion,
20
+ "systemName": device.systemName,
21
+ "name": device.name,
22
+ "screenWidth": screen.bounds.width,
23
+ "screenHeight": screen.bounds.height,
24
+ "scale": screen.scale
25
+ ]
26
+ callback(info, nil)
27
+
28
+ default:
29
+ callback(nil, "DeviceInfoModule: Unknown method '\(method)'")
30
+ }
31
+ }
32
+ }
33
+ }
34
+ #endif
@@ -0,0 +1,233 @@
1
+ #if canImport(UIKit)
2
+ import Foundation
3
+
4
+ /// Native module providing file system access.
5
+ ///
6
+ /// Methods:
7
+ /// - readFile(path: String, encoding: String?) -> String
8
+ /// - writeFile(path: String, content: String, encoding: String?)
9
+ /// - deleteFile(path: String)
10
+ /// - exists(path: String) -> Bool
11
+ /// - listDirectory(path: String) -> [String]
12
+ /// - downloadFile(url: String, destPath: String) -> String
13
+ /// - getDocumentsPath() -> String
14
+ /// - getCachesPath() -> String
15
+ /// - stat(path: String) -> { size, isDirectory, modified }
16
+ /// - mkdir(path: String)
17
+ /// - copyFile(srcPath: String, destPath: String)
18
+ /// - moveFile(srcPath: String, destPath: String)
19
+ final class FileSystemModule: NativeModule {
20
+ let moduleName = "FileSystem"
21
+
22
+ private let fileManager = FileManager.default
23
+
24
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
25
+ DispatchQueue.global(qos: .userInitiated).async { [weak self] in
26
+ guard let self = self else { return }
27
+ switch method {
28
+ case "readFile":
29
+ guard let path = args.first as? String else {
30
+ callback(nil, "readFile: missing path")
31
+ return
32
+ }
33
+ let encoding = (args.count > 1 ? args[1] as? String : nil) ?? "utf8"
34
+ guard self.fileManager.fileExists(atPath: path) else {
35
+ callback(nil, "readFile: file not found at \(path)")
36
+ return
37
+ }
38
+ guard let data = self.fileManager.contents(atPath: path) else {
39
+ callback(nil, "readFile: could not read file at \(path)")
40
+ return
41
+ }
42
+ if encoding == "base64" {
43
+ callback(data.base64EncodedString(), nil)
44
+ } else {
45
+ guard let text = String(data: data, encoding: .utf8) else {
46
+ callback(nil, "readFile: file is not valid UTF-8")
47
+ return
48
+ }
49
+ callback(text, nil)
50
+ }
51
+
52
+ case "writeFile":
53
+ guard args.count >= 2,
54
+ let path = args[0] as? String,
55
+ let content = args[1] as? String else {
56
+ callback(nil, "writeFile: missing path or content")
57
+ return
58
+ }
59
+ let encoding = (args.count > 2 ? args[2] as? String : nil) ?? "utf8"
60
+ let data: Data?
61
+ if encoding == "base64" {
62
+ data = Data(base64Encoded: content)
63
+ } else {
64
+ data = content.data(using: .utf8)
65
+ }
66
+ guard let fileData = data else {
67
+ callback(nil, "writeFile: could not encode content")
68
+ return
69
+ }
70
+ // Create parent directory if needed
71
+ let dir = (path as NSString).deletingLastPathComponent
72
+ if !self.fileManager.fileExists(atPath: dir) {
73
+ do {
74
+ try self.fileManager.createDirectory(atPath: dir, withIntermediateDirectories: true)
75
+ } catch {
76
+ callback(nil, "writeFile: could not create directory: \(error.localizedDescription)")
77
+ return
78
+ }
79
+ }
80
+ self.fileManager.createFile(atPath: path, contents: fileData)
81
+ callback(nil, nil)
82
+
83
+ case "deleteFile":
84
+ guard let path = args.first as? String else {
85
+ callback(nil, "deleteFile: missing path")
86
+ return
87
+ }
88
+ guard self.fileManager.fileExists(atPath: path) else {
89
+ callback(nil, "deleteFile: file not found at \(path)")
90
+ return
91
+ }
92
+ do {
93
+ try self.fileManager.removeItem(atPath: path)
94
+ callback(nil, nil)
95
+ } catch {
96
+ callback(nil, "deleteFile: \(error.localizedDescription)")
97
+ }
98
+
99
+ case "exists":
100
+ guard let path = args.first as? String else {
101
+ callback(nil, "exists: missing path")
102
+ return
103
+ }
104
+ callback(self.fileManager.fileExists(atPath: path), nil)
105
+
106
+ case "listDirectory":
107
+ guard let path = args.first as? String else {
108
+ callback(nil, "listDirectory: missing path")
109
+ return
110
+ }
111
+ do {
112
+ let contents = try self.fileManager.contentsOfDirectory(atPath: path)
113
+ callback(contents, nil)
114
+ } catch {
115
+ callback(nil, "listDirectory: \(error.localizedDescription)")
116
+ }
117
+
118
+ case "downloadFile":
119
+ guard args.count >= 2,
120
+ let urlString = args[0] as? String,
121
+ let destPath = args[1] as? String else {
122
+ callback(nil, "downloadFile: missing url or destPath")
123
+ return
124
+ }
125
+ guard let url = URL(string: urlString) else {
126
+ callback(nil, "downloadFile: invalid URL")
127
+ return
128
+ }
129
+ let task = URLSession.shared.dataTask(with: url) { data, response, error in
130
+ if let error = error {
131
+ callback(nil, "downloadFile: \(error.localizedDescription)")
132
+ return
133
+ }
134
+ guard let data = data else {
135
+ callback(nil, "downloadFile: no data received")
136
+ return
137
+ }
138
+ // Create parent directory if needed
139
+ let dir = (destPath as NSString).deletingLastPathComponent
140
+ if !self.fileManager.fileExists(atPath: dir) {
141
+ do {
142
+ try self.fileManager.createDirectory(atPath: dir, withIntermediateDirectories: true)
143
+ } catch {
144
+ callback(nil, "downloadFile: could not create directory: \(error.localizedDescription)")
145
+ return
146
+ }
147
+ }
148
+ self.fileManager.createFile(atPath: destPath, contents: data)
149
+ callback(destPath, nil)
150
+ }
151
+ task.resume()
152
+
153
+ case "getDocumentsPath":
154
+ let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
155
+ callback(paths.first, nil)
156
+
157
+ case "getCachesPath":
158
+ let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
159
+ callback(paths.first, nil)
160
+
161
+ case "stat":
162
+ guard let path = args.first as? String else {
163
+ callback(nil, "stat: missing path")
164
+ return
165
+ }
166
+ do {
167
+ let attrs = try self.fileManager.attributesOfItem(atPath: path)
168
+ let size = (attrs[.size] as? Int) ?? 0
169
+ let isDir = (attrs[.type] as? FileAttributeType) == .typeDirectory
170
+ let modified = (attrs[.modificationDate] as? Date)?.timeIntervalSince1970 ?? 0
171
+ callback([
172
+ "size": size,
173
+ "isDirectory": isDir,
174
+ "modified": modified * 1000 // milliseconds for JS
175
+ ] as [String: Any], nil)
176
+ } catch {
177
+ callback(nil, "stat: \(error.localizedDescription)")
178
+ }
179
+
180
+ case "mkdir":
181
+ guard let path = args.first as? String else {
182
+ callback(nil, "mkdir: missing path")
183
+ return
184
+ }
185
+ do {
186
+ try self.fileManager.createDirectory(atPath: path, withIntermediateDirectories: true)
187
+ callback(nil, nil)
188
+ } catch {
189
+ callback(nil, "mkdir: \(error.localizedDescription)")
190
+ }
191
+
192
+ case "copyFile":
193
+ guard args.count >= 2,
194
+ let srcPath = args[0] as? String,
195
+ let destPath = args[1] as? String else {
196
+ callback(nil, "copyFile: missing srcPath or destPath")
197
+ return
198
+ }
199
+ do {
200
+ // Remove destination if it exists (copyItem throws if dest exists)
201
+ if self.fileManager.fileExists(atPath: destPath) {
202
+ try self.fileManager.removeItem(atPath: destPath)
203
+ }
204
+ try self.fileManager.copyItem(atPath: srcPath, toPath: destPath)
205
+ callback(nil, nil)
206
+ } catch {
207
+ callback(nil, "copyFile: \(error.localizedDescription)")
208
+ }
209
+
210
+ case "moveFile":
211
+ guard args.count >= 2,
212
+ let srcPath = args[0] as? String,
213
+ let destPath = args[1] as? String else {
214
+ callback(nil, "moveFile: missing srcPath or destPath")
215
+ return
216
+ }
217
+ do {
218
+ if self.fileManager.fileExists(atPath: destPath) {
219
+ try self.fileManager.removeItem(atPath: destPath)
220
+ }
221
+ try self.fileManager.moveItem(atPath: srcPath, toPath: destPath)
222
+ callback(nil, nil)
223
+ } catch {
224
+ callback(nil, "moveFile: \(error.localizedDescription)")
225
+ }
226
+
227
+ default:
228
+ callback(nil, "FileSystemModule: Unknown method '\(method)'")
229
+ }
230
+ }
231
+ }
232
+ }
233
+ #endif
@@ -0,0 +1,147 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+ import CoreLocation
4
+
5
+ /// Native module for GPS/location access.
6
+ ///
7
+ /// Methods:
8
+ /// - getCurrentPosition() -> location payload
9
+ /// - watchPosition() -> watchId (Int); fires "location:update" global events
10
+ /// - clearWatch(watchId: Int)
11
+ ///
12
+ /// Location payload keys: latitude, longitude, altitude, accuracy,
13
+ /// altitudeAccuracy, heading, speed, timestamp
14
+ final class GeolocationModule: NativeModule {
15
+ var moduleName: String { "Geolocation" }
16
+ private weak var bridge: NativeBridge?
17
+
18
+ init(bridge: NativeBridge) { self.bridge = bridge }
19
+
20
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
21
+ switch method {
22
+ case "getCurrentPosition":
23
+ DispatchQueue.main.async {
24
+ GeolocationManager.shared.getCurrentPosition(callback: callback)
25
+ }
26
+ case "watchPosition":
27
+ let weakBridge = bridge
28
+ DispatchQueue.main.async {
29
+ let watchId = GeolocationManager.shared.watchPosition(bridge: weakBridge)
30
+ callback(watchId, nil)
31
+ }
32
+ case "clearWatch":
33
+ guard let watchId = args.first.flatMap({ $0 as? Int }) else {
34
+ callback(nil, nil); return
35
+ }
36
+ DispatchQueue.main.async {
37
+ GeolocationManager.shared.clearWatch(watchId)
38
+ callback(nil, nil)
39
+ }
40
+ default:
41
+ callback(nil, "GeolocationModule: Unknown method '\(method)'")
42
+ }
43
+ }
44
+
45
+ func invokeSync(method: String, args: [Any]) -> Any? { nil }
46
+ }
47
+
48
+ // MARK: - Internal location manager
49
+
50
+ /// All CLLocationManager interactions happen on @MainActor (main thread),
51
+ /// matching the UIKit + CoreLocation threading requirement.
52
+ @MainActor
53
+ private final class GeolocationManager: NSObject, CLLocationManagerDelegate {
54
+ static let shared = GeolocationManager()
55
+
56
+ private var manager: CLLocationManager?
57
+ private var pendingCallbacks: [(Any?, String?) -> Void] = []
58
+
59
+ // Map watchId -> weak bridge reference
60
+ private struct WeakBridge { weak var bridge: NativeBridge? }
61
+ private var watchCallbacks: [Int: WeakBridge] = [:]
62
+ private var nextWatchId = 1
63
+
64
+ // MARK: Setup
65
+
66
+ private func ensureManager() {
67
+ guard manager == nil else { return }
68
+ let mgr = CLLocationManager()
69
+ mgr.delegate = self
70
+ mgr.desiredAccuracy = kCLLocationAccuracyBest
71
+ manager = mgr
72
+ }
73
+
74
+ // MARK: Public interface (called on main thread)
75
+
76
+ func getCurrentPosition(callback: @escaping (Any?, String?) -> Void) {
77
+ ensureManager()
78
+ guard let manager = manager else {
79
+ callback(nil, "Failed to initialize location manager"); return
80
+ }
81
+ let status = manager.authorizationStatus
82
+ guard status == .authorizedWhenInUse || status == .authorizedAlways else {
83
+ callback(nil, "Location permission not granted"); return
84
+ }
85
+ pendingCallbacks.append(callback)
86
+ manager.requestLocation()
87
+ }
88
+
89
+ func watchPosition(bridge: NativeBridge?) -> Int {
90
+ ensureManager()
91
+ guard let manager = manager else {
92
+ return -1
93
+ }
94
+ let status = manager.authorizationStatus
95
+ guard status == .authorizedWhenInUse || status == .authorizedAlways else {
96
+ // Return a sentinel; caller will get no updates
97
+ return -1
98
+ }
99
+ let watchId = nextWatchId; nextWatchId += 1
100
+ watchCallbacks[watchId] = WeakBridge(bridge: bridge)
101
+ manager.startUpdatingLocation()
102
+ return watchId
103
+ }
104
+
105
+ func clearWatch(_ watchId: Int) {
106
+ watchCallbacks.removeValue(forKey: watchId)
107
+ if watchCallbacks.isEmpty {
108
+ manager?.stopUpdatingLocation()
109
+ }
110
+ }
111
+
112
+ // MARK: CLLocationManagerDelegate
113
+ // nonisolated required by protocol; we hop to @MainActor via Task.
114
+
115
+ nonisolated func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
116
+ guard let loc = locations.last else { return }
117
+ let payload: [String: Any] = [
118
+ "latitude": loc.coordinate.latitude,
119
+ "longitude": loc.coordinate.longitude,
120
+ "altitude": loc.altitude,
121
+ "accuracy": loc.horizontalAccuracy,
122
+ "altitudeAccuracy": loc.verticalAccuracy,
123
+ "heading": loc.course,
124
+ "speed": loc.speed,
125
+ "timestamp": loc.timestamp.timeIntervalSince1970 * 1000
126
+ ]
127
+ Task { @MainActor in
128
+ // Fire one-shot callbacks
129
+ let cbs = self.pendingCallbacks
130
+ self.pendingCallbacks.removeAll()
131
+ for cb in cbs { cb(payload, nil) }
132
+ // Fire watch callbacks
133
+ for (_, wb) in self.watchCallbacks {
134
+ wb.bridge?.dispatchGlobalEvent("location:update", payload: payload)
135
+ }
136
+ }
137
+ }
138
+
139
+ nonisolated func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
140
+ Task { @MainActor in
141
+ let cbs = self.pendingCallbacks
142
+ self.pendingCallbacks.removeAll()
143
+ for cb in cbs { cb(nil, error.localizedDescription) }
144
+ }
145
+ }
146
+ }
147
+ #endif