@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
@@ -0,0 +1,436 @@
1
+ import { LegendList, type LegendListRef, type LegendListRenderItemProps } from "@legendapp/list/react-native";
2
+ import { cn } from "@legendapp/spark-ui/src/classnames";
3
+ import { SidebarSplitView, type SidebarSplitViewAppearance, type SidebarSplitViewResizeEvent } from "@legendapp/spark-ui/src/appkit-split-view";
4
+ import { SparkError, nativeError } from "@legendapp/spark-desktop-app/src/contracts";
5
+ import { createContext, type ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
6
+ import { Pressable, Platform, ScrollView, StyleSheet, Text, View } from "react-native";
7
+
8
+ const SETTINGS_SIDEBAR_TOP_INSET = 40;
9
+ const SETTINGS_TITLEBAR_CONTENT_INSET = 56;
10
+ const settingsContentInset = { bottom: 0, left: 0, right: 0, top: SETTINGS_TITLEBAR_CONTENT_INSET };
11
+ const settingsSidebarPressablePlatformProps = Platform.OS === "macos" ? { enableFocusRing: false } : {};
12
+ const SettingsRowGroupContext = createContext(false);
13
+ export * from "./options";
14
+
15
+ export interface SettingsWindowPage<PageId extends string = string> {
16
+ id: PageId;
17
+ title: string;
18
+ render: () => ReactNode;
19
+ }
20
+ export interface SettingsWindowBaseProps<PageId extends string = string> {
21
+ /** Immutable for this mount. Remount to change the owning window. */
22
+ windowId: string;
23
+ pages: readonly SettingsWindowPage<PageId>[];
24
+ appearance?: SidebarSplitViewAppearance;
25
+ backgroundClassName?: string;
26
+ contentBackgroundClassName?: string;
27
+ contentMinWidth?: number;
28
+ sidebarMinWidth?: number;
29
+ onError?: (error: SparkError) => void;
30
+ }
31
+ export type SettingsWindowSelectionProps<PageId extends string = string> =
32
+ | { selectedPageId: PageId; defaultPageId?: never; onSelectionChange: (pageId: PageId) => void }
33
+ | { selectedPageId?: never; defaultPageId?: PageId; onSelectionChange?: (pageId: PageId) => void };
34
+ export type SettingsWindowProps<PageId extends string = string> = SettingsWindowBaseProps<PageId> & SettingsWindowSelectionProps<PageId>;
35
+ export type VirtualizedSettingsWindowProps<PageId extends string = string> = SettingsWindowProps<PageId> & { estimatedItemSize?: number };
36
+
37
+ function useSettingsSelection<PageId extends string>(props: SettingsWindowProps<PageId>) {
38
+ const { pages, windowId, selectedPageId, defaultPageId, onSelectionChange } = props;
39
+ const controlled = selectedPageId !== undefined;
40
+ const identity = useRef({ windowId, controlled });
41
+ if (!windowId || windowId.includes("\0") || identity.current.windowId !== windowId) throw new SparkError("E_INVALID_ARGUMENT", "Settings windowId must be nonempty and immutable; remount to change it");
42
+ if (identity.current.controlled !== controlled || (controlled && defaultPageId !== undefined) || (controlled && typeof onSelectionChange !== "function")) throw new SparkError("E_INVALID_ARGUMENT", "Settings selection must have one stable owner");
43
+ const ids = new Set<string>();
44
+ for (const page of pages) {
45
+ if (!page.id || page.id.includes("\0") || ids.has(page.id) || !page.title || typeof page.render !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Settings pages require unique nonempty IDs, titles and render callbacks");
46
+ ids.add(page.id);
47
+ }
48
+ if (!pages.length || (controlled && !ids.has(selectedPageId))) throw new SparkError("E_INVALID_ARGUMENT", "Settings selection must identify an existing page");
49
+ const [local, setLocal] = useState(() => {
50
+ if (defaultPageId !== undefined && !ids.has(defaultPageId)) throw new SparkError("E_INVALID_ARGUMENT", "Unknown default settings page");
51
+ return defaultPageId ?? pages[0].id;
52
+ });
53
+ const selected = controlled ? selectedPageId : ids.has(local) ? local : pages[0].id;
54
+ useEffect(() => { if (!controlled && local !== selected) setLocal(selected); }, [controlled, local, selected]);
55
+ const [revision, setRevision] = useState(0);
56
+ const requestSelection = useCallback((id: PageId) => {
57
+ if (!pages.some(page => page.id === id)) return;
58
+ if (!controlled) setLocal(id);
59
+ // A controlled parent may keep its value; the scrolling variant must restore it.
60
+ setRevision(value => value + 1);
61
+ if (selected !== id) onSelectionChange?.(id);
62
+ }, [controlled, onSelectionChange, pages, selected]);
63
+ return { selected, requestSelection, revision };
64
+ }
65
+
66
+ function useSettingsWindow(windowId: string, title: string, appearance: SidebarSplitViewAppearance, onError: SettingsWindowBaseProps["onError"], contentReadyInitially: boolean) {
67
+ const errorRef = useRef(onError); errorRef.current = onError;
68
+ const active = useRef(false);
69
+ const contentReady = useRef(contentReadyInitially);
70
+ const splitReady = useRef(false);
71
+ const shown = useRef(false);
72
+ const report = useCallback((cause: unknown) => {
73
+ if (active.current) {
74
+ const error = nativeError(cause);
75
+ if (errorRef.current) errorRef.current(error); else console.error(error);
76
+ }
77
+ }, []);
78
+ const showIfReady = useCallback(() => {
79
+ if (!active.current || !contentReady.current || !splitReady.current || shown.current) return;
80
+ shown.current = true;
81
+ void import("@legendapp/spark-desktop-windows/src/api").then(async windows => {
82
+ if (!active.current) { shown.current = false; return; }
83
+ await windows.showWindow(windowId);
84
+ }).catch(cause => { shown.current = false; report(cause); });
85
+ }, [report, windowId]);
86
+ useEffect(() => { active.current = true; showIfReady(); return () => { active.current = false; }; }, [showIfReady]);
87
+ useEffect(() => {
88
+ let current = true;
89
+ void import("@legendapp/spark-desktop-windows/src/api").then(async windows => {
90
+ if (current) await windows.setWindowOptions(windowId, { title, appearance });
91
+ }).catch(cause => { if (current) report(cause); });
92
+ return () => { current = false; };
93
+ }, [appearance, report, title, windowId]);
94
+ const onResize = useCallback((event: SidebarSplitViewResizeEvent) => {
95
+ if (event.phase === "ready" && event.contentHeight > 0 && event.contentWidth > 0 && event.sidebarHeight > 0 && event.sidebarWidth > 0) {
96
+ splitReady.current = true; showIfReady();
97
+ }
98
+ }, [showIfReady]);
99
+ const markContentReady = useCallback(() => { contentReady.current = true; showIfReady(); }, [showIfReady]);
100
+ return { onResize, markContentReady, report };
101
+ }
102
+
103
+ export function SettingsWindow<PageId extends string = string>(props: SettingsWindowProps<PageId>) {
104
+ const { appearance = "system", backgroundClassName = "bg-background", contentBackgroundClassName = backgroundClassName, contentMinWidth = 340, pages, sidebarMinWidth = 180, windowId, onError } = props;
105
+ const { selected, requestSelection } = useSettingsSelection(props);
106
+ const page = pages.find(page => page.id === selected)!;
107
+ const { onResize, report } = useSettingsWindow(windowId, page.title, appearance, onError, true);
108
+ return <SidebarSplitView appearance={appearance} className={cn("flex-1", backgroundClassName)} contentMinWidth={contentMinWidth} onResize={onResize} onError={report} sidebarMinWidth={sidebarMinWidth} style={styles.root}
109
+ sidebar={<View className="min-w-0 flex-1 overflow-hidden" style={styles.pane}>
110
+ <SettingsSidebar onSelectionChange={requestSelection} pages={pages} selectedPageId={selected} />
111
+ <SettingsToolbarBackground variant="sidebar" />
112
+ </View>}
113
+ content={<View className={cn("min-w-0 flex-1 overflow-hidden", contentBackgroundClassName)} style={styles.pane}>
114
+ {page.render()}<SettingsToolbarBackground variant="content" />
115
+ </View>}
116
+ />;
117
+ }
118
+
119
+ export function VirtualizedSettingsWindow<PageId extends string = string>(props: VirtualizedSettingsWindowProps<PageId>) {
120
+ const { appearance = "system", backgroundClassName = "bg-background", contentBackgroundClassName = backgroundClassName, contentMinWidth = 340, estimatedItemSize = 520, pages, sidebarMinWidth = 180, windowId, onError } = props;
121
+ if (!Number.isFinite(estimatedItemSize) || estimatedItemSize <= 0) throw new SparkError("E_INVALID_ARGUMENT", "estimatedItemSize must be positive");
122
+ const { selected, requestSelection, revision } = useSettingsSelection(props);
123
+ const listRef = useRef<LegendListRef | null>(null);
124
+ const page = pages.find(page => page.id === selected)!;
125
+ const { onResize, markContentReady, report } = useSettingsWindow(windowId, page.title, appearance, onError, false);
126
+ const programmatic = useRef(0);
127
+ const visiblePage = useRef<PageId | undefined>(undefined);
128
+ const initialized = useRef(false);
129
+ const pageIndexById = useMemo(() => new Map(pages.map((page, index) => [page.id, index])), [pages]);
130
+ useEffect(() => {
131
+ let current = true;
132
+ const generation = ++programmatic.current;
133
+ const frame = requestAnimationFrame(() => {
134
+ if (visiblePage.current === selected && initialized.current) { programmatic.current = 0; return; }
135
+ const list = listRef.current;
136
+ if (!list) { report(new SparkError("E_UNAVAILABLE", "Settings list is not mounted")); return; }
137
+ void list.scrollToIndex({ animated: initialized.current, index: pageIndexById.get(selected)!, viewOffset: SETTINGS_TITLEBAR_CONTENT_INSET, viewPosition: 0 })
138
+ .then(() => { if (current) visiblePage.current = selected; })
139
+ .catch(cause => { if (current) report(cause); })
140
+ .finally(() => {
141
+ if (!current) return;
142
+ initialized.current = true;
143
+ if (programmatic.current === generation) programmatic.current = 0;
144
+ markContentReady();
145
+ });
146
+ });
147
+ return () => { current = false; cancelAnimationFrame(frame); };
148
+ }, [markContentReady, pageIndexById, report, revision, selected]);
149
+ const onFirstVisibleItemChanged = useCallback((info: { index: number }) => {
150
+ if (programmatic.current) return;
151
+ const state = listRef.current?.getState();
152
+ let index = info.index;
153
+ if (state) {
154
+ const visibleTop = state.scroll + SETTINGS_TITLEBAR_CONTENT_INSET;
155
+ while (index < pages.length - 1 && state.positionAtIndex(index) + state.sizeAtIndex(index) <= visibleTop) index++;
156
+ }
157
+ const page = pages[index];
158
+ if (page && visiblePage.current !== page.id) {
159
+ visiblePage.current = page.id;
160
+ requestSelection(page.id);
161
+ }
162
+ }, [pages, requestSelection]);
163
+ const onScroll = useCallback(() => {
164
+ const state = listRef.current?.getState();
165
+ if (state) onFirstVisibleItemChanged({ index: state.start });
166
+ }, [onFirstVisibleItemChanged]);
167
+ const renderItem = useCallback(({ index, item }: LegendListRenderItemProps<SettingsWindowPage<PageId>>) => (
168
+ <View className="flex-col gap-5" style={[styles.virtualizedSettingsListPage, index > 0 && styles.virtualizedSettingsListPageAfterFirst]}>
169
+ <View className="flex-col gap-2"><Text className="text-xl font-semibold text-text-primary leading-tight">{item.title}</Text></View>
170
+ <View className="flex-col">{item.render()}</View>
171
+ </View>
172
+ ), []);
173
+ return <SidebarSplitView appearance={appearance} className={cn("flex-1", backgroundClassName)} contentMinWidth={contentMinWidth} onResize={onResize} onError={report} sidebarMinWidth={sidebarMinWidth} style={styles.root}
174
+ sidebar={<View className="min-w-0 flex-1 overflow-hidden" style={styles.pane}>
175
+ <SettingsSidebar onSelectionChange={requestSelection} pages={pages} selectedPageId={selected} /><SettingsToolbarBackground variant="sidebar" />
176
+ </View>}
177
+ content={<View className={cn("min-w-0 flex-1 overflow-hidden", contentBackgroundClassName)} style={styles.pane}>
178
+ <LegendList contentInset={settingsContentInset} contentContainerStyle={styles.virtualizedSettingsListContent} data={pages} estimatedItemSize={estimatedItemSize} keyExtractor={settingsPageKey} onFirstVisibleItemChanged={onFirstVisibleItemChanged} onScroll={onScroll} scrollEventThrottle={16} ref={listRef} renderItem={renderItem} recycleItems style={styles.virtualizedSettingsList} />
179
+ <SettingsToolbarBackground variant="content" />
180
+ </View>}
181
+ />;
182
+ }
183
+ const settingsPageKey = (page: SettingsWindowPage) => page.id;
184
+
185
+ function SettingsToolbarBackground({ variant }: { variant: "content" | "sidebar" }) {
186
+ return (
187
+ <View
188
+ className="absolute left-0 right-0 top-0 bg-gradient-to-b from-background-primary from-60% to-background-primary/0"
189
+ pointerEvents="none"
190
+ style={[styles.toolbarBackground, variant === "sidebar" ? styles.sidebarToolbarBackground : undefined]}
191
+ />
192
+ );
193
+ }
194
+
195
+ export type SettingsSidebarProps<PageId extends string = string> = {
196
+ onSelectionChange: (pageId: PageId) => void;
197
+ pages: readonly Pick<SettingsWindowPage<PageId>, "id" | "title">[];
198
+ selectedPageId: PageId;
199
+ };
200
+
201
+ export function SettingsSidebar<PageId extends string = string>({
202
+ onSelectionChange,
203
+ pages,
204
+ selectedPageId,
205
+ }: SettingsSidebarProps<PageId>) {
206
+ return (
207
+ <View className="flex-1 min-h-0">
208
+ <ScrollView
209
+ className="flex-1"
210
+ contentContainerStyle={styles.sidebarContent}
211
+ showsVerticalScrollIndicator={false}
212
+ >
213
+ {pages.map((page) => {
214
+ const isSelected = selectedPageId === page.id;
215
+
216
+ return (
217
+ <Pressable
218
+ {...settingsSidebarPressablePlatformProps}
219
+ accessibilityRole="button"
220
+ accessibilityState={{ selected: isSelected }}
221
+ collapsable={false}
222
+ style={styles.sidebarRow}
223
+ className={cn(
224
+ "justify-center rounded-md px-2",
225
+ isSelected ? "bg-primary/15" : "hover:bg-background-secondary/60 active:bg-background-secondary",
226
+ )}
227
+ key={page.id}
228
+ onPress={() => onSelectionChange(page.id)}
229
+ >
230
+ <Text
231
+ className={isSelected ? "text-sm font-medium text-text-primary" : "text-sm text-text-secondary"}
232
+ numberOfLines={1}
233
+ >
234
+ {page.title}
235
+ </Text>
236
+ </Pressable>
237
+ );
238
+ })}
239
+ </ScrollView>
240
+ </View>
241
+ );
242
+ }
243
+
244
+ export interface SettingsPageProps {
245
+ actions?: ReactNode;
246
+ children: ReactNode;
247
+ contentClassName?: string;
248
+ }
249
+
250
+ export function SettingsPage({ actions, children, contentClassName }: SettingsPageProps) {
251
+ return (
252
+ <View className="w-full flex-1 self-stretch overflow-hidden">
253
+ {actions ? <View className="flex-row justify-end px-6 pt-4">{actions}</View> : null}
254
+ <ScrollView
255
+ className="flex-1"
256
+ contentContainerClassName={cn("w-full max-w-4xl flex-col self-center px-8 pb-7", contentClassName)}
257
+ contentInset={settingsContentInset}
258
+ horizontal={false}
259
+ >
260
+ {children}
261
+ </ScrollView>
262
+ </View>
263
+ );
264
+ }
265
+
266
+ export interface SettingsSectionProps {
267
+ card?: boolean;
268
+ children?: ReactNode;
269
+ className?: string;
270
+ contentClassName?: string;
271
+ description?: string;
272
+ first?: boolean;
273
+ headerRight?: ReactNode;
274
+ title?: string | null;
275
+ }
276
+
277
+ export function SettingsSection({
278
+ card = true,
279
+ children,
280
+ className,
281
+ contentClassName,
282
+ description,
283
+ first = false,
284
+ headerRight,
285
+ title,
286
+ }: SettingsSectionProps) {
287
+ const containerClassName = cn("flex flex-col gap-3", !first && "mt-7", className);
288
+ const hasHeader = Boolean(title || description || headerRight);
289
+ const contentNode = children !== undefined && children !== null
290
+ ? card
291
+ ? <SettingsRowGroup className={contentClassName}>{children}</SettingsRowGroup>
292
+ : <View className={cn("flex flex-col gap-4", contentClassName)}>{children}</View>
293
+ : null;
294
+
295
+ return (
296
+ <View className={containerClassName}>
297
+ {hasHeader ? (
298
+ <View className="flex-row items-start justify-between gap-4">
299
+ <View className="flex-1 flex-col gap-1">
300
+ {title ? (
301
+ <Text className="text-sm font-semibold leading-tight text-text-secondary">{title}</Text>
302
+ ) : null}
303
+ {description ? (
304
+ <Text className="text-xs leading-relaxed text-text-secondary">{description}</Text>
305
+ ) : null}
306
+ </View>
307
+ {headerRight ? <View className="flex-none ml-4">{headerRight}</View> : null}
308
+ </View>
309
+ ) : null}
310
+ {contentNode}
311
+ </View>
312
+ );
313
+ }
314
+
315
+ export interface SettingsCardProps {
316
+ children: ReactNode;
317
+ className?: string;
318
+ }
319
+
320
+ export function SettingsCard({ children, className }: SettingsCardProps) {
321
+ return (
322
+ <View className={cn("overflow-hidden rounded-xl border border-border-primary bg-background-secondary/20", className)}>
323
+ {children}
324
+ </View>
325
+ );
326
+ }
327
+
328
+ export interface SettingsRowGroupProps {
329
+ children: ReactNode;
330
+ className?: string;
331
+ }
332
+
333
+ export function SettingsRowGroup({ children, className }: SettingsRowGroupProps) {
334
+ return (
335
+ <SettingsRowGroupContext.Provider value>
336
+ <SettingsCard className={className}>{children}</SettingsCard>
337
+ </SettingsRowGroupContext.Provider>
338
+ );
339
+ }
340
+
341
+ export interface SettingsRowProps {
342
+ align?: "start" | "center";
343
+ className?: string;
344
+ contentClassName?: string;
345
+ control: ReactNode;
346
+ controlWrapperClassName?: string;
347
+ description?: string;
348
+ /** Visual emphasis only. Disable the control itself when needed. */
349
+ muted?: boolean;
350
+ title: string;
351
+ }
352
+
353
+ export function SettingsRow({
354
+ align = "start",
355
+ className,
356
+ contentClassName,
357
+ control,
358
+ controlWrapperClassName,
359
+ description,
360
+ muted = false,
361
+ title,
362
+ }: SettingsRowProps) {
363
+ const grouped = useContext(SettingsRowGroupContext);
364
+
365
+ return (
366
+ <View
367
+ className={cn(
368
+ "flex-row justify-between gap-5 px-4 py-4",
369
+ align === "center" ? "items-center" : "items-start",
370
+ grouped ? "border-border-primary" : "",
371
+ muted ? "opacity-60" : "",
372
+ className,
373
+ )}
374
+ style={grouped ? styles.groupedRow : undefined}
375
+ >
376
+ <View className={cn("min-w-0 flex-1 flex-col gap-1 pr-6", contentClassName)}>
377
+ <Text className="text-sm font-semibold leading-tight text-text-primary">{title}</Text>
378
+ {description ? (
379
+ <Text className="text-xs leading-relaxed text-text-secondary">{description}</Text>
380
+ ) : null}
381
+ </View>
382
+ <View className={cn("max-w-full flex-shrink items-end", controlWrapperClassName)}>
383
+ {control}
384
+ </View>
385
+ </View>
386
+ );
387
+ }
388
+
389
+ const styles = StyleSheet.create({
390
+ pane: {
391
+ flex: 1,
392
+ minWidth: 0,
393
+ },
394
+ root: {
395
+ flex: 1,
396
+ },
397
+ virtualizedSettingsList: {
398
+ flex: 1,
399
+ },
400
+ virtualizedSettingsListContent: {
401
+ flexDirection: "column",
402
+ paddingBottom: 28,
403
+ },
404
+ // Keep horizontal sizing inside the item, so the virtualized scroll content
405
+ // cannot add its padding to the measured page width and clip the controls.
406
+ virtualizedSettingsListPage: {
407
+ alignSelf: "center",
408
+ maxWidth: 896,
409
+ paddingHorizontal: 32,
410
+ width: "100%",
411
+ },
412
+ virtualizedSettingsListPageAfterFirst: {
413
+ marginTop: 40,
414
+ },
415
+ groupedRow: {
416
+ borderBottomWidth: StyleSheet.hairlineWidth,
417
+ },
418
+ // Selection adds a background to an otherwise flattenable row. Keep its native
419
+ // bounds stable and clip painting when Fabric updates selection during scroll.
420
+ sidebarRow: {
421
+ height: 28,
422
+ flexShrink: 0,
423
+ overflow: "hidden",
424
+ },
425
+ sidebarContent: {
426
+ paddingHorizontal: 8,
427
+ paddingTop: SETTINGS_SIDEBAR_TOP_INSET,
428
+ },
429
+ sidebarToolbarBackground: {
430
+ height: SETTINGS_SIDEBAR_TOP_INSET,
431
+ },
432
+ toolbarBackground: {
433
+ height: SETTINGS_TITLEBAR_CONTENT_INSET,
434
+ zIndex: 1,
435
+ },
436
+ });
@@ -0,0 +1,10 @@
1
+ import type { NavigatorWindowOptions } from "@legendapp/spark-desktop-windows/src/windows/types";
2
+ export type CreateSettingsWindowOptionsInput = NavigatorWindowOptions;
3
+ /** SettingsWindow presents the hidden window when its native layout is ready. */
4
+ export function createSettingsWindowOptions(options: CreateSettingsWindowOptionsInput = {}): NavigatorWindowOptions {
5
+ return {
6
+ title: "Settings", transparent: true, size: { width: 820, height: 640 }, minSize: { width: 720, height: 500 }, titleBarStyle: "overlay",
7
+ ...options, show: false,
8
+ macos: { ...options.macos, titleBar: { transparent: true, separator: "none", titleVisibility: "visible", ...options.macos?.titleBar }, toolbar: { visible: true, style: "unified", ...options.macos?.toolbar } },
9
+ };
10
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/spark-sqlite",
3
- "version": "0.0.1-next.2",
3
+ "version": "0.0.1-next.4",
4
4
  "license": "MIT",
5
5
  "main": "src/index.ts",
6
6
  "react-native": "src/index.ts",
@@ -9,8 +9,8 @@
9
9
  ],
10
10
  "dependencies": {
11
11
  "@op-engineering/op-sqlite": "18.2.1",
12
- "@legendapp/spark-desktop-app": "0.0.1-next.2",
13
- "@legendapp/spark-file-system": "0.0.1-next.2"
12
+ "@legendapp/spark-desktop-app": "0.0.1-next.4",
13
+ "@legendapp/spark-file-system": "0.0.1-next.4"
14
14
  },
15
15
  "private": true
16
16
  }
@@ -0,0 +1,182 @@
1
+ import { SparkError, nativeError as normalizeNativeError } from "@legendapp/spark-desktop-app/src/contracts";
2
+ import type { Database, IntegerMode, RunResult, SqlExecutor, SqlRow, SqlValue } from "./types";
3
+
4
+ /** Internal protocol: submit statements in FIFO order, snapshot bindings on submission,
5
+ * and return fresh, mutable rows/buffers owned by the caller. Native drivers own this work. */
6
+ export interface SqlBackend {
7
+ execute(sql: string, params: readonly SqlValue[]): Promise<{ rows: unknown; rowsAffected: number; insertId?: number | string | bigint }>;
8
+ close(): void | Promise<void>;
9
+ }
10
+ function validNumber(value: number, code: "E_INVALID_ARGUMENT" | "E_INVALID_DATA") {
11
+ if (!Number.isFinite(value) || (Number.isInteger(value) && !Number.isSafeInteger(value))) {
12
+ throw new SparkError(code, "SQLite numbers must be finite and integers must be safely representable; use integers: \"text\" for 64-bit values");
13
+ }
14
+ return value;
15
+ }
16
+ /** Text-mode reads turn unsafe integer values into strings so large stored rows remain readable. */
17
+ function textifyNumbers(value: Record<string, unknown>) {
18
+ for (const key of Object.keys(value)) {
19
+ const item = value[key];
20
+ if (typeof item === "number" && Number.isInteger(item) && !Number.isSafeInteger(item)) value[key] = String(item);
21
+ else if (typeof item === "bigint") value[key] = item.toString();
22
+ }
23
+ return value;
24
+ }
25
+ function parameters(sql: string, params: readonly SqlValue[], deferred: boolean): readonly SqlValue[] {
26
+ if (typeof sql !== "string" || !sql.trim() || sql.includes("\0") || !Array.isArray(params)) {
27
+ throw new SparkError("E_INVALID_ARGUMENT", "Expected SQL text and positional parameters");
28
+ }
29
+ for (const value of params) {
30
+ if (typeof value === "number") validNumber(value, "E_INVALID_ARGUMENT");
31
+ else if (value !== null && typeof value !== "string" && !(value instanceof Uint8Array)) {
32
+ throw new SparkError("E_INVALID_ARGUMENT", "SQL parameters must be null, string, number or Uint8Array");
33
+ }
34
+ }
35
+ // Only Spark-deferred work needs a snapshot; direct calls are snapshotted by the driver.
36
+ return deferred ? params.map(value => value instanceof Uint8Array ? value.slice() : value) : params;
37
+ }
38
+ function nativeError(cause: unknown): never {
39
+ throw normalizeNativeError(cause);
40
+ }
41
+ function row(value: unknown, integers: IntegerMode): SqlRow {
42
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
43
+ throw new SparkError("E_INVALID_DATA", "Expected a SQLite row object");
44
+ }
45
+ const result = value as Record<string, unknown>;
46
+ if (integers === "text") textifyNumbers(result);
47
+ for (const key of Object.keys(result)) {
48
+ const item = result[key];
49
+ if (item === null || typeof item === "string") continue;
50
+ if (typeof item === "number") { validNumber(item, "E_INVALID_DATA"); continue; }
51
+ if (item instanceof Uint8Array) continue;
52
+ if (item instanceof ArrayBuffer) { result[key] = new Uint8Array(item); continue; }
53
+ if (ArrayBuffer.isView(item)) { result[key] = new Uint8Array(item.buffer, item.byteOffset, item.byteLength); continue; }
54
+ throw new SparkError("E_INVALID_DATA", "Unexpected SQLite value");
55
+ }
56
+ return result as SqlRow;
57
+ }
58
+ type NativeResult = Awaited<ReturnType<SqlBackend["execute"]>>;
59
+ function resultRows(result: NativeResult): unknown[] {
60
+ if (!Array.isArray(result.rows)) throw new SparkError("E_INVALID_DATA", "Expected SQLite rows");
61
+ return result.rows;
62
+ }
63
+ function all(result: NativeResult, integers: IntegerMode): SqlRow[] {
64
+ const values = resultRows(result);
65
+ for (const value of values) row(value, integers);
66
+ return values as SqlRow[];
67
+ }
68
+ function first(result: NativeResult, integers: IntegerMode): SqlRow | null {
69
+ const values = resultRows(result);
70
+ return values.length ? row(values[0], integers) : null;
71
+ }
72
+ function mutation(result: NativeResult, integers: IntegerMode): RunResult {
73
+ const changes = validNumber(result.rowsAffected, "E_INVALID_DATA");
74
+ if (!Number.isSafeInteger(changes) || changes < 0) throw new SparkError("E_INVALID_DATA", "Invalid SQLite change count");
75
+ const insertId = result.insertId;
76
+ if (insertId == null) return { changes, lastInsertRowId: null };
77
+ if (typeof insertId === "bigint") return { changes, lastInsertRowId: integers === "text" ? insertId.toString() : validNumber(Number(insertId), "E_INVALID_DATA") };
78
+ if (typeof insertId === "string") {
79
+ if (integers !== "text" || !/^[+-]?\d+$/.test(insertId)) throw new SparkError("E_INVALID_DATA", "Invalid SQLite insert ID");
80
+ return { changes, lastInsertRowId: insertId };
81
+ }
82
+ if (integers === "text" && !Number.isSafeInteger(insertId)) return { changes, lastInsertRowId: insertId.toString() };
83
+ return { changes, lastInsertRowId: validNumber(insertId, "E_INVALID_DATA") };
84
+ }
85
+ type Submit = <T>(sql: string, params: readonly SqlValue[], convert: (result: NativeResult) => T) => Promise<T>;
86
+ function executor(submit: Submit, integers: IntegerMode): SqlExecutor {
87
+ return {
88
+ run: (sql, params = []) => submit(sql, params, result => mutation(result, integers)),
89
+ getAll: (sql, params = []) => submit(sql, params, result => all(result, integers)),
90
+ getFirst: (sql, params = []) => submit(sql, params, result => first(result, integers)),
91
+ };
92
+ }
93
+ export function createDatabase(backend: SqlBackend, integers: IntegerMode = "number"): Database {
94
+ let pending = 0;
95
+ let idle: (() => void) | undefined;
96
+ let closing: Promise<void> | undefined;
97
+ let barrier: Promise<void> | undefined;
98
+ let inTransaction = false;
99
+ const closed = () => new SparkError("E_CLOSED", "Database is closing or closed");
100
+ const busy = () => new SparkError("E_BUSY", "Use the transaction executor while a transaction is active");
101
+ function finished() { if (--pending === 0) { const resolve = idle; idle = undefined; resolve?.(); } }
102
+ function execute<T>(sql: string, params: readonly SqlValue[], convert: (result: NativeResult) => T): Promise<T> {
103
+ if (closing) return Promise.reject(closed());
104
+ if (inTransaction) return Promise.reject(busy());
105
+ const blocked = barrier;
106
+ let bound: readonly SqlValue[];
107
+ try { bound = parameters(sql, params, blocked !== undefined); }
108
+ catch (error) { return Promise.reject(error); }
109
+ pending++;
110
+ const submit = () => {
111
+ try {
112
+ return backend.execute(sql, bound).then(result => {
113
+ try { return convert(result); } finally { finished(); }
114
+ }, cause => { finished(); return nativeError(cause); });
115
+ } catch (cause) { finished(); return Promise.reject(cause).catch(nativeError); }
116
+ };
117
+ return blocked ? blocked.then(submit) : submit();
118
+ }
119
+ return {
120
+ integers,
121
+ ...executor(execute, integers),
122
+ transaction<T>(operation: (tx: SqlExecutor) => Promise<T>): Promise<T> {
123
+ if (typeof operation !== "function") return Promise.reject(new SparkError("E_INVALID_ARGUMENT", "Expected a transaction callback"));
124
+ if (closing) return Promise.reject(closed());
125
+ if (inTransaction) return Promise.reject(busy());
126
+ pending++;
127
+ const perform = async () => {
128
+ let accepting = true;
129
+ let statements: Promise<unknown> = Promise.resolve();
130
+ let failed = false;
131
+ let failure: unknown;
132
+ const tx = executor(<R>(sql: string, params: readonly SqlValue[], convert: (result: NativeResult) => R): Promise<R> => {
133
+ if (!accepting) return Promise.reject(new SparkError("E_CLOSED", "Transaction callback has finished"));
134
+ let bound: readonly SqlValue[];
135
+ try { bound = parameters(sql, params, true); }
136
+ catch (error) { return Promise.reject(error); }
137
+ // Preserve transaction poisoning: caught errors still roll back, and later
138
+ // accepted statements cannot run after an earlier statement has failed.
139
+ const next = statements.then(() => {
140
+ if (failed) throw failure;
141
+ try { return backend.execute(sql, bound).then(convert, nativeError); }
142
+ catch (cause) { return nativeError(cause); }
143
+ });
144
+ statements = next.catch(error => { failed = true; failure = error; });
145
+ return next;
146
+ }, integers);
147
+ try {
148
+ try { await backend.execute("BEGIN", []); } catch (cause) { nativeError(cause); }
149
+ inTransaction = true;
150
+ try {
151
+ const value = await operation(tx);
152
+ accepting = false;
153
+ await statements;
154
+ if (failed) throw failure;
155
+ try { await backend.execute("COMMIT", []); } catch (cause) { nativeError(cause); }
156
+ return value;
157
+ } catch (error) {
158
+ accepting = false;
159
+ await statements;
160
+ try { await backend.execute("ROLLBACK", []); }
161
+ catch (cause) { throw new SparkError("E_NATIVE", "SQLite transaction failed and rollback also failed", { cause: new AggregateError([error, cause]) }); }
162
+ throw error;
163
+ }
164
+ } finally { accepting = false; inTransaction = false; }
165
+ };
166
+ const operationResult = barrier ? barrier.then(perform) : perform();
167
+ const completion = operationResult.then(() => {}, () => {});
168
+ barrier = completion;
169
+ // Only multi-statement callbacks reserve a JS barrier; ordinary statements
170
+ // go straight to the driver's native queue.
171
+ void completion.then(() => { if (barrier === completion) barrier = undefined; });
172
+ return operationResult.then(value => { finished(); return value; }, error => { finished(); throw error; });
173
+ },
174
+ close() {
175
+ if (inTransaction) return Promise.reject(busy());
176
+ if (closing) return closing;
177
+ const drained = pending ? new Promise<void>(resolve => { idle = resolve; }) : Promise.resolve();
178
+ closing = drained.then(() => backend.close()).then(() => {}).catch(error => { closing = undefined; throw error; });
179
+ return closing;
180
+ },
181
+ };
182
+ }