mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-19 05:45:01 -04:00
Merge branch 'main' into release-build-fixes
This commit is contained in:
10
Cargo.toml
10
Cargo.toml
@@ -143,3 +143,13 @@ lto = true # Enables link to optimizations
|
||||
opt-level = "s" # Optimize for binary size
|
||||
panic = "unwind" # Sadly we need unwind to avoid unexpected crashes on third party crates
|
||||
strip = true # Remove debug symbols
|
||||
|
||||
# Fast mobile development profile - trades binary size for build speed
|
||||
# Use with: cargo build --profile mobile-dev
|
||||
# For production mobile releases, use --release instead
|
||||
[profile.mobile-dev]
|
||||
inherits = "release"
|
||||
codegen-units = 16 # Allow parallel compilation (vs 1 in release)
|
||||
lto = false # Disable link-time optimization (saves 15-20 min per arch)
|
||||
opt-level = 2 # Good optimization without extreme size focus
|
||||
strip = true # Still remove debug symbols
|
||||
|
||||
124
README.md
124
README.md
@@ -127,26 +127,66 @@ Peer-to-peer synchronization without central coordinators. Device-specific data
|
||||
**Core**
|
||||
|
||||
- **Rust** - Entire VDFS implementation (~183k lines)
|
||||
- **SQLite + SeaORM** - Local-first database with type-safe queries
|
||||
- **Iroh** - P2P networking with QUIC transport and hole-punching
|
||||
- **Tokio** - Async runtime
|
||||
- **SQLite + SeaORM** - Local-first database with type-safe ORM queries
|
||||
- **Iroh** - P2P networking with QUIC transport, hole-punching, and local discovery
|
||||
- **BLAKE3** - Fast cryptographic hashing for content identity
|
||||
- **WASM** - Sandboxed extension runtime
|
||||
- **Wasmer** - Sandboxed WASM extension runtime
|
||||
- **Axum** - HTTP/GraphQL server for web and API access
|
||||
- **OpenDAL** - Unified cloud storage abstraction (S3, Google Drive, OneDrive, Dropbox, Azure Blob, GCS)
|
||||
- **Specta** - Auto-generated TypeScript and Swift types from Rust
|
||||
|
||||
**Apps**
|
||||
**Cryptography & Security**
|
||||
|
||||
- **CLI** - Command-line interface (available now)
|
||||
- **Server** - Headless daemon for Docker deployment ([self-hosting guide](https://v2.spacedrive.com/overview/self-hosting))
|
||||
- **Tauri** - Cross-platform desktop with React frontend (macOS and Linux now, Windows in alpha.2)
|
||||
- **Web** - Web interface and shared UI components (available now)
|
||||
- **Mobile** - React Native mobile app (iOS and Android coming soon)
|
||||
- **Prototypes** - Native Swift apps (iOS, macOS) and GPUI media viewer for exploration
|
||||
- **Ed25519 / X25519** - Signatures and key exchange
|
||||
- **ChaCha20-Poly1305 / AES-GCM** - Authenticated encryption
|
||||
- **Argon2** - Password hashing
|
||||
- **BIP39** - Mnemonic phrase support for key backup
|
||||
- **redb** - Encrypted key-value store for credentials
|
||||
|
||||
**Media Processing**
|
||||
|
||||
- **FFmpeg** (via custom `sd-ffmpeg` crate) - Video thumbnails, audio extraction
|
||||
- **libheif** - HEIF/HEIC image support
|
||||
- **Pdfium** - PDF rendering
|
||||
- **Whisper** - On-device speech recognition (Metal-accelerated on Apple platforms)
|
||||
- **Blurhash** - Compact image placeholders
|
||||
|
||||
**Interface** (shared across web and desktop)
|
||||
|
||||
- **React 19** - UI framework
|
||||
- **Vite** - Build tooling
|
||||
- **TypeScript** - Type-safe frontend code
|
||||
- **TanStack Query** - Server state management
|
||||
- **Zustand** - Client state management
|
||||
- **Radix UI** - Accessible headless components
|
||||
- **Tailwind CSS** - Utility-first styling
|
||||
- **Framer Motion** - Animations
|
||||
- **React Hook Form + Zod** - Form management and validation
|
||||
- **Three.js / React Three Fiber** - 3D visualization
|
||||
- **dnd-kit** - Drag and drop
|
||||
- **TanStack Virtual / TanStack Table** - Virtualized lists and tables
|
||||
|
||||
**Desktop**
|
||||
|
||||
- **Tauri 2** - Cross-platform desktop shell (macOS, Linux, Windows)
|
||||
|
||||
**Mobile (React Native)**
|
||||
|
||||
- **React Native** 0.81 + **Expo** - Cross-platform mobile framework
|
||||
- **Expo Router** - File-based routing
|
||||
- **NativeWind** - Tailwind CSS for React Native
|
||||
- **React Navigation** - Native navigation stack
|
||||
- **Reanimated** - Native-thread animations
|
||||
- **sd-mobile-core** - Rust core bridge via FFI
|
||||
|
||||
**Architecture Patterns**
|
||||
|
||||
- Event-driven design with centralized EventBus
|
||||
- CQRS: Actions (mutations) and Queries (reads) with preview-commit-verify
|
||||
- Durable jobs with MessagePack serialization
|
||||
- Durable jobs with MessagePack serialization and checkpointing
|
||||
- Domain-separated sync with clear data ownership boundaries
|
||||
- Compile-time operation registration via `inventory` crate
|
||||
|
||||
---
|
||||
|
||||
@@ -154,25 +194,49 @@ Peer-to-peer synchronization without central coordinators. Device-specific data
|
||||
|
||||
```
|
||||
spacedrive/
|
||||
├── core/ # Rust VDFS implementation
|
||||
├── core/ # Rust VDFS implementation
|
||||
│ ├── src/
|
||||
│ │ ├── domain/ # Core models (Entry, Library, Device, Tag)
|
||||
│ │ ├── ops/ # CQRS operations (actions & queries)
|
||||
│ │ ├── infra/ # Infrastructure (DB, events, jobs, sync)
|
||||
│ │ ├── service/ # High-level services (network, file sharing)
|
||||
│ │ ├── location/ # Location management and indexing
|
||||
│ │ ├── library/ # Library lifecycle and operations
|
||||
│ │ └── volume/ # Volume detection and fingerprinting
|
||||
│ │ ├── domain/ # Core models (Entry, Library, Device, Tag, Volume)
|
||||
│ │ ├── ops/ # CQRS operations (actions & queries)
|
||||
│ │ ├── infra/ # Infrastructure (DB, events, jobs, sync)
|
||||
│ │ ├── service/ # High-level services (network, file sharing, sync)
|
||||
│ │ ├── crypto/ # Key management and encryption
|
||||
│ │ ├── device/ # Device identity and configuration
|
||||
│ │ ├── filetype/ # File type detection and registry
|
||||
│ │ ├── location/ # Location management and indexing
|
||||
│ │ ├── library/ # Library lifecycle and operations
|
||||
│ │ └── volume/ # Volume detection and fingerprinting
|
||||
│ └── tests/ # Integration tests (pairing, sync, file transfer)
|
||||
├── apps/
|
||||
│ ├── cli/ # CLI for managing libraries and running daemon
|
||||
│ ├── server/ # Headless server daemon
|
||||
│ ├── tauri/ # Cross-platform desktop app (macOS, Windows, Linux)
|
||||
│ ├── ios/ # Native prototype (private)
|
||||
│ ├── macos/ # Native prototype (private)
|
||||
│ └── gpui-photo-grid/ # GPUI media viewer prototype
|
||||
├── extensions/ # WASM extensions
|
||||
├── crates/ # Shared Rust utilities
|
||||
└── docs/ # Architecture documentation
|
||||
│ ├── cli/ # CLI and daemon entry point
|
||||
│ ├── server/ # Headless server for Docker/self-hosting
|
||||
│ ├── tauri/ # Desktop app shell (macOS, Windows, Linux)
|
||||
│ ├── web/ # Web app (Vite, connects to daemon via WebSocket)
|
||||
│ ├── mobile/ # React Native mobile app (Expo)
|
||||
│ ├── api/ # Cloud API server (Bun + Elysia)
|
||||
│ ├── landing/ # Marketing site and docs (Next.js)
|
||||
│ ├── ios/ # Native iOS prototype (Swift)
|
||||
│ ├── macos/ # Native macOS prototype (Swift)
|
||||
│ └── gpui-photo-grid/ # GPUI media viewer prototype
|
||||
├── packages/
|
||||
│ ├── interface/ # Shared React UI (used by web and desktop)
|
||||
│ ├── ts-client/ # Auto-generated TypeScript client and hooks
|
||||
│ ├── swift-client/ # Auto-generated Swift client
|
||||
│ ├── ui/ # Shared component library
|
||||
│ └── assets/ # Icons and images
|
||||
├── crates/
|
||||
│ ├── crypto/ # Cryptographic primitives
|
||||
│ ├── ffmpeg/ # FFmpeg bindings for video/audio
|
||||
│ ├── images/ # Image processing (HEIF, PDF, SVG)
|
||||
│ ├── media-metadata/ # EXIF/media metadata extraction
|
||||
│ ├── fs-watcher/ # Cross-platform file system watcher
|
||||
│ ├── sdk/ # WASM extension SDK
|
||||
│ ├── sdk-macros/ # Extension procedural macros
|
||||
│ ├── task-system/ # Durable job execution engine
|
||||
│ ├── sd-client/ # Rust client library
|
||||
│ └── ... # actors, fda, log-analyzer, utils
|
||||
├── extensions/ # WASM extensions (photos, test-extension)
|
||||
└── docs/ # Architecture documentation
|
||||
```
|
||||
|
||||
---
|
||||
@@ -262,10 +326,6 @@ cargo run -p sd-cli -- search .
|
||||
# Now launch Tauri app - it will connect to the running daemon
|
||||
```
|
||||
|
||||
### Native Prototypes
|
||||
|
||||
Experimental native apps are available in `apps/ios/`, `apps/macos/`, and `apps/gpui-photo-grid/` but are not documented for public use. These prototypes explore platform-specific optimizations and alternative UI approaches.
|
||||
|
||||
### Running Tests
|
||||
|
||||
Spacedrive has a comprehensive test suite covering single-device operations and multi-device networking scenarios.
|
||||
|
||||
@@ -7,8 +7,12 @@ const workspaceRoot = path.resolve(projectRoot, "../..");
|
||||
|
||||
const config = getDefaultConfig(projectRoot);
|
||||
|
||||
// Watch entire monorepo for hot reload
|
||||
config.watchFolders = [workspaceRoot];
|
||||
// Watch only relevant directories for hot reload (not entire monorepo)
|
||||
// This avoids watching Rust target/ dirs (4.5GB+) and other build artifacts
|
||||
config.watchFolders = [
|
||||
path.resolve(projectRoot, "src"),
|
||||
path.resolve(workspaceRoot, "packages"),
|
||||
];
|
||||
|
||||
// Configure resolver for monorepo and SVG support
|
||||
config.resolver = {
|
||||
@@ -25,17 +29,18 @@ config.resolver = {
|
||||
path.resolve(workspaceRoot, "node_modules"),
|
||||
],
|
||||
|
||||
// Exclude build outputs and prevent loading wrong React version from root
|
||||
// Exclude build outputs
|
||||
blockList: [
|
||||
/\/apps\/mobile\/ios\/build\/.*/,
|
||||
/\/apps\/mobile\/android\/build\/.*/,
|
||||
// Block React from workspace root to force local version
|
||||
new RegExp(`^${workspaceRoot}/node_modules/react/.*`),
|
||||
],
|
||||
|
||||
// Force React resolution from mobile app's node_modules
|
||||
// Dynamically resolve React/React Native from wherever the package manager installed them
|
||||
extraNodeModules: {
|
||||
react: path.resolve(projectRoot, "node_modules/react"),
|
||||
react: path.dirname(require.resolve("react/package.json", { paths: [projectRoot, workspaceRoot] })),
|
||||
"react-native": path.dirname(
|
||||
require.resolve("react-native/package.json", { paths: [projectRoot, workspaceRoot] })
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -17,10 +17,14 @@ pwd
|
||||
export CFLAGS_aarch64_apple_ios="-fno-stack-check -fno-stack-protector"
|
||||
export CFLAGS_aarch64_apple_ios_sim="-fno-stack-check -fno-stack-protector"
|
||||
|
||||
# Clean aws-lc-sys build cache to avoid stale cmake state
|
||||
echo "Cleaning aws-lc-sys build cache..."
|
||||
rm -rf apps/mobile/modules/sd-mobile-core/core/target/aarch64-apple-ios/release/build/aws-lc-sys-* || true
|
||||
rm -rf apps/mobile/modules/sd-mobile-core/core/target/aarch64-apple-ios-sim/release/build/aws-lc-sys-* || true
|
||||
# Clean aws-lc-sys build cache if requested (fixes stale cmake state when
|
||||
# switching between device/simulator or after Xcode updates)
|
||||
# Usage: export CLEAN_AWS_LC=1 before building in Xcode, or: CLEAN_AWS_LC=1 bun run ios
|
||||
if [ "${CLEAN_AWS_LC:-0}" = "1" ]; then
|
||||
echo "Cleaning aws-lc-sys build cache..."
|
||||
rm -rf target/aarch64-apple-ios/release/build/aws-lc-sys-* || true
|
||||
rm -rf target/aarch64-apple-ios-sim/release/build/aws-lc-sys-* || true
|
||||
fi
|
||||
|
||||
# Run xtask to build mobile libraries
|
||||
cargo xtask build-mobile
|
||||
|
||||
3638
apps/mobile/modules/sd-mobile-core/package-lock.json
generated
3638
apps/mobile/modules/sd-mobile-core/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -67,7 +67,6 @@
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/plugin-transform-runtime": "^7.28.5",
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@types/react": "~19.1.10",
|
||||
"babel-preset-expo": "~54.0.0",
|
||||
"eslint": "^9.15.0",
|
||||
"prettier": "^3.3.3",
|
||||
|
||||
@@ -181,9 +181,9 @@ impl LocationManager {
|
||||
accessed_at: Set(None),
|
||||
indexed_at: Set(Some(now)), // Record when location root was created
|
||||
permissions: Set(None),
|
||||
inode: Set(inode.map(|i| i as i64)),
|
||||
parent_id: Set(None), // Location root has no parent
|
||||
volume_id: Set(Some(volume_id)), // Volume is required for all locations
|
||||
inode: Set(inode.map(|i| i as i64)), // Use extracted inode
|
||||
parent_id: Set(None), // Location root has no parent
|
||||
volume_id: Set(Some(volume_id)), // Volume is required for all locations
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
"typecheck": "bun run --filter @sd/tauri typecheck"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "~19.1.10",
|
||||
"@types/react-dom": "~19.1.10",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.24.0",
|
||||
"@cspell/dict-rust": "^4.0.2",
|
||||
"@cspell/dict-typescript": "^3.1.2",
|
||||
@@ -30,6 +32,8 @@
|
||||
"packageManager": "bun@1.3.0",
|
||||
"overrides": {
|
||||
"@types/node": ">18.18.x",
|
||||
"@types/react": "~19.1.10",
|
||||
"@types/react-dom": "~19.1.10",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-router": "=6.20.1",
|
||||
|
||||
@@ -6,6 +6,19 @@
|
||||
"name": "@spacedriveapp/assets"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"types": "./types.d.ts",
|
||||
"exports": {
|
||||
"./icons": "./icons/index.ts",
|
||||
"./icons/*": "./icons/*",
|
||||
"./images": "./images/index.ts",
|
||||
"./images/*": "./images/*",
|
||||
"./svgs/*": "./svgs/*",
|
||||
"./sounds": "./sounds/index.ts",
|
||||
"./sounds/*": "./sounds/*",
|
||||
"./videos/*": "./videos/*",
|
||||
"./lottie/*": "./lottie/*",
|
||||
"./util": "./util/index.ts"
|
||||
},
|
||||
"files": [
|
||||
"icons",
|
||||
"images",
|
||||
@@ -13,7 +26,8 @@
|
||||
"sounds",
|
||||
"svgs",
|
||||
"videos",
|
||||
"util"
|
||||
"util",
|
||||
"types.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"gen": "node ./scripts/generate.mjs"
|
||||
|
||||
42
packages/assets/types.d.ts
vendored
Normal file
42
packages/assets/types.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Type declarations for @sd/assets
|
||||
|
||||
declare module "@sd/assets/icons/*.png" {
|
||||
const value: number; // React Native uses numeric IDs for local images
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module "@sd/assets/icons/*.jpg" {
|
||||
const value: number;
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module "@sd/assets/images/*.png" {
|
||||
const value: number;
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module "@sd/assets/images/*.jpg" {
|
||||
const value: number;
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module "@sd/assets/svgs/*.svg" {
|
||||
import type { FC } from "react";
|
||||
const content: FC<Record<string, unknown>>;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module "@sd/assets/videos/*.mp4" {
|
||||
const value: number;
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module "@sd/assets/sounds/*.mp3" {
|
||||
const value: number | string; // number on React Native (asset ID), string on web (URL)
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module "@sd/assets/lottie/*.json" {
|
||||
const value: object;
|
||||
export default value;
|
||||
}
|
||||
BIN
packages/interface/pnpm-lock.yaml
generated
BIN
packages/interface/pnpm-lock.yaml
generated
Binary file not shown.
@@ -3,6 +3,7 @@ import { Ball } from "@sd/assets/images";
|
||||
import Orb from "../../components/Orb";
|
||||
import { TopBarButton } from "@sd/ui";
|
||||
import { GlobeHemisphereWest, GithubLogo, DiscordLogo } from "@phosphor-icons/react";
|
||||
import contributors from "../../contributors.json";
|
||||
|
||||
export function AboutSettings() {
|
||||
|
||||
@@ -96,11 +97,36 @@ export function AboutSettings() {
|
||||
</a>
|
||||
</motion.div>
|
||||
|
||||
{/* Contributors */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.45 }}
|
||||
className="max-w-lg text-center mb-8 px-4"
|
||||
>
|
||||
<p className="text-[11px] leading-relaxed text-white/30">
|
||||
{contributors.map((c: { name: string; github: string }, i) => (
|
||||
<span key={c.github}>
|
||||
{i > 0 && " · "}
|
||||
<a
|
||||
href={`https://github.com/${c.github}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title={`@${c.github}`}
|
||||
className="hover:text-white/50 transition-colors"
|
||||
>
|
||||
{c.name}
|
||||
</a>
|
||||
</span>
|
||||
))}
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* License */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.5, delay: 0.5 }}
|
||||
transition={{ duration: 0.5, delay: 0.55 }}
|
||||
className="text-center"
|
||||
>
|
||||
<a
|
||||
|
||||
450
packages/interface/src/contributors.json
Normal file
450
packages/interface/src/contributors.json
Normal file
@@ -0,0 +1,450 @@
|
||||
[
|
||||
{
|
||||
"name": "Jamie Pine",
|
||||
"github": "jamiepine"
|
||||
},
|
||||
{
|
||||
"name": "Brendan Allan",
|
||||
"github": "Brendonovich"
|
||||
},
|
||||
{
|
||||
"name": "Oscar Beaumont",
|
||||
"github": "oscartbeaumont"
|
||||
},
|
||||
{
|
||||
"name": "Ameer Al Ashhab",
|
||||
"github": "ameer2468"
|
||||
},
|
||||
{
|
||||
"name": "Arnab Chakraborty",
|
||||
"github": "Rocky43007"
|
||||
},
|
||||
{
|
||||
"name": "Ericson \"Fogo\" Soares",
|
||||
"github": "fogodev"
|
||||
},
|
||||
{
|
||||
"name": "nikec",
|
||||
"github": "niikeec"
|
||||
},
|
||||
{
|
||||
"name": "Vítor Vasconcellos",
|
||||
"github": "HeavenVolkoff"
|
||||
},
|
||||
{
|
||||
"name": "maxichrome",
|
||||
"github": "maxichrome"
|
||||
},
|
||||
{
|
||||
"name": "jake",
|
||||
"github": "brxken128"
|
||||
},
|
||||
{
|
||||
"name": "Utku",
|
||||
"github": "utkubakir"
|
||||
},
|
||||
{
|
||||
"name": "Lynx",
|
||||
"github": "iLynxcat"
|
||||
},
|
||||
{
|
||||
"name": "Matthew Yung",
|
||||
"github": "myung03"
|
||||
},
|
||||
{
|
||||
"name": "Julian Braha",
|
||||
"github": "julianbraha"
|
||||
},
|
||||
{
|
||||
"name": "Gedeon",
|
||||
"github": "gedeondoescode"
|
||||
},
|
||||
{
|
||||
"name": "William Stoneham",
|
||||
"github": "RockBacon9922"
|
||||
},
|
||||
{
|
||||
"name": "Haris",
|
||||
"github": "xPolar"
|
||||
},
|
||||
{
|
||||
"name": "Artsiom Voitas",
|
||||
"github": "artsiom-voitas"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin",
|
||||
"github": "benja"
|
||||
},
|
||||
{
|
||||
"name": "Consoli",
|
||||
"github": "matheus-consoli"
|
||||
},
|
||||
{
|
||||
"name": "Andre",
|
||||
"github": "CreatingBytes"
|
||||
},
|
||||
{
|
||||
"name": "Aditya",
|
||||
"github": "Raghav-45"
|
||||
},
|
||||
{
|
||||
"name": "pr",
|
||||
"github": "PineappleRind"
|
||||
},
|
||||
{
|
||||
"name": "Stella",
|
||||
"github": "KodingDev"
|
||||
},
|
||||
{
|
||||
"name": "voletro",
|
||||
"github": "voletro"
|
||||
},
|
||||
{
|
||||
"name": "Lars Gyrup Brink Nielsen",
|
||||
"github": "LayZeeDK"
|
||||
},
|
||||
{
|
||||
"name": "Olen Latham",
|
||||
"github": "PyRo1121"
|
||||
},
|
||||
{
|
||||
"name": "Starbird",
|
||||
"github": "StarbirdTech"
|
||||
},
|
||||
{
|
||||
"name": "Harry Hopkinson",
|
||||
"github": "Harry-Hopkinson"
|
||||
},
|
||||
{
|
||||
"name": "Abhinav A",
|
||||
"github": "abhnva"
|
||||
},
|
||||
{
|
||||
"name": "wany-oh",
|
||||
"github": "wany-oh"
|
||||
},
|
||||
{
|
||||
"name": "Zakher Masri",
|
||||
"github": "zaaakher"
|
||||
},
|
||||
{
|
||||
"name": "Yukeey",
|
||||
"github": "Yukeey07"
|
||||
},
|
||||
{
|
||||
"name": "Md. Fahim Bin Amin",
|
||||
"github": "FahimFBA"
|
||||
},
|
||||
{
|
||||
"name": "Baran Mordoğan",
|
||||
"github": "okunamayanad"
|
||||
},
|
||||
{
|
||||
"name": "Na Risong",
|
||||
"github": "HeavySnowJakarta"
|
||||
},
|
||||
{
|
||||
"name": "Sreecharan",
|
||||
"github": "sr2echa"
|
||||
},
|
||||
{
|
||||
"name": "matt morris",
|
||||
"github": "mmattbtw"
|
||||
},
|
||||
{
|
||||
"name": "Jules Guesnon",
|
||||
"github": "JulesGuesnon"
|
||||
},
|
||||
{
|
||||
"name": "Madison Konig",
|
||||
"github": "MadisonKonig"
|
||||
},
|
||||
{
|
||||
"name": "Omar Hamad",
|
||||
"github": "etahamad"
|
||||
},
|
||||
{
|
||||
"name": "he1d1",
|
||||
"github": "he1d1"
|
||||
},
|
||||
{
|
||||
"name": "Ned Park",
|
||||
"github": "ned-park"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"github": "berbaroovez"
|
||||
},
|
||||
{
|
||||
"name": "Tom Heaton",
|
||||
"github": "tomheaton"
|
||||
},
|
||||
{
|
||||
"name": "Tim Havlicek",
|
||||
"github": "luckydye"
|
||||
},
|
||||
{
|
||||
"name": "Tilo",
|
||||
"github": "Tilo-K"
|
||||
},
|
||||
{
|
||||
"name": "Sinan Gençoğlu",
|
||||
"github": "SinanGncgl"
|
||||
},
|
||||
{
|
||||
"name": "Michelangelo Guerra",
|
||||
"github": "XSPGMike"
|
||||
},
|
||||
{
|
||||
"name": "Marques Scripps",
|
||||
"github": "MarquesCoding"
|
||||
},
|
||||
{
|
||||
"name": "Abe",
|
||||
"github": "FastestMolasses"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"github": "Carterpersall"
|
||||
},
|
||||
{
|
||||
"name": "Vikram Srinivas",
|
||||
"github": "vikram2009"
|
||||
},
|
||||
{
|
||||
"name": "Twan L",
|
||||
"github": "TwanLuttik"
|
||||
},
|
||||
{
|
||||
"name": "Syntax",
|
||||
"github": "TheUltDev"
|
||||
},
|
||||
{
|
||||
"name": "Takshil Mistry",
|
||||
"github": "daUnknownCoder"
|
||||
},
|
||||
{
|
||||
"name": "Sarah Bobbe",
|
||||
"github": "SBobbe"
|
||||
},
|
||||
{
|
||||
"name": "Ramprakash",
|
||||
"github": "CodePurble"
|
||||
},
|
||||
{
|
||||
"name": "Johan Sandgren",
|
||||
"github": "Qrutz"
|
||||
},
|
||||
{
|
||||
"name": "Phedona",
|
||||
"github": "Phedona"
|
||||
},
|
||||
{
|
||||
"name": "Percy Ma",
|
||||
"github": "kecrily"
|
||||
},
|
||||
{
|
||||
"name": "Param Birje",
|
||||
"github": "ParamBirje"
|
||||
},
|
||||
{
|
||||
"name": "Niklas Wojtkowiak",
|
||||
"github": "0xnim"
|
||||
},
|
||||
{
|
||||
"name": "Nicolás Fishman",
|
||||
"github": "nicofishman"
|
||||
},
|
||||
{
|
||||
"name": "Mykola",
|
||||
"github": "handicraftsman"
|
||||
},
|
||||
{
|
||||
"name": "Nicholas",
|
||||
"github": "alsonick"
|
||||
},
|
||||
{
|
||||
"name": "0xBA5E64",
|
||||
"github": "0xBA5E64"
|
||||
},
|
||||
{
|
||||
"name": "Whisht",
|
||||
"github": "Whisht"
|
||||
},
|
||||
{
|
||||
"name": "Yousef Abu-Salah",
|
||||
"github": "ykabusalah"
|
||||
},
|
||||
{
|
||||
"name": "andriizaiets",
|
||||
"github": "andriizaiets"
|
||||
},
|
||||
{
|
||||
"name": "devqore",
|
||||
"github": "devqore"
|
||||
},
|
||||
{
|
||||
"name": "erikpodusel",
|
||||
"github": "erikpodusel"
|
||||
},
|
||||
{
|
||||
"name": "David",
|
||||
"github": "fivestones"
|
||||
},
|
||||
{
|
||||
"name": "Christopher",
|
||||
"github": "itschip"
|
||||
},
|
||||
{
|
||||
"name": "jenniferdewan",
|
||||
"github": "jenniferdewan"
|
||||
},
|
||||
{
|
||||
"name": "leo",
|
||||
"github": "greendoescode"
|
||||
},
|
||||
{
|
||||
"name": "lzt1008",
|
||||
"github": "lzt1008"
|
||||
},
|
||||
{
|
||||
"name": "mark-strudwick",
|
||||
"github": "mark-strudwick"
|
||||
},
|
||||
{
|
||||
"name": "markrieder",
|
||||
"github": "markrieder"
|
||||
},
|
||||
{
|
||||
"name": "mooy",
|
||||
"github": "mooyg"
|
||||
},
|
||||
{
|
||||
"name": "S.L",
|
||||
"github": "slvnlrt"
|
||||
},
|
||||
{
|
||||
"name": "AhmedKaram",
|
||||
"github": "Adamkaram"
|
||||
},
|
||||
{
|
||||
"name": "Alex",
|
||||
"github": "misxki"
|
||||
},
|
||||
{
|
||||
"name": "Allie",
|
||||
"github": "ChildishGiant"
|
||||
},
|
||||
{
|
||||
"name": "Anthony Morris",
|
||||
"github": "amorriscode"
|
||||
},
|
||||
{
|
||||
"name": "BI3TKL",
|
||||
"github": "Nightingale0504"
|
||||
},
|
||||
{
|
||||
"name": "briamoe",
|
||||
"github": "briamoe"
|
||||
},
|
||||
{
|
||||
"name": "Bryan",
|
||||
"github": "CodeWithBryan"
|
||||
},
|
||||
{
|
||||
"name": "Cavell Blood",
|
||||
"github": "cavellblood"
|
||||
},
|
||||
{
|
||||
"name": "Cedric ",
|
||||
"github": "ceddy4395"
|
||||
},
|
||||
{
|
||||
"name": "Christo Todorov",
|
||||
"github": "chroxify"
|
||||
},
|
||||
{
|
||||
"name": "Colin Griffin",
|
||||
"github": "krumware"
|
||||
},
|
||||
{
|
||||
"name": "Conrad Crawford",
|
||||
"github": "cnrad"
|
||||
},
|
||||
{
|
||||
"name": "Eric Wyne",
|
||||
"github": "ecwyne"
|
||||
},
|
||||
{
|
||||
"name": "HardikBandhiya",
|
||||
"github": "BandhiyaHardik"
|
||||
},
|
||||
{
|
||||
"name": "Ilkka Poutanen",
|
||||
"github": "ilkka"
|
||||
},
|
||||
{
|
||||
"name": "Hesham Abourgheba",
|
||||
"github": "IllusionMan1212"
|
||||
},
|
||||
{
|
||||
"name": "Jeremy Möglich",
|
||||
"github": "JeremyMoeglich"
|
||||
},
|
||||
{
|
||||
"name": "Jesse Rodrigo",
|
||||
"github": "JSSRDRG"
|
||||
},
|
||||
{
|
||||
"name": "John Xu",
|
||||
"github": "dyxushuai"
|
||||
},
|
||||
{
|
||||
"name": "Jx",
|
||||
"github": "JxJxxJxJ"
|
||||
},
|
||||
{
|
||||
"name": "erian",
|
||||
"github": "oopserian"
|
||||
},
|
||||
{
|
||||
"name": "Leora",
|
||||
"github": "Kuuchuu"
|
||||
},
|
||||
{
|
||||
"name": "Liam Brewer",
|
||||
"github": "liambrewer"
|
||||
},
|
||||
{
|
||||
"name": "Lkhsss",
|
||||
"github": "Lkhsss"
|
||||
},
|
||||
{
|
||||
"name": "Majal",
|
||||
"github": "majal"
|
||||
},
|
||||
{
|
||||
"name": "Marc Espin",
|
||||
"github": "marc2332"
|
||||
},
|
||||
{
|
||||
"name": "Matteo Galiazzo",
|
||||
"github": "gekoxyz"
|
||||
},
|
||||
{
|
||||
"name": "Matthias Berchtold",
|
||||
"github": "iammatthi"
|
||||
},
|
||||
{
|
||||
"name": "Mohammed Bajuaifer",
|
||||
"github": "MohammedBajuaifer"
|
||||
},
|
||||
{
|
||||
"name": "Naman Garg",
|
||||
"github": "namanlp"
|
||||
},
|
||||
{
|
||||
"name": "Nebhay",
|
||||
"github": "Nebhay"
|
||||
}
|
||||
]
|
||||
@@ -8,6 +8,7 @@
|
||||
"module": "ESNext",
|
||||
"target": "ES2022",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
|
||||
3595
packages/ts-client/package-lock.json
generated
3595
packages/ts-client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,9 +13,29 @@
|
||||
"types": "./src/generated/types.ts",
|
||||
"default": "./src/generated/types.ts"
|
||||
},
|
||||
"./src/generated/types": {
|
||||
"types": "./src/generated/types.ts",
|
||||
"default": "./src/generated/types.ts"
|
||||
},
|
||||
"./hooks": {
|
||||
"types": "./src/hooks/index.ts",
|
||||
"default": "./src/hooks/index.ts"
|
||||
},
|
||||
"./hooks/useClient": {
|
||||
"types": "./src/hooks/useClient.tsx",
|
||||
"default": "./src/hooks/useClient.tsx"
|
||||
},
|
||||
"./hooks/useNormalizedQuery": {
|
||||
"types": "./src/hooks/useNormalizedQuery.ts",
|
||||
"default": "./src/hooks/useNormalizedQuery.ts"
|
||||
},
|
||||
"./src/hooks/useClient": {
|
||||
"types": "./src/hooks/useClient.tsx",
|
||||
"default": "./src/hooks/useClient.tsx"
|
||||
},
|
||||
"./src/hooks/useNormalizedQuery": {
|
||||
"types": "./src/hooks/useNormalizedQuery.ts",
|
||||
"default": "./src/hooks/useNormalizedQuery.ts"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
@@ -46,12 +66,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@happy-dom/global-registrator": "^15.11.0",
|
||||
"@tanstack/react-query": "^5.62.0",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@testing-library/react": "^16.0.0",
|
||||
"@types/jest": "^29.0.0",
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/react": "^19.0.0",
|
||||
"happy-dom": "^15.11.0",
|
||||
"jest": "^29.0.0",
|
||||
"jest-environment-jsdom": "^29.0.0",
|
||||
@@ -64,8 +82,6 @@
|
||||
"@sd/assets": "workspace:*",
|
||||
"ws": "^8.0.0",
|
||||
"zustand": "^5.0.8",
|
||||
"react": "^19.0.0",
|
||||
"@tanstack/react-query": "^5.62.0",
|
||||
"ts-deepmerge": "^7.0.1",
|
||||
"tiny-invariant": "^1.3.3",
|
||||
"valibot": "^1.0.0",
|
||||
@@ -75,4 +91,4 @@
|
||||
"dist/**/*",
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ anyhow = "1"
|
||||
flate2 = "1.0"
|
||||
mustache = "0.9"
|
||||
owo-colors = "4"
|
||||
reqwest = { version = "0.12", features = ["blocking", "rustls-tls"], default-features = false }
|
||||
reqwest = { version = "0.12", features = ["blocking", "json", "rustls-tls"], default-features = false }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tar = "0.4"
|
||||
|
||||
@@ -120,16 +120,13 @@ pub fn generate_cargo_config(
|
||||
protoc,
|
||||
mobile_native_deps,
|
||||
android_ndk_home,
|
||||
// Android NDK host tag - the prebuilt directory is always named darwin-x86_64 on macOS,
|
||||
// but the binaries are universal (fat) binaries with native ARM64 support.
|
||||
// Google kept the path name for backwards compatibility.
|
||||
host_tag: match system.os {
|
||||
Os::Windows => "windows-x86_64",
|
||||
Os::Linux => "linux-x86_64",
|
||||
Os::MacOS => {
|
||||
if cfg!(target_arch = "aarch64") {
|
||||
"darwin-aarch64"
|
||||
} else {
|
||||
"darwin-x86_64"
|
||||
}
|
||||
}
|
||||
Os::MacOS => "darwin-x86_64",
|
||||
},
|
||||
is_win: matches!(system.os, Os::Windows),
|
||||
is_macos: matches!(system.os, Os::MacOS),
|
||||
|
||||
159
xtask/src/contributors.rs
Normal file
159
xtask/src/contributors.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
use anyhow::{Context, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
|
||||
const REPO: &str = "spacedriveapp/spacedrive";
|
||||
const OUTPUT_PATH: &str = "packages/interface/src/contributors.json";
|
||||
const EXCLUDED_LOGINS: &[&str] = &["cursoragent"];
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct GitHubContributor {
|
||||
login: String,
|
||||
#[serde(rename = "type")]
|
||||
account_type: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct GitHubUser {
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Contributor {
|
||||
name: String,
|
||||
github: String,
|
||||
}
|
||||
|
||||
/// Try to get a GitHub token from the environment or `gh` CLI
|
||||
fn get_github_token() -> Option<String> {
|
||||
if let Ok(token) = std::env::var("GITHUB_TOKEN") {
|
||||
return Some(token);
|
||||
}
|
||||
|
||||
std::process::Command::new("gh")
|
||||
.args(["auth", "token"])
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|o| {
|
||||
if o.status.success() {
|
||||
String::from_utf8(o.stdout).ok().map(|s| s.trim().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn github_get(
|
||||
client: &reqwest::blocking::Client,
|
||||
url: &str,
|
||||
token: Option<&str>,
|
||||
) -> reqwest::blocking::RequestBuilder {
|
||||
let mut req = client.get(url);
|
||||
if let Some(token) = token {
|
||||
req = req.bearer_auth(token);
|
||||
}
|
||||
req
|
||||
}
|
||||
|
||||
pub fn update(project_root: &Path) -> Result<()> {
|
||||
println!("Fetching contributors from GitHub...");
|
||||
|
||||
let token = get_github_token();
|
||||
if token.is_some() {
|
||||
println!(" using authenticated requests");
|
||||
} else {
|
||||
println!(" no token found, using unauthenticated requests (may hit rate limits)");
|
||||
println!(" tip: install `gh` CLI and run `gh auth login` for higher limits");
|
||||
}
|
||||
|
||||
let client = reqwest::blocking::Client::builder()
|
||||
.user_agent("spacedrive-xtask")
|
||||
.timeout(std::time::Duration::from_secs(20))
|
||||
.build()
|
||||
.context("Failed to build HTTP client")?;
|
||||
|
||||
// Paginate through all contributors
|
||||
let mut all_contributors = Vec::new();
|
||||
let mut page = 1u32;
|
||||
|
||||
loop {
|
||||
let url = format!(
|
||||
"https://api.github.com/repos/{}/contributors?per_page=100&page={}",
|
||||
REPO, page
|
||||
);
|
||||
|
||||
let resp: Vec<GitHubContributor> = github_get(&client, &url, token.as_deref())
|
||||
.send()
|
||||
.context("Failed to fetch contributors")?
|
||||
.json()
|
||||
.context("Failed to parse contributors response")?;
|
||||
|
||||
if resp.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
all_contributors.extend(resp);
|
||||
page += 1;
|
||||
}
|
||||
|
||||
// Filter out bots and excluded accounts
|
||||
let humans: Vec<_> = all_contributors
|
||||
.iter()
|
||||
.filter(|c| c.account_type == "User" && !EXCLUDED_LOGINS.contains(&c.login.as_str()))
|
||||
.collect();
|
||||
|
||||
println!("Found {} contributors, resolving names...", humans.len());
|
||||
|
||||
let mut contributors = Vec::new();
|
||||
|
||||
for (i, contributor) in humans.iter().enumerate() {
|
||||
let name = match resolve_name(&client, &contributor.login, token.as_deref()) {
|
||||
Ok(Some(n)) => n,
|
||||
_ => contributor.login.clone(),
|
||||
};
|
||||
|
||||
contributors.push(Contributor {
|
||||
name,
|
||||
github: contributor.login.clone(),
|
||||
});
|
||||
|
||||
// Progress indicator every 25 users
|
||||
if (i + 1) % 25 == 0 {
|
||||
println!(" resolved {}/{}", i + 1, humans.len());
|
||||
}
|
||||
}
|
||||
|
||||
println!(" resolved {}/{}", contributors.len(), humans.len());
|
||||
|
||||
let output_path = project_root.join(OUTPUT_PATH);
|
||||
let json = serde_json::to_string_pretty(&contributors)
|
||||
.context("Failed to serialize contributors")?;
|
||||
|
||||
std::fs::write(&output_path, format!("{}\n", json))
|
||||
.context("Failed to write contributors.json")?;
|
||||
|
||||
println!(
|
||||
"Wrote {} contributors to {}",
|
||||
contributors.len(),
|
||||
OUTPUT_PATH
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_name(
|
||||
client: &reqwest::blocking::Client,
|
||||
login: &str,
|
||||
token: Option<&str>,
|
||||
) -> Result<Option<String>> {
|
||||
let url = format!("https://api.github.com/users/{}", login);
|
||||
let user: GitHubUser = github_get(client, &url, token)
|
||||
.send()
|
||||
.context("Failed to fetch user")?
|
||||
.error_for_status()
|
||||
.context("GitHub API returned an error")?
|
||||
.json()
|
||||
.context("Failed to parse user response")?;
|
||||
|
||||
Ok(user.name.filter(|n: &String| !n.is_empty()))
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
mod bump;
|
||||
mod config;
|
||||
mod contributors;
|
||||
mod native_deps;
|
||||
mod system;
|
||||
mod test_core;
|
||||
@@ -69,6 +70,9 @@ fn main() -> Result<()> {
|
||||
eprintln!(" build-mobile Build sd-mobile-core for React Native iOS/Android");
|
||||
eprintln!(" test-core Run all core integration tests with progress tracking");
|
||||
eprintln!(" bump <ver> Bump version across all packages (e.g. bump 2.0.0-alpha.2)");
|
||||
eprintln!(
|
||||
" update-contributors Fetch contributors from GitHub and update contributors.json"
|
||||
);
|
||||
eprintln!();
|
||||
eprintln!("Examples:");
|
||||
eprintln!(" cargo xtask setup # First time setup");
|
||||
@@ -99,6 +103,10 @@ fn main() -> Result<()> {
|
||||
let root = find_workspace_root()?;
|
||||
bump::bump(&root, &version)?;
|
||||
}
|
||||
"update-contributors" => {
|
||||
let project_root = find_workspace_root()?;
|
||||
contributors::update(&project_root)?;
|
||||
}
|
||||
_ => {
|
||||
eprintln!("Unknown command: {}", args[1]);
|
||||
eprintln!("Run 'cargo xtask' for usage information.");
|
||||
@@ -273,7 +281,10 @@ fn setup() -> Result<()> {
|
||||
// Create target-suffixed daemon binary for Tauri bundler
|
||||
// Tauri's externalBin appends the target triple to binary names
|
||||
let exe_ext = if cfg!(windows) { ".exe" } else { "" };
|
||||
let daemon_source = project_root.join(format!("target/{}/release/sd-daemon{}", target_triple, exe_ext));
|
||||
let daemon_source = project_root.join(format!(
|
||||
"target/{}/release/sd-daemon{}",
|
||||
target_triple, exe_ext
|
||||
));
|
||||
let daemon_target = project_root.join(format!(
|
||||
"target/release/sd-daemon-{}{}",
|
||||
target_triple, exe_ext
|
||||
@@ -534,7 +545,14 @@ fn build_mobile() -> Result<()> {
|
||||
println!(" Building for iOS {} ({})...", name, target);
|
||||
|
||||
let status = Command::new("cargo")
|
||||
.args(["build", "--release", "-p", "sd-mobile-core", "--target", target])
|
||||
.args([
|
||||
"build",
|
||||
"--release",
|
||||
"-p",
|
||||
"sd-mobile-core",
|
||||
"--target",
|
||||
target,
|
||||
])
|
||||
.current_dir(&project_root)
|
||||
.env("IPHONEOS_DEPLOYMENT_TARGET", "18.0")
|
||||
.status()
|
||||
@@ -571,7 +589,14 @@ fn build_mobile() -> Result<()> {
|
||||
println!(" Building for Android {} ({})...", name, target);
|
||||
|
||||
let status = Command::new("cargo")
|
||||
.args(["build", "--release", "-p", "sd-mobile-core", "--target", target])
|
||||
.args([
|
||||
"build",
|
||||
"--release",
|
||||
"-p",
|
||||
"sd-mobile-core",
|
||||
"--target",
|
||||
target,
|
||||
])
|
||||
.current_dir(&project_root)
|
||||
.status()
|
||||
.context(format!("Failed to build for {}", target))?;
|
||||
|
||||
Reference in New Issue
Block a user