[workspace]
members = [
    "solitaire_core",
    "solitaire_sync",
    "solitaire_data",
    "solitaire_engine",
    "solitaire_server",
    "solitaire_app",
    "solitaire_assetgen",
    "solitaire_wasm",
    "solitaire_web",
]
resolver = "2"

[workspace.package]
edition = "2024"
version = "0.1.0"
license = "MIT"
rust-version = "1.95"

# Pedantic correctness lints applied across every member crate via
# `[lints] workspace = true`.
[workspace.lints.rust]
# Workspace-wide ban on `unsafe`. The sole exception is `solitaire_app`,
# which sets its own `deny`-level lints (see its Cargo.toml) because the
# Android cdylib entry point must reconstruct raw JNI handles. Every other
# crate reaches Android JNI through the safe `solitaire_data::android_jni`
# bridge and stays fully unsafe-free.
unsafe_code = "forbid"
single_use_lifetimes = "warn"
trivial_casts = "warn"
unused_lifetimes = "warn"
unused_qualifications = "warn"
variant_size_differences = "warn"
unexpected_cfgs = "warn"

[workspace.dependencies]
serde       = { version = "1", features = ["derive"] }
serde_json  = "1"
uuid        = { version = "1", features = ["v4", "serde"] }
chrono      = { version = "0.4", features = ["serde", "wasmbind"] }
thiserror   = "2"
rand        = "0.9"
async-trait = "0.1"
tokio       = { version = "1", features = ["full"] }
dirs        = "6"
keyring     = "4"
keyring-core = "1"
reqwest     = { version = "0.13", features = ["json", "rustls", "rustls-native-certs"], default-features = false }
sha2        = "0.10"
arboard     = { version = "3", default-features = false }
jni         = { version = "0.21", default-features = false }

solitaire_core   = { path = "solitaire_core" }
solitaire_sync   = { path = "solitaire_sync" }
solitaire_data   = { path = "solitaire_data" }
solitaire_engine = { path = "solitaire_engine" }
klondike         = { version = "0.4.0", registry = "Quaternions", features = ["serde"] }
card_game        = { version = "0.4.1", registry = "Quaternions", features = ["serde"] }

# Bevy with `default-features = false` to avoid the unused
# `bevy_audio → rodio + symphonia + cpal 0.15 + alsa 0.9` chain.
# Audio is handled directly by `kira` in `audio_plugin.rs`, so the
# `bevy_audio` feature is intentionally omitted. The features below
# enumerate every leaf of the standard `2d` + `ui` meta-features that
# we actually use; new features should only be added with a
# corresponding use site.
bevy = { version = "0.18", default-features = false, features = [
    # default_app
    "async_executor",
    "bevy_asset",
    "bevy_input_focus",
    "bevy_log",
    "bevy_state",
    "bevy_window",
    "custom_cursor",
    "reflect_auto_register",
    # default_platform (desktop subset)
    "std",
    "bevy_winit",
    "default_font",
    "multi_threaded",
    # winit prefers Wayland when WAYLAND_DISPLAY is set on the
    # session and falls through to X11 otherwise. Without `wayland`,
    # winit-on-Wayland-session falls back to XWayland which renders
    # the game in an X11 frame inside the Wayland compositor.
    "wayland",
    "x11",
    # Android: NativeActivity glue. The feature is target-gated inside
    # bevy_internal — desktop builds compile it out, so leaving it on
    # the always-on list is harmless on Linux/macOS/Windows. Pairs with
    # cargo-apk's NativeActivity wrapper (cargo-apk 0.10+ uses this by
    # default). Switch to `android-game-activity` later if we want
    # AndroidX GameActivity for Google Play Games integration.
    "android-native-activity",
    # common_api
    "bevy_color",
    "bevy_image",
    "bevy_mesh",
    "bevy_shader",
    "bevy_text",
    "png",
    # 2d rendering
    "bevy_camera",
    "bevy_render",
    "bevy_core_pipeline",
    "bevy_sprite",
    "bevy_sprite_render",
    # UI rendering
    "bevy_ui",
    "bevy_ui_render",
] }
kira = "0.12"

# SVG rasterisation pipeline for the runtime card-theme system.
# usvg parses + simplifies; resvg renders to a tiny-skia Pixmap;
# tiny-skia provides the CPU rasteriser. All three are maintained
# together by the resvg-rs project and version in lockstep.
usvg      = "0.47"
resvg     = "0.47"
tiny-skia = "0.12"

# Theme manifest format. RON keeps the file human-editable while
# preserving Rust-style structures the importer can validate.
ron = "0.12"

# Importer-only: reads user-supplied theme zip archives, validates
# their contents, and unpacks them into the user themes directory.
# Default features are disabled to keep the dependency footprint small;
# only `deflate` is needed because the importer rejects other
# compression methods anyway (see Phase 7 spec).
zip = { version = "8.6", default-features = false, features = ["deflate"] }
# Image decoding for avatar bytes received from the server.
# Features mirror what Bevy already enables via bevy_image.
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "webp", "gif"] }

# Importer-only test dependency: tests build zip archives in a
# scratch directory so they don't pollute the real user themes path
# on the developer's machine.
tempfile = "3.27"

axum               = "0.8"
sqlx               = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
jsonwebtoken       = { version = "10", default-features = false, features = ["rust_crypto"] }
bcrypt             = "0.19"
tower_governor     = "0.8"
tracing            = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
dotenvy            = "0.15"

[profile.dev]
opt-level = 1

[profile.dev.package."*"]
opt-level = 3

[profile.release]
opt-level = 3
lto = "thin"

# Size-focused profile for the browser canvas build (solitaire_web →
# canvas_bg.wasm). Download size is the constraint on the web, not peak
# throughput: fat LTO + one codegen unit + opt-level "s" cut the Bevy wasm
# bundle substantially versus plain release. This is rustc-side sizing only —
# the binaryen pass in build_wasm.sh stays at wasm-opt -O2 because -Oz has
# miscompiled Bevy's render pipeline before (grey screen on first load).
[profile.wasm-release]
inherits = "release"
opt-level = "s"
lto = "fat"
codegen-units = 1
# No `strip`: on wasm it also removes the target_features custom section,
# which makes wasm-opt reject the module ("all used features should be
# allowed" on trunc_sat). wasm-opt drops the name section in its output
# anyway, so strip buys nothing here.
