diff --git a/.github/actions/publish-artifacts/.eslintrc.cjs b/.github/actions/publish-artifacts/.eslintrc.cjs index aa5b12709..d0db437e9 100644 --- a/.github/actions/publish-artifacts/.eslintrc.cjs +++ b/.github/actions/publish-artifacts/.eslintrc.cjs @@ -1,8 +1,23 @@ module.exports = { - extends: [require.resolve('@sd/config/eslint/base.js')], - parserOptions: { - tsconfigRootDir: __dirname, - project: './tsconfig.json' + root: true, + env: { + 'node': true, + 'es2022': true, + 'browser': false, + 'commonjs': false, + 'shared-node-browser': false }, - ignorePatterns: ['dist/**/*'] + parser: '@typescript-eslint/parser', + extends: [ + 'eslint:recommended', + 'standard', + 'plugin:@typescript-eslint/strict-type-checked', + 'plugin:@typescript-eslint/stylistic-type-checked', + 'plugin:prettier/recommended' + ], + plugins: ['@typescript-eslint'], + parserOptions: { + project: true + }, + ignorePatterns: ['node_modules/**/*', 'dist/**/*'] }; diff --git a/.github/actions/publish-artifacts/index.ts b/.github/actions/publish-artifacts/index.ts index 1896f8247..a5bb1648a 100644 --- a/.github/actions/publish-artifacts/index.ts +++ b/.github/actions/publish-artifacts/index.ts @@ -6,11 +6,16 @@ import { exists } from '@actions/io/lib/io-util'; type OS = 'darwin' | 'windows' | 'linux'; type Arch = 'x64' | 'arm64'; -type TargetConfig = { bundle: string; ext: string }; -type BuildTarget = { + +interface TargetConfig { + ext: string; + bundle: string; +} + +interface BuildTarget { updater: false | { bundle: string; bundleExt: string; archiveExt: string }; - standalone: Array; -}; + standalone: TargetConfig[]; +} const OS_TARGETS = { darwin: { @@ -36,8 +41,8 @@ const OS_TARGETS = { } satisfies Record; // Workflow inputs -const OS: OS = core.getInput('os') as any; -const ARCH: Arch = core.getInput('arch') as any; +const OS = core.getInput('os') as OS; +const ARCH = core.getInput('arch') as Arch; const TARGET = core.getInput('target'); const PROFILE = core.getInput('profile'); @@ -59,7 +64,11 @@ async function uploadFrontend() { return; } - await client.uploadArtifact(FRONTEND_ARCHIVE_NAME, [FRONT_END_BUNDLE], 'apps/desktop'); + const artifactName = `${FRONTEND_ARCHIVE_NAME}.tar.xz`; + const artifactPath = `${ARTIFACTS_DIR}/${artifactName}`; + + await io.cp(FRONT_END_BUNDLE, artifactPath); + await client.uploadArtifact(artifactName, [artifactPath], ARTIFACTS_DIR); } async function uploadUpdater(updater: BuildTarget['updater']) { @@ -69,7 +78,7 @@ async function uploadUpdater(updater: BuildTarget['updater']) { const files = await globFiles(`${BUNDLE_DIR}/${bundle}/*.${fullExt}*`); const updaterPath = files.find((file) => file.endsWith(fullExt)); - if (!updaterPath) throw new Error(`Updater path not found. Files: ${files}`); + if (!updaterPath) throw new Error(`Updater path not found. Files: ${files.join(',')}`); const artifactPath = `${ARTIFACTS_DIR}/${UPDATER_ARTIFACT_NAME}.${archiveExt}`; @@ -88,7 +97,7 @@ async function uploadStandalone({ bundle, ext }: TargetConfig) { const files = await globFiles(`${BUNDLE_DIR}/${bundle}/*.${ext}*`); const standalonePath = files.find((file) => file.endsWith(ext)); - if (!standalonePath) throw new Error(`Standalone path not found. Files: ${files}`); + if (!standalonePath) throw new Error(`Standalone path not found. Files: ${files.join(',')}`); const artifactName = `${ARTIFACT_BASE}.${ext}`; const artifactPath = `${ARTIFACTS_DIR}/${artifactName}`; @@ -108,4 +117,8 @@ async function run() { ...standalone.map((config) => uploadStandalone(config)) ]); } -run(); + +run().catch((error: unknown) => { + console.error(error); + process.exit(1); +}); diff --git a/.github/actions/publish-artifacts/package.json b/.github/actions/publish-artifacts/package.json index 124890dd7..89d600f00 100644 --- a/.github/actions/publish-artifacts/package.json +++ b/.github/actions/publish-artifacts/package.json @@ -7,13 +7,12 @@ "lint": "eslint . --cache" }, "dependencies": { - "@actions/artifact": "^2.1.7", + "@actions/artifact": "^2.1.9", "@actions/core": "^1.10.1", - "@actions/glob": "^0.4.0", + "@actions/glob": "^0.5.0", "@actions/io": "^1.1.3" }, "devDependencies": { - "@vercel/ncc": "^0.38.1", - "@sd/config": "workspace:*" + "@vercel/ncc": "^0.38.1" } } diff --git a/.github/actions/publish-artifacts/tsconfig.json b/.github/actions/publish-artifacts/tsconfig.json index 66c202ad4..53d5ed597 100644 --- a/.github/actions/publish-artifacts/tsconfig.json +++ b/.github/actions/publish-artifacts/tsconfig.json @@ -1,12 +1,30 @@ { "compilerOptions": { - "target": "es2015" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - "module": "esnext" /* Specify what module code is generated. */, - "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - "strict": true /* Enable all strict type-checking options. */, - "skipLibCheck": true /* Skip type checking all .d.ts files. */, - "noEmit": true - } + "lib": ["esnext"], + "noEmit": true, + "strict": true, + "module": "esnext", + "target": "esnext", + "declaration": false, + "incremental": true, + "skipLibCheck": true, + "removeComments": false, + "noUnusedLocals": true, + "isolatedModules": true, + "esModuleInterop": true, + "disableSizeLimit": true, + "moduleResolution": "node", + "noImplicitReturns": true, + "resolveJsonModule": true, + "noUnusedParameters": true, + "experimentalDecorators": true, + "useDefineForClassFields": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "forceConsistentCasingInFileNames": true, + "noPropertyAccessFromIndexSignature": false + }, + "include": ["./**/*.ts"], + "exclude": ["dist", "node_modules"], + "$schema": "https://json.schemastore.org/tsconfig" } diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0b91ca579..123a02c88 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,7 @@ on: pull_request: paths: - '.github/workflows/release.yml' + - '.github/actions/publish-artifacts/**' workflow_dispatch: # From: https://github.com/rust-lang/rust-analyzer/blob/master/.github/workflows/release.yaml#L13-L21 @@ -19,12 +20,12 @@ jobs: settings: - host: macos-13 target: x86_64-apple-darwin - bundles: app,dmg + bundles: dmg,app os: darwin arch: x86_64 - host: macos-14 target: aarch64-apple-darwin - bundles: app,dmg + bundles: dmg,app os: darwin arch: aarch64 - host: windows-latest @@ -101,7 +102,7 @@ jobs: - name: Build run: | - pnpm tauri build --ci -v --target ${{ matrix.settings.target }} --bundles ${{ matrix.settings.bundles }},updater + pnpm tauri build --ci -v --target ${{ matrix.settings.target }} --bundles ${{ matrix.settings.bundles }} env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} @@ -141,7 +142,7 @@ jobs: - name: Create Release # TODO: Change to stable version when available - uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981 + uses: softprops/action-gh-release@v2 with: draft: true files: '*/**' diff --git a/.prettierrc.js b/.prettierrc.js index 209a288f7..56224606c 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -23,7 +23,7 @@ module.exports = { '^[./]' ], importOrderParserPlugins: ['typescript', 'jsx', 'decorators'], - importOrderTypeScriptVersion: '4.4.0', + importOrderTypeScriptVersion: '5.0.0', tailwindConfig: './packages/ui/tailwind.config.js', plugins: ['@ianvs/prettier-plugin-sort-imports', 'prettier-plugin-tailwindcss'] }; diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json index c873befb1..85c60bc0c 100644 --- a/apps/desktop/src-tauri/tauri.conf.json +++ b/apps/desktop/src-tauri/tauri.conf.json @@ -47,6 +47,7 @@ "category": "Productivity", "shortDescription": "Spacedrive", "longDescription": "Cross-platform universal file explorer, powered by an open-source virtual distributed filesystem.", + "createUpdaterArtifacts": "v1Compatible", "icon": [ "icons/32x32.png", "icons/128x128.png", @@ -66,7 +67,18 @@ "minimumSystemVersion": "10.15", "exceptionDomain": null, "entitlements": null, - "frameworks": ["../../.deps/Spacedrive.framework"] + "frameworks": ["../../.deps/Spacedrive.framework"], + "dmg": { + "background": "dmg-background.png", + "appPosition": { + "x": 190, + "y": 190 + }, + "applicationFolderPosition": { + "x": 470, + "y": 190 + } + } }, "windows": { "certificateThumbprint": null, @@ -84,8 +96,6 @@ }, "plugins": { "updater": { - "active": true, - "dialog": false, "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEZBMURCMkU5NEU3NDAyOEMKUldTTUFuUk82YklkK296dlkxUGkrTXhCT3ZMNFFVOWROcXNaS0RqWU1kMUdRV2tDdFdIS0Y3YUsK", "endpoints": [ "https://spacedrive.com/api/releases/tauri/{{version}}/{{target}}/{{arch}}" diff --git a/apps/mobile/src/navigation/DrawerNavigator.tsx b/apps/mobile/src/navigation/DrawerNavigator.tsx index e75d896cc..51d191b6e 100644 --- a/apps/mobile/src/navigation/DrawerNavigator.tsx +++ b/apps/mobile/src/navigation/DrawerNavigator.tsx @@ -5,8 +5,7 @@ import DrawerContent from '~/components/drawer/DrawerContent'; import { tw } from '~/lib/tailwind'; import type { RootStackParamList } from '.'; -import type { TabParamList } from './TabNavigator'; -import TabNavigator from './TabNavigator'; +import TabNavigator, { type TabParamList } from './TabNavigator'; const Drawer = createDrawerNavigator(); diff --git a/interface/app/$libraryId/Explorer/DragOverlay.tsx b/interface/app/$libraryId/Explorer/DragOverlay.tsx index 2296fabf5..4d5c087b8 100644 --- a/interface/app/$libraryId/Explorer/DragOverlay.tsx +++ b/interface/app/$libraryId/Explorer/DragOverlay.tsx @@ -1,5 +1,4 @@ -import type { ClientRect, Modifier } from '@dnd-kit/core'; -import { DragOverlay as DragOverlayPrimitive } from '@dnd-kit/core'; +import { DragOverlay as DragOverlayPrimitive, type ClientRect, type Modifier } from '@dnd-kit/core'; import { getEventCoordinates } from '@dnd-kit/utilities'; import clsx from 'clsx'; import { memo, useEffect, useRef } from 'react'; diff --git a/interface/app/$libraryId/Explorer/useExplorer.ts b/interface/app/$libraryId/Explorer/useExplorer.ts index 7f47c04ed..97af144b8 100644 --- a/interface/app/$libraryId/Explorer/useExplorer.ts +++ b/interface/app/$libraryId/Explorer/useExplorer.ts @@ -2,16 +2,18 @@ import { useCallback, useEffect, useMemo, useRef, useState, type RefObject } fro import { useDebouncedCallback } from 'use-debounce'; import { proxy, snapshot, subscribe, useSnapshot } from 'valtio'; import { z } from 'zod'; -import type { - ExplorerItem, - ExplorerLayout, - ExplorerSettings, - FilePath, - Location, - NodeState, - Tag +import { + ObjectKindEnum, + type ExplorerItem, + type ExplorerLayout, + type ExplorerSettings, + type FilePath, + type Location, + type NodeState, + type Ordering, + type OrderingKeys, + type Tag } from '@sd/client'; -import { ObjectKindEnum, type Ordering, type OrderingKeys } from '@sd/client'; import { createDefaultExplorerSettings } from './store'; import { uniqueId } from './util'; diff --git a/packages/client/src/utils/index.ts b/packages/client/src/utils/index.ts index 905c41af0..c8978c4d3 100644 --- a/packages/client/src/utils/index.ts +++ b/packages/client/src/utils/index.ts @@ -2,8 +2,12 @@ import { QueryClient } from '@tanstack/react-query'; import { useMemo } from 'react'; import type { Object } from '..'; -import type { ExplorerItem, FilePath, NonIndexedPathItem } from '../core'; -import { LibraryConfigWrapped } from '../core'; +import { + LibraryConfigWrapped, + type ExplorerItem, + type FilePath, + type NonIndexedPathItem +} from '../core'; export * from './jobs'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 246aace0e..5589091fc 100644 Binary files a/pnpm-lock.yaml and b/pnpm-lock.yaml differ diff --git a/scripts/tauri.mjs b/scripts/tauri.mjs index d5271b7db..152079e72 100755 --- a/scripts/tauri.mjs +++ b/scripts/tauri.mjs @@ -41,13 +41,6 @@ const __cleanup = /** @type {string[]} */ ([]) const cleanUp = () => Promise.all(__cleanup.map(file => fs.unlink(file).catch(() => {}))) process.on('SIGINT', cleanUp) -// Check if file/dir exists -const exists = (/** @type {string} */ path) => - fs - .access(path, fs.constants.R_OK) - .then(() => true) - .catch(() => false) - // Export environment variables defined in cargo.toml const cargoConfig = await fs .readFile(path.resolve(__root, '.cargo', 'config.toml'), { encoding: 'binary' }) @@ -82,7 +75,7 @@ if (process.platform === 'linux' && (args[0] === 'dev' || args[0] === 'build')) try { switch (args[0]) { case 'dev': { - __cleanup.push(...(await patchTauri(__root, nativeDeps, targets, bundles, args))) + __cleanup.push(...(await patchTauri(__root, nativeDeps, targets, args))) switch (process.platform) { case 'linux': @@ -103,21 +96,7 @@ try { env.GENERATE_SOURCEMAP = 'false' - __cleanup.push(...(await patchTauri(__root, nativeDeps, targets, bundles, args))) - - if (process.platform === 'darwin') { - // Configure DMG background - env.BACKGROUND_FILE = path.resolve(desktopApp, 'src-tauri', 'dmg-background.png') - env.BACKGROUND_FILE_NAME = path.basename(env.BACKGROUND_FILE) - env.BACKGROUND_CLAUSE = `set background picture of opts to file ".background:${env.BACKGROUND_FILE_NAME}"` - - if (!(await exists(env.BACKGROUND_FILE))) - console.warn( - `WARNING: DMG background file not found at ${env.BACKGROUND_FILE}` - ) - - break - } + __cleanup.push(...(await patchTauri(__root, nativeDeps, targets, args))) } } diff --git a/scripts/utils/patchTauri.mjs b/scripts/utils/patchTauri.mjs index cc7b7d561..adb371d32 100644 --- a/scripts/utils/patchTauri.mjs +++ b/scripts/utils/patchTauri.mjs @@ -53,11 +53,10 @@ export async function tauriUpdaterKey(nativeDeps) { * @param {string} root * @param {string} nativeDeps * @param {string[]} targets - * @param {string[]} bundles * @param {string[]} args * @returns {Promise} */ -export async function patchTauri(root, nativeDeps, targets, bundles, args) { +export async function patchTauri(root, nativeDeps, targets, args) { if (args.findIndex(e => e === '-c' || e === '--config') !== -1) { throw new Error('Custom tauri build config is not supported.') } @@ -91,18 +90,12 @@ export async function patchTauri(root, nativeDeps, targets, bundles, args) { .readFile(path.join(tauriRoot, 'tauri.conf.json'), 'utf-8') .then(JSON.parse) - if (bundles.length === 0) { - const defaultBundles = tauriConfig?.bundle?.targets - if (Array.isArray(defaultBundles)) bundles.push(...defaultBundles) - if (bundles.length === 0) bundles.push('all') - } - switch (args[0]) { case 'dev': tauriPatch.build.features.push('devtools') break case 'build': { - if (tauriConfig?.plugins?.updater?.active) { + if (tauriConfig?.bundle?.createUpdaterArtifacts !== false) { const pubKey = await tauriUpdaterKey(nativeDeps) if (pubKey != null) tauriPatch.plugins.updater.pubkey = pubKey } @@ -111,6 +104,7 @@ export async function patchTauri(root, nativeDeps, targets, bundles, args) { } if (osType === 'Darwin') { + // arm64 support was added in macOS 11.0 const macOSArm64MinimumVersion = '11.0' let macOSMinimumVersion = tauriConfig?.bundle?.macOS?.minimumSystemVersion