neoagent 2.3.1-beta.2 → 2.3.1-beta.21

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 (264) hide show
  1. package/.env.example +39 -0
  2. package/README.md +2 -0
  3. package/docs/capabilities.md +2 -2
  4. package/docs/configuration.md +13 -5
  5. package/docs/integrations.md +4 -1
  6. package/flutter_app/.metadata +42 -0
  7. package/flutter_app/README.md +21 -0
  8. package/flutter_app/analysis_options.yaml +32 -0
  9. package/flutter_app/android/app/build.gradle.kts +109 -0
  10. package/flutter_app/android/app/src/debug/AndroidManifest.xml +7 -0
  11. package/flutter_app/android/app/src/main/AndroidManifest.xml +147 -0
  12. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +747 -0
  13. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthConnectGateway.kt +280 -0
  14. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncNotifications.kt +113 -0
  15. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncPayload.kt +57 -0
  16. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncScheduler.kt +78 -0
  17. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncWorker.kt +253 -0
  18. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/PermissionsRationaleActivity.kt +46 -0
  19. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +21 -0
  20. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +586 -0
  21. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +78 -0
  22. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +104 -0
  23. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiHomeWidgetProvider.kt +457 -0
  24. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiWidgetStore.kt +194 -0
  25. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/VoiceLaunchWidgetProvider.kt +67 -0
  26. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetConfigActivity.kt +228 -0
  27. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncScheduler.kt +72 -0
  28. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncWorker.kt +186 -0
  29. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetTaskRunWorker.kt +210 -0
  30. package/flutter_app/android/app/src/main/res/drawable/launch_background.xml +12 -0
  31. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_bg.xml +11 -0
  32. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_task_bg.xml +8 -0
  33. package/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  34. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget.xml +138 -0
  35. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget_task_row.xml +52 -0
  36. package/flutter_app/android/app/src/main/res/layout/neoagent_voice_widget.xml +49 -0
  37. package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  38. package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  39. package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  40. package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  41. package/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  42. package/flutter_app/android/app/src/main/res/values/strings.xml +12 -0
  43. package/flutter_app/android/app/src/main/res/values/styles.xml +18 -0
  44. package/flutter_app/android/app/src/main/res/values-night/styles.xml +18 -0
  45. package/flutter_app/android/app/src/main/res/xml/file_paths.xml +6 -0
  46. package/flutter_app/android/app/src/main/res/xml/neoagent_ai_widget_info.xml +12 -0
  47. package/flutter_app/android/app/src/main/res/xml/neoagent_voice_widget_info.xml +12 -0
  48. package/flutter_app/android/app/src/profile/AndroidManifest.xml +7 -0
  49. package/flutter_app/android/build.gradle.kts +24 -0
  50. package/flutter_app/android/ci-release.keystore +0 -0
  51. package/flutter_app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  52. package/flutter_app/android/gradle.properties +3 -0
  53. package/flutter_app/android/key.properties +4 -0
  54. package/flutter_app/android/settings.gradle.kts +26 -0
  55. package/flutter_app/assets/branding/app_icon_1024.png +0 -0
  56. package/flutter_app/assets/branding/app_icon_128.png +0 -0
  57. package/flutter_app/assets/branding/app_icon_192.png +0 -0
  58. package/flutter_app/assets/branding/app_icon_256.png +0 -0
  59. package/flutter_app/assets/branding/app_icon_32.png +0 -0
  60. package/flutter_app/assets/branding/app_icon_512.png +0 -0
  61. package/flutter_app/assets/branding/app_icon_64.png +0 -0
  62. package/flutter_app/assets/branding/tray_icon_template.png +0 -0
  63. package/flutter_app/lib/features/location/location_service.dart +119 -0
  64. package/flutter_app/lib/features/notifications/notification_interceptor.dart +97 -0
  65. package/flutter_app/lib/main.dart +23057 -0
  66. package/flutter_app/lib/main_app_shell.dart +1682 -0
  67. package/flutter_app/lib/main_integrations.dart +931 -0
  68. package/flutter_app/lib/main_launcher.dart +959 -0
  69. package/flutter_app/lib/main_launcher_entry.dart +5 -0
  70. package/flutter_app/lib/main_models.dart +3473 -0
  71. package/flutter_app/lib/main_shared.dart +2861 -0
  72. package/flutter_app/lib/main_theme.dart +204 -0
  73. package/flutter_app/lib/main_voice_assistant.dart +831 -0
  74. package/flutter_app/lib/src/android_apk_drop_zone.dart +32 -0
  75. package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +16 -0
  76. package/flutter_app/lib/src/android_apk_drop_zone_web.dart +348 -0
  77. package/flutter_app/lib/src/android_app_installer.dart +22 -0
  78. package/flutter_app/lib/src/android_app_installer_io.dart +122 -0
  79. package/flutter_app/lib/src/android_app_installer_stub.dart +21 -0
  80. package/flutter_app/lib/src/android_launcher_bridge.dart +239 -0
  81. package/flutter_app/lib/src/app_launch_bridge.dart +29 -0
  82. package/flutter_app/lib/src/app_release_updater.dart +511 -0
  83. package/flutter_app/lib/src/backend_client.dart +1833 -0
  84. package/flutter_app/lib/src/desktop_companion.dart +2 -0
  85. package/flutter_app/lib/src/desktop_companion_actions.dart +586 -0
  86. package/flutter_app/lib/src/desktop_companion_io.dart +538 -0
  87. package/flutter_app/lib/src/desktop_companion_stub.dart +59 -0
  88. package/flutter_app/lib/src/desktop_native_bridge.dart +91 -0
  89. package/flutter_app/lib/src/desktop_screen_capture.dart +21 -0
  90. package/flutter_app/lib/src/desktop_screen_capture_io.dart +142 -0
  91. package/flutter_app/lib/src/desktop_screen_capture_stub.dart +12 -0
  92. package/flutter_app/lib/src/diagnostics_logger.dart +119 -0
  93. package/flutter_app/lib/src/health_bridge.dart +136 -0
  94. package/flutter_app/lib/src/live_voice_capture.dart +85 -0
  95. package/flutter_app/lib/src/messaging_access_summary.dart +46 -0
  96. package/flutter_app/lib/src/network/app_http_client.dart +53 -0
  97. package/flutter_app/lib/src/network/app_http_client_factory.dart +6 -0
  98. package/flutter_app/lib/src/network/app_http_client_io.dart +138 -0
  99. package/flutter_app/lib/src/network/app_http_client_stub.dart +3 -0
  100. package/flutter_app/lib/src/network/app_http_client_web.dart +94 -0
  101. package/flutter_app/lib/src/oauth_launcher.dart +33 -0
  102. package/flutter_app/lib/src/oauth_launcher_io.dart +77 -0
  103. package/flutter_app/lib/src/oauth_launcher_stub.dart +33 -0
  104. package/flutter_app/lib/src/oauth_launcher_web.dart +107 -0
  105. package/flutter_app/lib/src/recording_bridge.dart +232 -0
  106. package/flutter_app/lib/src/recording_bridge_io.dart +1019 -0
  107. package/flutter_app/lib/src/recording_bridge_stub.dart +120 -0
  108. package/flutter_app/lib/src/recording_bridge_web.dart +689 -0
  109. package/flutter_app/lib/src/recording_payloads.dart +86 -0
  110. package/flutter_app/lib/src/theme/palette.dart +81 -0
  111. package/flutter_app/lib/src/widget_bridge.dart +49 -0
  112. package/flutter_app/linux/CMakeLists.txt +128 -0
  113. package/flutter_app/linux/flutter/CMakeLists.txt +88 -0
  114. package/flutter_app/linux/flutter/generated_plugin_registrant.cc +43 -0
  115. package/flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
  116. package/flutter_app/linux/flutter/generated_plugins.cmake +31 -0
  117. package/flutter_app/linux/runner/CMakeLists.txt +26 -0
  118. package/flutter_app/linux/runner/main.cc +6 -0
  119. package/flutter_app/linux/runner/my_application.cc +144 -0
  120. package/flutter_app/linux/runner/my_application.h +18 -0
  121. package/flutter_app/linux/runner/resources/app_icon.png +0 -0
  122. package/flutter_app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
  123. package/flutter_app/macos/Flutter/Flutter-Release.xcconfig +2 -0
  124. package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +40 -0
  125. package/flutter_app/macos/Podfile +42 -0
  126. package/flutter_app/macos/Podfile.lock +87 -0
  127. package/flutter_app/macos/Runner/AppDelegate.swift +576 -0
  128. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  129. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  130. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  131. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  132. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  133. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  134. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  135. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  136. package/flutter_app/macos/Runner/Base.lproj/MainMenu.xib +342 -0
  137. package/flutter_app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  138. package/flutter_app/macos/Runner/Configs/Debug.xcconfig +2 -0
  139. package/flutter_app/macos/Runner/Configs/Release.xcconfig +2 -0
  140. package/flutter_app/macos/Runner/Configs/Warnings.xcconfig +13 -0
  141. package/flutter_app/macos/Runner/DebugProfile.entitlements +16 -0
  142. package/flutter_app/macos/Runner/Info.plist +36 -0
  143. package/flutter_app/macos/Runner/MainFlutterWindow.swift +19 -0
  144. package/flutter_app/macos/Runner/Release.entitlements +12 -0
  145. package/flutter_app/macos/Runner.xcodeproj/project.pbxproj +801 -0
  146. package/flutter_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  147. package/flutter_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
  148. package/flutter_app/macos/Runner.xcworkspace/contents.xcworkspacedata +10 -0
  149. package/flutter_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  150. package/flutter_app/macos/RunnerTests/RunnerTests.swift +12 -0
  151. package/flutter_app/patch_strings.py +12 -0
  152. package/flutter_app/pubspec.lock +1088 -0
  153. package/flutter_app/pubspec.yaml +53 -0
  154. package/flutter_app/test/messaging_access_summary_test.dart +22 -0
  155. package/flutter_app/test/recording_payloads_test.dart +53 -0
  156. package/flutter_app/third_party/desktop_audio_capture/LICENSE +21 -0
  157. package/flutter_app/third_party/desktop_audio_capture/README.md +262 -0
  158. package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +65 -0
  159. package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +153 -0
  160. package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +110 -0
  161. package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +461 -0
  162. package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +91 -0
  163. package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +106 -0
  164. package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +219 -0
  165. package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +336 -0
  166. package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +101 -0
  167. package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +692 -0
  168. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +35 -0
  169. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +36 -0
  170. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +32 -0
  171. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +32 -0
  172. package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +878 -0
  173. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +27 -0
  174. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +1172 -0
  175. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +655 -0
  176. package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +12 -0
  177. package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +30 -0
  178. package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +87 -0
  179. package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +105 -0
  180. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +80 -0
  181. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +31 -0
  182. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +12 -0
  183. package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +23 -0
  184. package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +25 -0
  185. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +1117 -0
  186. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +115 -0
  187. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +777 -0
  188. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +87 -0
  189. package/flutter_app/third_party/flutter_secure_storage_linux/linux/CMakeLists.txt +30 -0
  190. package/flutter_app/third_party/flutter_secure_storage_linux/linux/flutter_secure_storage_linux_plugin.cc +215 -0
  191. package/flutter_app/third_party/flutter_secure_storage_linux/linux/include/flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h +27 -0
  192. package/flutter_app/third_party/flutter_secure_storage_linux/pubspec.yaml +20 -0
  193. package/flutter_app/tool/generate_desktop_branding.py +219 -0
  194. package/flutter_app/web/favicon.png +0 -0
  195. package/flutter_app/web/favicon.svg +12 -0
  196. package/flutter_app/web/icons/Icon-192.png +0 -0
  197. package/flutter_app/web/icons/Icon-512.png +0 -0
  198. package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
  199. package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
  200. package/flutter_app/web/index.html +39 -0
  201. package/flutter_app/web/manifest.json +35 -0
  202. package/flutter_app/windows/CMakeLists.txt +108 -0
  203. package/flutter_app/windows/flutter/CMakeLists.txt +109 -0
  204. package/flutter_app/windows/flutter/generated_plugin_registrant.cc +47 -0
  205. package/flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
  206. package/flutter_app/windows/flutter/generated_plugins.cmake +35 -0
  207. package/flutter_app/windows/runner/CMakeLists.txt +41 -0
  208. package/flutter_app/windows/runner/Runner.rc +121 -0
  209. package/flutter_app/windows/runner/flutter_window.cpp +533 -0
  210. package/flutter_app/windows/runner/flutter_window.h +37 -0
  211. package/flutter_app/windows/runner/main.cpp +53 -0
  212. package/flutter_app/windows/runner/resource.h +16 -0
  213. package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
  214. package/flutter_app/windows/runner/runner.exe.manifest +14 -0
  215. package/flutter_app/windows/runner/utils.cpp +65 -0
  216. package/flutter_app/windows/runner/utils.h +19 -0
  217. package/flutter_app/windows/runner/win32_window.cpp +299 -0
  218. package/flutter_app/windows/runner/win32_window.h +102 -0
  219. package/lib/manager.js +231 -7
  220. package/package.json +3 -1
  221. package/server/db/database.js +68 -0
  222. package/server/http/middleware.js +50 -0
  223. package/server/http/routes.js +3 -1
  224. package/server/index.js +1 -0
  225. package/server/public/.last_build_id +1 -1
  226. package/server/public/assets/NOTICES +61 -0
  227. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  228. package/server/public/flutter_bootstrap.js +1 -1
  229. package/server/public/main.dart.js +65262 -64422
  230. package/server/routes/integrations.js +86 -0
  231. package/server/routes/memory.js +11 -2
  232. package/server/routes/screenHistory.js +46 -0
  233. package/server/routes/triggers.js +81 -0
  234. package/server/services/ai/models.js +30 -0
  235. package/server/services/ai/providers/githubCopilot.js +97 -0
  236. package/server/services/ai/providers/openai.js +2 -1
  237. package/server/services/ai/providers/openaiCodex.js +31 -0
  238. package/server/services/ai/settings.js +20 -0
  239. package/server/services/ai/systemPrompt.js +1 -1
  240. package/server/services/ai/tools.js +35 -6
  241. package/server/services/browser/controller.js +47 -3
  242. package/server/services/desktop/screenRecorder.js +172 -0
  243. package/server/services/integrations/env.js +5 -0
  244. package/server/services/integrations/github/common.js +106 -0
  245. package/server/services/integrations/github/provider.js +499 -0
  246. package/server/services/integrations/github/repos.js +1124 -0
  247. package/server/services/integrations/home_assistant/provider.js +306 -26
  248. package/server/services/integrations/manager.js +63 -7
  249. package/server/services/integrations/oauth_provider.js +13 -6
  250. package/server/services/integrations/provider_config_store.js +76 -0
  251. package/server/services/integrations/registry.js +4 -0
  252. package/server/services/integrations/trello/provider.js +744 -0
  253. package/server/services/integrations/whatsapp/provider.js +6 -2
  254. package/server/services/manager.js +22 -0
  255. package/server/services/memory/manager.js +39 -2
  256. package/server/services/skills/base_catalog.js +33 -0
  257. package/server/services/tasks/adapters/index.js +1 -0
  258. package/server/services/tasks/adapters/manual.js +12 -0
  259. package/server/services/tasks/runtime.js +1 -1
  260. package/server/services/voice/openaiClient.js +4 -1
  261. package/server/services/voice/providers.js +2 -1
  262. package/server/services/widgets/service.js +49 -4
  263. package/server/utils/local_secrets.js +56 -0
  264. package/server/utils/logger.js +37 -9
@@ -0,0 +1,138 @@
1
+ import 'dart:typed_data';
2
+
3
+ import 'package:http/http.dart' as http;
4
+
5
+ import 'app_http_client.dart';
6
+
7
+ AppHttpClient createPlatformHttpClient() => IoAppHttpClient();
8
+
9
+ class IoAppHttpClient implements AppHttpClient {
10
+ final http.Client _client = http.Client();
11
+ String? _sessionCookie;
12
+
13
+ HttpResponseData _toResponseData(http.Response response) {
14
+ return HttpResponseData(
15
+ statusCode: response.statusCode,
16
+ body: response.body,
17
+ bodyBytes: response.bodyBytes,
18
+ headers: response.headers,
19
+ );
20
+ }
21
+
22
+ @override
23
+ Future<HttpResponseData> get(Uri uri, {Map<String, String>? headers}) async {
24
+ final response = await _client.get(uri, headers: _withCookie(headers));
25
+ _storeCookie(response.headers);
26
+ return _toResponseData(response);
27
+ }
28
+
29
+ @override
30
+ Future<HttpResponseData> post(
31
+ Uri uri, {
32
+ Map<String, String>? headers,
33
+ Object? body,
34
+ }) async {
35
+ final response = await _client.post(
36
+ uri,
37
+ headers: _withCookie(headers),
38
+ body: body,
39
+ );
40
+ _storeCookie(response.headers);
41
+ return _toResponseData(response);
42
+ }
43
+
44
+ @override
45
+ Future<HttpResponseData> postMultipart(
46
+ Uri uri, {
47
+ Map<String, String>? headers,
48
+ required String fieldName,
49
+ required String filename,
50
+ required Uint8List bytes,
51
+ }) async {
52
+ final request = http.MultipartRequest('POST', uri);
53
+ request.headers.addAll(_withCookie(headers));
54
+ request.files.add(
55
+ http.MultipartFile.fromBytes(fieldName, bytes, filename: filename),
56
+ );
57
+ final response = await http.Response.fromStream(
58
+ await _client.send(request),
59
+ );
60
+ _storeCookie(response.headers);
61
+ return _toResponseData(response);
62
+ }
63
+
64
+ @override
65
+ Future<HttpResponseData> put(
66
+ Uri uri, {
67
+ Map<String, String>? headers,
68
+ Object? body,
69
+ }) async {
70
+ final response = await _client.put(
71
+ uri,
72
+ headers: _withCookie(headers),
73
+ body: body,
74
+ );
75
+ _storeCookie(response.headers);
76
+ return _toResponseData(response);
77
+ }
78
+
79
+ @override
80
+ Future<HttpResponseData> delete(
81
+ Uri uri, {
82
+ Map<String, String>? headers,
83
+ Object? body,
84
+ }) async {
85
+ final response = await _client.delete(
86
+ uri,
87
+ headers: _withCookie(headers),
88
+ body: body,
89
+ );
90
+ _storeCookie(response.headers);
91
+ return _toResponseData(response);
92
+ }
93
+
94
+ Map<String, String> _withCookie(Map<String, String>? headers) {
95
+ final next = <String, String>{...?headers};
96
+ if (_sessionCookie != null && _sessionCookie!.isNotEmpty) {
97
+ next['Cookie'] = _sessionCookie!;
98
+ }
99
+ return next;
100
+ }
101
+
102
+ void _storeCookie(Map<String, String> headers) {
103
+ final rawCookie = headers['set-cookie'];
104
+ if (rawCookie == null || rawCookie.isEmpty) {
105
+ return;
106
+ }
107
+ final firstCookieField = rawCookie.split(';').first.trim();
108
+ final separatorIndex = firstCookieField.indexOf('=');
109
+ if (separatorIndex <= 0) {
110
+ return;
111
+ }
112
+ final name = firstCookieField.substring(0, separatorIndex).trim();
113
+ final value = firstCookieField.substring(separatorIndex + 1).trim();
114
+ if (name.isEmpty || value.isEmpty) {
115
+ return;
116
+ }
117
+ _sessionCookie = '$name=$value';
118
+ }
119
+
120
+ @override
121
+ Future<void> close() async {
122
+ _client.close();
123
+ }
124
+
125
+ @override
126
+ void clearSession() {
127
+ _sessionCookie = null;
128
+ }
129
+
130
+ @override
131
+ void restoreSession(String? sessionCookie) {
132
+ final normalized = sessionCookie?.trim() ?? '';
133
+ _sessionCookie = normalized.isEmpty ? null : normalized;
134
+ }
135
+
136
+ @override
137
+ String? get sessionCookie => _sessionCookie;
138
+ }
@@ -0,0 +1,3 @@
1
+ Never createPlatformHttpClient() {
2
+ throw UnsupportedError('No HTTP client implementation for this platform.');
3
+ }
@@ -0,0 +1,94 @@
1
+ import 'dart:typed_data';
2
+
3
+ import 'package:http/browser_client.dart';
4
+ import 'package:http/http.dart' as http;
5
+
6
+ import 'app_http_client.dart';
7
+
8
+ AppHttpClient createPlatformHttpClient() => WebAppHttpClient();
9
+
10
+ class WebAppHttpClient implements AppHttpClient {
11
+ WebAppHttpClient() : _client = BrowserClient()..withCredentials = true;
12
+
13
+ final BrowserClient _client;
14
+
15
+ HttpResponseData _toResponseData(http.Response response) {
16
+ return HttpResponseData(
17
+ statusCode: response.statusCode,
18
+ body: response.body,
19
+ bodyBytes: response.bodyBytes,
20
+ headers: response.headers,
21
+ );
22
+ }
23
+
24
+ @override
25
+ Future<HttpResponseData> get(Uri uri, {Map<String, String>? headers}) async {
26
+ final response = await _client.get(uri, headers: headers);
27
+ return _toResponseData(response);
28
+ }
29
+
30
+ @override
31
+ Future<HttpResponseData> post(
32
+ Uri uri, {
33
+ Map<String, String>? headers,
34
+ Object? body,
35
+ }) async {
36
+ final response = await _client.post(uri, headers: headers, body: body);
37
+ return _toResponseData(response);
38
+ }
39
+
40
+ @override
41
+ Future<HttpResponseData> postMultipart(
42
+ Uri uri, {
43
+ Map<String, String>? headers,
44
+ required String fieldName,
45
+ required String filename,
46
+ required Uint8List bytes,
47
+ }) async {
48
+ final request = http.MultipartRequest('POST', uri);
49
+ if (headers != null) {
50
+ request.headers.addAll(headers);
51
+ }
52
+ request.files.add(
53
+ http.MultipartFile.fromBytes(fieldName, bytes, filename: filename),
54
+ );
55
+ final response = await http.Response.fromStream(
56
+ await _client.send(request),
57
+ );
58
+ return _toResponseData(response);
59
+ }
60
+
61
+ @override
62
+ Future<HttpResponseData> put(
63
+ Uri uri, {
64
+ Map<String, String>? headers,
65
+ Object? body,
66
+ }) async {
67
+ final response = await _client.put(uri, headers: headers, body: body);
68
+ return _toResponseData(response);
69
+ }
70
+
71
+ @override
72
+ Future<HttpResponseData> delete(
73
+ Uri uri, {
74
+ Map<String, String>? headers,
75
+ Object? body,
76
+ }) async {
77
+ final response = await _client.delete(uri, headers: headers, body: body);
78
+ return _toResponseData(response);
79
+ }
80
+
81
+ @override
82
+ Future<void> close() async {
83
+ _client.close();
84
+ }
85
+
86
+ @override
87
+ void clearSession() {}
88
+
89
+ @override
90
+ void restoreSession(String? sessionCookie) {}
91
+
92
+ @override
93
+ String? get sessionCookie => null;
94
+ }
@@ -0,0 +1,33 @@
1
+ import 'oauth_launcher_stub.dart'
2
+ if (dart.library.html) 'oauth_launcher_web.dart'
3
+ if (dart.library.io) 'oauth_launcher_io.dart';
4
+
5
+ OAuthLauncher createOAuthLauncher() => createPlatformOAuthLauncher();
6
+
7
+ abstract class OAuthLauncher {
8
+ Future<OAuthLaunchResult> launch({
9
+ required String url,
10
+ required String provider,
11
+ Duration timeout = const Duration(minutes: 2),
12
+ });
13
+
14
+ Future<OAuthLaunchResult> openExternal({
15
+ required String url,
16
+ required String label,
17
+ Duration timeout = const Duration(seconds: 10),
18
+ });
19
+
20
+ void dispose() {}
21
+ }
22
+
23
+ class OAuthLaunchResult {
24
+ const OAuthLaunchResult({
25
+ required this.launched,
26
+ required this.completed,
27
+ this.error,
28
+ });
29
+
30
+ final bool launched;
31
+ final bool completed;
32
+ final String? error;
33
+ }
@@ -0,0 +1,77 @@
1
+ import 'dart:async';
2
+ import 'dart:io';
3
+
4
+ import 'oauth_launcher.dart';
5
+
6
+ OAuthLauncher createPlatformOAuthLauncher() => _IoOAuthLauncher();
7
+
8
+ class _IoOAuthLauncher extends OAuthLauncher {
9
+ _IoOAuthLauncher();
10
+
11
+ @override
12
+ Future<OAuthLaunchResult> launch({
13
+ required String url,
14
+ required String provider,
15
+ Duration timeout = const Duration(minutes: 2),
16
+ }) async {
17
+ try {
18
+ late final ProcessResult result;
19
+ if (Platform.isMacOS) {
20
+ result = await Process.run(
21
+ 'open',
22
+ <String>[url],
23
+ ).timeout(timeout);
24
+ } else if (Platform.isLinux) {
25
+ result = await Process.run(
26
+ 'xdg-open',
27
+ <String>[url],
28
+ ).timeout(timeout);
29
+ } else if (Platform.isWindows) {
30
+ result = await Process.run(
31
+ 'start',
32
+ <String>[url],
33
+ runInShell: true,
34
+ ).timeout(timeout);
35
+ } else {
36
+ return const OAuthLaunchResult(
37
+ launched: false,
38
+ completed: false,
39
+ error: 'External browser launch is not supported on this platform.',
40
+ );
41
+ }
42
+
43
+ if (result.exitCode != 0) {
44
+ return OAuthLaunchResult(
45
+ launched: false,
46
+ completed: false,
47
+ error: (result.stderr?.toString().trim().isNotEmpty ?? false)
48
+ ? result.stderr.toString().trim()
49
+ : 'External browser launch failed with exit code ${result.exitCode}.',
50
+ );
51
+ }
52
+
53
+ return const OAuthLaunchResult(launched: true, completed: false);
54
+ } on TimeoutException {
55
+ return const OAuthLaunchResult(
56
+ launched: false,
57
+ completed: false,
58
+ error: 'External browser launch timed out.',
59
+ );
60
+ } catch (error) {
61
+ return OAuthLaunchResult(
62
+ launched: false,
63
+ completed: false,
64
+ error: error.toString(),
65
+ );
66
+ }
67
+ }
68
+
69
+ @override
70
+ Future<OAuthLaunchResult> openExternal({
71
+ required String url,
72
+ required String label,
73
+ Duration timeout = const Duration(seconds: 10),
74
+ }) {
75
+ return launch(url: url, provider: label, timeout: timeout);
76
+ }
77
+ }
@@ -0,0 +1,33 @@
1
+ import 'oauth_launcher.dart';
2
+
3
+ OAuthLauncher createPlatformOAuthLauncher() => _StubOAuthLauncher();
4
+
5
+ class _StubOAuthLauncher extends OAuthLauncher {
6
+ _StubOAuthLauncher();
7
+
8
+ @override
9
+ Future<OAuthLaunchResult> launch({
10
+ required String url,
11
+ required String provider,
12
+ Duration timeout = const Duration(minutes: 2),
13
+ }) async {
14
+ return const OAuthLaunchResult(
15
+ launched: false,
16
+ completed: false,
17
+ error: 'OAuth launch is not supported on this platform.',
18
+ );
19
+ }
20
+
21
+ @override
22
+ Future<OAuthLaunchResult> openExternal({
23
+ required String url,
24
+ required String label,
25
+ Duration timeout = const Duration(seconds: 10),
26
+ }) async {
27
+ return const OAuthLaunchResult(
28
+ launched: false,
29
+ completed: false,
30
+ error: 'External browser launch is not supported on this platform.',
31
+ );
32
+ }
33
+ }
@@ -0,0 +1,107 @@
1
+ // ignore_for_file: deprecated_member_use, avoid_web_libraries_in_flutter
2
+
3
+ import 'dart:async';
4
+ import 'dart:html' as html;
5
+
6
+ import 'oauth_launcher.dart';
7
+
8
+ OAuthLauncher createPlatformOAuthLauncher() => _WebOAuthLauncher();
9
+
10
+ class _WebOAuthLauncher extends OAuthLauncher {
11
+ StreamSubscription<html.MessageEvent>? _messageSubscription;
12
+ Timer? _timeoutTimer;
13
+
14
+ @override
15
+ Future<OAuthLaunchResult> launch({
16
+ required String url,
17
+ required String provider,
18
+ Duration timeout = const Duration(minutes: 2),
19
+ }) async {
20
+ final expectedOrigin = _deriveExpectedOrigin(url);
21
+ html.window.open(
22
+ url,
23
+ 'neoagent_oauth_${provider.replaceAll(RegExp(r'[^a-zA-Z0-9]+'), '_')}',
24
+ 'width=640,height=760',
25
+ );
26
+
27
+ final completer = Completer<OAuthLaunchResult>();
28
+
29
+ void finish(OAuthLaunchResult result) {
30
+ if (completer.isCompleted) return;
31
+ _timeoutTimer?.cancel();
32
+ _timeoutTimer = null;
33
+ _messageSubscription?.cancel();
34
+ _messageSubscription = null;
35
+ completer.complete(result);
36
+ }
37
+
38
+ _messageSubscription = html.window.onMessage.listen((event) {
39
+ if (expectedOrigin != null && event.origin != expectedOrigin) return;
40
+ final data = event.data;
41
+ if (data is! Map) return;
42
+ final type = data['type']?.toString();
43
+ final incomingProvider = data['provider']?.toString();
44
+ if (incomingProvider != null && incomingProvider != provider) return;
45
+ if (type == 'integration_oauth_success' || type == 'auth_oauth_success') {
46
+ finish(const OAuthLaunchResult(launched: true, completed: true));
47
+ } else if (type == 'integration_oauth_error' || type == 'auth_oauth_error') {
48
+ finish(
49
+ OAuthLaunchResult(
50
+ launched: true,
51
+ completed: false,
52
+ error: data['error']?.toString() ?? 'Authentication failed.',
53
+ ),
54
+ );
55
+ }
56
+ });
57
+
58
+ _timeoutTimer = Timer(timeout, () {
59
+ finish(
60
+ const OAuthLaunchResult(
61
+ launched: true,
62
+ completed: false,
63
+ error: 'Authentication timed out.',
64
+ ),
65
+ );
66
+ });
67
+
68
+ return completer.future;
69
+ }
70
+
71
+ @override
72
+ Future<OAuthLaunchResult> openExternal({
73
+ required String url,
74
+ required String label,
75
+ Duration timeout = const Duration(seconds: 10),
76
+ }) async {
77
+ html.window.open(
78
+ url,
79
+ label.replaceAll(RegExp(r'[^a-zA-Z0-9]+'), '_'),
80
+ 'noopener',
81
+ );
82
+ return const OAuthLaunchResult(launched: true, completed: false);
83
+ }
84
+
85
+ @override
86
+ void dispose() {
87
+ _timeoutTimer?.cancel();
88
+ _timeoutTimer = null;
89
+ _messageSubscription?.cancel();
90
+ _messageSubscription = null;
91
+ }
92
+
93
+ String? _deriveExpectedOrigin(String url) {
94
+ try {
95
+ final uri = Uri.parse(url);
96
+ final redirect = uri.queryParameters['redirect_uri'];
97
+ if (redirect != null && redirect.trim().isNotEmpty) {
98
+ final redirectUri = Uri.parse(redirect);
99
+ return redirectUri.origin;
100
+ }
101
+ if (uri.hasScheme && uri.host.isNotEmpty) {
102
+ return uri.origin;
103
+ }
104
+ } catch (_) {}
105
+ return null;
106
+ }
107
+ }