@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.
- package/LICENSE +21 -0
- package/README.md +10 -4
- package/ai-codex.ts +1 -0
- package/ai.ts +1 -0
- package/app-documents.ts +1 -0
- package/camera.ts +13 -0
- package/config-plugin.d.cts +2 -0
- package/contracts.ts +2 -0
- package/diagnostics.ts +1 -0
- package/expo-config.d.cts +1 -0
- package/metro.cjs +4 -1
- package/metro.d.cts +12 -0
- package/native.cjs +3 -1
- package/native.d.cts +6 -0
- package/package.json +93 -15
- package/patches/camera/react-native-nitro-image.patch +320 -0
- package/patches/camera/react-native-nitro-modules.patch +50 -0
- package/patches/camera/react-native-vision-camera.patch +2662 -0
- package/patches/camera/upstream.json +22 -0
- package/patches/dependencies.json +8 -0
- package/patches/react-native-enriched-markdown@1.0.2.patch +8684 -0
- package/postinstall.cjs +1 -0
- package/schema.json +276 -58
- package/settings-observable.ts +1 -0
- package/settings-window.ts +1 -0
- package/shortcuts-commands.ts +1 -0
- package/shortcuts-keyboard.ts +3 -0
- package/ui-classnames.ts +1 -0
- package/ui-glass.ts +1 -0
- package/ui-search.ts +1 -0
- package/ui-sidebar.ts +1 -0
- package/ui-split-view.ts +1 -0
- package/ui-swipe.ts +1 -0
- package/ui-symbol.ts +1 -0
- package/vendor/node_modules/@legendapp/spark-ai/package.json +19 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/availability.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/index.ts +15 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/invocations.ts +34 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/output.ts +62 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/run.ts +12 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/types.ts +16 -0
- package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.h +2 -1
- package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.mm +126 -24
- package/vendor/node_modules/@legendapp/spark-audio/package.json +5 -2
- package/vendor/node_modules/@legendapp/spark-audio/src/NativeSparkAudio.ts +5 -1
- package/vendor/node_modules/@legendapp/spark-audio/src/desktop.ts +36 -32
- package/vendor/node_modules/@legendapp/spark-audio/src/events.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-audio/src/hooks.ts +65 -0
- package/vendor/node_modules/@legendapp/spark-audio/src/index.web.ts +92 -33
- package/vendor/node_modules/@legendapp/spark-audio/src/media-session-unavailable.ts +6 -4
- package/vendor/node_modules/@legendapp/spark-audio/src/media-session.ts +52 -19
- package/vendor/node_modules/@legendapp/spark-audio/src/media-session.web.ts +18 -10
- package/vendor/node_modules/@legendapp/spark-audio/src/media-types.ts +40 -13
- package/vendor/node_modules/@legendapp/spark-audio/src/mobile.ts +40 -32
- package/vendor/node_modules/@legendapp/spark-audio/src/player.ts +97 -0
- package/vendor/node_modules/@legendapp/spark-audio/src/status-listeners.ts +21 -15
- package/vendor/node_modules/@legendapp/spark-audio/src/types.ts +9 -4
- package/vendor/node_modules/@legendapp/spark-audio/windows/SparkAudio/SparkAudio.h +67 -20
- package/vendor/node_modules/@legendapp/spark-auth-session/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-auth-session/src/core.ts +60 -42
- package/vendor/node_modules/@legendapp/spark-auth-session/src/index.ts +28 -12
- package/vendor/node_modules/@legendapp/spark-auth-session/src/mobile.ts +97 -41
- package/vendor/node_modules/@legendapp/spark-auth-session/src/types.ts +20 -9
- package/vendor/node_modules/@legendapp/spark-cli/dist/add-desktop.js +50 -7
- package/vendor/node_modules/@legendapp/spark-cli/dist/build-mode.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/build.js +145 -59
- package/vendor/node_modules/@legendapp/spark-cli/dist/cli-arguments.js +61 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/commands.js +10 -4
- package/vendor/node_modules/@legendapp/spark-cli/dist/create.js +37 -8
- package/vendor/node_modules/@legendapp/spark-cli/dist/credentials.js +86 -25
- package/vendor/node_modules/@legendapp/spark-cli/dist/dependency-pins.js +132 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/dev-command.js +13 -4
- package/vendor/node_modules/@legendapp/spark-cli/dist/dev.js +13 -10
- package/vendor/node_modules/@legendapp/spark-cli/dist/errors.js +100 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/examples.js +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-dev-patch.cjs +4 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-metro.cjs +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-native.cjs +5 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-node.js +3 -3
- package/vendor/node_modules/@legendapp/spark-cli/dist/helpers.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/index.js +52 -44
- package/vendor/node_modules/@legendapp/spark-cli/dist/json.js +16 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/local.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/metro.cjs +26 -5
- package/vendor/node_modules/@legendapp/spark-cli/dist/native-metadata.js +26 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/native-patch-preflight.js +86 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/native-preparation.js +88 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/notary-profiles.js +75 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/package.js +4 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/platform.js +16 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/process.js +7 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/project.js +90 -32
- package/vendor/node_modules/@legendapp/spark-cli/dist/release.js +86 -5
- package/vendor/node_modules/@legendapp/spark-cli/dist/release.json +23 -18
- package/vendor/node_modules/@legendapp/spark-cli/dist/runner-install.js +145 -31
- package/vendor/node_modules/@legendapp/spark-cli/dist/signing.js +4 -3
- package/vendor/node_modules/@legendapp/spark-cli/dist/universal.cjs +2 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/updates.js +41 -4
- package/vendor/node_modules/@legendapp/spark-cli/dist/windows.js +5 -9
- package/vendor/node_modules/@legendapp/spark-cli/package.json +7 -6
- package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/App.tsx +6 -12
- package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/desktop.config.json +5 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/package.json +12 -10
- package/vendor/node_modules/@legendapp/spark-cli/templates/diff-lite/Git.macos.tsx +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.macos.tsx +23 -21
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.windows.tsx +23 -21
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.desktop.ts +11 -8
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.macos.ts +3 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/Lifecycle.desktop.tsx +8 -14
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/OpenFiles.desktop.tsx +5 -10
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.desktop.ts +11 -8
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.macos.ts +3 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/music-lite/assets.desktop.ts +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Activation.desktop.tsx +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Desktop.desktop.ts +37 -15
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/session.ts +5 -6
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/window-session.ts +5 -4
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/desktop.config.json +5 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/metro.config.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/package.json +14 -12
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/react-native.config.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/templates/windows/package.json +14 -12
- package/vendor/node_modules/@legendapp/spark-cli/templates/windows/react-native.config.js +1 -1
- package/vendor/node_modules/@legendapp/spark-clipboard/macos/RNDesktopClipboard.mm +10 -16
- package/vendor/node_modules/@legendapp/spark-clipboard/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-clipboard/src/NativeDesktopClipboard.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-clipboard/src/desktop.ts +55 -31
- package/vendor/node_modules/@legendapp/spark-clipboard/src/expo.ts +21 -11
- package/vendor/node_modules/@legendapp/spark-clipboard/src/options.ts +8 -0
- package/vendor/node_modules/@legendapp/spark-clipboard/src/types.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.h +38 -15
- package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.vcxproj +2 -0
- package/vendor/node_modules/@legendapp/spark-codex/RNCodex.podspec +22 -0
- package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.hpp +23 -0
- package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.mm +1529 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitro.json +21 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/.gitattributes +1 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex+autolinking.rb +62 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.cpp +17 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.hpp +27 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Umbrella.hpp +38 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.mm +35 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.swift +16 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexAvailability.hpp +95 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexRunResult.hpp +99 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.cpp +24 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.hpp +71 -0
- package/vendor/node_modules/@legendapp/spark-codex/package.json +35 -0
- package/vendor/node_modules/@legendapp/spark-codex/react-native.config.js +11 -0
- package/vendor/node_modules/@legendapp/spark-codex/src/Codex.nitro.ts +30 -0
- package/vendor/node_modules/@legendapp/spark-codex/src/index.ts +65 -0
- package/vendor/node_modules/@legendapp/spark-codex/src/native.ts +6 -0
- package/vendor/node_modules/@legendapp/spark-commands/package.json +21 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/bindings.ts +90 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/index.tsx +400 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/router.ts +138 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/storage.ts +20 -0
- package/vendor/node_modules/@legendapp/spark-context-menu/macos/RNContextMenu.mm +7 -8
- package/vendor/node_modules/@legendapp/spark-context-menu/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-context-menu/src/NativeContextMenu.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-context-menu/src/index.ts +26 -26
- package/vendor/node_modules/@legendapp/spark-context-menu/windows/SparkContextMenu/SparkContextMenu.h +3 -2
- package/vendor/node_modules/@legendapp/spark-desktop-app/RNDesktopApp.podspec +2 -1
- package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryJSI.hpp +89 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryWindows.hpp +22 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/RNDesktopApp.mm +13 -7
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkBinaryJSI.h +48 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.h +4 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.mm +33 -33
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktopError.h +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.h +26 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.mm +49 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.h +9 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.mm +70 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkWindow.mm +9 -6
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/recent-documents/RNRecentDocumentController.mm +55 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/package.json +5 -3
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/NativeDesktopApp.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/api.ts +86 -40
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/accelerator.ts +40 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/index.ts +56 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/menu.ts +116 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/native-buffer.ts +22 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/path.ts +24 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/events.ts +75 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.ts +2 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.windows.ts +2 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/open-requests.ts +43 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/restoration.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/transport.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.cjs +10 -5
- package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.d.cts +3 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/autolinking.cjs +35 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/config.cjs +18 -3
- package/vendor/node_modules/@legendapp/spark-desktop-config/config.d.cts +89 -9
- package/vendor/node_modules/@legendapp/spark-desktop-config/expo.cjs +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/expo.d.cts +3 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/identity.cjs +3 -2
- package/vendor/node_modules/@legendapp/spark-desktop-config/lifecycle.cjs +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.cjs +106 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.d.cts +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/package.json +7 -5
- package/vendor/node_modules/@legendapp/spark-desktop-config/schema.json +276 -58
- package/vendor/node_modules/@legendapp/spark-desktop-config/updates.cjs +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/validation.cjs +35 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/windows.plugin.cjs +2 -1
- package/vendor/node_modules/@legendapp/spark-desktop-host/AppDelegate.mm +129 -11
- package/vendor/node_modules/@legendapp/spark-desktop-host/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-desktop-host/windows/application.inc +277 -121
- package/vendor/node_modules/@legendapp/spark-desktop-links/common/AuthLoopback.h +5 -7
- package/vendor/node_modules/@legendapp/spark-desktop-links/macos/RNDesktopLinks.mm +10 -9
- package/vendor/node_modules/@legendapp/spark-desktop-links/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/NativeDesktopLinks.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/api.ts +27 -33
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/expo.ts +3 -4
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/native.ts +9 -0
- package/vendor/node_modules/@legendapp/spark-desktop-links/windows/SparkLinks/SparkLinks.h +22 -22
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/RNDesktopShortcuts.podspec +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/RNDesktopShortcuts.mm +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.h +9 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.mm +307 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/package.json +8 -5
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/NativeDesktopShortcuts.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/api.ts +39 -14
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/NativeKeyboardManager.ts +12 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/codes.ts +108 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/index.ts +99 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/RNDesktopWindows.podspec +2 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/RNDesktopWindows.mm +229 -103
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/SparkWindowGeometry.h +63 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.h +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.mm +27 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.h +12 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.mm +3169 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManagerStartup.mm +31 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/SidebarStartupFallbacks.mm +14 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/package.json +10 -6
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/NativeDesktopWindowManager.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/api.ts +146 -70
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/diagnostics.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.windows.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos-adapter.ts +53 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos.ts +51 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/transport.ts +41 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/types.ts +140 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/validation.ts +162 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/window-manager/NativeWindowManager.ts +28 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/WindowProvider.tsx +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/createWindowsNavigator.tsx +78 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/index.ts +6 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/primaryWindowLifecycle.ts +34 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/types.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/usePrimaryWindowLifecycle.ts +18 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/useWindowFocusEffect.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-documents/package.json +22 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/controller.ts +97 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/documentTransition.ts +13 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/hooks.ts +139 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/index.tsx +50 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/reload.ts +39 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/requests.ts +15 -0
- package/vendor/node_modules/@legendapp/spark-drag-drop/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-drag-drop/src/DesktopDragViewNativeComponent.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-drag-drop/src/contracts.ts +73 -18
- package/vendor/node_modules/@legendapp/spark-drag-drop/src/index.tsx +58 -15
- package/vendor/node_modules/@legendapp/spark-drag-drop/windows/SparkDragDrop/SparkDragDrop.h +14 -8
- package/vendor/node_modules/@legendapp/spark-file-dialog/ios/RNFileDialog.mm +34 -121
- package/vendor/node_modules/@legendapp/spark-file-dialog/package.json +12 -5
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/NativeFileDialog.ts +1 -5
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.ts +19 -84
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/native.ts +12 -0
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/options.ts +34 -14
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/types.ts +26 -0
- package/vendor/node_modules/@legendapp/spark-file-dialog/windows/SparkFileDialog/SparkFileDialog.h +42 -58
- package/vendor/node_modules/@legendapp/spark-file-system/RNDesktopFileSystem.podspec +1 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/RNDesktopFileSystem.mm +32 -21
- package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.h +24 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.mm +215 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.h +9 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.mm +82 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.h +47 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.mm +306 -0
- package/vendor/node_modules/@legendapp/spark-file-system/package.json +8 -6
- package/vendor/node_modules/@legendapp/spark-file-system/src/NativeDesktopFileSystem.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/NativeFileScanner.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/index.ts +93 -0
- package/vendor/node_modules/@legendapp/spark-file-system/src/handles.ts +48 -14
- package/vendor/node_modules/@legendapp/spark-file-system/src/index.ts +134 -45
- package/vendor/node_modules/@legendapp/spark-file-system/src/path.ts +1 -9
- package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.h +102 -26
- package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.vcxproj +2 -0
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/RNDesktopGlobalShortcuts.podspec +1 -0
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/macos/RNDesktopGlobalShortcuts.mm +7 -4
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/NativeDesktopGlobalShortcuts.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/index.ts +39 -10
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/windows/SparkGlobalShortcuts/SparkGlobalShortcuts.h +5 -4
- package/vendor/node_modules/@legendapp/spark-message-dialog/macos/RNDesktopMessageDialog.mm +2 -2
- package/vendor/node_modules/@legendapp/spark-message-dialog/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-message-dialog/src/NativeDesktopMessageDialog.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-message-dialog/src/index.ts +48 -11
- package/vendor/node_modules/@legendapp/spark-native-menu/ios/RNNativeMenu.mm +141 -609
- package/vendor/node_modules/@legendapp/spark-native-menu/package.json +9 -4
- package/vendor/node_modules/@legendapp/spark-native-menu/src/NativeMenu.ts +2 -7
- package/vendor/node_modules/@legendapp/spark-native-menu/src/api.ts +76 -121
- package/vendor/node_modules/@legendapp/spark-native-menu/src/hooks.ts +97 -0
- package/vendor/node_modules/@legendapp/spark-native-menu/src/windows-menus.ts +43 -37
- package/vendor/node_modules/@legendapp/spark-notifications/macos/RNDesktopNotifications.mm +75 -30
- package/vendor/node_modules/@legendapp/spark-notifications/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-notifications/src/NativeDesktopNotifications.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-notifications/src/index.ts +130 -42
- package/vendor/node_modules/@legendapp/spark-notifications/windows/SparkNotifications/SparkNotifications.h +51 -8
- package/vendor/node_modules/@legendapp/spark-processes/macos/RNDesktopProcesses.mm +94 -21
- package/vendor/node_modules/@legendapp/spark-processes/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-processes/src/NativeDesktopProcesses.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-processes/src/index.ts +124 -28
- package/vendor/node_modules/@legendapp/spark-processes/src/types.ts +34 -0
- package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.h +83 -34
- package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.vcxproj +2 -0
- package/vendor/node_modules/@legendapp/spark-secure-storage/macos/RNDesktopSecureStorage.mm +49 -40
- package/vendor/node_modules/@legendapp/spark-secure-storage/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/NativeDesktopSecureStorage.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/desktop.ts +16 -14
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/expo.ts +0 -1
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/options.ts +3 -2
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/unavailable.ts +6 -3
- package/vendor/node_modules/@legendapp/spark-settings/package.json +10 -3
- package/vendor/node_modules/@legendapp/spark-settings/src/fileStorage.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-settings/src/index.ts +7 -9
- package/vendor/node_modules/@legendapp/spark-settings/src/storage/index.ts +142 -0
- package/vendor/node_modules/@legendapp/spark-settings/src/store.ts +63 -21
- package/vendor/node_modules/@legendapp/spark-settings-ui/package.json +20 -0
- package/vendor/node_modules/@legendapp/spark-settings-ui/src/index.tsx +436 -0
- package/vendor/node_modules/@legendapp/spark-settings-ui/src/options.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-sqlite/package.json +3 -3
- package/vendor/node_modules/@legendapp/spark-sqlite/src/database.ts +182 -0
- package/vendor/node_modules/@legendapp/spark-sqlite/src/index.ts +19 -6
- package/vendor/node_modules/@legendapp/spark-sqlite/src/types.ts +22 -0
- package/vendor/node_modules/@legendapp/spark-system/macos/RNDesktopSystem.mm +36 -11
- package/vendor/node_modules/@legendapp/spark-system/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-system/src/NativeDesktopSystem.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-system/src/index.ts +89 -32
- package/vendor/node_modules/@legendapp/spark-system/windows/SparkSystem/SparkSystem.h +8 -4
- package/vendor/node_modules/@legendapp/spark-tray/macos/RNDesktopTray.mm +20 -8
- package/vendor/node_modules/@legendapp/spark-tray/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-tray/src/NativeDesktopTray.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-tray/src/index.ts +91 -34
- package/vendor/node_modules/@legendapp/spark-tray/windows/SparkTray/SparkTray.h +45 -15
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkButton.mm +2 -1
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkTextInput.mm +10 -2
- package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.mm +1419 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/glass-effect-view/RNGlassEffectView.mm +72 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.mm +194 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.mm +180 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.mm +155 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.h +18 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.mm +645 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.h +10 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.mm +422 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.mm +164 -0
- package/vendor/node_modules/@legendapp/spark-ui/package.json +17 -4
- package/vendor/node_modules/@legendapp/spark-ui/src/SparkSelectNativeComponent.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-ui/src/SparkTextInputNativeComponent.ts +6 -2
- package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/SidebarSplitViewNativeComponent.ts +37 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/index.tsx +86 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/availability.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/classnames/index.ts +8 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/control.ts +42 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/desktop.tsx +56 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/glass-effect-view/index.tsx +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/index.android.tsx +35 -21
- package/vendor/node_modules/@legendapp/spark-ui/src/index.ios.tsx +55 -26
- package/vendor/node_modules/@legendapp/spark-ui/src/index.tsx +1 -27
- package/vendor/node_modules/@legendapp/spark-ui/src/index.web.tsx +45 -14
- package/vendor/node_modules/@legendapp/spark-ui/src/index.windows.tsx +1 -42
- package/vendor/node_modules/@legendapp/spark-ui/src/mobile-input.tsx +11 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSegmentedControlNativeComponent.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSelectNativeComponent.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/select.ts +5 -3
- package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/SFSymbolNativeComponent.ts +13 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/index.tsx +27 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarItemNativeComponent.ts +25 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarNativeComponent.ts +24 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/index.tsx +104 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/specialized.ts +22 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/SwipeActionsNativeComponent.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/index.tsx +41 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/TextInputSearchNativeComponent.ts +33 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/index.tsx +34 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/types.ts +30 -19
- package/vendor/node_modules/@legendapp/spark-ui/uniwind.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-ui/uniwind.web.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-ui/windows/SparkUI/SparkUI.h +16 -11
- package/vendor/node_modules/@legendapp/spark-updates/macos/RNDesktopUpdates.mm +21 -8
- package/vendor/node_modules/@legendapp/spark-updates/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-updates/src/NativeDesktopUpdates.ts +3 -2
- package/vendor/node_modules/@legendapp/spark-updates/src/index.ts +71 -15
- package/vendor/node_modules/@legendapp/spark-webview/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-webview/src/WebView.tsx +11 -0
- package/vendor/node_modules/@legendapp/spark-webview/src/adapter.ts +55 -0
- package/vendor/node_modules/@legendapp/spark-webview/src/index.ts +2 -2
- package/vendor/node_modules/@legendapp/spark-webview/src/types.ts +32 -0
- package/vendor/node_modules/@legendapp/spark-webview/src/view-props.ts +28 -0
- package/vendor/node_modules/@legendapp/spark-window-options/index.cjs +51 -14
- package/vendor/node_modules/@legendapp/spark-window-options/index.d.ts +21 -8
- package/vendor/node_modules/@legendapp/spark-window-options/package.json +1 -1
- package/windows-macos.ts +1 -0
- package/expo-metro.cjs +0 -1
- package/message-dialog.ts +0 -1
- package/universal.cjs +0 -1
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/accelerator.ts +0 -22
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows-options.ts +0 -11
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.windows.ts +0 -15
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/accelerator.ts +0 -22
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.h +0 -4
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.mm +0 -53
package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.mm
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
#import "RNFileScannerCore.h"
|
|
2
|
+
|
|
3
|
+
@implementation RNFileScannerOptions
|
|
4
|
+
|
|
5
|
+
- (instancetype)init
|
|
6
|
+
{
|
|
7
|
+
if (self = [super init]) {
|
|
8
|
+
_allowedExtensions = [NSSet set];
|
|
9
|
+
_batchSize = 64;
|
|
10
|
+
_includeHidden = NO;
|
|
11
|
+
_includeStats = NO;
|
|
12
|
+
_skipLookup = @{};
|
|
13
|
+
}
|
|
14
|
+
return self;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@end
|
|
18
|
+
|
|
19
|
+
NSString *RNFileScannerNormalizePath(NSString *path)
|
|
20
|
+
{
|
|
21
|
+
if (![path isKindOfClass:NSString.class] || path.length == 0) {
|
|
22
|
+
return @"";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
NSString *normalized = path;
|
|
26
|
+
if ([normalized hasPrefix:@"file://"]) {
|
|
27
|
+
NSURL *url = [NSURL URLWithString:normalized];
|
|
28
|
+
if (url.path.length > 0) {
|
|
29
|
+
normalized = url.path;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
normalized = [normalized stringByExpandingTildeInPath].stringByStandardizingPath;
|
|
34
|
+
while ([normalized hasSuffix:@"/"] && normalized.length > 1) {
|
|
35
|
+
normalized = [normalized substringToIndex:normalized.length - 1];
|
|
36
|
+
}
|
|
37
|
+
return normalized;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
NSString *RNFileScannerRelativePath(NSString *fullPath, NSString *rootPath)
|
|
41
|
+
{
|
|
42
|
+
NSString *normalizedFullPath = RNFileScannerNormalizePath(fullPath);
|
|
43
|
+
NSString *normalizedRoot = RNFileScannerNormalizePath(rootPath);
|
|
44
|
+
if (normalizedFullPath.length == 0 || normalizedRoot.length == 0) {
|
|
45
|
+
return normalizedFullPath;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if ([normalizedFullPath isEqualToString:normalizedRoot]) {
|
|
49
|
+
return normalizedFullPath.lastPathComponent ?: normalizedFullPath;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
NSString *rootPrefix = [normalizedRoot stringByAppendingString:@"/"];
|
|
53
|
+
if ([normalizedFullPath hasPrefix:rootPrefix]) {
|
|
54
|
+
NSString *relativePath = [normalizedFullPath substringFromIndex:rootPrefix.length];
|
|
55
|
+
return relativePath.length > 0 ? relativePath : (normalizedFullPath.lastPathComponent ?: normalizedFullPath);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return normalizedFullPath;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
NSArray<NSString *> *RNFileScannerNormalizeRoots(NSArray<NSString *> *paths)
|
|
62
|
+
{
|
|
63
|
+
NSMutableArray<NSString *> *roots = [NSMutableArray array];
|
|
64
|
+
for (id rawPath in paths) {
|
|
65
|
+
NSString *normalized = RNFileScannerNormalizePath([rawPath isKindOfClass:NSString.class] ? rawPath : @"");
|
|
66
|
+
if (normalized.length > 0) {
|
|
67
|
+
[roots addObject:normalized];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return roots;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
NSSet<NSString *> *RNFileScannerExtensionsFromArray(NSArray<NSString *> *extensions, NSArray<NSString *> *defaultExtensions)
|
|
74
|
+
{
|
|
75
|
+
NSArray<NSString *> *source = extensions.count > 0 ? extensions : defaultExtensions;
|
|
76
|
+
NSMutableSet<NSString *> *normalized = [NSMutableSet set];
|
|
77
|
+
for (id value in source) {
|
|
78
|
+
if (![value isKindOfClass:NSString.class]) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
NSString *extension = [[(NSString *)value lowercaseString] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
|
|
82
|
+
if ([extension hasPrefix:@"."]) {
|
|
83
|
+
extension = [extension substringFromIndex:1];
|
|
84
|
+
}
|
|
85
|
+
if (extension.length > 0) {
|
|
86
|
+
[normalized addObject:extension];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return normalized;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
NSDictionary<NSNumber *, NSSet<NSString *> *> *RNFileScannerSkipLookupFromArray(NSArray *skipEntries)
|
|
93
|
+
{
|
|
94
|
+
if (![skipEntries isKindOfClass:NSArray.class]) {
|
|
95
|
+
return @{};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
NSMutableDictionary<NSNumber *, NSMutableSet<NSString *> *> *lookup = [NSMutableDictionary dictionary];
|
|
99
|
+
for (id rawEntry in skipEntries) {
|
|
100
|
+
if (![rawEntry isKindOfClass:NSDictionary.class]) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
NSDictionary *entry = (NSDictionary *)rawEntry;
|
|
104
|
+
NSNumber *rootIndex = [entry[@"rootIndex"] isKindOfClass:NSNumber.class] ? entry[@"rootIndex"] : nil;
|
|
105
|
+
NSString *relativePath = [entry[@"relativePath"] isKindOfClass:NSString.class] ? entry[@"relativePath"] : nil;
|
|
106
|
+
if (!rootIndex || relativePath.length == 0) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
NSNumber *rootKey = @([rootIndex unsignedIntegerValue]);
|
|
110
|
+
NSMutableSet<NSString *> *rootSet = lookup[rootKey];
|
|
111
|
+
if (!rootSet) {
|
|
112
|
+
rootSet = [NSMutableSet set];
|
|
113
|
+
lookup[rootKey] = rootSet;
|
|
114
|
+
}
|
|
115
|
+
[rootSet addObject:relativePath];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
NSMutableDictionary<NSNumber *, NSSet<NSString *> *> *immutable = [NSMutableDictionary dictionaryWithCapacity:lookup.count];
|
|
119
|
+
[lookup enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSMutableSet<NSString *> *value, BOOL *stop) {
|
|
120
|
+
immutable[key] = [value copy];
|
|
121
|
+
}];
|
|
122
|
+
return immutable;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
NSDictionary *RNFileScannerDefaultFileItem(NSURL *fileURL,
|
|
126
|
+
NSString *rootPath,
|
|
127
|
+
NSUInteger rootIndex,
|
|
128
|
+
NSString *relativePath,
|
|
129
|
+
BOOL skipped,
|
|
130
|
+
BOOL includeStats)
|
|
131
|
+
{
|
|
132
|
+
NSMutableDictionary *item = [@{
|
|
133
|
+
@"rootIndex": @(rootIndex),
|
|
134
|
+
@"relativePath": relativePath ?: fileURL.path ?: @"",
|
|
135
|
+
@"fileName": fileURL.lastPathComponent ?: relativePath ?: fileURL.path ?: @"",
|
|
136
|
+
@"absolutePath": fileURL.path ?: @"",
|
|
137
|
+
@"extension": fileURL.pathExtension.lowercaseString ?: @"",
|
|
138
|
+
} mutableCopy];
|
|
139
|
+
|
|
140
|
+
if (skipped) {
|
|
141
|
+
item[@"skipped"] = @YES;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (includeStats) {
|
|
145
|
+
NSDictionary<NSFileAttributeKey, id> *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fileURL.path error:nil];
|
|
146
|
+
NSNumber *fileSize = attributes[NSFileSize];
|
|
147
|
+
NSDate *modifiedDate = attributes[NSFileModificationDate];
|
|
148
|
+
if ([fileSize isKindOfClass:NSNumber.class]) {
|
|
149
|
+
item[@"size"] = fileSize;
|
|
150
|
+
}
|
|
151
|
+
if ([modifiedDate isKindOfClass:NSDate.class]) {
|
|
152
|
+
item[@"modifiedTime"] = @([modifiedDate timeIntervalSince1970] * 1000.0);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return item;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
NSDictionary *RNFileScannerRun(NSArray<NSString *> *paths,
|
|
160
|
+
RNFileScannerOptions *options,
|
|
161
|
+
RNFileScannerMapFileBlock mapFile,
|
|
162
|
+
RNFileScannerEmitBatchBlock emitBatch,
|
|
163
|
+
RNFileScannerProgressBlock emitProgress,
|
|
164
|
+
BOOL (^isCancelled)(void))
|
|
165
|
+
{
|
|
166
|
+
NSArray<NSString *> *roots = RNFileScannerNormalizeRoots(paths);
|
|
167
|
+
NSUInteger totalRoots = roots.count;
|
|
168
|
+
if (totalRoots == 0) {
|
|
169
|
+
return @{@"totalFiles": @0, @"totalRoots": @0, @"errors": @[]};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
RNFileScannerOptions *scanOptions = options ?: [RNFileScannerOptions new];
|
|
173
|
+
NSUInteger batchSize = scanOptions.batchSize > 0 ? scanOptions.batchSize : 64;
|
|
174
|
+
NSSet<NSString *> *allowedExtensions = scanOptions.allowedExtensions ?: [NSSet set];
|
|
175
|
+
NSMutableArray<NSString *> *errors = [NSMutableArray array];
|
|
176
|
+
NSUInteger totalFiles = 0;
|
|
177
|
+
NSUInteger completedRoots = 0;
|
|
178
|
+
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
179
|
+
|
|
180
|
+
for (NSUInteger rootIndex = 0; rootIndex < roots.count; rootIndex++) {
|
|
181
|
+
if (isCancelled && isCancelled()) break;
|
|
182
|
+
@autoreleasepool {
|
|
183
|
+
NSString *rootPath = roots[rootIndex];
|
|
184
|
+
BOOL isDirectory = NO;
|
|
185
|
+
BOOL exists = [fileManager fileExistsAtPath:rootPath isDirectory:&isDirectory];
|
|
186
|
+
if (!exists) {
|
|
187
|
+
[errors addObject:[NSString stringWithFormat:@"Root not found: %@", rootPath]];
|
|
188
|
+
completedRoots += 1;
|
|
189
|
+
if (emitProgress) {
|
|
190
|
+
emitProgress(rootIndex, completedRoots, totalRoots);
|
|
191
|
+
}
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (!isDirectory) {
|
|
196
|
+
NSURL *fileURL = [NSURL fileURLWithPath:rootPath isDirectory:NO];
|
|
197
|
+
NSString *extension = fileURL.pathExtension.lowercaseString ?: @"";
|
|
198
|
+
if (allowedExtensions.count == 0 || [allowedExtensions containsObject:extension]) {
|
|
199
|
+
NSString *relativePath = fileURL.lastPathComponent ?: rootPath;
|
|
200
|
+
BOOL skipped = [scanOptions.skipLookup[@(rootIndex)] containsObject:relativePath];
|
|
201
|
+
NSDictionary *item = mapFile
|
|
202
|
+
? mapFile(fileURL, rootPath.stringByDeletingLastPathComponent ?: rootPath, rootIndex, relativePath, skipped)
|
|
203
|
+
: RNFileScannerDefaultFileItem(fileURL, rootPath.stringByDeletingLastPathComponent ?: rootPath, rootIndex, relativePath, skipped, scanOptions.includeStats);
|
|
204
|
+
if (item) {
|
|
205
|
+
totalFiles += 1;
|
|
206
|
+
if (emitBatch) {
|
|
207
|
+
emitBatch(@[item], rootIndex, completedRoots, totalRoots);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
completedRoots += 1;
|
|
212
|
+
if (emitProgress) {
|
|
213
|
+
emitProgress(rootIndex, completedRoots, totalRoots);
|
|
214
|
+
}
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
NSDirectoryEnumerationOptions enumerationOptions = NSDirectoryEnumerationSkipsPackageDescendants;
|
|
219
|
+
if (!scanOptions.includeHidden) {
|
|
220
|
+
enumerationOptions |= NSDirectoryEnumerationSkipsHiddenFiles;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
NSURL *rootURL = [NSURL fileURLWithPath:rootPath isDirectory:YES];
|
|
224
|
+
NSDirectoryEnumerator<NSURL *> *enumerator =
|
|
225
|
+
[fileManager enumeratorAtURL:rootURL
|
|
226
|
+
includingPropertiesForKeys:@[NSURLIsDirectoryKey]
|
|
227
|
+
options:enumerationOptions
|
|
228
|
+
errorHandler:^BOOL(NSURL *url, NSError *error) {
|
|
229
|
+
@synchronized(errors) {
|
|
230
|
+
[errors addObject:error.localizedDescription ?: @"Unknown scan error"];
|
|
231
|
+
}
|
|
232
|
+
return YES;
|
|
233
|
+
}];
|
|
234
|
+
|
|
235
|
+
if (!enumerator) {
|
|
236
|
+
[errors addObject:[NSString stringWithFormat:@"Failed to enumerate: %@", rootPath]];
|
|
237
|
+
completedRoots += 1;
|
|
238
|
+
if (emitProgress) {
|
|
239
|
+
emitProgress(rootIndex, completedRoots, totalRoots);
|
|
240
|
+
}
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
NSMutableArray<NSDictionary *> *batch = [NSMutableArray arrayWithCapacity:batchSize];
|
|
245
|
+
for (NSURL *fileURL in enumerator) {
|
|
246
|
+
if (isCancelled && isCancelled()) break;
|
|
247
|
+
NSNumber *isDirectoryValue = nil;
|
|
248
|
+
[fileURL getResourceValue:&isDirectoryValue forKey:NSURLIsDirectoryKey error:nil];
|
|
249
|
+
if (isDirectoryValue.boolValue) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
NSString *extension = fileURL.pathExtension.lowercaseString ?: @"";
|
|
254
|
+
if (allowedExtensions.count > 0 && ![allowedExtensions containsObject:extension]) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
NSString *relativePath = RNFileScannerRelativePath(fileURL.path, rootPath);
|
|
259
|
+
BOOL skipped = [scanOptions.skipLookup[@(rootIndex)] containsObject:relativePath];
|
|
260
|
+
NSDictionary *item = mapFile
|
|
261
|
+
? mapFile(fileURL, rootPath, rootIndex, relativePath, skipped)
|
|
262
|
+
: RNFileScannerDefaultFileItem(fileURL, rootPath, rootIndex, relativePath, skipped, scanOptions.includeStats);
|
|
263
|
+
if (!item) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
[batch addObject:item];
|
|
268
|
+
totalFiles += 1;
|
|
269
|
+
if (batch.count >= batchSize) {
|
|
270
|
+
if (emitBatch) {
|
|
271
|
+
emitBatch([batch copy], rootIndex, completedRoots, totalRoots);
|
|
272
|
+
}
|
|
273
|
+
[batch removeAllObjects];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if ((!isCancelled || !isCancelled()) && batch.count > 0 && emitBatch) {
|
|
278
|
+
emitBatch([batch copy], rootIndex, completedRoots, totalRoots);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (isCancelled && isCancelled()) break;
|
|
282
|
+
completedRoots += 1;
|
|
283
|
+
if (emitProgress) {
|
|
284
|
+
emitProgress(rootIndex, completedRoots, totalRoots);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return @{@"totalFiles": @(totalFiles), @"totalRoots": @(totalRoots), @"errors": errors};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
NSString *RNFileScannerJSONString(id object)
|
|
293
|
+
{
|
|
294
|
+
id value = object ?: [NSNull null];
|
|
295
|
+
NSData *data = [NSJSONSerialization dataWithJSONObject:value options:0 error:nil];
|
|
296
|
+
return data ? [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] : @"null";
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
id RNFileScannerJSONObjectFromString(NSString *json)
|
|
300
|
+
{
|
|
301
|
+
if (![json isKindOfClass:NSString.class] || json.length == 0) {
|
|
302
|
+
return nil;
|
|
303
|
+
}
|
|
304
|
+
NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding];
|
|
305
|
+
return data ? [NSJSONSerialization JSONObjectWithData:data options:0 error:nil] : nil;
|
|
306
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@legendapp/spark-file-system",
|
|
3
|
-
"version": "0.0.1-next.
|
|
3
|
+
"version": "0.0.1-next.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -21,14 +21,17 @@
|
|
|
21
21
|
"jsSrcsDir": "src",
|
|
22
22
|
"ios": {
|
|
23
23
|
"modulesProvider": {
|
|
24
|
-
"NativeDesktopFileSystem": "RNDesktopFileSystem"
|
|
25
|
-
|
|
24
|
+
"NativeDesktopFileSystem": "RNDesktopFileSystem",
|
|
25
|
+
"NativeFileScanner": "RNFileScanner"
|
|
26
|
+
},
|
|
27
|
+
"componentProvider": {}
|
|
26
28
|
}
|
|
27
29
|
},
|
|
28
30
|
"spark": {
|
|
29
31
|
"sdk": true,
|
|
30
32
|
"nativeModules": [
|
|
31
|
-
"NativeDesktopFileSystem"
|
|
33
|
+
"NativeDesktopFileSystem",
|
|
34
|
+
"NativeFileScanner"
|
|
32
35
|
],
|
|
33
36
|
"pod": "RNDesktopFileSystem",
|
|
34
37
|
"platforms": [
|
|
@@ -40,8 +43,7 @@
|
|
|
40
43
|
]
|
|
41
44
|
},
|
|
42
45
|
"dependencies": {
|
|
43
|
-
"@legendapp/spark-desktop-app": "0.0.1-next.
|
|
44
|
-
"base64-js": "1.5.1"
|
|
46
|
+
"@legendapp/spark-desktop-app": "0.0.1-next.4"
|
|
45
47
|
},
|
|
46
48
|
"private": true
|
|
47
49
|
}
|
|
@@ -5,4 +5,4 @@ export interface Spec extends TurboModule {
|
|
|
5
5
|
addListener(eventName: string): void;
|
|
6
6
|
removeListeners(count: number): void;
|
|
7
7
|
}
|
|
8
|
-
export default TurboModuleRegistry.
|
|
8
|
+
export default TurboModuleRegistry.get<Spec>("NativeDesktopFileSystem");
|
package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/NativeFileScanner.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TurboModule } from "react-native";
|
|
2
|
+
import { TurboModuleRegistry } from "react-native";
|
|
3
|
+
|
|
4
|
+
export interface Spec extends TurboModule {
|
|
5
|
+
scanFiles(id: string, pathsJson: string, optionsJson: string): Promise<string>;
|
|
6
|
+
cancelScan(id: string): Promise<void>;
|
|
7
|
+
addListener(eventName: string): void;
|
|
8
|
+
removeListeners(count: number): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default TurboModuleRegistry.get<Spec>("NativeFileScanner");
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { NativeEventEmitter, Platform } from "react-native";
|
|
2
|
+
import { SparkError, invokeNative, parseNativeResult, type Availability, type Subscription } from "@legendapp/spark-desktop-app/src/contracts";
|
|
3
|
+
import { nativePath } from "@legendapp/spark-desktop-app/src/contracts/path";
|
|
4
|
+
import Native from "./NativeFileScanner";
|
|
5
|
+
export interface FileScanSkipEntry { relativePath: string; rootIndex: number }
|
|
6
|
+
export interface ScannedFile {
|
|
7
|
+
path: string;
|
|
8
|
+
name: string;
|
|
9
|
+
extension: string;
|
|
10
|
+
relativePath: string;
|
|
11
|
+
rootIndex: number;
|
|
12
|
+
modifiedAt?: number;
|
|
13
|
+
size?: number;
|
|
14
|
+
skipped: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface FileScanProgress { completedRoots: number; rootIndex: number; totalRoots: number }
|
|
17
|
+
export interface FileScanBatch extends FileScanProgress { files: ScannedFile[] }
|
|
18
|
+
export interface FileScanResult { totalFiles: number; totalRoots: number; errors: string[] }
|
|
19
|
+
export interface FileScanOptions {
|
|
20
|
+
extensions?: readonly string[];
|
|
21
|
+
batchSize?: number;
|
|
22
|
+
includeHidden?: boolean;
|
|
23
|
+
includeStats?: boolean;
|
|
24
|
+
/** Marks known entries as skipped in emitted batches; it does not exclude their names. */
|
|
25
|
+
skip?: readonly FileScanSkipEntry[];
|
|
26
|
+
onBatch?: (event: FileScanBatch) => void;
|
|
27
|
+
onProgress?: (event: FileScanProgress) => void;
|
|
28
|
+
/** Cancellation is cooperative between filesystem operations; the promise waits for native work to stop. */
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
}
|
|
31
|
+
export function getFileScanAvailability(): Availability {
|
|
32
|
+
if (Platform.OS !== "macos") return { available: false, reason: "unsupported-platform" };
|
|
33
|
+
return Native ? { available: true } : { available: false, reason: "missing-module" };
|
|
34
|
+
}
|
|
35
|
+
const count = (value: unknown): value is number => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
36
|
+
const record = (value: unknown): value is Record<string, unknown> => !!value && typeof value === "object";
|
|
37
|
+
function progress(value: unknown, roots: number): FileScanProgress {
|
|
38
|
+
if (!record(value) || !count(value.rootIndex) || value.rootIndex >= roots || !count(value.completedRoots) || value.completedRoots > roots || value.totalRoots !== roots) throw new SparkError("E_INVALID_DATA", "Invalid scan progress");
|
|
39
|
+
return { rootIndex: value.rootIndex, completedRoots: value.completedRoots, totalRoots: value.totalRoots };
|
|
40
|
+
}
|
|
41
|
+
function scannedFile(value: unknown, roots: number): ScannedFile {
|
|
42
|
+
if (!record(value) || !count(value.rootIndex) || value.rootIndex >= roots || typeof value.absolutePath !== "string" || !value.absolutePath.startsWith("/") || typeof value.fileName !== "string" || typeof value.relativePath !== "string" || typeof value.extension !== "string" || (value.size !== undefined && !count(value.size)) || (value.modifiedTime !== undefined && (typeof value.modifiedTime !== "number" || !Number.isFinite(value.modifiedTime))) || (value.skipped !== undefined && typeof value.skipped !== "boolean")) throw new SparkError("E_INVALID_DATA", "Invalid scanned file");
|
|
43
|
+
return { path: value.absolutePath, name: value.fileName, extension: value.extension, relativePath: value.relativePath, rootIndex: value.rootIndex, size: value.size, modifiedAt: value.modifiedTime, skipped: value.skipped ?? false };
|
|
44
|
+
}
|
|
45
|
+
let nextScan = 0;
|
|
46
|
+
export async function scanFiles(paths: readonly string[], options: FileScanOptions = {}): Promise<FileScanResult> {
|
|
47
|
+
if (!Array.isArray(paths)) throw new SparkError("E_INVALID_ARGUMENT", "Expected scan paths");
|
|
48
|
+
const roots = Array.from(paths, path => nativePath(path, Platform.OS));
|
|
49
|
+
if (!options || typeof options !== "object") throw new SparkError("E_INVALID_ARGUMENT", "Expected scan options");
|
|
50
|
+
for (const key of Object.keys(options)) if (!["extensions", "batchSize", "includeHidden", "includeStats", "skip", "onBatch", "onProgress", "signal"].includes(key)) throw new SparkError("E_UNSUPPORTED_OPTION", `Unsupported scan option: ${key}`);
|
|
51
|
+
if (options.batchSize !== undefined && (!count(options.batchSize) || options.batchSize < 1 || options.batchSize > 10000)) throw new SparkError("E_INVALID_ARGUMENT", "batchSize must be between 1 and 10000");
|
|
52
|
+
for (const value of [options.includeHidden, options.includeStats]) if (value !== undefined && typeof value !== "boolean") throw new SparkError("E_INVALID_ARGUMENT", "Scan flags must be boolean");
|
|
53
|
+
for (const value of [options.onBatch, options.onProgress]) if (value !== undefined && typeof value !== "function") throw new SparkError("E_INVALID_ARGUMENT", "Scan callbacks must be functions");
|
|
54
|
+
if (options.extensions !== undefined && (!Array.isArray(options.extensions) || options.extensions.some(value => typeof value !== "string" || !/^[a-z0-9][a-z0-9_-]*$/i.test(value)))) throw new SparkError("E_INVALID_ARGUMENT", "Expected file extensions without dots or wildcards");
|
|
55
|
+
if (options.skip !== undefined && (!Array.isArray(options.skip) || options.skip.some(value => !value || !count(value.rootIndex) || value.rootIndex >= roots.length || typeof value.relativePath !== "string" || !value.relativePath || value.relativePath.startsWith("/") || value.relativePath.split("/").includes("..")))) throw new SparkError("E_INVALID_ARGUMENT", "Invalid skipped file entry");
|
|
56
|
+
const availability = getFileScanAvailability();
|
|
57
|
+
if (!availability.available) throw new SparkError(availability.reason === "unsupported-platform" ? "E_UNSUPPORTED_PLATFORM" : "E_MODULE_UNAVAILABLE", "File scanning requires a macOS host with NativeFileScanner installed");
|
|
58
|
+
const { signal, onBatch, onProgress, extensions, ...nativeOptions } = options;
|
|
59
|
+
if (signal !== undefined && (!signal || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) throw new SparkError("E_INVALID_ARGUMENT", "Expected an AbortSignal");
|
|
60
|
+
const aborted = () => new SparkError("E_ABORTED", "File scan aborted", { cause: signal?.reason });
|
|
61
|
+
if (signal?.aborted) throw aborted();
|
|
62
|
+
const id = `scan-${Date.now()}-${++nextScan}`;
|
|
63
|
+
const subscriptions: Subscription[] = [];
|
|
64
|
+
let callbackError: unknown;
|
|
65
|
+
let callbackFailed = false;
|
|
66
|
+
let cancellation: Promise<void> | undefined;
|
|
67
|
+
const cancel = () => { cancellation ??= invokeNative(() => Native!.cancelScan(id)); void cancellation.catch(() => undefined); };
|
|
68
|
+
const deliver = (value: unknown, callback: (value: Record<string, unknown>) => void) => {
|
|
69
|
+
if (!record(value) || value.id !== id || signal?.aborted || callbackFailed) return;
|
|
70
|
+
try { callback(value); } catch (error) { callbackFailed = true; callbackError = error; cancel(); }
|
|
71
|
+
};
|
|
72
|
+
try {
|
|
73
|
+
const emitter = new NativeEventEmitter(Native!);
|
|
74
|
+
if (onProgress) subscriptions.push(emitter.addListener("onFileScanProgress", value => deliver(value, event => onProgress?.(progress(event, roots.length)))));
|
|
75
|
+
if (onBatch) subscriptions.push(emitter.addListener("onFileScanBatch", value => deliver(value, event => {
|
|
76
|
+
const snapshot = progress(event, roots.length);
|
|
77
|
+
if (!Array.isArray(event.files)) throw new SparkError("E_INVALID_DATA", "Invalid scan batch");
|
|
78
|
+
const files = event.files.map((file: unknown) => scannedFile(file, roots.length));
|
|
79
|
+
onBatch?.({ ...snapshot, files });
|
|
80
|
+
})));
|
|
81
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
82
|
+
let json: string;
|
|
83
|
+
try { json = await invokeNative(() => Native!.scanFiles(id, JSON.stringify(roots), JSON.stringify({ ...nativeOptions, allowedExtensions: extensions }))); }
|
|
84
|
+
catch (error) { if (callbackFailed) throw callbackError; if (signal?.aborted) throw aborted(); throw error; }
|
|
85
|
+
if (callbackFailed) throw callbackError;
|
|
86
|
+
if (signal?.aborted) throw aborted();
|
|
87
|
+
return parseNativeResult(json, (value): value is FileScanResult => !!value && typeof value === "object" && "totalFiles" in value && count(value.totalFiles) && "totalRoots" in value && value.totalRoots === roots.length && "errors" in value && Array.isArray(value.errors) && value.errors.every(error => typeof error === "string"));
|
|
88
|
+
} finally {
|
|
89
|
+
signal?.removeEventListener("abort", cancel);
|
|
90
|
+
subscriptions.forEach(subscription => subscription.remove());
|
|
91
|
+
if (cancellation) await cancellation;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SparkError, asyncRegistration } from "@legendapp/spark-desktop-app/src/contracts";
|
|
2
|
+
import { nativeBytes } from "@legendapp/spark-desktop-app/src/contracts/native-buffer";
|
|
2
3
|
export const MAX_CHUNK_SIZE = 1024 * 1024;
|
|
3
4
|
export type FileMode = "read" | "readWrite" | "write" | "createNew";
|
|
4
5
|
export type FileHandle = {
|
|
@@ -7,39 +8,72 @@ export type FileHandle = {
|
|
|
7
8
|
flush(): Promise<void>;
|
|
8
9
|
close(): Promise<void>;
|
|
9
10
|
};
|
|
11
|
+
export class FileCleanupError extends SparkError {
|
|
12
|
+
readonly operationFailed: boolean;
|
|
13
|
+
readonly operationError: unknown;
|
|
14
|
+
readonly cleanupError: unknown;
|
|
15
|
+
readonly retryCleanup: () => Promise<void>;
|
|
16
|
+
|
|
17
|
+
constructor(operationFailed: boolean, operationError: unknown, cleanupError: unknown, retryCleanup: () => Promise<void>) {
|
|
18
|
+
const cause = operationFailed
|
|
19
|
+
? new AggregateError([operationError, cleanupError], "File operation and handle cleanup both failed")
|
|
20
|
+
: cleanupError;
|
|
21
|
+
super("E_NATIVE", operationFailed ? "File operation and handle cleanup both failed" : "File handle cleanup failed", { cause });
|
|
22
|
+
this.name = "FileCleanupError";
|
|
23
|
+
this.operationFailed = operationFailed;
|
|
24
|
+
this.operationError = operationError;
|
|
25
|
+
this.cleanupError = cleanupError;
|
|
26
|
+
this.retryCleanup = retryCleanup;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
10
29
|
export type FileCall = <T>(method: string, args: object) => Promise<T>;
|
|
11
|
-
function offset(value: number) { if (!Number.isSafeInteger(value) || value < 0) throw new
|
|
12
|
-
function length(value: number) { if (!Number.isInteger(value) || value < 1 || value > MAX_CHUNK_SIZE) throw new
|
|
13
|
-
function aborted(signal?: AbortSignal) { if (signal?.aborted) throw signal.reason
|
|
30
|
+
function offset(value: number) { if (!Number.isSafeInteger(value) || value < 0) throw new SparkError("E_INVALID_ARGUMENT", "Offset must be a nonnegative safe integer"); }
|
|
31
|
+
function length(value: number) { if (!Number.isInteger(value) || value < 1 || value > MAX_CHUNK_SIZE) throw new SparkError("E_INVALID_ARGUMENT", "Chunk size must be between 1 byte and 1 MiB"); }
|
|
32
|
+
function aborted(signal?: AbortSignal) { if (signal?.aborted) throw new SparkError("E_ABORTED", signal.reason instanceof Error ? signal.reason.message : "File operation aborted", { cause: signal.reason }); }
|
|
14
33
|
/** Positional I/O: handles have no shared cursor. Calls are serialized natively. */
|
|
15
34
|
export async function createFileHandle(call: FileCall, path: string, mode: FileMode = "read"): Promise<FileHandle> {
|
|
16
|
-
if (!["read", "readWrite", "write", "createNew"].includes(mode)) throw new
|
|
35
|
+
if (!["read", "readWrite", "write", "createNew"].includes(mode)) throw new SparkError("E_INVALID_ARGUMENT", "Invalid file mode");
|
|
17
36
|
const id = await call<string>("openFile", { path, mode });
|
|
18
|
-
|
|
19
|
-
|
|
37
|
+
if (typeof id !== "string" || !id) throw new SparkError("E_INVALID_DATA", "Invalid file handle ID");
|
|
38
|
+
let closed = false;
|
|
39
|
+
const cleanup = asyncRegistration(() => { closed = true; }, () => call<void>("closeFile", { id }));
|
|
40
|
+
const active = () => { if (closed) throw new SparkError("E_CLOSED", "File handle is closed"); };
|
|
20
41
|
return {
|
|
21
|
-
async read(size, position) { active(); length(size); offset(position); if (!Number.isSafeInteger(position + size)) throw new
|
|
22
|
-
async write(bytes, position) { active(); if (!(bytes instanceof Uint8Array)) throw new
|
|
42
|
+
async read(size, position) { active(); length(size); offset(position); if (!Number.isSafeInteger(position + size)) throw new SparkError("E_INVALID_ARGUMENT", "Read range exceeds safe integer bounds"); const bytes = nativeBytes(await call<ArrayBuffer>("readChunk", { id, length: size, offset: position })); if (bytes.length > size) throw new SparkError("E_INVALID_DATA", "Read exceeded requested length"); return bytes; },
|
|
43
|
+
async write(bytes, position) { active(); if (!(bytes instanceof Uint8Array)) throw new SparkError("E_INVALID_ARGUMENT", "Expected Uint8Array"); offset(position); if (!Number.isSafeInteger(position + bytes.byteLength)) throw new SparkError("E_INVALID_ARGUMENT", "Write range exceeds safe integer bounds"); if (!bytes.length) return 0; length(bytes.length); const written = await call<number>("writeChunk", { id, bytes, offset: position }); if (written !== bytes.length) throw new SparkError("E_NATIVE", "Native write did not write the complete chunk"); return written; },
|
|
23
44
|
async flush() { active(); await call("flushFile", { id }); },
|
|
24
|
-
close() { return
|
|
45
|
+
close() { return cleanup.remove(); },
|
|
25
46
|
};
|
|
26
47
|
}
|
|
27
48
|
export type ReadChunksOptions = { offset?: number; chunkSize?: number; signal?: AbortSignal };
|
|
28
49
|
export async function* iterateFile(open: () => Promise<FileHandle>, options: ReadChunksOptions = {}) {
|
|
29
50
|
let position = options.offset ?? 0; offset(position); const size = options.chunkSize ?? 64 * 1024; length(size); aborted(options.signal);
|
|
30
51
|
const file = await open();
|
|
52
|
+
let operationFailed = false, operationError: unknown;
|
|
31
53
|
try {
|
|
32
54
|
for (;;) { aborted(options.signal); const bytes = await file.read(size, position); aborted(options.signal); if (!bytes.length) break; position += bytes.length; yield bytes; }
|
|
33
|
-
}
|
|
55
|
+
} catch (error) { operationFailed = true; operationError = error; }
|
|
56
|
+
finally {
|
|
57
|
+
try { await file.close(); }
|
|
58
|
+
catch (cleanupError) { throw new FileCleanupError(operationFailed, operationError, cleanupError, () => file.close()); }
|
|
59
|
+
}
|
|
60
|
+
if (operationFailed) throw operationError;
|
|
34
61
|
}
|
|
35
62
|
export async function writeFileChunks(open: () => Promise<FileHandle>, chunks: AsyncIterable<Uint8Array> | Iterable<Uint8Array>, signal?: AbortSignal) {
|
|
36
63
|
aborted(signal); const file = await open(); let position = 0;
|
|
64
|
+
let operationFailed = false, operationError: unknown;
|
|
37
65
|
try {
|
|
38
66
|
for await (const bytes of chunks) {
|
|
39
67
|
aborted(signal);
|
|
40
|
-
if (!(bytes instanceof Uint8Array)) throw new
|
|
68
|
+
if (!(bytes instanceof Uint8Array)) throw new SparkError("E_INVALID_ARGUMENT", "Expected Uint8Array chunks");
|
|
41
69
|
for (let start = 0; start < bytes.length; start += MAX_CHUNK_SIZE) { aborted(signal); const part = bytes.subarray(start, start + MAX_CHUNK_SIZE); position += await file.write(part, position); }
|
|
42
70
|
}
|
|
43
|
-
aborted(signal); await file.flush();
|
|
44
|
-
}
|
|
71
|
+
aborted(signal); await file.flush();
|
|
72
|
+
} catch (error) { operationFailed = true; operationError = error; }
|
|
73
|
+
finally {
|
|
74
|
+
try { await file.close(); }
|
|
75
|
+
catch (cleanupError) { throw new FileCleanupError(operationFailed, operationError, cleanupError, () => file.close()); }
|
|
76
|
+
}
|
|
77
|
+
if (operationFailed) throw operationError;
|
|
78
|
+
return position;
|
|
45
79
|
}
|