@legendapp/spark 0.0.1-next.2 → 0.0.1-next.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 (422) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -4
  3. package/ai-codex.ts +1 -0
  4. package/ai.ts +1 -0
  5. package/app-documents.ts +1 -0
  6. package/camera.ts +13 -0
  7. package/config-plugin.d.cts +2 -0
  8. package/contracts.ts +2 -0
  9. package/diagnostics.ts +1 -0
  10. package/expo-config.d.cts +1 -0
  11. package/metro.cjs +4 -1
  12. package/metro.d.cts +12 -0
  13. package/native.cjs +3 -1
  14. package/native.d.cts +6 -0
  15. package/package.json +93 -15
  16. package/patches/camera/react-native-nitro-image.patch +320 -0
  17. package/patches/camera/react-native-nitro-modules.patch +50 -0
  18. package/patches/camera/react-native-vision-camera.patch +2662 -0
  19. package/patches/camera/upstream.json +22 -0
  20. package/patches/dependencies.json +8 -0
  21. package/patches/react-native-enriched-markdown@1.0.2.patch +8684 -0
  22. package/postinstall.cjs +1 -0
  23. package/schema.json +276 -58
  24. package/settings-observable.ts +1 -0
  25. package/settings-window.ts +1 -0
  26. package/shortcuts-commands.ts +1 -0
  27. package/shortcuts-keyboard.ts +3 -0
  28. package/ui-classnames.ts +1 -0
  29. package/ui-glass.ts +1 -0
  30. package/ui-search.ts +1 -0
  31. package/ui-sidebar.ts +1 -0
  32. package/ui-split-view.ts +1 -0
  33. package/ui-swipe.ts +1 -0
  34. package/ui-symbol.ts +1 -0
  35. package/vendor/node_modules/@legendapp/spark-ai/package.json +19 -0
  36. package/vendor/node_modules/@legendapp/spark-ai/src/availability.ts +17 -0
  37. package/vendor/node_modules/@legendapp/spark-ai/src/index.ts +15 -0
  38. package/vendor/node_modules/@legendapp/spark-ai/src/invocations.ts +34 -0
  39. package/vendor/node_modules/@legendapp/spark-ai/src/output.ts +62 -0
  40. package/vendor/node_modules/@legendapp/spark-ai/src/run.ts +12 -0
  41. package/vendor/node_modules/@legendapp/spark-ai/src/types.ts +16 -0
  42. package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.h +2 -1
  43. package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.mm +126 -24
  44. package/vendor/node_modules/@legendapp/spark-audio/package.json +5 -2
  45. package/vendor/node_modules/@legendapp/spark-audio/src/NativeSparkAudio.ts +5 -1
  46. package/vendor/node_modules/@legendapp/spark-audio/src/desktop.ts +36 -32
  47. package/vendor/node_modules/@legendapp/spark-audio/src/events.ts +11 -0
  48. package/vendor/node_modules/@legendapp/spark-audio/src/hooks.ts +65 -0
  49. package/vendor/node_modules/@legendapp/spark-audio/src/index.web.ts +92 -33
  50. package/vendor/node_modules/@legendapp/spark-audio/src/media-session-unavailable.ts +6 -4
  51. package/vendor/node_modules/@legendapp/spark-audio/src/media-session.ts +52 -19
  52. package/vendor/node_modules/@legendapp/spark-audio/src/media-session.web.ts +18 -10
  53. package/vendor/node_modules/@legendapp/spark-audio/src/media-types.ts +40 -13
  54. package/vendor/node_modules/@legendapp/spark-audio/src/mobile.ts +40 -32
  55. package/vendor/node_modules/@legendapp/spark-audio/src/player.ts +97 -0
  56. package/vendor/node_modules/@legendapp/spark-audio/src/status-listeners.ts +21 -15
  57. package/vendor/node_modules/@legendapp/spark-audio/src/types.ts +9 -4
  58. package/vendor/node_modules/@legendapp/spark-audio/windows/SparkAudio/SparkAudio.h +67 -20
  59. package/vendor/node_modules/@legendapp/spark-auth-session/package.json +4 -3
  60. package/vendor/node_modules/@legendapp/spark-auth-session/src/core.ts +60 -42
  61. package/vendor/node_modules/@legendapp/spark-auth-session/src/index.ts +28 -12
  62. package/vendor/node_modules/@legendapp/spark-auth-session/src/mobile.ts +97 -41
  63. package/vendor/node_modules/@legendapp/spark-auth-session/src/types.ts +20 -9
  64. package/vendor/node_modules/@legendapp/spark-cli/dist/add-desktop.js +50 -7
  65. package/vendor/node_modules/@legendapp/spark-cli/dist/build-mode.js +1 -1
  66. package/vendor/node_modules/@legendapp/spark-cli/dist/build.js +145 -59
  67. package/vendor/node_modules/@legendapp/spark-cli/dist/cli-arguments.js +61 -0
  68. package/vendor/node_modules/@legendapp/spark-cli/dist/commands.js +10 -4
  69. package/vendor/node_modules/@legendapp/spark-cli/dist/create.js +37 -8
  70. package/vendor/node_modules/@legendapp/spark-cli/dist/credentials.js +86 -25
  71. package/vendor/node_modules/@legendapp/spark-cli/dist/dependency-pins.js +132 -0
  72. package/vendor/node_modules/@legendapp/spark-cli/dist/dev-command.js +13 -4
  73. package/vendor/node_modules/@legendapp/spark-cli/dist/dev.js +13 -10
  74. package/vendor/node_modules/@legendapp/spark-cli/dist/errors.js +100 -0
  75. package/vendor/node_modules/@legendapp/spark-cli/dist/examples.js +2 -2
  76. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-dev-patch.cjs +4 -2
  77. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-metro.cjs +1 -1
  78. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-native.cjs +5 -1
  79. package/vendor/node_modules/@legendapp/spark-cli/dist/expo-node.js +3 -3
  80. package/vendor/node_modules/@legendapp/spark-cli/dist/helpers.js +1 -1
  81. package/vendor/node_modules/@legendapp/spark-cli/dist/index.js +52 -44
  82. package/vendor/node_modules/@legendapp/spark-cli/dist/json.js +16 -0
  83. package/vendor/node_modules/@legendapp/spark-cli/dist/local.js +1 -1
  84. package/vendor/node_modules/@legendapp/spark-cli/dist/metro.cjs +26 -5
  85. package/vendor/node_modules/@legendapp/spark-cli/dist/native-metadata.js +26 -0
  86. package/vendor/node_modules/@legendapp/spark-cli/dist/native-patch-preflight.js +86 -0
  87. package/vendor/node_modules/@legendapp/spark-cli/dist/native-preparation.js +88 -0
  88. package/vendor/node_modules/@legendapp/spark-cli/dist/notary-profiles.js +75 -0
  89. package/vendor/node_modules/@legendapp/spark-cli/dist/package.js +4 -2
  90. package/vendor/node_modules/@legendapp/spark-cli/dist/platform.js +16 -2
  91. package/vendor/node_modules/@legendapp/spark-cli/dist/process.js +7 -0
  92. package/vendor/node_modules/@legendapp/spark-cli/dist/project.js +90 -32
  93. package/vendor/node_modules/@legendapp/spark-cli/dist/release.js +86 -5
  94. package/vendor/node_modules/@legendapp/spark-cli/dist/release.json +23 -18
  95. package/vendor/node_modules/@legendapp/spark-cli/dist/runner-install.js +145 -31
  96. package/vendor/node_modules/@legendapp/spark-cli/dist/signing.js +4 -3
  97. package/vendor/node_modules/@legendapp/spark-cli/dist/universal.cjs +2 -1
  98. package/vendor/node_modules/@legendapp/spark-cli/dist/updates.js +41 -4
  99. package/vendor/node_modules/@legendapp/spark-cli/dist/windows.js +5 -9
  100. package/vendor/node_modules/@legendapp/spark-cli/package.json +7 -6
  101. package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/App.tsx +6 -12
  102. package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/desktop.config.json +5 -3
  103. package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/package.json +12 -10
  104. package/vendor/node_modules/@legendapp/spark-cli/templates/diff-lite/Git.macos.tsx +2 -2
  105. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.macos.tsx +23 -21
  106. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.windows.tsx +23 -21
  107. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.desktop.ts +11 -8
  108. package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.macos.ts +3 -3
  109. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/Lifecycle.desktop.tsx +8 -14
  110. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/OpenFiles.desktop.tsx +5 -10
  111. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.desktop.ts +11 -8
  112. package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.macos.ts +3 -3
  113. package/vendor/node_modules/@legendapp/spark-cli/templates/music-lite/assets.desktop.ts +2 -2
  114. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Activation.desktop.tsx +2 -2
  115. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Desktop.desktop.ts +37 -15
  116. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/session.ts +5 -6
  117. package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/window-session.ts +5 -4
  118. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/desktop.config.json +5 -3
  119. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/metro.config.js +1 -1
  120. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/package.json +14 -12
  121. package/vendor/node_modules/@legendapp/spark-cli/templates/universal/react-native.config.js +1 -1
  122. package/vendor/node_modules/@legendapp/spark-cli/templates/windows/package.json +14 -12
  123. package/vendor/node_modules/@legendapp/spark-cli/templates/windows/react-native.config.js +1 -1
  124. package/vendor/node_modules/@legendapp/spark-clipboard/macos/RNDesktopClipboard.mm +10 -16
  125. package/vendor/node_modules/@legendapp/spark-clipboard/package.json +2 -2
  126. package/vendor/node_modules/@legendapp/spark-clipboard/src/NativeDesktopClipboard.ts +1 -1
  127. package/vendor/node_modules/@legendapp/spark-clipboard/src/desktop.ts +55 -31
  128. package/vendor/node_modules/@legendapp/spark-clipboard/src/expo.ts +21 -11
  129. package/vendor/node_modules/@legendapp/spark-clipboard/src/options.ts +8 -0
  130. package/vendor/node_modules/@legendapp/spark-clipboard/src/types.ts +10 -0
  131. package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.h +38 -15
  132. package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.vcxproj +2 -0
  133. package/vendor/node_modules/@legendapp/spark-codex/RNCodex.podspec +22 -0
  134. package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.hpp +23 -0
  135. package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.mm +1529 -0
  136. package/vendor/node_modules/@legendapp/spark-codex/nitro.json +21 -0
  137. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/.gitattributes +1 -0
  138. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex+autolinking.rb +62 -0
  139. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.cpp +17 -0
  140. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.hpp +27 -0
  141. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Umbrella.hpp +38 -0
  142. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.mm +35 -0
  143. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.swift +16 -0
  144. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexAvailability.hpp +95 -0
  145. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexRunResult.hpp +99 -0
  146. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.cpp +24 -0
  147. package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.hpp +71 -0
  148. package/vendor/node_modules/@legendapp/spark-codex/package.json +35 -0
  149. package/vendor/node_modules/@legendapp/spark-codex/react-native.config.js +11 -0
  150. package/vendor/node_modules/@legendapp/spark-codex/src/Codex.nitro.ts +30 -0
  151. package/vendor/node_modules/@legendapp/spark-codex/src/index.ts +65 -0
  152. package/vendor/node_modules/@legendapp/spark-codex/src/native.ts +6 -0
  153. package/vendor/node_modules/@legendapp/spark-commands/package.json +21 -0
  154. package/vendor/node_modules/@legendapp/spark-commands/src/bindings.ts +90 -0
  155. package/vendor/node_modules/@legendapp/spark-commands/src/index.tsx +400 -0
  156. package/vendor/node_modules/@legendapp/spark-commands/src/router.ts +138 -0
  157. package/vendor/node_modules/@legendapp/spark-commands/src/storage.ts +20 -0
  158. package/vendor/node_modules/@legendapp/spark-context-menu/macos/RNContextMenu.mm +7 -8
  159. package/vendor/node_modules/@legendapp/spark-context-menu/package.json +4 -3
  160. package/vendor/node_modules/@legendapp/spark-context-menu/src/NativeContextMenu.ts +1 -1
  161. package/vendor/node_modules/@legendapp/spark-context-menu/src/index.ts +26 -26
  162. package/vendor/node_modules/@legendapp/spark-context-menu/windows/SparkContextMenu/SparkContextMenu.h +3 -2
  163. package/vendor/node_modules/@legendapp/spark-desktop-app/RNDesktopApp.podspec +2 -1
  164. package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryJSI.hpp +89 -0
  165. package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryWindows.hpp +22 -0
  166. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/RNDesktopApp.mm +13 -7
  167. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkBinaryJSI.h +48 -0
  168. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.h +4 -0
  169. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.mm +33 -33
  170. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktopError.h +20 -0
  171. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.h +26 -0
  172. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.mm +49 -0
  173. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.h +9 -0
  174. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.mm +70 -0
  175. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkWindow.mm +9 -6
  176. package/vendor/node_modules/@legendapp/spark-desktop-app/macos/recent-documents/RNRecentDocumentController.mm +55 -0
  177. package/vendor/node_modules/@legendapp/spark-desktop-app/package.json +5 -3
  178. package/vendor/node_modules/@legendapp/spark-desktop-app/src/NativeDesktopApp.ts +1 -1
  179. package/vendor/node_modules/@legendapp/spark-desktop-app/src/api.ts +86 -40
  180. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/accelerator.ts +40 -0
  181. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/index.ts +56 -0
  182. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/menu.ts +116 -0
  183. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/native-buffer.ts +22 -0
  184. package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/path.ts +24 -0
  185. package/vendor/node_modules/@legendapp/spark-desktop-app/src/events.ts +75 -0
  186. package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.ts +2 -0
  187. package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.windows.ts +2 -0
  188. package/vendor/node_modules/@legendapp/spark-desktop-app/src/open-requests.ts +43 -0
  189. package/vendor/node_modules/@legendapp/spark-desktop-app/src/restoration.ts +11 -0
  190. package/vendor/node_modules/@legendapp/spark-desktop-app/src/transport.ts +10 -0
  191. package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.cjs +10 -5
  192. package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.d.cts +3 -0
  193. package/vendor/node_modules/@legendapp/spark-desktop-config/autolinking.cjs +35 -0
  194. package/vendor/node_modules/@legendapp/spark-desktop-config/config.cjs +18 -3
  195. package/vendor/node_modules/@legendapp/spark-desktop-config/config.d.cts +89 -9
  196. package/vendor/node_modules/@legendapp/spark-desktop-config/expo.cjs +1 -0
  197. package/vendor/node_modules/@legendapp/spark-desktop-config/expo.d.cts +3 -0
  198. package/vendor/node_modules/@legendapp/spark-desktop-config/identity.cjs +3 -2
  199. package/vendor/node_modules/@legendapp/spark-desktop-config/lifecycle.cjs +20 -0
  200. package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.cjs +106 -0
  201. package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.d.cts +1 -0
  202. package/vendor/node_modules/@legendapp/spark-desktop-config/package.json +7 -5
  203. package/vendor/node_modules/@legendapp/spark-desktop-config/schema.json +276 -58
  204. package/vendor/node_modules/@legendapp/spark-desktop-config/updates.cjs +1 -0
  205. package/vendor/node_modules/@legendapp/spark-desktop-config/validation.cjs +35 -0
  206. package/vendor/node_modules/@legendapp/spark-desktop-config/windows.plugin.cjs +2 -1
  207. package/vendor/node_modules/@legendapp/spark-desktop-host/AppDelegate.mm +129 -11
  208. package/vendor/node_modules/@legendapp/spark-desktop-host/package.json +2 -2
  209. package/vendor/node_modules/@legendapp/spark-desktop-host/windows/application.inc +277 -121
  210. package/vendor/node_modules/@legendapp/spark-desktop-links/common/AuthLoopback.h +5 -7
  211. package/vendor/node_modules/@legendapp/spark-desktop-links/macos/RNDesktopLinks.mm +10 -9
  212. package/vendor/node_modules/@legendapp/spark-desktop-links/package.json +2 -2
  213. package/vendor/node_modules/@legendapp/spark-desktop-links/src/NativeDesktopLinks.ts +1 -1
  214. package/vendor/node_modules/@legendapp/spark-desktop-links/src/api.ts +27 -33
  215. package/vendor/node_modules/@legendapp/spark-desktop-links/src/expo.ts +3 -4
  216. package/vendor/node_modules/@legendapp/spark-desktop-links/src/native.ts +9 -0
  217. package/vendor/node_modules/@legendapp/spark-desktop-links/windows/SparkLinks/SparkLinks.h +22 -22
  218. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/RNDesktopShortcuts.podspec +1 -0
  219. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/RNDesktopShortcuts.mm +1 -1
  220. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.h +9 -0
  221. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.mm +307 -0
  222. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/package.json +8 -5
  223. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/NativeDesktopShortcuts.ts +1 -1
  224. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/api.ts +39 -14
  225. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/NativeKeyboardManager.ts +12 -0
  226. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/codes.ts +108 -0
  227. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/index.ts +99 -0
  228. package/vendor/node_modules/@legendapp/spark-desktop-windows/RNDesktopWindows.podspec +2 -0
  229. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/RNDesktopWindows.mm +229 -103
  230. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/SparkWindowGeometry.h +63 -0
  231. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.h +20 -0
  232. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.mm +27 -0
  233. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.h +12 -0
  234. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.mm +3169 -0
  235. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManagerStartup.mm +31 -0
  236. package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/SidebarStartupFallbacks.mm +14 -0
  237. package/vendor/node_modules/@legendapp/spark-desktop-windows/package.json +10 -6
  238. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/NativeDesktopWindowManager.ts +1 -1
  239. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/api.ts +146 -70
  240. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/diagnostics.ts +17 -0
  241. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.ts +3 -1
  242. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.windows.ts +3 -1
  243. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos-adapter.ts +53 -0
  244. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos.ts +51 -0
  245. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/transport.ts +41 -0
  246. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/types.ts +140 -0
  247. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/validation.ts +162 -0
  248. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/window-manager/NativeWindowManager.ts +28 -0
  249. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/WindowProvider.tsx +20 -0
  250. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/createWindowsNavigator.tsx +78 -0
  251. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/index.ts +6 -0
  252. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/primaryWindowLifecycle.ts +34 -0
  253. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/types.ts +11 -0
  254. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/usePrimaryWindowLifecycle.ts +18 -0
  255. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/useWindowFocusEffect.ts +17 -0
  256. package/vendor/node_modules/@legendapp/spark-documents/package.json +22 -0
  257. package/vendor/node_modules/@legendapp/spark-documents/src/controller.ts +97 -0
  258. package/vendor/node_modules/@legendapp/spark-documents/src/documentTransition.ts +13 -0
  259. package/vendor/node_modules/@legendapp/spark-documents/src/hooks.ts +139 -0
  260. package/vendor/node_modules/@legendapp/spark-documents/src/index.tsx +50 -0
  261. package/vendor/node_modules/@legendapp/spark-documents/src/reload.ts +39 -0
  262. package/vendor/node_modules/@legendapp/spark-documents/src/requests.ts +15 -0
  263. package/vendor/node_modules/@legendapp/spark-drag-drop/package.json +4 -3
  264. package/vendor/node_modules/@legendapp/spark-drag-drop/src/DesktopDragViewNativeComponent.ts +1 -1
  265. package/vendor/node_modules/@legendapp/spark-drag-drop/src/contracts.ts +73 -18
  266. package/vendor/node_modules/@legendapp/spark-drag-drop/src/index.tsx +58 -15
  267. package/vendor/node_modules/@legendapp/spark-drag-drop/windows/SparkDragDrop/SparkDragDrop.h +14 -8
  268. package/vendor/node_modules/@legendapp/spark-file-dialog/ios/RNFileDialog.mm +34 -121
  269. package/vendor/node_modules/@legendapp/spark-file-dialog/package.json +12 -5
  270. package/vendor/node_modules/@legendapp/spark-file-dialog/src/NativeFileDialog.ts +1 -5
  271. package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.ts +19 -84
  272. package/vendor/node_modules/@legendapp/spark-file-dialog/src/native.ts +12 -0
  273. package/vendor/node_modules/@legendapp/spark-file-dialog/src/options.ts +34 -14
  274. package/vendor/node_modules/@legendapp/spark-file-dialog/src/types.ts +26 -0
  275. package/vendor/node_modules/@legendapp/spark-file-dialog/windows/SparkFileDialog/SparkFileDialog.h +42 -58
  276. package/vendor/node_modules/@legendapp/spark-file-system/RNDesktopFileSystem.podspec +1 -0
  277. package/vendor/node_modules/@legendapp/spark-file-system/macos/RNDesktopFileSystem.mm +32 -21
  278. package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.h +24 -0
  279. package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.mm +215 -0
  280. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.h +9 -0
  281. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.mm +82 -0
  282. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.h +47 -0
  283. package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.mm +306 -0
  284. package/vendor/node_modules/@legendapp/spark-file-system/package.json +8 -6
  285. package/vendor/node_modules/@legendapp/spark-file-system/src/NativeDesktopFileSystem.ts +1 -1
  286. package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/NativeFileScanner.ts +11 -0
  287. package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/index.ts +93 -0
  288. package/vendor/node_modules/@legendapp/spark-file-system/src/handles.ts +48 -14
  289. package/vendor/node_modules/@legendapp/spark-file-system/src/index.ts +134 -45
  290. package/vendor/node_modules/@legendapp/spark-file-system/src/path.ts +1 -9
  291. package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.h +102 -26
  292. package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.vcxproj +2 -0
  293. package/vendor/node_modules/@legendapp/spark-global-shortcuts/RNDesktopGlobalShortcuts.podspec +1 -0
  294. package/vendor/node_modules/@legendapp/spark-global-shortcuts/macos/RNDesktopGlobalShortcuts.mm +7 -4
  295. package/vendor/node_modules/@legendapp/spark-global-shortcuts/package.json +4 -3
  296. package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/NativeDesktopGlobalShortcuts.ts +1 -1
  297. package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/index.ts +39 -10
  298. package/vendor/node_modules/@legendapp/spark-global-shortcuts/windows/SparkGlobalShortcuts/SparkGlobalShortcuts.h +5 -4
  299. package/vendor/node_modules/@legendapp/spark-message-dialog/macos/RNDesktopMessageDialog.mm +2 -2
  300. package/vendor/node_modules/@legendapp/spark-message-dialog/package.json +2 -2
  301. package/vendor/node_modules/@legendapp/spark-message-dialog/src/NativeDesktopMessageDialog.ts +1 -1
  302. package/vendor/node_modules/@legendapp/spark-message-dialog/src/index.ts +48 -11
  303. package/vendor/node_modules/@legendapp/spark-native-menu/ios/RNNativeMenu.mm +141 -609
  304. package/vendor/node_modules/@legendapp/spark-native-menu/package.json +9 -4
  305. package/vendor/node_modules/@legendapp/spark-native-menu/src/NativeMenu.ts +2 -7
  306. package/vendor/node_modules/@legendapp/spark-native-menu/src/api.ts +76 -121
  307. package/vendor/node_modules/@legendapp/spark-native-menu/src/hooks.ts +97 -0
  308. package/vendor/node_modules/@legendapp/spark-native-menu/src/windows-menus.ts +43 -37
  309. package/vendor/node_modules/@legendapp/spark-notifications/macos/RNDesktopNotifications.mm +75 -30
  310. package/vendor/node_modules/@legendapp/spark-notifications/package.json +2 -2
  311. package/vendor/node_modules/@legendapp/spark-notifications/src/NativeDesktopNotifications.ts +1 -1
  312. package/vendor/node_modules/@legendapp/spark-notifications/src/index.ts +130 -42
  313. package/vendor/node_modules/@legendapp/spark-notifications/windows/SparkNotifications/SparkNotifications.h +51 -8
  314. package/vendor/node_modules/@legendapp/spark-processes/macos/RNDesktopProcesses.mm +94 -21
  315. package/vendor/node_modules/@legendapp/spark-processes/package.json +4 -3
  316. package/vendor/node_modules/@legendapp/spark-processes/src/NativeDesktopProcesses.ts +1 -1
  317. package/vendor/node_modules/@legendapp/spark-processes/src/index.ts +124 -28
  318. package/vendor/node_modules/@legendapp/spark-processes/src/types.ts +34 -0
  319. package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.h +83 -34
  320. package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.vcxproj +2 -0
  321. package/vendor/node_modules/@legendapp/spark-secure-storage/macos/RNDesktopSecureStorage.mm +49 -40
  322. package/vendor/node_modules/@legendapp/spark-secure-storage/package.json +2 -2
  323. package/vendor/node_modules/@legendapp/spark-secure-storage/src/NativeDesktopSecureStorage.ts +1 -1
  324. package/vendor/node_modules/@legendapp/spark-secure-storage/src/desktop.ts +16 -14
  325. package/vendor/node_modules/@legendapp/spark-secure-storage/src/expo.ts +0 -1
  326. package/vendor/node_modules/@legendapp/spark-secure-storage/src/options.ts +3 -2
  327. package/vendor/node_modules/@legendapp/spark-secure-storage/src/unavailable.ts +6 -3
  328. package/vendor/node_modules/@legendapp/spark-settings/package.json +10 -3
  329. package/vendor/node_modules/@legendapp/spark-settings/src/fileStorage.ts +11 -0
  330. package/vendor/node_modules/@legendapp/spark-settings/src/index.ts +7 -9
  331. package/vendor/node_modules/@legendapp/spark-settings/src/storage/index.ts +142 -0
  332. package/vendor/node_modules/@legendapp/spark-settings/src/store.ts +63 -21
  333. package/vendor/node_modules/@legendapp/spark-settings-ui/package.json +20 -0
  334. package/vendor/node_modules/@legendapp/spark-settings-ui/src/index.tsx +436 -0
  335. package/vendor/node_modules/@legendapp/spark-settings-ui/src/options.ts +10 -0
  336. package/vendor/node_modules/@legendapp/spark-sqlite/package.json +3 -3
  337. package/vendor/node_modules/@legendapp/spark-sqlite/src/database.ts +182 -0
  338. package/vendor/node_modules/@legendapp/spark-sqlite/src/index.ts +19 -6
  339. package/vendor/node_modules/@legendapp/spark-sqlite/src/types.ts +22 -0
  340. package/vendor/node_modules/@legendapp/spark-system/macos/RNDesktopSystem.mm +36 -11
  341. package/vendor/node_modules/@legendapp/spark-system/package.json +2 -2
  342. package/vendor/node_modules/@legendapp/spark-system/src/NativeDesktopSystem.ts +1 -1
  343. package/vendor/node_modules/@legendapp/spark-system/src/index.ts +89 -32
  344. package/vendor/node_modules/@legendapp/spark-system/windows/SparkSystem/SparkSystem.h +8 -4
  345. package/vendor/node_modules/@legendapp/spark-tray/macos/RNDesktopTray.mm +20 -8
  346. package/vendor/node_modules/@legendapp/spark-tray/package.json +2 -2
  347. package/vendor/node_modules/@legendapp/spark-tray/src/NativeDesktopTray.ts +1 -1
  348. package/vendor/node_modules/@legendapp/spark-tray/src/index.ts +91 -34
  349. package/vendor/node_modules/@legendapp/spark-tray/windows/SparkTray/SparkTray.h +45 -15
  350. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkButton.mm +2 -1
  351. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkTextInput.mm +10 -2
  352. package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.h +15 -0
  353. package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.mm +1419 -0
  354. package/vendor/node_modules/@legendapp/spark-ui/macos/glass-effect-view/RNGlassEffectView.mm +72 -0
  355. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.h +15 -0
  356. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.mm +194 -0
  357. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.h +15 -0
  358. package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.mm +180 -0
  359. package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.h +15 -0
  360. package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.mm +155 -0
  361. package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.h +18 -0
  362. package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.mm +645 -0
  363. package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.h +10 -0
  364. package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.mm +422 -0
  365. package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.h +15 -0
  366. package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.mm +164 -0
  367. package/vendor/node_modules/@legendapp/spark-ui/package.json +17 -4
  368. package/vendor/node_modules/@legendapp/spark-ui/src/SparkSelectNativeComponent.ts +3 -1
  369. package/vendor/node_modules/@legendapp/spark-ui/src/SparkTextInputNativeComponent.ts +6 -2
  370. package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/SidebarSplitViewNativeComponent.ts +37 -0
  371. package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/index.tsx +86 -0
  372. package/vendor/node_modules/@legendapp/spark-ui/src/availability.ts +10 -0
  373. package/vendor/node_modules/@legendapp/spark-ui/src/classnames/index.ts +8 -0
  374. package/vendor/node_modules/@legendapp/spark-ui/src/control.ts +42 -0
  375. package/vendor/node_modules/@legendapp/spark-ui/src/desktop.tsx +56 -0
  376. package/vendor/node_modules/@legendapp/spark-ui/src/glass-effect-view/index.tsx +15 -0
  377. package/vendor/node_modules/@legendapp/spark-ui/src/index.android.tsx +35 -21
  378. package/vendor/node_modules/@legendapp/spark-ui/src/index.ios.tsx +55 -26
  379. package/vendor/node_modules/@legendapp/spark-ui/src/index.tsx +1 -27
  380. package/vendor/node_modules/@legendapp/spark-ui/src/index.web.tsx +45 -14
  381. package/vendor/node_modules/@legendapp/spark-ui/src/index.windows.tsx +1 -42
  382. package/vendor/node_modules/@legendapp/spark-ui/src/mobile-input.tsx +11 -0
  383. package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSegmentedControlNativeComponent.ts +17 -0
  384. package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSelectNativeComponent.ts +17 -0
  385. package/vendor/node_modules/@legendapp/spark-ui/src/select.ts +5 -3
  386. package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/SFSymbolNativeComponent.ts +13 -0
  387. package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/index.tsx +27 -0
  388. package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarItemNativeComponent.ts +25 -0
  389. package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarNativeComponent.ts +24 -0
  390. package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/index.tsx +104 -0
  391. package/vendor/node_modules/@legendapp/spark-ui/src/specialized.ts +22 -0
  392. package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/SwipeActionsNativeComponent.ts +11 -0
  393. package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/index.tsx +41 -0
  394. package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/TextInputSearchNativeComponent.ts +33 -0
  395. package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/index.tsx +34 -0
  396. package/vendor/node_modules/@legendapp/spark-ui/src/types.ts +30 -19
  397. package/vendor/node_modules/@legendapp/spark-ui/uniwind.ts +3 -1
  398. package/vendor/node_modules/@legendapp/spark-ui/uniwind.web.ts +3 -1
  399. package/vendor/node_modules/@legendapp/spark-ui/windows/SparkUI/SparkUI.h +16 -11
  400. package/vendor/node_modules/@legendapp/spark-updates/macos/RNDesktopUpdates.mm +21 -8
  401. package/vendor/node_modules/@legendapp/spark-updates/package.json +2 -2
  402. package/vendor/node_modules/@legendapp/spark-updates/src/NativeDesktopUpdates.ts +3 -2
  403. package/vendor/node_modules/@legendapp/spark-updates/src/index.ts +71 -15
  404. package/vendor/node_modules/@legendapp/spark-webview/package.json +2 -2
  405. package/vendor/node_modules/@legendapp/spark-webview/src/WebView.tsx +11 -0
  406. package/vendor/node_modules/@legendapp/spark-webview/src/adapter.ts +55 -0
  407. package/vendor/node_modules/@legendapp/spark-webview/src/index.ts +2 -2
  408. package/vendor/node_modules/@legendapp/spark-webview/src/types.ts +32 -0
  409. package/vendor/node_modules/@legendapp/spark-webview/src/view-props.ts +28 -0
  410. package/vendor/node_modules/@legendapp/spark-window-options/index.cjs +51 -14
  411. package/vendor/node_modules/@legendapp/spark-window-options/index.d.ts +21 -8
  412. package/vendor/node_modules/@legendapp/spark-window-options/package.json +1 -1
  413. package/windows-macos.ts +1 -0
  414. package/expo-metro.cjs +0 -1
  415. package/message-dialog.ts +0 -1
  416. package/universal.cjs +0 -1
  417. package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/accelerator.ts +0 -22
  418. package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows-options.ts +0 -11
  419. package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.windows.ts +0 -15
  420. package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/accelerator.ts +0 -22
  421. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.h +0 -4
  422. package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.mm +0 -53
@@ -1,7 +1,7 @@
1
1
  import { openFileDialog } from "@legendapp/spark/dialogs";
2
2
  import type { Track } from "./model";
3
3
  export async function importTracks(): Promise<Track[]> {
4
- const paths = await openFileDialog({ allowedFileTypes: ["mp3", "m4a", "wav", "aac", "flac", "ogg"], allowsMultipleSelection: true });
5
- return (paths ?? []).map(uri => ({ id: uri, uri, name: uri.split(/[\\/]/).pop()! }));
4
+ const paths = await openFileDialog({ filters: [{ extensions: ["mp3", "m4a", "wav", "aac", "flac", "ogg"] }], multiple: true });
5
+ return (paths.canceled ? [] : paths.paths).map(uri => ({ id: uri, uri, name: uri.split(/[\\/]/).pop()! }));
6
6
  }
7
7
  export const resolveTrack = async (track: Track) => ({ uri: track.uri, release() {} });
@@ -1,5 +1,5 @@
1
- import { readTextFile } from "@legendapp/spark/dialogs";
1
+ import { readText } from "@legendapp/spark/files";
2
2
  import { OpenFiles } from "./shared/OpenFiles";
3
3
  import { notes } from "./store";
4
- const open = async (path: string) => { await notes.load(); if (!notes.getSnapshot().ready) throw new Error("Notes storage is unavailable"); const text = await readTextFile(path); notes.create(text); };
4
+ const open = async (path: string) => { await notes.load(); if (!notes.getSnapshot().ready) throw new Error("Notes storage is unavailable"); const text = await readText(path); notes.create(text); };
5
5
  export function Activation({ windowId, onError }: { windowId: string; onError(message: string): void }) { return <OpenFiles windowId={windowId} onFile={open} onError={onError} />; }
@@ -1,25 +1,47 @@
1
- import { getDisplays, listWindows, openWindow, setWindowFrame, showWindow, onWindowEvent } from "@legendapp/spark/windows";
1
+ import { addWindowListener, getDisplays, listWindows, openWindow, setWindowBounds, showWindow } from "@legendapp/spark/windows";
2
+ import type { AsyncRegistration } from "@legendapp/spark/contracts";
2
3
  import { notes } from "./store";
3
4
  import { WindowSession } from "./window-session";
4
5
  export const desktop = true;
5
6
  const session = new WindowSession(notes, {
6
- list: listWindows,
7
- workAreas: async () => (await getDisplays()).map(display => display.workArea),
7
+ list: async () => (await listWindows()).map(window => ({ id: window.id, frame: window.bounds })),
8
+ workAreas: async () => (await getDisplays()).sort((a, b) => Number(b.primary) - Number(a.primary)).map(display => ({ ...display.workArea, displayId: display.id })),
8
9
  show: showWindow,
9
- frame: setWindowFrame,
10
- open: window => openWindow({ id: window.id, title: window.id === "settings" ? "Notes Settings" : "Notes", width: window.frame.width, height: window.frame.height, props: window.id === "settings" ? { settings: true } : { noteId: window.noteId } }),
10
+ frame: setWindowBounds,
11
+ open: window => openWindow({ id: window.id, component: "main", title: window.id === "settings" ? "Notes Settings" : "Notes", size: { width: window.frame.width, height: window.frame.height }, position: { displayId: window.frame.displayId, x: window.frame.x, y: window.frame.y }, props: { windowId: window.id, windowProps: window.id === "settings" ? { settings: true } : { noteId: window.noteId } } }),
11
12
  });
12
- export const openNote = (noteId: string) => session.openNote(noteId);
13
- export const openSettings = () => session.openSettings();
13
+ const watchers = new Set<(message: string) => void>();
14
+ const registrations = new Map<string, AsyncRegistration[]>();
15
+ let generation = 0, timer: ReturnType<typeof setTimeout> | undefined;
16
+ function report(error: unknown) { for (const watcher of watchers) watcher(String(error)); }
17
+ function changed() { clearTimeout(timer); timer = setTimeout(() => { void session.capture().catch(report); }, 150); }
18
+ let pending: Promise<void> = Promise.resolve();
19
+ function observeWindows() {
20
+ const epoch = generation;
21
+ const task = pending.then(async () => {
22
+ if (!watchers.size || epoch !== generation) return;
23
+ for (const window of await listWindows()) {
24
+ if (!session.known(window.id) || registrations.has(window.id)) continue;
25
+ const owned: AsyncRegistration[] = [];
26
+ try {
27
+ owned.push(await addWindowListener(window.id, "boundsChanged", changed));
28
+ owned.push(await addWindowListener(window.id, "closed", () => { registrations.delete(window.id); for (const value of owned) void value.remove().catch(report); changed(); }));
29
+ if (watchers.size && epoch === generation) registrations.set(window.id, owned);
30
+ else for (const value of owned) await value.remove();
31
+ } catch (error) { for (const value of owned) await value.remove(); throw error; }
32
+ }
33
+ });
34
+ pending = task.catch(() => {}); return task;
35
+ }
36
+ export async function openNote(noteId: string) { await session.openNote(noteId); await observeWindows(); }
37
+ export async function openSettings() { await session.openSettings(); await observeWindows(); }
14
38
  export const showNotebook = () => showWindow("main");
15
- export const restoreSession = session.restore;
39
+ export async function restoreSession() { await session.restore(); await observeWindows(); }
16
40
  export const flushSession = session.quit;
17
41
  export function watchSession(onError: (message: string) => void) {
18
- let timer: ReturnType<typeof setTimeout> | undefined;
19
- const subscription = onWindowEvent(event => {
20
- if (!session.known(event.windowId) || !["move", "resize", "closed"].includes(event.type)) return;
21
- clearTimeout(timer);
22
- timer = setTimeout(() => { void session.restore().then(session.capture).catch(error => onError(String(error))); }, 150);
23
- });
24
- return { remove() { clearTimeout(timer); subscription.remove(); } };
42
+ watchers.add(onError); void observeWindows().catch(report);
43
+ return { remove() {
44
+ watchers.delete(onError);
45
+ if (!watchers.size) { generation++; clearTimeout(timer); for (const owned of registrations.values()) for (const value of owned) void value.remove().catch(console.error); registrations.clear(); }
46
+ } };
25
47
  }
@@ -1,16 +1,15 @@
1
1
  export type Theme = "system" | "light" | "dark";
2
- export type Frame = { x: number; y: number; width: number; height: number };
2
+ export type Frame = { displayId: string; x: number; y: number; width: number; height: number };
3
3
  export type SavedWindow = { id: string; noteId?: string; frame: Frame };
4
4
  export function decodeWindows(value: unknown): SavedWindow[] {
5
5
  if (value === undefined) return [];
6
- if (!Array.isArray(value) || !value.every(item => item && typeof item.id === "string" && /^(main|settings|note-[a-zA-Z0-9_-]+)$/.test(item.id) && (item.noteId === undefined || typeof item.noteId === "string") && item.frame && ["x", "y", "width", "height"].every(key => Number.isFinite(item.frame[key])) && item.frame.width >= 100 && item.frame.height >= 100 && item.frame.width <= 20000 && item.frame.height <= 20000) || new Set(value.map(item => item.id)).size !== value.length) throw new Error("Unsupported window session");
6
+ if (!Array.isArray(value) || !value.every(item => item && typeof item.id === "string" && /^(main|settings|note-[a-zA-Z0-9_-]+)$/.test(item.id) && (item.noteId === undefined || typeof item.noteId === "string") && item.frame && typeof item.frame.displayId === "string" && item.frame.displayId.length > 0 && ["x", "y", "width", "height"].every(key => Number.isFinite(item.frame[key])) && item.frame.width >= 100 && item.frame.height >= 100 && item.frame.width <= 20000 && item.frame.height <= 20000) || new Set(value.map(item => item.id)).size !== value.length) throw new Error("Unsupported window session");
7
7
  return value;
8
8
  }
9
- /** Both platforms return frames/work areas in their own matching coordinate system. */
9
+ /** Saved bounds and work areas use the same display-relative logical units. */
10
10
  export function fitFrame(frame: Frame, workAreas: Frame[]): Frame {
11
11
  if (!workAreas.length) return frame;
12
- const overlap = (area: Frame) => Math.max(0, Math.min(frame.x + frame.width, area.x + area.width) - Math.max(frame.x, area.x)) * Math.max(0, Math.min(frame.y + frame.height, area.y + area.height) - Math.max(frame.y, area.y));
13
- const area = workAreas.reduce((best, current) => overlap(current) > overlap(best) ? current : best);
12
+ const area = workAreas.find(area => area.displayId === frame.displayId) ?? workAreas[0];
14
13
  const width = Math.min(frame.width, area.width), height = Math.min(frame.height, area.height);
15
- return { x: Math.max(area.x, Math.min(frame.x, area.x + area.width - width)), y: Math.max(area.y, Math.min(frame.y, area.y + area.height - height)), width, height };
14
+ return { displayId: area.displayId, x: Math.max(area.x, Math.min(frame.x, area.x + area.width - width)), y: Math.max(area.y, Math.min(frame.y, area.y + area.height - height)), width, height };
16
15
  }
@@ -20,13 +20,13 @@ export class WindowSession {
20
20
  const id = `note-${noteId}`;
21
21
  this.noteIds.set(id, noteId);
22
22
  if ((await this.host.list()).some(window => window.id === id)) await this.host.show(id);
23
- else await this.host.open({ id, noteId, frame: { x: 0, y: 0, width: 700, height: 600 } });
23
+ else await this.host.open({ id, noteId, frame: fitFrame({ displayId: "", x: 0, y: 0, width: 700, height: 600 }, await this.host.workAreas()) });
24
24
  await this.capture();
25
25
  }
26
26
  async openSettings() {
27
27
  await this.restore();
28
28
  if ((await this.host.list()).some(window => window.id === "settings")) await this.host.show("settings");
29
- else await this.host.open({ id: "settings", frame: { x: 0, y: 0, width: 460, height: 360 } });
29
+ else await this.host.open({ id: "settings", frame: fitFrame({ displayId: "", x: 0, y: 0, width: 460, height: 360 }, await this.host.workAreas()) });
30
30
  await this.capture();
31
31
  }
32
32
  capture = () => {
@@ -46,8 +46,9 @@ export class WindowSession {
46
46
  for (const window of saved) {
47
47
  if (window.id !== "main" && window.id !== "settings" && !this.notes.getSnapshot().notes.some(note => note.id === window.noteId && !note.deleted)) continue;
48
48
  if (window.noteId) this.noteIds.set(window.id, window.noteId);
49
- if (window.id !== "main" && !(await this.host.list()).some(item => item.id === window.id)) await this.host.open(window);
50
- await this.host.frame(window.id, fitFrame(window.frame, areas));
49
+ const frame = fitFrame(window.frame, areas);
50
+ if (window.id !== "main" && !(await this.host.list()).some(item => item.id === window.id)) await this.host.open({ ...window, frame });
51
+ await this.host.frame(window.id, frame);
51
52
  }
52
53
  await this.capture();
53
54
  })();
@@ -3,9 +3,11 @@
3
3
  "name": "HelloWorld",
4
4
  "version": "0.0.1",
5
5
  "window": {
6
- "width": 1000,
7
- "height": 700,
8
- "restoreFrame": true
6
+ "size": {
7
+ "width": 1000,
8
+ "height": 700
9
+ },
10
+ "restoreBounds": true
9
11
  },
10
12
  "macos": {
11
13
  "bundleIdentifier": "so.legend.spark.prototype.helloworld"
@@ -1,5 +1,5 @@
1
1
  const { withUniwindConfig } = require("uniwind/metro");
2
- const { metroConfig } = require("@legendapp/spark/universal");
2
+ const { metroConfig } = require("@legendapp/spark/metro");
3
3
 
4
4
  module.exports = withUniwindConfig(metroConfig(__dirname), {
5
5
  cssEntryFile: "./global.css",
@@ -18,11 +18,11 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "expo": "54.0.37",
21
- "expo-desktop": "1.0.0-beta.6",
22
- "expo-desktop-prebuild-config": "1.1.0-beta.1",
23
- "expo-desktop-config-plugins": "1.2.0-beta.1",
24
- "expo-desktop-metro-config": "54.81.0-beta.3",
25
- "expo-desktop-template-bare-minimum": "54.81.1-beta.6",
21
+ "expo-desktop": "1.0.0",
22
+ "expo-desktop-prebuild-config": "1.1.0",
23
+ "expo-desktop-config-plugins": "1.2.0",
24
+ "expo-desktop-metro-config": "54.81.0",
25
+ "expo-desktop-template-bare-minimum": "54.81.1",
26
26
  "react": "19.1.4",
27
27
  "react-native": "0.81.6",
28
28
  "react-native-macos": "0.81.7",
@@ -30,8 +30,8 @@
30
30
  "typescript": "5.9.3",
31
31
  "@types/react": "19.1.10",
32
32
  "react-native-windows": "0.81.35",
33
- "expo-desktop-modules-core": "54.0.14-beta.0",
34
- "expo-desktop-stubs": "54.0.14-beta.0",
33
+ "expo-desktop-modules-core": "54.0.14",
34
+ "expo-desktop-stubs": "54.0.14",
35
35
  "@expo/ui": "0.2.0-beta.9",
36
36
  "expo-dev-client": "6.0.21",
37
37
  "expo-clipboard": "8.0.8",
@@ -41,11 +41,11 @@
41
41
  "react-native-web": "0.21.0",
42
42
  "uniwind": "1.6.3",
43
43
  "tailwindcss": "4.2.4",
44
- "@legendapp/spark": "0.0.1-next.2"
44
+ "@legendapp/spark": "0.0.1-next.4"
45
45
  },
46
46
  "overrides": {
47
47
  "@expo/cli": "54.0.27",
48
- "react-native-nitro-modules": "0.35.7",
48
+ "react-native-nitro-modules": "0.37.0",
49
49
  "react-native-webview": "16.0.0",
50
50
  "@op-engineering/op-sqlite": "18.2.1",
51
51
  "expo-asset": "12.0.13",
@@ -54,10 +54,12 @@
54
54
  "expo-font": "14.0.12",
55
55
  "expo-keep-awake": "15.0.8",
56
56
  "expo-modules-core": "3.0.30",
57
- "expo-desktop-modules-core": "54.0.14-beta.0",
58
- "expo-desktop-stubs": "54.0.14-beta.0",
57
+ "expo-desktop-modules-core": "54.0.14",
58
+ "expo-desktop-stubs": "54.0.14",
59
59
  "react": "19.1.4",
60
- "react-native": "0.81.6"
60
+ "react-native": "0.81.6",
61
+ "react-native-macos": "0.81.7",
62
+ "react-native-windows": "0.81.35"
61
63
  },
62
64
  "expo": {
63
65
  "install": {
@@ -1,2 +1,2 @@
1
1
  // Generated by spark; extend with configuration plugins.
2
- module.exports = require("@legendapp/spark/universal").nativeConfig(__dirname);
2
+ module.exports = require("@legendapp/spark/native").nativeConfig(__dirname);
@@ -14,24 +14,24 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "expo": "54.0.37",
17
- "expo-desktop": "1.0.0-beta.6",
18
- "expo-desktop-prebuild-config": "1.1.0-beta.1",
19
- "expo-desktop-config-plugins": "1.2.0-beta.1",
20
- "expo-desktop-metro-config": "54.81.0-beta.3",
21
- "expo-desktop-template-bare-minimum": "54.81.1-beta.6",
17
+ "expo-desktop": "1.0.0",
18
+ "expo-desktop-prebuild-config": "1.1.0",
19
+ "expo-desktop-config-plugins": "1.2.0",
20
+ "expo-desktop-metro-config": "54.81.0",
21
+ "expo-desktop-template-bare-minimum": "54.81.1",
22
22
  "react": "19.1.4",
23
23
  "react-native": "0.81.6",
24
24
  "@react-native-community/cli": "20.1.3",
25
25
  "typescript": "5.9.3",
26
26
  "@types/react": "19.1.10",
27
27
  "react-native-windows": "0.81.35",
28
- "expo-desktop-modules-core": "54.0.14-beta.0",
29
- "expo-desktop-stubs": "54.0.14-beta.0",
30
- "@legendapp/spark": "0.0.1-next.2"
28
+ "expo-desktop-modules-core": "54.0.14",
29
+ "expo-desktop-stubs": "54.0.14",
30
+ "@legendapp/spark": "0.0.1-next.4"
31
31
  },
32
32
  "overrides": {
33
33
  "@expo/cli": "54.0.27",
34
- "react-native-nitro-modules": "0.35.7",
34
+ "react-native-nitro-modules": "0.37.0",
35
35
  "react-native-webview": "16.0.0",
36
36
  "@op-engineering/op-sqlite": "18.2.1",
37
37
  "expo-asset": "12.0.13",
@@ -40,10 +40,12 @@
40
40
  "expo-font": "14.0.12",
41
41
  "expo-keep-awake": "15.0.8",
42
42
  "expo-modules-core": "3.0.30",
43
- "expo-desktop-modules-core": "54.0.14-beta.0",
44
- "expo-desktop-stubs": "54.0.14-beta.0",
43
+ "expo-desktop-modules-core": "54.0.14",
44
+ "expo-desktop-stubs": "54.0.14",
45
45
  "react": "19.1.4",
46
- "react-native": "0.81.6"
46
+ "react-native": "0.81.6",
47
+ "react-native-macos": "0.81.7",
48
+ "react-native-windows": "0.81.35"
47
49
  },
48
50
  "expo": {
49
51
  "install": {
@@ -1,2 +1,2 @@
1
1
  // Generated by spark; extend with configuration plugins.
2
- module.exports = require("@legendapp/spark/universal").nativeConfig(__dirname);
2
+ module.exports = require("@legendapp/spark/native").nativeConfig(__dirname);
@@ -1,11 +1,13 @@
1
1
  #import "RNDesktopClipboard.h"
2
+ #import <RNDesktopApp/SparkBinaryJSI.h>
2
3
  #import <RNDesktopApp/SparkDesktop.h>
3
4
  @implementation RNDesktopClipboard
4
5
  RCT_EXPORT_MODULE(NativeDesktopClipboard)
5
- - (void)call:(NSString *)method args:(NSString *)json resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
6
+ - (void)call:(NSString *)method args:(NSString *)json resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self perform:method args:SparkArgs(json) binary:NO resolve:resolve reject:reject]; }
7
+ - (void)binaryCall:(NSString *)method args:(NSString *)json bytes:(NSData *)bytes resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { NSMutableDictionary *args = [SparkArgs(json) mutableCopy]; if (bytes) args[@"imagePNG"] = bytes; [self perform:method args:args binary:YES resolve:resolve reject:reject]; }
8
+ - (void)perform:(NSString *)method args:(NSDictionary *)args binary:(BOOL)binary resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
6
9
  dispatch_async(dispatch_get_main_queue(), ^{
7
10
  NSPasteboard *board = NSPasteboard.generalPasteboard;
8
- NSDictionary *args = SparkArgs(json);
9
11
  if ([method isEqual:@"hasString"]) {
10
12
  resolve(SparkJSON(@([board availableTypeFromArray:@[NSPasteboardTypeString, NSPasteboardTypeHTML, NSPasteboardTypeRTF]] != nil))); return;
11
13
  }
@@ -24,8 +26,7 @@ RCT_EXPORT_MODULE(NativeDesktopClipboard)
24
26
  if (rich) [item setString:rich.string forType:NSPasteboardTypeString];
25
27
  }
26
28
  [board clearContents];
27
- if (![board writeObjects:@[item]]) { reject(@"E_CLIPBOARD", @"Could not write clipboard", nil); return; }
28
- resolve(@"null"); return;
29
+ resolve(SparkJSON(@([board writeObjects:@[item]]))); return;
29
30
  }
30
31
  NSString *text = [board stringForType:html ? NSPasteboardTypeHTML : NSPasteboardTypeString];
31
32
  if (!text) {
@@ -50,10 +51,10 @@ RCT_EXPORT_MODULE(NativeDesktopClipboard)
50
51
  for (NSString *key in types) { NSString *value = [board stringForType:types[key]]; if (value) content[key] = value; }
51
52
  NSData *image = [board dataForType:NSPasteboardTypePNG];
52
53
  if (!image) { NSData *tiff = [board dataForType:NSPasteboardTypeTIFF]; if (tiff) image = [[NSBitmapImageRep imageRepWithData:tiff] representationUsingType:NSBitmapImageFileTypePNG properties:@{}]; }
53
- if (image) content[@"imagePNG"] = [image base64EncodedStringWithOptions:0];
54
+ if (image) content[@"imagePNG"] = image;
54
55
  NSArray *urls = [board readObjectsForClasses:@[NSURL.class] options:@{ NSPasteboardURLReadingFileURLsOnlyKey: @YES }];
55
56
  if (urls.count) content[@"files"] = [urls valueForKey:@"path"];
56
- resolve(SparkJSON(content)); return;
57
+ resolve(binary ? content : SparkJSON(content)); return;
57
58
  }
58
59
  if ([method isEqual:@"write"]) {
59
60
  NSMutableArray *objects = [NSMutableArray new];
@@ -62,7 +63,7 @@ RCT_EXPORT_MODULE(NativeDesktopClipboard)
62
63
  NSPasteboardItem *item = [NSPasteboardItem new];
63
64
  for (NSString *key in types) if (args[key]) [item setString:args[key] forType:types[key]];
64
65
  if (args[@"imagePNG"]) {
65
- NSData *image = [[NSData alloc] initWithBase64EncodedString:args[@"imagePNG"] options:0];
66
+ NSData *image = args[@"imagePNG"];
66
67
  if (!image || ![NSBitmapImageRep imageRepWithData:image]) { SparkInvalid(reject, @"Invalid clipboard image"); return; }
67
68
  [item setData:image forType:NSPasteboardTypePNG];
68
69
  }
@@ -71,17 +72,10 @@ RCT_EXPORT_MODULE(NativeDesktopClipboard)
71
72
  [board clearContents]; if (objects.count && ![board writeObjects:objects]) { reject(@"E_CLIPBOARD", @"Could not write clipboard", nil); return; }
72
73
  resolve(@"null"); return;
73
74
  }
74
- if ([method isEqual:@"readText"]) resolve(SparkJSON([board stringForType:NSPasteboardTypeString] ?: @""));
75
- else if ([method isEqual:@"hasText"]) resolve(SparkJSON(@([board availableTypeFromArray:@[NSPasteboardTypeString]] != nil)));
76
- else if ([method isEqual:@"writeText"]) {
77
- if (![args[@"text"] isKindOfClass:NSString.class]) { SparkInvalid(reject, @"Expected clipboard text"); return; }
78
- [board clearContents];
79
- if (![board setString:args[@"text"] forType:NSPasteboardTypeString]) { reject(@"E_CLIPBOARD", @"Could not write clipboard", nil); return; }
80
- resolve(@"null");
81
- } else SparkInvalid(reject, @"Unknown clipboard operation");
75
+ SparkInvalid(reject, @"Unknown clipboard operation");
82
76
  });
83
77
  }
84
78
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
85
- return std::make_shared<facebook::react::NativeDesktopClipboardSpecJSI>(params);
79
+ return std::make_shared<spark::binary::Module<facebook::react::NativeDesktopClipboardSpecJSI>>(params);
86
80
  }
87
81
  @end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/spark-clipboard",
3
- "version": "0.0.1-next.2",
3
+ "version": "0.0.1-next.4",
4
4
  "license": "MIT",
5
5
  "main": "src/index",
6
6
  "react-native": "src/index",
@@ -41,7 +41,7 @@
41
41
  ]
42
42
  },
43
43
  "dependencies": {
44
- "@legendapp/spark-desktop-app": "0.0.1-next.2"
44
+ "@legendapp/spark-desktop-app": "0.0.1-next.4"
45
45
  },
46
46
  "peerDependenciesMeta": {
47
47
  "expo-clipboard": {
@@ -3,4 +3,4 @@ import { TurboModuleRegistry } from "react-native";
3
3
  export interface Spec extends TurboModule {
4
4
  call(method: string, args: string): Promise<string>;
5
5
  }
6
- export default TurboModuleRegistry.getEnforcing<Spec>("NativeDesktopClipboard");
6
+ export default TurboModuleRegistry.get<Spec>("NativeDesktopClipboard");
@@ -1,39 +1,63 @@
1
1
  import { Platform } from "react-native";
2
+ import { callBinary, nativeBytes } from "@legendapp/spark-desktop-app/src/contracts/native-buffer";
3
+ import { SparkError, parseNativeResult, invokeNative, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
4
+ import { nativePath } from "@legendapp/spark-desktop-app/src/contracts/path";
2
5
  import Native from "./NativeDesktopClipboard";
3
- async function call<T = void>(method: string, args: object = {}): Promise<T> { return JSON.parse(await Native.call(method, JSON.stringify(args))) as T; }
4
- export const readClipboardText = () => call<string>("readText");
5
- export const writeClipboardText = (text: string) => call("writeText", { text });
6
- export const hasClipboardText = () => call<boolean>("hasText");
7
-
8
- export type ClipboardContent = { text?: string; html?: string; rtf?: string; imagePNG?: string; files?: string[] };
9
- /** imagePNG contains base64-encoded PNG bytes. */
10
- export async function readClipboard(): Promise<ClipboardContent> { return JSON.parse(await Native.call("read", "{}")); }
11
- export async function getClipboardFormats(): Promise<string[]> { return JSON.parse(await Native.call("formats", "{}")); }
12
- export async function clearClipboard() { await Native.call("clear", "{}"); }
13
- export async function writeClipboard(content: ClipboardContent) {
14
- for (const key of Object.keys(content)) if (!["text", "html", "rtf", "imagePNG", "files"].includes(key)) throw new Error(`Unknown clipboard format: ${key}`);
15
- if (content.files && (Object.keys(content).length !== 1 || content.files.some(file => Platform.OS === "windows" ? !/^(?:[a-z]:[\\/]|\\\\[^\\/]+[\\/][^\\/]+)/i.test(file) : !file.startsWith("/")))) throw new Error("Files must be absolute paths and written separately from other formats");
16
- for (const key of ["text", "html", "rtf", "imagePNG"] as const) if (content[key] !== undefined && typeof content[key] !== "string") throw new Error(`Invalid clipboard ${key}`);
17
- await Native.call("write", JSON.stringify(content));
18
- }
19
-
20
- import { StringFormat } from "./formats";
6
+ import { stringOptions } from "./options";
7
+ import type { ClipboardContent, ClipboardWriteContent, GetStringOptions, SetStringOptions } from "./types";
21
8
  export { StringFormat } from "./formats";
22
- export type GetStringOptions = { preferredFormat?: StringFormat };
23
- export type SetStringOptions = { inputFormat?: StringFormat };
24
- function stringOptions(options: object, key: string) {
25
- if (!options || Object.keys(options).some(name => name !== key)) throw new Error("Unsupported clipboard option");
26
- const format = (options as Record<string, unknown>)[key] ?? StringFormat.PLAIN_TEXT;
27
- if (format !== StringFormat.PLAIN_TEXT && format !== StringFormat.HTML) throw new Error("Invalid clipboard string format");
28
- return format;
9
+ export type { ClipboardContent, ClipboardWriteContent, ClipboardImage, GetStringOptions, SetStringOptions } from "./types";
10
+ export function getRichClipboardAvailability(): Availability {
11
+ if (Platform.OS !== "macos" && Platform.OS !== "windows") return { available: false, reason: "unsupported-platform" };
12
+ return Native ? { available: true } : { available: false, reason: "missing-module" };
13
+ }
14
+ function native() {
15
+ const availability = getRichClipboardAvailability();
16
+ if (!availability.available) throw new SparkError(availability.reason === "unsupported-platform" ? "E_UNSUPPORTED_PLATFORM" : "E_MODULE_UNAVAILABLE", "Desktop clipboard module is unavailable");
17
+ return Native!;
18
+ }
19
+ async function call<T>(method: string, args: object, validate: (value: unknown) => value is T): Promise<T> {
20
+ return parseNativeResult(await invokeNative(() => native().call(method, JSON.stringify(args))), validate);
29
21
  }
30
- /** Expo-compatible text/HTML subset. Rich desktop formats remain available above. */
22
+ const isVoid = (value: unknown): value is null => value === null;
23
+ const isBoolean = (value: unknown): value is boolean => typeof value === "boolean";
24
+ /** Expo-compatible text/HTML subset. */
31
25
  export async function getStringAsync(options: GetStringOptions = {}): Promise<string> {
32
- return call("getString", { format: stringOptions(options, "preferredFormat") });
26
+ return call("getString", { format: stringOptions(options, "preferredFormat") }, (value): value is string => typeof value === "string");
33
27
  }
34
28
  export async function setStringAsync(text: string, options: SetStringOptions = {}): Promise<boolean> {
35
- if (typeof text !== "string") throw new TypeError("Clipboard text must be a string");
36
- await call("setString", { text, format: stringOptions(options, "inputFormat") });
37
- return true;
29
+ if (typeof text !== "string") throw new SparkError("E_INVALID_ARGUMENT", "Clipboard text must be a string");
30
+ return call("setString", { text, format: stringOptions(options, "inputFormat") }, isBoolean);
31
+ }
32
+ export async function hasStringAsync(): Promise<boolean> { return call("hasString", {}, (value): value is boolean => typeof value === "boolean"); }
33
+ export async function readClipboard(): Promise<ClipboardContent> {
34
+ const raw = await invokeNative(() => callBinary(native(), "__sparkClipboardBinary", "read", {})) as Record<string, unknown>;
35
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw new SparkError("E_INVALID_DATA", "Invalid clipboard content");
36
+ const result: ClipboardContent = {};
37
+ for (const key of ["text", "html", "rtf"] as const) {
38
+ if (raw[key] !== undefined && typeof raw[key] !== "string") throw new SparkError("E_INVALID_DATA", `Invalid clipboard ${key}`);
39
+ if (typeof raw[key] === "string") result[key] = raw[key];
40
+ }
41
+ if (raw.files !== undefined) {
42
+ if (!Array.isArray(raw.files) || raw.files.some(value => typeof value !== "string")) throw new SparkError("E_INVALID_DATA", "Invalid clipboard files");
43
+ try { result.files = raw.files.map(value => nativePath(value, Platform.OS)); }
44
+ catch (cause) { throw new SparkError("E_INVALID_DATA", "Invalid clipboard file paths", { cause }); }
45
+ }
46
+ if (raw.imagePNG !== undefined) {
47
+ result.image = { format: "png", bytes: nativeBytes(raw.imagePNG) };
48
+ }
49
+ return result;
50
+ }
51
+ export async function getClipboardFormats(): Promise<string[]> { return call("formats", {}, (value): value is string[] => Array.isArray(value) && value.every(format => typeof format === "string")); }
52
+ export async function clearClipboard(): Promise<void> { await call("clear", {}, isVoid); }
53
+ export async function writeClipboard(content: ClipboardWriteContent): Promise<void> {
54
+ if (!content || typeof content !== "object" || Array.isArray(content)) throw new SparkError("E_INVALID_ARGUMENT", "Expected clipboard content");
55
+ for (const key of Object.keys(content)) if (!["text", "html", "rtf", "image", "files"].includes(key)) throw new SparkError("E_UNSUPPORTED_OPTION", `Unknown clipboard format: ${key}`);
56
+ for (const key of ["text", "html", "rtf"] as const) if (content[key] !== undefined && typeof content[key] !== "string") throw new SparkError("E_INVALID_ARGUMENT", `Invalid clipboard ${key}`);
57
+ if (content.files !== undefined && (!Array.isArray(content.files) || Object.entries(content).some(([key, value]) => key !== "files" && value !== undefined))) throw new SparkError("E_INVALID_ARGUMENT", "Files must be written separately from other formats");
58
+ const files = content.files?.map(path => nativePath(path, Platform.OS));
59
+ const { image, ...rest } = content;
60
+ if (image !== undefined && (!image || image.format !== "png" || !(image.bytes instanceof Uint8Array))) throw new SparkError("E_INVALID_ARGUMENT", "Expected PNG image bytes");
61
+ const response = await invokeNative(() => callBinary(native(), "__sparkClipboardBinary", "write", { ...rest, files }, image?.bytes));
62
+ if (response !== null) throw new SparkError("E_INVALID_DATA", "Invalid native clipboard response");
38
63
  }
39
- export const hasStringAsync = (): Promise<boolean> => call("hasString");
@@ -1,12 +1,22 @@
1
1
  import * as Clipboard from "expo-clipboard";
2
- export { getStringAsync, setStringAsync, hasStringAsync, StringFormat } from "expo-clipboard";
3
- export type { GetStringOptions, SetStringOptions } from "expo-clipboard";
4
- export type { ClipboardContent } from "./index";
5
- export const readClipboardText = Clipboard.getStringAsync;
6
- export async function writeClipboardText(text: string): Promise<void> { await Clipboard.setStringAsync(text); }
7
- export const hasClipboardText = Clipboard.hasStringAsync;
8
- const unavailable = async (..._args: unknown[]): Promise<never> => { throw Object.assign(new Error("Rich desktop clipboard operations are unavailable on this platform"), { code: "E_UNAVAILABLE" }); };
9
- export const readClipboard = unavailable;
10
- export const getClipboardFormats = unavailable;
11
- export const clearClipboard = unavailable;
12
- export const writeClipboard = unavailable;
2
+ import { SparkError, type Availability } from "@legendapp/spark-desktop-app/src/contracts";
3
+ import { StringFormat } from "./formats";
4
+ import { stringOptions } from "./options";
5
+ import type { ClipboardContent, ClipboardWriteContent, GetStringOptions, SetStringOptions } from "./types";
6
+ export { StringFormat } from "./formats";
7
+ export type { ClipboardContent, ClipboardWriteContent, ClipboardImage, GetStringOptions, SetStringOptions } from "./types";
8
+ export async function getStringAsync(options: GetStringOptions = {}): Promise<string> {
9
+ const format = stringOptions(options, "preferredFormat");
10
+ return Clipboard.getStringAsync({ preferredFormat: format === StringFormat.HTML ? Clipboard.StringFormat.HTML : Clipboard.StringFormat.PLAIN_TEXT });
11
+ }
12
+ export async function setStringAsync(text: string, options: SetStringOptions = {}): Promise<boolean> {
13
+ const format = stringOptions(options, "inputFormat");
14
+ return Clipboard.setStringAsync(text, { inputFormat: format === StringFormat.HTML ? Clipboard.StringFormat.HTML : Clipboard.StringFormat.PLAIN_TEXT });
15
+ }
16
+ export const hasStringAsync = Clipboard.hasStringAsync;
17
+ export function getRichClipboardAvailability(): Availability { return { available: false, reason: "unsupported-platform" }; }
18
+ function unavailable(): never { throw new SparkError("E_UNSUPPORTED_PLATFORM", "Rich clipboard operations require a desktop host"); }
19
+ export async function readClipboard(): Promise<ClipboardContent> { return unavailable(); }
20
+ export async function getClipboardFormats(): Promise<string[]> { return unavailable(); }
21
+ export async function clearClipboard(): Promise<void> { return unavailable(); }
22
+ export async function writeClipboard(_content: ClipboardWriteContent): Promise<void> { return unavailable(); }
@@ -0,0 +1,8 @@
1
+ import { SparkError } from "@legendapp/spark-desktop-app/src/contracts";
2
+ import { StringFormat } from "./formats";
3
+ export function stringOptions(options: object, key: string): StringFormat {
4
+ if (!options || typeof options !== "object" || Object.keys(options).some(name => name !== key)) throw new SparkError("E_UNSUPPORTED_OPTION", "Unsupported clipboard option");
5
+ const format = (options as Record<string, unknown>)[key] ?? StringFormat.PLAIN_TEXT;
6
+ if (format !== StringFormat.PLAIN_TEXT && format !== StringFormat.HTML) throw new SparkError("E_INVALID_ARGUMENT", "Invalid clipboard string format");
7
+ return format;
8
+ }
@@ -0,0 +1,10 @@
1
+ import type { StringFormat } from "./formats";
2
+ export type GetStringOptions = { preferredFormat?: StringFormat };
3
+ export type SetStringOptions = { inputFormat?: StringFormat };
4
+ export interface ClipboardImage { format: "png"; bytes: Uint8Array }
5
+ /** Reading preserves all OS representations, which can coexist. */
6
+ export interface ClipboardContent { text?: string; html?: string; rtf?: string; image?: ClipboardImage; files?: readonly string[] }
7
+ /** File lists must be written separately from text/image representations. */
8
+ export type ClipboardWriteContent =
9
+ | { files: readonly string[]; text?: never; html?: never; rtf?: never; image?: never }
10
+ | { files?: never; text?: string; html?: string; rtf?: string; image?: ClipboardImage };