From fec36402201d902f892f0d9f5063827f27dbd68d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 22:57:06 +0000 Subject: [PATCH] Remove unused code and dependencies Code the compiler cannot flag as dead because it is `pub`, and dependencies nothing imports: - Rust items nothing referenced: `OidcMetadataClient::with_ttls` and `verify_jwt` (its doc moves to `verify_jwt_inner`), `SessionService:: with_touch_throttle_secs`, `NUPKG_CONTENT_TYPE`/`NUSPEC_CONTENT_TYPE`, `upstream_secret`, `Cache::get_or_try_insert_local_with_tags`, `auth_realm_dao::change_marker`, `model::GroupMember`, `trusted_publisher_dao::{find_for_repository, validate_repository}`, `user_dao::set_user_realm`, the Helm `PROVENANCE` media type, `Extractor::found_attachment`, `OidcConfig::clock_skew`, `EmailSettings::invitation_ttl` and `UpstreamBasicAuthConfig::to_core`, with the three `.sqlx` entries of the removed queries. - Items only tests used: `UpstreamHttp::get_json` (and with it `UpstreamError::Json`, so `SourceError::of` loses its unused `url`), `Principal::is_user`, `nuspec::metadata_from_nuspec` (the test reads `manifest_summary`), `raw_dao::directory_exists`; `get_bytes`, `SpooledBody::is_on_disk` and `EnvelopeService::revoke_key` become `#[cfg(test)]`. - Doc links that named the removed functions now name the ones called. - Cargo: `base64` (apt), `anyhow` and `futures-util` (e2e), the dev `serde_json` (traffic) and `tempfile` (npm), and 25 dev-dependencies that repeated a normal dependency with the same features. - Web: the never-imported `Breadcrumbs`, `Paginator`, `RepoFormatBadge` and `RepoKindBadge`, the `CopyButton` re-export only its test used, `RoleLabel`, the design system's `Digest` and `ICON_NAMES`, barrel exports no screen imports, `OauthAuthorizeMethod`, the e2e `addGroupMember`, eight CSS rules no component uses, the two TanStack devtools packages, the esbuild build-script allowance (Vite 8 has no esbuild), and the stale, tracked `tsconfig.tsbuildinfo`. No behaviour changes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012e6DJZJ5VT9e32viHMCHoq --- ...ecbe1af07a62092fc57b042de8a226c83b738.json | 28 -- ...418efacecd508a43a2c758014e0ed0a9d326a.json | 15 - ...6830b72f3058b1e33b9b7ff3b90fa82fb5e9b.json | 25 -- Cargo.lock | 5 - crates/cache/Cargo.toml | 1 - crates/cache/src/lib.rs | 26 +- crates/core/Cargo.toml | 5 - crates/core/src/auth/authz.rs | 20 - crates/core/src/auth/cred_cache.rs | 21 +- crates/core/src/auth/principal.rs | 20 - crates/core/src/net/upstream.rs | 53 +-- crates/core/src/oidc/jwks.rs | 42 +- crates/core/src/repo/mod.rs | 5 - crates/core/src/repo/proxy.rs | 11 - crates/core/src/session/mod.rs | 6 - crates/crypto/src/service.rs | 7 +- crates/db/Cargo.toml | 2 - crates/db/src/auth_realm_dao.rs | 14 - crates/db/src/model.rs | 8 - crates/db/src/raw_dao.rs | 23 -- crates/db/src/trusted_publisher_dao.rs | 26 -- crates/db/src/user_dao.rs | 19 - crates/db/tests/raw.rs | 6 - crates/e2e/Cargo.toml | 8 - crates/formats/apt/Cargo.toml | 1 - crates/formats/docker/src/chart.rs | 2 - crates/formats/npm/Cargo.toml | 1 - crates/formats/npm/src/publish.rs | 5 - crates/formats/nuget/src/nuspec.rs | 5 - crates/formats/nuget/tests/parse.rs | 5 +- crates/server/Cargo.toml | 11 - crates/server/src/auth/wif.rs | 2 +- crates/server/src/config.rs | 31 -- crates/server/src/email/settings.rs | 6 - crates/server/src/import/apt.rs | 6 +- crates/server/src/import/feed.rs | 11 +- crates/server/src/import/npm.rs | 10 +- crates/server/src/import/raw.rs | 10 +- crates/storage/Cargo.toml | 1 - crates/traffic/Cargo.toml | 1 - web/.gitignore | 3 + web/e2e/helpers.ts | 14 - web/package.json | 2 - web/pnpm-lock.yaml | 387 ------------------ web/pnpm-workspace.yaml | 6 +- web/src/api/email.ts | 3 - web/src/components/Breadcrumbs.tsx | 11 - web/src/components/CopyButton.test.tsx | 2 +- web/src/components/CopyButton.tsx | 5 - web/src/components/Paginator.tsx | 1 - web/src/components/RbacLabels.tsx | 17 - web/src/components/RepoFormatBadge.tsx | 12 - web/src/components/RepoKindBadge.tsx | 9 - web/src/components/ui/badges.tsx | 37 -- web/src/components/ui/icons.tsx | 3 - web/src/components/ui/index.ts | 10 +- web/src/styles/forge-ui.css | 12 +- web/tsconfig.tsbuildinfo | 1 - 58 files changed, 70 insertions(+), 969 deletions(-) delete mode 100644 .sqlx/query-142bfa1c5ac853eeacab3795490ecbe1af07a62092fc57b042de8a226c83b738.json delete mode 100644 .sqlx/query-9e8bdab9174dc2946e96ee4603f418efacecd508a43a2c758014e0ed0a9d326a.json delete mode 100644 .sqlx/query-ed6569f35fd50fffb77a667a6a16830b72f3058b1e33b9b7ff3b90fa82fb5e9b.json delete mode 100644 web/src/components/Breadcrumbs.tsx delete mode 100644 web/src/components/CopyButton.tsx delete mode 100644 web/src/components/Paginator.tsx delete mode 100644 web/src/components/RepoFormatBadge.tsx delete mode 100644 web/src/components/RepoKindBadge.tsx delete mode 100644 web/tsconfig.tsbuildinfo diff --git a/.sqlx/query-142bfa1c5ac853eeacab3795490ecbe1af07a62092fc57b042de8a226c83b738.json b/.sqlx/query-142bfa1c5ac853eeacab3795490ecbe1af07a62092fc57b042de8a226c83b738.json deleted file mode 100644 index cb3762c2..00000000 --- a/.sqlx/query-142bfa1c5ac853eeacab3795490ecbe1af07a62092fc57b042de8a226c83b738.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT count(*) AS \"count!\", max(updated_at) AS \"max_updated\" FROM auth_realm", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "count!", - "type_info": "Int8", - "origin": "Expression" - }, - { - "ordinal": 1, - "name": "max_updated", - "type_info": "Timestamptz", - "origin": "Expression" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - null, - null - ] - }, - "hash": "142bfa1c5ac853eeacab3795490ecbe1af07a62092fc57b042de8a226c83b738" -} diff --git a/.sqlx/query-9e8bdab9174dc2946e96ee4603f418efacecd508a43a2c758014e0ed0a9d326a.json b/.sqlx/query-9e8bdab9174dc2946e96ee4603f418efacecd508a43a2c758014e0ed0a9d326a.json deleted file mode 100644 index 44a48314..00000000 --- a/.sqlx/query-9e8bdab9174dc2946e96ee4603f418efacecd508a43a2c758014e0ed0a9d326a.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE app_user\n SET realm_id = $2\n WHERE id = $1 AND realm_id IS DISTINCT FROM $2\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "9e8bdab9174dc2946e96ee4603f418efacecd508a43a2c758014e0ed0a9d326a" -} diff --git a/.sqlx/query-ed6569f35fd50fffb77a667a6a16830b72f3058b1e33b9b7ff3b90fa82fb5e9b.json b/.sqlx/query-ed6569f35fd50fffb77a667a6a16830b72f3058b1e33b9b7ff3b90fa82fb5e9b.json deleted file mode 100644 index a1ab252f..00000000 --- a/.sqlx/query-ed6569f35fd50fffb77a667a6a16830b72f3058b1e33b9b7ff3b90fa82fb5e9b.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT EXISTS (\n SELECT 1 FROM raw_file\n WHERE repository_id = $1 AND path >= $2 AND ($3::text IS NULL OR path < $3)\n ) AS \"exists!\"\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "exists!", - "type_info": "Bool", - "origin": "Expression" - } - ], - "parameters": { - "Left": [ - "Int8", - "Text", - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "ed6569f35fd50fffb77a667a6a16830b72f3058b1e33b9b7ff3b90fa82fb5e9b" -} diff --git a/Cargo.lock b/Cargo.lock index 01848478..0e141890 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2260,7 +2260,6 @@ dependencies = [ name = "forge-e2e" version = "2.1.0" dependencies = [ - "anyhow", "aws-credential-types", "aws-sigv4", "axum", @@ -2274,7 +2273,6 @@ dependencies = [ "forge-format-nuget", "forge-server", "forge-storage", - "futures-util", "hex", "jsonwebtoken", "rand 0.10.3", @@ -2297,7 +2295,6 @@ dependencies = [ name = "forge-format-apt" version = "1.0.0" dependencies = [ - "base64 0.23.1", "chrono", "flate2", "forge-plugin-api", @@ -2340,7 +2337,6 @@ dependencies = [ "sha1 0.11.0", "sha2 0.11.1", "tar", - "tempfile", ] [[package]] @@ -2518,7 +2514,6 @@ dependencies = [ "parquet_derive", "rand 0.10.3", "serde", - "serde_json", "tokio", "tracing", ] diff --git a/crates/cache/Cargo.toml b/crates/cache/Cargo.toml index 54b90140..46e948a1 100644 --- a/crates/cache/Cargo.toml +++ b/crates/cache/Cargo.toml @@ -21,5 +21,4 @@ tracing = { workspace = true } thiserror = { workspace = true } [dev-dependencies] -tokio = { workspace = true, features = ["rt-multi-thread", "macros", "sync", "time"] } testcontainers = "0.27" diff --git a/crates/cache/src/lib.rs b/crates/cache/src/lib.rs index c949e473..c62b3cc2 100644 --- a/crates/cache/src/lib.rs +++ b/crates/cache/src/lib.rs @@ -56,8 +56,8 @@ //! authorization set, credential verdict, JWKS, workload-token verdict, or a //! proxy's upstream service index, manifest or registration would be accepted //! by every instance. Such values go through [`Cache::get_or_try_insert_local`] / -//! [`Cache::get_or_try_insert_local_with_tags`]: they live in L1 only and -//! are never read from or written to Redis. Redis still carries their +//! [`Cache::get_or_try_insert_local_with_tags_expiring`]: they live in L1 only +//! and are never read from or written to Redis. Redis still carries their //! **invalidations** (tag generations over the backplane), so an //! invalidation on one instance still evicts them everywhere — the worst a //! Redis writer can do to them is evict entries early. @@ -535,26 +535,8 @@ impl Cache { self.load(ns, key, &[], ttl, factory, false).await } - /// [`Cache::get_or_try_insert_local`] with logical tags, like - /// [`Cache::get_or_try_insert_with_tags`]. - pub async fn get_or_try_insert_local_with_tags( - &self, - ns: &str, - key: &str, - tags: &[String], - ttl: Duration, - factory: F, - ) -> Result - where - T: Serialize + DeserializeOwned + Send + Sync + 'static, - F: FnOnce() -> Fut, - Fut: Future>, - E: Clone + Send + Sync + 'static, - { - self.load(ns, key, tags, ttl, factory, false).await - } - - /// [`Cache::get_or_try_insert_local_with_tags`] for a value whose own + /// [`Cache::get_or_try_insert_local`] with logical tags (like + /// [`Cache::get_or_try_insert_with_tags`]), for a value whose own /// lifetime the factory knows: it returns the value with how long it may /// live, and the entry expires after the shorter of that and `ttl` (counted /// from the start of the fill). For a value copied from a record that diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index ac9d1d93..f4c13328 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -73,23 +73,18 @@ flate2 = { version = "1.1", default-features = false, features = ["zlib-rs"] } [dev-dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "macros", "fs", "io-util", "time", "net", "test-util"] } -forge-db = { path = "../db" } # NuGet, the format most integration tests use: the built-in plugin and its # Format (a dev-only cycle through forge-plugin, which Cargo permits). forge-format-nuget = { path = "../formats/nuget" } forge-plugin = { path = "../plugin" } argon2 = { workspace = true, features = ["password-hash"] } -serde_json = { workspace = true } -chrono = { workspace = true } zip = { version = "9.0", default-features = false, features = ["deflate"] } testcontainers = "0.27" testcontainers-modules = { version = "0.15", features = ["postgres"] } axum = { workspace = true } -forge-cache = { path = "../cache" } # Mock HTTP server for discovery/JWKS unit tests (no real network). wiremock = "0.6" # Generate a throwaway RSA keypair in-test: sign a self-signed ID token and # publish its public n/e in a static JWKS. Verifier is exercised end-to-end # without touching the network. rsa = { version = "0.9", features = ["sha2", "getrandom"] } -rand = { workspace = true } diff --git a/crates/core/src/auth/authz.rs b/crates/core/src/auth/authz.rs index 477100f9..66250040 100644 --- a/crates/core/src/auth/authz.rs +++ b/crates/core/src/auth/authz.rs @@ -513,20 +513,6 @@ fn deny_all_scope() -> TokenScope { mod tests { use super::*; - fn user() -> Principal { - Principal::User { - user_id: 42, - token_id: None, - method: crate::auth::AuthMethod::Password, - } - } - - fn anon() -> Principal { - Principal::Anonymous { - ip: "127.0.0.1".parse().unwrap(), - } - } - /// A pool that is never actually queried in the pure tests below (they cover /// only paths that short-circuit before any DB access). fn authz() -> Authz { @@ -583,10 +569,4 @@ mod tests { } assert!(!eff.is_admin()); } - - #[test] - fn principals_distinguish_user_anon() { - assert!(user().is_user()); - assert!(!anon().is_user()); - } } diff --git a/crates/core/src/auth/cred_cache.rs b/crates/core/src/auth/cred_cache.rs index 81ac9afc..d452f6ac 100644 --- a/crates/core/src/auth/cred_cache.rs +++ b/crates/core/src/auth/cred_cache.rs @@ -13,12 +13,12 @@ //! still reads it and avoids re-forwarding (the no in-memory-only-authoritative //! -state rule). //! * **Hot path:** [`forge_cache::Cache`], **in-process only** -//! ([`forge_cache::Cache::get_or_try_insert_local_with_tags`]) and keyed by -//! the credential HMAC, with the Postgres read as its factory. A verdict is -//! an authentication decision, so it never lives in Redis (anyone with -//! access to Redis could otherwise mark any password valid). Invalidation -//! broadcasts on the cache backplane so a revoke on one node drops the L1 -//! entry on every node. +//! ([`forge_cache::Cache::get_or_try_insert_local_with_tags_expiring`]) +//! and keyed by the credential HMAC, with the Postgres read as its factory. +//! A verdict is an authentication decision, so it never lives in Redis +//! (anyone with access to Redis could otherwise mark any password valid). +//! Invalidation broadcasts on the cache backplane so a revoke on one node +//! drops the L1 entry on every node. //! * **Success log:** every definitive upstream ACCEPT also records //! `(username, provider_id)` in `auth_success` //! ([`forge_db::validated_credential_dao::record_auth_success`]) — rejected @@ -212,10 +212,11 @@ struct CachedVerdict { /// Errors from a credential-cache lookup. /// -/// `Clone` because [`forge_cache::Cache::get_or_try_insert_with`] hands every -/// coalesced waiter a shared error on a failing factory — and, crucially, does -/// **not** cache it, which is exactly the fail-closed behavior we want for -/// [`Self::Unavailable`]. +/// `Clone` because +/// [`forge_cache::Cache::get_or_try_insert_local_with_tags_expiring`] hands +/// every coalesced waiter a shared error on a failing factory — and, +/// crucially, does **not** cache it, which is exactly the fail-closed behavior +/// we want for [`Self::Unavailable`]. #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] pub enum CredCacheError { /// The upstream was unavailable and there was no valid cached verdict. diff --git a/crates/core/src/auth/principal.rs b/crates/core/src/auth/principal.rs index 88bd04ee..682178e4 100644 --- a/crates/core/src/auth/principal.rs +++ b/crates/core/src/auth/principal.rs @@ -173,11 +173,6 @@ impl Principal { _ => None, } } - - /// Whether this principal is an authenticated user. - pub fn is_user(&self) -> bool { - matches!(self, Principal::User { .. }) - } } #[cfg(test)] @@ -238,19 +233,4 @@ mod tests { } ); } - - #[test] - fn is_user_only_for_user_variant() { - assert!(Principal::User { - user_id: 1, - token_id: None, - method: AuthMethod::Password - } - .is_user()); - assert!(!Principal::Unauthenticated.is_user()); - assert!(!Principal::Anonymous { - ip: "127.0.0.1".parse().unwrap() - } - .is_user()); - } } diff --git a/crates/core/src/net/upstream.rs b/crates/core/src/net/upstream.rs index 4b6e2b35..ba066f65 100644 --- a/crates/core/src/net/upstream.rs +++ b/crates/core/src/net/upstream.rs @@ -49,7 +49,6 @@ use std::time::Duration; use futures_util::future::BoxFuture; use hyper_util::client::proxy::matcher::Matcher as ProxyMatcher; use serde::{Deserialize, Serialize}; -use serde_json::Value as JsonValue; use tracing::Instrument; use url::Url; @@ -131,15 +130,6 @@ pub enum UpstreamError { /// Local spool / temp-file I/O failure. #[error("spool upstream body: {0}")] Io(#[from] std::io::Error), - /// The body was not valid JSON. - #[error("parse upstream JSON from {url}: {source}")] - Json { - /// Requested URL. - url: String, - /// Parser error. - #[source] - source: serde_json::Error, - }, /// The request, or a redirect hop, targets a link-local / cloud-metadata /// endpoint ([`is_metadata_target`], or a proxied name resolving to one). #[error("upstream GET {url}: refusing link-local / cloud-metadata target")] @@ -777,32 +767,9 @@ impl UpstreamHttp { .is_ok_and(|uri| self.proxies.intercept(&uri).is_some()) } - /// GET a JSON document. `Ok(None)` on a 404; any other non-2xx is an error. - /// The body is size-bounded while streaming and spooled to disk past the - /// in-memory threshold; parsing runs on the blocking pool. - pub async fn get_json( - &self, - url: &str, - auth: Option<&UpstreamAuth<'_>>, - ) -> Result, UpstreamError> { - let Some(spool) = self.get_metadata_body(url, auth, None).await? else { - return Ok(None); - }; - let url_owned = url.to_string(); - let parsed = tokio::task::spawn_blocking(move || { - serde_json::from_reader::<_, JsonValue>(std::io::BufReader::new(spool.into_reader()?)) - .map_err(|source| UpstreamError::Json { - url: url_owned, - source, - }) - }) - .await - .map_err(|e| UpstreamError::Io(std::io::Error::other(e)))??; - Ok(Some(parsed)) - } - - /// GET a small metadata body as bytes (e.g. a `.nuspec`). `Ok(None)` on 404. - pub async fn get_bytes( + /// [`Self::get_bytes_accepting`] without an `Accept` header. + #[cfg(test)] + async fn get_bytes( &self, url: &str, auth: Option<&UpstreamAuth<'_>>, @@ -810,7 +777,8 @@ impl UpstreamHttp { self.get_bytes_accepting(url, auth, None).await } - /// [`Self::get_bytes`] with an `Accept` header. + /// GET a small metadata body as bytes (e.g. a `.nuspec`), with an + /// optional `Accept` header. `Ok(None)` on 404. pub async fn get_bytes_accepting( &self, url: &str, @@ -998,7 +966,8 @@ impl SpooledBody { } /// Whether the body spilled to disk. - pub fn is_on_disk(&self) -> bool { + #[cfg(test)] + fn is_on_disk(&self) -> bool { self.inner.is_rolled() } @@ -1414,7 +1383,11 @@ mod tests { let url = serve_raw(resp.clone()).await; let http = UpstreamHttp::new(UpstreamHttpConfig::default()).unwrap(); - assert_eq!(http.get_json(&url, None).await.unwrap().unwrap(), doc); + let inflated = http.get_bytes(&url, None).await.unwrap().unwrap(); + assert_eq!( + serde_json::from_slice::(&inflated).unwrap(), + doc + ); // The cap applies to the decoded bytes, not just the compressed ones. let tight = UpstreamHttp::new(UpstreamHttpConfig { @@ -1424,7 +1397,7 @@ mod tests { .unwrap(); let url = serve_raw(resp).await; assert!(matches!( - tight.get_json(&url, None).await.unwrap_err(), + tight.get_bytes(&url, None).await.unwrap_err(), UpstreamError::TooLarge { limit: 8, .. } )); } diff --git a/crates/core/src/oidc/jwks.rs b/crates/core/src/oidc/jwks.rs index 5f1b34a9..e33f0bd7 100644 --- a/crates/core/src/oidc/jwks.rs +++ b/crates/core/src/oidc/jwks.rs @@ -245,13 +245,6 @@ impl OidcMetadataClient { self } - /// Override the discovery/JWKS TTLs (mainly for tests). - pub fn with_ttls(mut self, discovery_ttl: Duration, jwks_ttl: Duration) -> Self { - self.discovery_ttl = discovery_ttl; - self.jwks_ttl = jwks_ttl; - self - } - /// The configured issuer. pub fn issuer(&self) -> &str { &self.issuer @@ -424,33 +417,6 @@ impl OidcMetadataClient { .await } - /// Verify a JWT against this issuer, accepting **any** of `audiences` - /// (WIF: a workload realm trusts a set of allowed audiences and - /// presents no nonce). This is the shared core of [`verify_id_token`]: - /// signature against the cached JWKS (one kid-miss refetch), the RSA-only - /// algorithm allowlist, `iss` = configured issuer, `aud` ∈ `audiences`, - /// `exp`/`nbf` with leeway, and an optional `nonce` equality check. - /// - /// `audiences` must be non-empty; an empty slice would make `jsonwebtoken` - /// skip the audience check, so callers must pass at least one. - pub async fn verify_jwt( - &self, - token: &str, - audiences: &[&str], - nonce: Option<&str>, - leeway_seconds: u64, - ) -> Result { - self.verify_jwt_inner( - token, - audiences, - nonce, - leeway_seconds, - DiscoveryKind::Interactive, - false, - ) - .await - } - /// Verify a non-interactive workload JWT. /// /// This differs deliberately from browser-login ID-token verification: @@ -485,6 +451,14 @@ impl OidcMetadataClient { Ok(verified) } + /// The shared core of [`Self::verify_id_token`] and + /// [`Self::verify_workload_jwt`]: signature against the cached JWKS (one + /// kid-miss refetch), the RSA-only algorithm allowlist, `iss` = configured + /// issuer, `aud` ∈ `audiences`, `exp`/`nbf` with leeway, and an optional + /// `nonce` equality check. + /// + /// `audiences` must be non-empty; an empty slice would make `jsonwebtoken` + /// skip the audience check, so callers must pass at least one. async fn verify_jwt_inner( &self, token: &str, diff --git a/crates/core/src/repo/mod.rs b/crates/core/src/repo/mod.rs index bd77e6cf..a0f00b80 100644 --- a/crates/core/src/repo/mod.rs +++ b/crates/core/src/repo/mod.rs @@ -32,11 +32,6 @@ pub const NUPKG_ASSET_PATH: &str = "package.nupkg"; /// (NuGet's [`crate::format::Format::manifest_asset_path`]). pub const NUSPEC_ASSET_PATH: &str = "package.nuspec"; -/// Content type stored/served for the `.nupkg` asset. -pub const NUPKG_CONTENT_TYPE: &str = "application/octet-stream"; -/// Content type stored/served for the derived `.nuspec` asset. -pub const NUSPEC_CONTENT_TYPE: &str = "application/xml"; - /// Errors the read/write ops surface to callers. #[derive(Debug, thiserror::Error)] pub enum RepoError { diff --git a/crates/core/src/repo/proxy.rs b/crates/core/src/repo/proxy.rs index 8be174e5..b8db77a6 100644 --- a/crates/core/src/repo/proxy.rs +++ b/crates/core/src/repo/proxy.rs @@ -460,17 +460,6 @@ async fn upstream_password( .map_err(|e| RepoError::Storage(format!("decrypt upstream password: {e}"))) } -/// The upstream secret of `repo` alone, with the `remote_url` it belongs -/// to: what a proxy sends as a Bearer token when it has no username (npm -/// registries take a token). Decrypted like [`upstream_credentials`]. -pub async fn upstream_secret( - pool: &PgPool, - envelope: &forge_crypto::service::EnvelopeService, - repo: &Repository, -) -> Result)>, RepoError> { - upstream_password(pool, envelope, repo).await -} - /// The Basic credentials for `repo`'s upstream, if both a username and a /// password are configured. They are attached only to the origin of the /// `remote_url` the password was read (and, encrypted, bound) with, which diff --git a/crates/core/src/session/mod.rs b/crates/core/src/session/mod.rs index 673ba255..e6a13b77 100644 --- a/crates/core/src/session/mod.rs +++ b/crates/core/src/session/mod.rs @@ -105,12 +105,6 @@ impl SessionService { (lifetimes.idle, lifetimes.absolute) } - /// Override the `last_seen_at` touch throttle (mainly for tests). - pub fn with_touch_throttle_secs(mut self, secs: i64) -> Self { - self.touch_throttle_secs = secs; - self - } - /// Create a fresh session for `user_id`, returning the row + the one-time /// cookie secret. A new CSRF secret is generated and stored on the row for /// the double-submit defense. diff --git a/crates/crypto/src/service.rs b/crates/crypto/src/service.rs index 9d95713b..3394d157 100644 --- a/crates/crypto/src/service.rs +++ b/crates/crypto/src/service.rs @@ -434,7 +434,8 @@ impl EnvelopeService { /// references the key; the rotation paths use the commit-time checked /// [`Self::revoke_unreferenced_keks`] and `forge-db`'s /// `secret_dao::revoke_unreferenced_deks` instead. - pub async fn revoke_key(&self, layer: KeyLayer, version: i32) -> Result<(), CryptoError> { + #[cfg(test)] + async fn revoke_key(&self, layer: KeyLayer, version: i32) -> Result<(), CryptoError> { let rec = self .store .get_version(layer, self.scope(), version) @@ -444,10 +445,6 @@ impl EnvelopeService { scope: self.scope().to_string(), version, })?; - self.revoke(&rec).await - } - - async fn revoke(&self, rec: &KeyRecord) -> Result<(), CryptoError> { self.store.set_state(rec.id, KeyState::Revoked).await?; self.keys.invalidate(&(rec.layer, rec.version)).await; tracing::info!(layer = %rec.layer, version = rec.version, "revoked encryption key"); diff --git a/crates/db/Cargo.toml b/crates/db/Cargo.toml index b7e39e13..6728f0e7 100644 --- a/crates/db/Cargo.toml +++ b/crates/db/Cargo.toml @@ -34,7 +34,5 @@ base64 = { workspace = true } [dev-dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "macros", "net", "sync", "time"] } -chrono = { version = "0.4", default-features = false, features = ["clock", "serde"] } -sqlx = { workspace = true, features = ["json"] } testcontainers = "0.27" testcontainers-modules = { version = "0.15", features = ["postgres"] } diff --git a/crates/db/src/auth_realm_dao.rs b/crates/db/src/auth_realm_dao.rs index 5364d675..eb5a39d0 100644 --- a/crates/db/src/auth_realm_dao.rs +++ b/crates/db/src/auth_realm_dao.rs @@ -12,7 +12,6 @@ //! through [`crate::secret_dao`]'s realm helpers, which call //! [`update_realm_and_secrets`] here. -use chrono::{DateTime, Utc}; use serde_json::Value as JsonValue; use sqlx::{PgExecutor, PgPool}; @@ -438,16 +437,3 @@ pub async fn reorder_realms(pool: &PgPool, order: &[i64]) -> sqlx::Result sqlx::Result<(i64, Option>)> { - let row = sqlx::query!( - r#"SELECT count(*) AS "count!", max(updated_at) AS "max_updated" FROM auth_realm"# - ) - .fetch_one(pool) - .await?; - Ok((row.count, row.max_updated)) -} diff --git a/crates/db/src/model.rs b/crates/db/src/model.rs index 892cbd36..b7d8f245 100644 --- a/crates/db/src/model.rs +++ b/crates/db/src/model.rs @@ -410,14 +410,6 @@ pub const PREFER_HOSTED_KEY: &str = "prefer_hosted"; /// `repository.config` key of [`Repository::reserved_prefixes`]. pub const RESERVED_PREFIXES_KEY: &str = "reserved_prefixes"; -/// A row of `group_member`. -#[derive(Debug, Clone, sqlx::FromRow)] -pub struct GroupMember { - pub group_id: i64, - pub member_id: i64, - pub priority: i32, -} - /// A row of `blob`. #[derive(Debug, Clone, sqlx::FromRow)] pub struct Blob { diff --git a/crates/db/src/raw_dao.rs b/crates/db/src/raw_dao.rs index 7444dad6..d94b703e 100644 --- a/crates/db/src/raw_dao.rs +++ b/crates/db/src/raw_dao.rs @@ -71,29 +71,6 @@ pub async fn find(pool: &PgPool, repository_id: i64, path: &str) -> sqlx::Result .await } -/// Whether repository `repository_id` has a file under directory `prefix` -/// (`""`: any file). -pub async fn directory_exists( - pool: &PgPool, - repository_id: i64, - prefix: &str, -) -> sqlx::Result { - let (lower, upper) = prefix_range(prefix); - sqlx::query_scalar!( - r#" - SELECT EXISTS ( - SELECT 1 FROM raw_file - WHERE repository_id = $1 AND path >= $2 AND ($3::text IS NULL OR path < $3) - ) AS "exists!" - "#, - repository_id, - lower, - upper, - ) - .fetch_one(pool) - .await -} - /// Whether `repository_id` has any file. Pass the transaction that holds the /// repository row lock so the answer stays true until commit. pub async fn repository_has_files<'e, E>(executor: E, repository_id: i64) -> sqlx::Result diff --git a/crates/db/src/trusted_publisher_dao.rs b/crates/db/src/trusted_publisher_dao.rs index 7f89fd10..87b00044 100644 --- a/crates/db/src/trusted_publisher_dao.rs +++ b/crates/db/src/trusted_publisher_dao.rs @@ -4,8 +4,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; use sqlx::{PgConnection, PgPool, Row, Transaction}; -use crate::model::Repository; - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct TrustedPublisherMatch { pub id: i64, @@ -93,26 +91,6 @@ pub async fn list_for_repository( rows.iter().map(from_row).collect() } -pub async fn find_for_repository( - pool: &PgPool, - repository_id: i64, - id: i64, -) -> sqlx::Result> { - let row = sqlx::query( - r#" - SELECT id, repository_id, realm_id, name, description, includes, - excludes, conditions, actions - FROM trusted_publisher - WHERE repository_id = $1 AND id = $2 - "#, - ) - .bind(repository_id) - .bind(id) - .fetch_optional(pool) - .await?; - row.as_ref().map(from_row).transpose() -} - pub async fn list_for_realm(pool: &PgPool, realm_id: i64) -> sqlx::Result> { let rows = sqlx::query( r#" @@ -332,7 +310,3 @@ pub async fn hosted_repository(pool: &PgPool, repository_id: i64) -> sqlx::Resul .fetch_one(pool) .await } - -pub fn validate_repository(repository: &Repository) -> bool { - repository.kind() == crate::model::RepoKind::Hosted -} diff --git a/crates/db/src/user_dao.rs b/crates/db/src/user_dao.rs index e3b894d6..b52ad49f 100644 --- a/crates/db/src/user_dao.rs +++ b/crates/db/src/user_dao.rs @@ -475,25 +475,6 @@ where Ok(res.rows_affected() > 0) } -/// Record which auth realm vouches for this user. For credential-forwarding -/// accounts this is an authorization input: only that realm may sign the -/// account in (see [`find_upstream_user`]). A no-op write when the value -/// is unchanged. -pub async fn set_user_realm(pool: &PgPool, user_id: i64, realm_id: i64) -> sqlx::Result<()> { - sqlx::query!( - r#" - UPDATE app_user - SET realm_id = $2 - WHERE id = $1 AND realm_id IS DISTINCT FROM $2 - "#, - user_id, - realm_id, - ) - .execute(pool) - .await?; - Ok(()) -} - /// The `credential_forwarding` realm config key that opts the realm in to /// keeping a password hash of the logins its upstream accepts. pub const CAPTURE_PASSWORD_HASH_KEY: &str = "capture_password_hash"; diff --git a/crates/db/tests/raw.rs b/crates/db/tests/raw.rs index de6728fc..83a7e407 100644 --- a/crates/db/tests/raw.rs +++ b/crates/db/tests/raw.rs @@ -238,12 +238,6 @@ async fn listings_walk_entries_in_byte_order_and_page() { .unwrap(); assert_eq!(names(&sub, "top/N/"), ["a", "b/", "z"]); - assert!(raw_dao::directory_exists(&pool, repo, "top/N/") - .await - .unwrap()); - assert!(!raw_dao::directory_exists(&pool, repo, "top/M/") - .await - .unwrap()); assert_eq!( raw_dao::paths_under(&pool, repo, "top/N/", "top/N/a", 10) .await diff --git a/crates/e2e/Cargo.toml b/crates/e2e/Cargo.toml index 4676dbab..e22d1e4e 100644 --- a/crates/e2e/Cargo.toml +++ b/crates/e2e/Cargo.toml @@ -30,7 +30,6 @@ axum = { workspace = true } sqlx = { workspace = true, features = ["migrate"] } serde = { workspace = true } serde_json = { workspace = true } -anyhow = { workspace = true } tracing = { workspace = true } reqwest = { workspace = true, features = ["multipart"] } @@ -61,11 +60,4 @@ aws-credential-types = { workspace = true } [dev-dependencies] forge-format-npm = { path = "../formats/npm" } -serde_json = { workspace = true } -sqlx = { workspace = true } -reqwest = { workspace = true, features = ["multipart"] } -base64 = { workspace = true } -sha2 = { workspace = true } -futures-util = { workspace = true } -chrono = { workspace = true } tempfile = "3" diff --git a/crates/formats/apt/Cargo.toml b/crates/formats/apt/Cargo.toml index 49340478..8b5ae02d 100644 --- a/crates/formats/apt/Cargo.toml +++ b/crates/formats/apt/Cargo.toml @@ -16,7 +16,6 @@ serde_json = { workspace = true } chrono = { workspace = true } sha2 = { workspace = true } hex = { workspace = true } -base64 = { workspace = true } url = { workspace = true } # A .deb is an ar archive whose control member is a tar, compressed with # gzip, xz or zstd (or not at all); indexes are published as gzip and xz. diff --git a/crates/formats/docker/src/chart.rs b/crates/formats/docker/src/chart.rs index 457aec24..29bd16b4 100644 --- a/crates/formats/docker/src/chart.rs +++ b/crates/formats/docker/src/chart.rs @@ -18,8 +18,6 @@ pub mod media { pub const CONFIG: &str = "application/vnd.cncf.helm.config.v1+json"; /// The layer holding the packaged chart (`-.tgz`). pub const CONTENT: &str = "application/vnd.cncf.helm.chart.content.v1.tar+gzip"; - /// The optional layer holding the chart's provenance file (`.prov`). - pub const PROVENANCE: &str = "application/vnd.cncf.helm.chart.provenance.v1.prov"; } /// Whether a layer of a chart is its packaged archive: Helm's media type, diff --git a/crates/formats/npm/Cargo.toml b/crates/formats/npm/Cargo.toml index a23b8b8b..56e0c718 100644 --- a/crates/formats/npm/Cargo.toml +++ b/crates/formats/npm/Cargo.toml @@ -27,4 +27,3 @@ semver = "1" [dev-dependencies] forge-plugin-api = { path = "../../plugin-api", features = ["testing"] } -tempfile = { workspace = true } diff --git a/crates/formats/npm/src/publish.rs b/crates/formats/npm/src/publish.rs index c4b7652a..32a54e68 100644 --- a/crates/formats/npm/src/publish.rs +++ b/crates/formats/npm/src/publish.rs @@ -143,11 +143,6 @@ impl Extractor { } } - /// Whether the extractor is inside the attachment's data, or past it. - pub fn found_attachment(&self) -> bool { - self.attachment.is_some() - } - fn malformed(&self, what: &str) -> ExtractError { ExtractError::Malformed(format!("{what} at byte {}", self.offset)) } diff --git a/crates/formats/nuget/src/nuspec.rs b/crates/formats/nuget/src/nuspec.rs index 9500f1c3..8fb32852 100644 --- a/crates/formats/nuget/src/nuspec.rs +++ b/crates/formats/nuget/src/nuspec.rs @@ -190,11 +190,6 @@ impl NuspecMetadata { } } -/// Extract the display metadata from raw `.nuspec` bytes. -pub fn metadata_from_nuspec(bytes: &[u8]) -> Result { - Ok(parse_nuspec(bytes).map_err(FormatError::from)?.metadata) -} - /// What the feed renders from a `.nuspec`: its display metadata and /// dependency groups. Computed once at publish and stored with the version /// (`component.manifest_summary`), so registration pages and search results diff --git a/crates/formats/nuget/tests/parse.rs b/crates/formats/nuget/tests/parse.rs index 1e30b782..00ff0b28 100644 --- a/crates/formats/nuget/tests/parse.rs +++ b/crates/formats/nuget/tests/parse.rs @@ -90,8 +90,9 @@ fn parses_a_utf16_manifest_with_a_byte_order_mark() { // The stored manifest is the package's own bytes, still UTF-16. assert_eq!(&parsed.manifest[..4], b"\xff\xfe<\x00"); - let metadata = forge_format_nuget::nuspec::metadata_from_nuspec(&parsed.manifest) - .expect("metadata of the stored manifest"); + let metadata = forge_format_nuget::nuspec::manifest_summary(&parsed.manifest) + .expect("metadata of the stored manifest") + .metadata; assert_eq!( metadata.description.as_deref(), Some("A manifest in UTF-16 \u{a9} Forge \u{1f4e6}") diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index b40bf757..712f3bb5 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -122,21 +122,14 @@ tikv-jemallocator = { version = "0.7", features = ["background_threads"] } [dev-dependencies] # Small MaxMind databases for the traffic statistics' tests. forge-traffic = { path = "../traffic", features = ["testing"] } -tar = { version = "0.4", default-features = false } -# Builds Helm chart archives for the registry tests. -flate2 = { version = "1.1", default-features = false, features = ["zlib-rs"] } tokio = { workspace = true, features = ["rt-multi-thread", "macros", "fs", "io-util", "time", "test-util"] } testcontainers = "0.27" testcontainers-modules = { version = "0.15", features = ["postgres"] } reqwest = { workspace = true, features = ["multipart", "query"] } -forge-format-nuget = { path = "../formats/nuget" } http-body-util = "0.1" -tower = { version = "0.5", features = ["util"] } figment = { version = "0.10", features = ["toml", "env", "test"] } zip = { version = "9.0", default-features = false, features = ["deflate"] } -serde_json = { workspace = true } tempfile = { workspace = true } -chrono = { workspace = true, features = ["serde"] } # Retention schedules' local times in the admin API tests. chrono-tz = { workspace = true } # Mock OIDC IdP for the /auth route integration tests: serve @@ -144,10 +137,6 @@ chrono-tz = { workspace = true } # Mirrors the forge-core OIDC test harness. wiremock = "0.6" rsa = { version = "0.9", features = ["sha2", "getrandom"] } -jsonwebtoken = { workspace = true } -base64 = { workspace = true } -rand = { workspace = true } -sqlx = { workspace = true } # The OpenTelemetry tests: in-memory exporters (tests/telemetry.rs), and a # mock OTLP/HTTP receiver decoding what is exported (tests/otlp_export.rs). opentelemetry_sdk = { workspace = true, features = ["testing"] } diff --git a/crates/server/src/auth/wif.rs b/crates/server/src/auth/wif.rs index e0037fd5..bb84b920 100644 --- a/crates/server/src/auth/wif.rs +++ b/crates/server/src/auth/wif.rs @@ -1033,7 +1033,7 @@ fn basic_credentials(b64: &str) -> Option<(String, String)> { /// If `secret` structurally parses as a JWT (three segments; header decodes with /// a real, non-`none` `alg`), return its **unverified** `iss` claim — used only /// to route to a realm; the cryptographic verification happens in -/// [`OidcMetadataClient::verify_jwt`]. Returns `None` for anything that is not a +/// [`OidcMetadataClient::verify_workload_jwt`]. Returns `None` for anything that is not a /// well-formed JWT carrying a string `iss`. fn jwt_issuer(secret: &str) -> Option { let mut parts = secret.split('.'); diff --git a/crates/server/src/config.rs b/crates/server/src/config.rs index e00a0251..f5ca3165 100644 --- a/crates/server/src/config.rs +++ b/crates/server/src/config.rs @@ -805,28 +805,6 @@ impl std::fmt::Debug for UpstreamBasicAuthConfig { } } -impl UpstreamBasicAuthConfig { - /// Build the `forge-core` provider config from this block. - pub fn to_core(&self) -> forge_core::auth::UpstreamBasicConfig { - forge_core::auth::UpstreamBasicConfig { - url: self.url.clone(), - method: self.method.to_ascii_uppercase(), - success_status: self.success_status.clone(), - reject_status: self.reject_status.clone(), - connect_timeout: Duration::from_millis(self.connect_timeout_ms), - request_timeout: Duration::from_millis(self.request_timeout_ms), - required_groups: self.required_groups.clone(), - groups_path: self.groups_path.clone(), - identity_path: self.identity_path.clone(), - admin_group: self.admin_group.clone(), - provider_id: forge_core::auth::UPSTREAM_BASIC_ID.to_string(), - realm_id: None, - // Kept hashes are bound to a realm row; the legacy block has none. - capture_password_hash: false, - } - } -} - /// `auth.upstream_basic.cache.*` — the validated-credential cache tuning. /// Unknown keys are refused (see [`UpstreamBasicAuthConfig`]). #[derive(Clone, Deserialize)] @@ -1970,10 +1948,6 @@ impl std::fmt::Debug for OidcConfig { } impl OidcConfig { - /// Clock-skew leeway as a [`Duration`]. - pub fn clock_skew(&self) -> Duration { - Duration::from_secs(self.clock_skew_seconds) - } /// Scopes with `openid` guaranteed present (added first if missing). pub fn effective_scopes(&self) -> Vec { let mut out = Vec::with_capacity(self.scopes.len() + 1); @@ -4688,11 +4662,6 @@ mod tests { assert_eq!(ub.request_timeout_ms, 5000); assert_eq!(ub.cache.positive_ttl_secs, 300); assert_eq!(ub.cache.negative_ttl_secs, 30); - // to_core mirrors the block. - let core = ub.to_core(); - assert_eq!(core.url, ub.url); - assert_eq!(core.method, "GET"); - assert_eq!(core.connect_timeout, Duration::from_millis(2000)); } #[test] diff --git a/crates/server/src/email/settings.rs b/crates/server/src/email/settings.rs index f26ba941..e51d53a2 100644 --- a/crates/server/src/email/settings.rs +++ b/crates/server/src/email/settings.rs @@ -10,7 +10,6 @@ //! secret belongs to changed ([`merge_secrets`]). use std::net::IpAddr; -use std::time::Duration; use lettre::message::Mailbox; use lettre::Address; @@ -490,11 +489,6 @@ impl EmailConfig { .transpose() } - /// How long an invitation stays valid. - pub fn invitation_ttl(&self) -> Duration { - Duration::from_secs(u64::from(self.invitation_ttl_hours) * 3600) - } - /// The document without its secrets, as the API returns it: each secret /// becomes `_set: true|false`. pub fn redacted(&self) -> JsonValue { diff --git a/crates/server/src/import/apt.rs b/crates/server/src/import/apt.rs index ac94c5d4..d1ac5dac 100644 --- a/crates/server/src/import/apt.rs +++ b/crates/server/src/import/apt.rs @@ -210,7 +210,7 @@ impl AptSource { .http .get(url, RequestClass::Metadata, self.auth().as_ref()) .await - .map_err(|e| SourceError::of(e, url))?; + .map_err(SourceError::of)?; let status = response.status(); let server = response .headers() @@ -230,7 +230,7 @@ impl AptSource { config.spool_memory_bytes, ) .await - .map_err(|e| SourceError::of(e, url))?; + .map_err(SourceError::of)?; self.http.count_bytes(body.len()); let bytes = tokio::task::spawn_blocking(move || -> std::io::Result> { let mut out = Vec::new(); @@ -360,7 +360,7 @@ impl AptSource { .http .get(&url, RequestClass::Download, self.auth().as_ref()) .await - .map_err(|e| SourceError::of(e, &url))?; + .map_err(SourceError::of)?; match response.status() { s if s.is_success() => Ok(Some(response)), StatusCode::NOT_FOUND | StatusCode::GONE => Ok(None), diff --git a/crates/server/src/import/feed.rs b/crates/server/src/import/feed.rs index 368c0513..1ef25ba2 100644 --- a/crates/server/src/import/feed.rs +++ b/crates/server/src/import/feed.rs @@ -78,7 +78,7 @@ impl Feed { .http .get(url, RequestClass::Metadata, feed.auth().as_ref()) .await - .map_err(|e| SourceError::of(e, url))?; + .map_err(SourceError::of)?; if !response.status().is_success() { return Err(SourceError::status(response.status(), url)); } @@ -189,7 +189,7 @@ impl Feed { .http .get(url, RequestClass::Download, self.auth().as_ref()) .await - .map_err(|e| SourceError::of(e, url))?; + .map_err(SourceError::of)?; if !response.status().is_success() { return Err(SourceError::status(response.status(), url)); } @@ -266,7 +266,7 @@ impl Feed { } Ok(None) => (Fetched::NotFound, Some(404)), Err(e) => { - let error = SourceError::of(e, &fetch.url); + let error = SourceError::of(e); let status = error.status_code(); let reason = error.to_string(); trouble.get_or_insert(error); @@ -301,11 +301,10 @@ fn unexpected(what: &str, answer: &UpstreamAnswer) -> SourceError { } impl SourceError { - /// A transport or status error of the upstream client for `url`. - pub fn of(e: UpstreamError, url: &str) -> Self { + /// A transport or status error of the upstream client. + pub fn of(e: UpstreamError) -> Self { match e { UpstreamError::Status { status, url } => SourceError::status(status, &url), - UpstreamError::Json { source, .. } => SourceError::Invalid(format!("{url}: {source}")), other => SourceError::Unreachable(other.to_string()), } } diff --git a/crates/server/src/import/npm.rs b/crates/server/src/import/npm.rs index aab3dcf1..82928378 100644 --- a/crates/server/src/import/npm.rs +++ b/crates/server/src/import/npm.rs @@ -91,7 +91,7 @@ impl NpmRegistry { .http .get(&url, RequestClass::Metadata, self.auth().as_ref()) .await - .map_err(|e| SourceError::of(e, &url))?; + .map_err(SourceError::of)?; self.server = response .headers() .get(reqwest::header::SERVER) @@ -120,7 +120,7 @@ impl NpmRegistry { { Ok(body) => Ok(body), Err(UpstreamError::Status { status, .. }) if not_served(status) => Ok(None), - Err(e) => Err(SourceError::of(e, url)), + Err(e) => Err(SourceError::of(e)), } } @@ -204,9 +204,9 @@ impl NpmRegistry { self.http .get_metadata_body(&url, self.auth().as_ref(), Some(ABBREVIATED_ACCEPT)) .await - .map_err(|e| SourceError::of(e, &url))? + .map_err(SourceError::of)? } - Err(e) => return Err(SourceError::of(e, &url)), + Err(e) => return Err(SourceError::of(e)), }; let Some(body) = body else { return Ok(None); @@ -233,7 +233,7 @@ impl NpmRegistry { .http .get(url, RequestClass::Download, self.auth().as_ref()) .await - .map_err(|e| SourceError::of(e, url))?; + .map_err(SourceError::of)?; if !response.status().is_success() { return Err(SourceError::status(response.status(), url)); } diff --git a/crates/server/src/import/raw.rs b/crates/server/src/import/raw.rs index ab93ac49..345ad401 100644 --- a/crates/server/src/import/raw.rs +++ b/crates/server/src/import/raw.rs @@ -288,7 +288,7 @@ impl RawSource { self.auth().as_ref(), ) .await - .map_err(|e| SourceError::of(e, url))?; + .map_err(SourceError::of)?; let status = response.status(); let server = header(&response, reqwest::header::SERVER); if !status.is_success() { @@ -310,7 +310,7 @@ impl RawSource { config.spool_memory_bytes, ) .await - .map_err(|e| SourceError::of(e, url))?; + .map_err(SourceError::of)?; let bytes = tokio::task::spawn_blocking(move || -> std::io::Result> { let mut out = Vec::new(); std::io::Read::read_to_end(&mut body.into_reader()?, &mut out)?; @@ -362,7 +362,7 @@ impl RawSource { self.auth().as_ref(), ) .await - .map_err(|e| SourceError::of(e, &url))?; + .map_err(SourceError::of)?; self.server = header(&response, reqwest::header::SERVER); let status = response.status(); if matches!(status, StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN) @@ -427,7 +427,7 @@ impl RawSource { self.auth().as_ref(), ) .await - .map_err(|e| SourceError::of(e, &url))?; + .map_err(SourceError::of)?; let status = response.status(); match status { StatusCode::NOT_FOUND | StatusCode::GONE => return Ok(None), @@ -469,7 +469,7 @@ impl RawSource { .http .get(&url, RequestClass::Download, self.auth().as_ref()) .await - .map_err(|e| SourceError::of(e, &url))?; + .map_err(SourceError::of)?; match response.status() { s if s.is_success() => Ok(Some(response)), StatusCode::NOT_FOUND | StatusCode::GONE => Ok(None), diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index 4e488caa..a739edec 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -37,6 +37,5 @@ tokio = { workspace = true, features = ["rt-multi-thread", "macros", "fs", "io-u # In-process fake S3 endpoint for the multipart-abort tests (fault injection # versitygw cannot do). axum = { workspace = true } -sqlx = { workspace = true } testcontainers = "0.27" testcontainers-modules = { version = "0.15", features = ["postgres"] } diff --git a/crates/traffic/Cargo.toml b/crates/traffic/Cargo.toml index 4b897f4a..b03550ba 100644 --- a/crates/traffic/Cargo.toml +++ b/crates/traffic/Cargo.toml @@ -28,7 +28,6 @@ rand = { workspace = true } [dev-dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "macros", "sync", "time"] } -serde_json = { workspace = true } [features] # `testing`: a writer of small MaxMind databases, for the tests of the crates diff --git a/web/.gitignore b/web/.gitignore index 9af5c7b5..8a6f2bae 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -9,3 +9,6 @@ dist/ /blob-report/ /.last-run.json e2e/.harness-facts.json + +# TypeScript incremental build state +*.tsbuildinfo diff --git a/web/e2e/helpers.ts b/web/e2e/helpers.ts index 5bfee7e4..9353eae5 100644 --- a/web/e2e/helpers.ts +++ b/web/e2e/helpers.ts @@ -74,20 +74,6 @@ export async function createRepo(body: Record): Promise { - const f = facts() - return fetch(`${f.baseUrl}/admin/repositories/${group}/members`, { - method: 'POST', - headers: { authorization: adminBasic(), 'content-type': 'application/json' }, - body: JSON.stringify({ member, priority }), - }) -} - /** * Fetch a package's browse detail (the read endpoint the SPA's detail page * uses). For a proxy it answers from what the proxy has cached and asks no diff --git a/web/package.json b/web/package.json index 2ef89d8f..eec8337a 100644 --- a/web/package.json +++ b/web/package.json @@ -31,8 +31,6 @@ "devDependencies": { "@playwright/test": "1.64.1", "@tailwindcss/vite": "4.3.3", - "@tanstack/react-query-devtools": "5.104.5", - "@tanstack/react-router-devtools": "1.167.2", "@tanstack/router-plugin": "1.168.48", "@tanstack/virtual-file-routes": "1.162.0", "@testing-library/jest-dom": "7.0.1", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index b0c06c7f..4ec3ec7b 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -40,12 +40,6 @@ importers: '@tailwindcss/vite': specifier: 4.3.3 version: 4.3.3(vite@8.3.5(@types/node@26.6.5)(jiti@2.7.0)) - '@tanstack/react-query-devtools': - specifier: 5.104.5 - version: 5.104.5(@tanstack/react-query@5.104.5(@types/react@19.3.0)(react@19.3.1))(@types/react@19.3.0)(csstype@3.2.3)(react@19.3.1) - '@tanstack/react-router-devtools': - specifier: 1.167.2 - version: 1.167.2(@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(@tanstack/router-core@1.171.39)(csstype@3.2.3)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) '@tanstack/router-plugin': specifier: 1.168.48 version: 1.168.48(@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(rolldown@1.2.15)(vite@8.3.5(@types/node@26.6.5)(jiti@2.7.0)) @@ -181,11 +175,6 @@ packages: resolution: {integrity: sha512-0GEz8qJWokkUVYQYRukmkSHIFNoBH8QTreeHrAFbvz1XFYc3Y+puhMs8PQ5x8GNugiC2l5jvDBXKLbBIByeSBw==} hasBin: true - '@corvu/utils@0.4.2': - resolution: {integrity: sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA==} - peerDependencies: - solid-js: ^1.8 - '@csstools/color-helpers@6.1.2': resolution: {integrity: sha512-grhRy3OKmniaAEKXMjua5z/EODX0MSqBGjunw8+j/3HQjOnahs2AGhvEOIYVUWcU6ScApbhLhVrQTX8XqrMrow==} engines: {node: '>=20.19.0'} @@ -231,24 +220,12 @@ packages: '@noble/hashes': optional: true - '@floating-ui/core@1.8.0': - resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} - - '@floating-ui/dom@1.8.0': - resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} - - '@floating-ui/utils@0.2.12': - resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} - '@fontsource-variable/ibm-plex-sans@5.3.0': resolution: {integrity: sha512-agG8tXFEo0hD9+J7npa4vbbWult52eMLVaQ6WQRlhs/iCAojrMAoejru85W9HTVXHfyUj96KM7gp/KGAS87XaQ==} '@fontsource-variable/jetbrains-mono@5.3.0': resolution: {integrity: sha512-F32xpS2NsGYoQi2ADSkKTgpJj7ozajsGgDJ8woTnqjmIB+dxDIqImjl4pXZVEExu8UFZ2ndhmX18EBS/hdz3Lw==} - '@internationalized/number@3.6.9': - resolution: {integrity: sha512-GgWy2caO/+hV9sT/oCTWGHvbjmJMPT9kkXzoKRLnkEq7adghhR7UprhvY9sXrKfrp3NcDfhF6QQHXR1KfQbB8g==} - '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -265,16 +242,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@kobalte/core@0.13.14': - resolution: {integrity: sha512-SBVB1lnvYbYt2x3t7fG0lo5fGLEbHQ6PII3NDPva8vD5e2v53On84ZVQiuIk0XI/55R4GQhden7Yem+R/XR8uQ==} - peerDependencies: - solid-js: ^1.9.8 - - '@kobalte/utils@0.9.2': - resolution: {integrity: sha512-jRVXr+zsVHxzDXRoh+CDeXzvCsFJ6uiHhqqNQ26Cw9ZsZ3D6nqPUBt1gGVtj2ZPmRL3a9Uk1v8D1aJ8/I12Dow==} - peerDependencies: - solid-js: ^1.8.8 - '@oxc-project/types@0.155.0': resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==} @@ -382,74 +349,6 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@solid-primitives/event-listener@2.4.6': - resolution: {integrity: sha512-5I0YJcTVYIWoMmgBSROBZGcz+ymhew/pGTg2dHW74BUjFKsV8Li4bOZYl0YAGP4mHw5o4UBd9/BEesqBci3wxw==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/keyed@1.5.3': - resolution: {integrity: sha512-zNadtyYBhJSOjXtogkGHmRxjGdz9KHc8sGGVAGlUABkE8BED2tbIZoxkwSqzOwde8OcUEH0bb5DLZUWIMvyBSA==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/map@0.4.13': - resolution: {integrity: sha512-B1zyFbsiTQvqPr+cuPCXO72sRuczG9Swncqk5P74NCGw1VE8qa/Ry9GlfI1e/VdeQYHjan+XkbE3rO2GW/qKew==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/media@2.3.6': - resolution: {integrity: sha512-pk49gPOq/UMRUJ+pTSrOfBiR8xJjRYHXIf1iR/jSnyQ/KroU+ZXhkZzavC7hvfp2vJeOTW5k2/HN0r3Q1VJ7Pw==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/props@3.2.4': - resolution: {integrity: sha512-MXXdvi2TSB6d+0N6ueA/HP1j/Kh9SEc4WdF1ZDMLwPagxW6pIHHSS9xbRO0RjqSVpNP4j0nxCWT1hx3CkJNhNA==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/refs@1.1.4': - resolution: {integrity: sha512-bLjwIs6ZPu8NQnuw04sU3Zc8qKSpbc0umUU/O4SHf6oWOdO4+dHY8vb1T7C4b/Tg103+9WGr6sEE0+NFlbaB/A==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/resize-observer@2.2.0': - resolution: {integrity: sha512-9Fuu/EWBeGj+atGHRJp70HKhdfalmpjwxY8a32NZixdLNmfCJ45AfhLQNr6uOzETbbiMx4iCKlTrJ8KZCHC2Ww==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/rootless@1.5.4': - resolution: {integrity: sha512-TOIZa1VUfVJ+9nkCcRajw3U4t9vBOP1HxX1WHNTbXq32mXwlqTvUnC4CRIilohcryBkT9u2ZkhUDSHRTaGp55g==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/static-store@0.1.4': - resolution: {integrity: sha512-LgtVaVBtB7EbmS4+M0b8xY5Iq6pUWXBsIC4VgtrFKDGDdyCaDt88sHk0fUlx1Enxm/XZnZyLXJABRoa39RjJqA==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/storage@1.3.11': - resolution: {integrity: sha512-PpQWR3TaTxHIJFbI9ZssYTM4Aa67g1vJIgps4TPhcXzHqqomrPAIveFC2FG7SDQoi9YQia8FVBjigELziJpfIg==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/transition-group@1.1.2': - resolution: {integrity: sha512-gnHS0OmcdjeoHN9n7Khu8KNrOlRc8a2weETDt2YT6o1zeW/XtUC6Db3Q9pkMU/9cCKdEmN4b0a/41MKAHRhzWA==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/trigger@1.2.4': - resolution: {integrity: sha512-Ju0e+ZOD7hpOp7nptJimvDSZHWFvIvF9iBWMvuwt30smX7c5wmB8Kmc0AdDuv0wOTi06PQ1J5IrP1WJbH2yUBQ==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/utils@6.4.1': - resolution: {integrity: sha512-ISSB5QX1qP2ynrheIpYwc4oKR5Ny4siNuUyf1qZniy+Il+p/PtDB0QK1Dnle8noiHpwRD3gpPdubOC3qI/Zamg==} - peerDependencies: - solid-js: ^1.6.12 - - '@swc/helpers@0.5.23': - resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} - '@tailwindcss/node@4.3.3': resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} @@ -548,26 +447,9 @@ packages: resolution: {integrity: sha512-w1+YvwmTkwt5n8yUqEH3IWZ9DsmorCZW/EQ3KYHnqEgIkOZpH54NvW6/Epq3Dzb8H0ifIeYX8PExvrNLIH5FIA==} engines: {node: '>=20.19'} - '@tanstack/match-sorter-utils@9.2.6': - resolution: {integrity: sha512-DIpUSOhPfQ7u/qfUi/Wgm0wBO56MyBYXGvnlI0NcauDRPqdBUlAZZjW2Dxm92m+k1UWVhKw8YJ4f47+75Aujyw==} - engines: {node: '>=20'} - '@tanstack/query-core@5.104.5': resolution: {integrity: sha512-Q94gI8Opd+CbdVNOdj8ZCyV8WqLYitrDq1t96Xc8WZT6lY0r5iRnJLXYDxMex7EEf2v+mXvn4FcjaBKSxXZQ9A==} - '@tanstack/query-devtools@5.104.5': - resolution: {integrity: sha512-BLVEw4lFF7aIRsfqGvI50SSR9oN46/EmlygC+3h5TUdI+fL8GnMQialL3H92TbYi7J1b/hYlUGnckBT2uG5h8w==} - - '@tanstack/react-query-devtools@5.104.5': - resolution: {integrity: sha512-2SMhSSYnOGSaPLuSTKLOj5nPoP4sqasOfkpTn5BLe6LIZuHzrpcqrJx0Rm8uUSN5Ob4lPAbh/1oWClnnGaR7Bg==} - peerDependencies: - '@tanstack/react-query': ^5.104.5 - '@types/react': ^18 || ^19 - react: ^18 || ^19 - peerDependenciesMeta: - '@types/react': - optional: true - '@tanstack/react-query@5.104.5': resolution: {integrity: sha512-RORgFe052U+93weaNuqg7qHq7vNVNzXN/VrXqD4bbAuQCWUqOl2lV5Ui9flWk5CVvMyL/Bh27QWhzwH0aaOx9g==} peerDependencies: @@ -577,18 +459,6 @@ packages: '@types/react': optional: true - '@tanstack/react-router-devtools@1.167.2': - resolution: {integrity: sha512-VuoqB7OhDUrBa4WOFSKiAQ8xI8sJpeZdo9sYE1hQa89iMuVFUQu1iWE4iCiQhB+6TYOZDZ9e+iHKxYjop4ZVYw==} - engines: {node: '>=20.19'} - peerDependencies: - '@tanstack/react-router': ^1.170.36 - '@tanstack/router-core': ^1.171.30 - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - peerDependenciesMeta: - '@tanstack/router-core': - optional: true - '@tanstack/react-router@1.170.46': resolution: {integrity: sha512-ez1iNIhsPjGlaDHg3BXWs67EWVIYzB2tbopEHYDESdkO7owgkGb5de52+5Kv2v1fxdkggcNzo35bdk4arTVGQw==} engines: {node: '>=20.19'} @@ -606,16 +476,6 @@ packages: resolution: {integrity: sha512-qUhoJ0meuSUqGYQbHbcJYdASr06YtK+bulbj6vtrhKYFkLgkSsZ6tXmMyym7sFxiSJSPYgasgozrL01LyyR/6A==} engines: {node: '>=20.19'} - '@tanstack/router-devtools-core@1.168.2': - resolution: {integrity: sha512-pCCdQ5M/NUeWdiAbPmjyfcNdls6G4vaVlIQbPf1IqZk1FLYFr00aQvi578yUuWFBNM2KNS2QcwM1uPucbtGf5Q==} - engines: {node: '>=20.19'} - peerDependencies: - '@tanstack/router-core': ^1.171.30 - csstype: ^3.0.10 - peerDependenciesMeta: - csstype: - optional: true - '@tanstack/router-generator@1.167.46': resolution: {integrity: sha512-JSailAThcqPvqBzE3+MhNh6zQyZM2IdmIsHOxZgAc061Lh++SZqamNm/Whe7QNXWK5sLP4E0J1F8AI0hP8wTSw==} engines: {node: '>=20.19'} @@ -920,10 +780,6 @@ packages: cookie-es@3.1.1: resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} - copy-anything@4.1.5: - resolution: {integrity: sha512-vePst2VLTSqPglW7Q98VwFpGiGpOHTyXIo81MO5VyLecA5zMbZw/P/V1vmwD1jksa2iJpn/YkDrJ3XhTfzUyhQ==} - engines: {node: '>=18'} - css-tree@3.2.1: resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} @@ -1011,11 +867,6 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - goober@2.1.19: - resolution: {integrity: sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==} - peerDependencies: - csstype: ^3.0.10 - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -1308,9 +1159,6 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} - remove-accents@0.5.0: - resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} - require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -1331,12 +1179,6 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - seroval-plugins@1.6.12: - resolution: {integrity: sha512-+reiwp/lYxiyctSrdvX7OQ1YLrcbWYgBiZrhSFL+V43b0/DGRLNVSDyZINbQe+tWplPOI2fw2dPrdv6hcc09kQ==} - engines: {node: '>=10'} - peerDependencies: - seroval: ~1.6.11 - seroval-plugins@1.7.2: resolution: {integrity: sha512-ud8kMCGLHmGkW9YtVDluJtqTukSx/4YBqtmPAvAz/HxbIwhwMeZU52imxeyZ1zoAXtqBDiaLwSasbnK9DptrDg==} engines: {node: '>=20'} @@ -1347,25 +1189,6 @@ packages: resolution: {integrity: sha512-CqbIVfk/7GL3ITwZI55lcPbpQbjHZ2DD5cUj4iH7E9YsCfHNJV1mx7yNp86Z84w5IpmkZZS/2s5vPOWmVWSdQg==} engines: {node: '>=10'} - solid-js@1.9.17: - resolution: {integrity: sha512-4GAmLOWPfNV8H9Jfn2LSFTpNEG6jiOKPiwd5lnLGQtehHaX6l3TOLzJqQ7mqwB/3k1Yy3zyumFVopmc/tm34ow==} - - solid-presence@0.2.0: - resolution: {integrity: sha512-YM92o+jvpzX3XGaD4rLYmq/Kc2ZVh47GSCLEufHBFQQIurvZTs8SoGJxO8BJGNDxBKdcS8F3dYhW1SDXp4BNjA==} - peerDependencies: - solid-js: ^1.8 - - solid-prevent-scroll@0.1.11: - resolution: {integrity: sha512-2PComVCDHaQN/5t7ogEqUYeHasritZKXZ8Sb/VLkl0Web8o9YhEwOo8LSujJEahvMlYCNyKt0zRJeHldOAeWZg==} - peerDependencies: - solid-js: ^1.8 - - solid-transition-group@0.2.3: - resolution: {integrity: sha512-iB72c9N5Kz9ykRqIXl0lQohOau4t0dhel9kjwFvx81UZJbVwaChMuBuyhiZmK24b8aKEK0w3uFM96ZxzcyZGdg==} - engines: {node: '>=18.0.0', pnpm: '>=8.6.0'} - peerDependencies: - solid-js: ^1.6.12 - source-map-js@1.2.2: resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} engines: {node: '>=0.10.0'} @@ -1377,10 +1200,6 @@ packages: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} - superjson@2.2.6: - resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} - engines: {node: '>=16'} - tailwindcss@4.3.3: resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} @@ -1415,9 +1234,6 @@ packages: resolution: {integrity: sha512-BcDSDW+SIGWVOns1Zm6Yg91q9AEj7eaID0QDY9oIqJD1A8dscNwMcl9Sms2DeuWCNov1X0/oXanHGYQBSLwZsg==} engines: {node: ^22.14.0 || >=24.0.0} - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - typescript@7.0.2: resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} engines: {node: '>=16.20.0'} @@ -1725,11 +1541,6 @@ snapshots: dependencies: css-tree: 3.2.1 - '@corvu/utils@0.4.2(solid-js@1.9.17)': - dependencies: - '@floating-ui/dom': 1.8.0 - solid-js: 1.9.17 - '@csstools/color-helpers@6.1.2': {} '@csstools/css-calc@3.4.3(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)': @@ -1756,25 +1567,10 @@ snapshots: '@exodus/bytes@1.16.0': {} - '@floating-ui/core@1.8.0': - dependencies: - '@floating-ui/utils': 0.2.12 - - '@floating-ui/dom@1.8.0': - dependencies: - '@floating-ui/core': 1.8.0 - '@floating-ui/utils': 0.2.12 - - '@floating-ui/utils@0.2.12': {} - '@fontsource-variable/ibm-plex-sans@5.3.0': {} '@fontsource-variable/jetbrains-mono@5.3.0': {} - '@internationalized/number@3.6.9': - dependencies: - '@swc/helpers': 0.5.23 - '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.6.0 @@ -1794,28 +1590,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.6.0 - '@kobalte/core@0.13.14(solid-js@1.9.17)': - dependencies: - '@floating-ui/dom': 1.8.0 - '@internationalized/number': 3.6.9 - '@kobalte/utils': 0.9.2(solid-js@1.9.17) - '@solid-primitives/props': 3.2.4(solid-js@1.9.17) - '@solid-primitives/resize-observer': 2.2.0(solid-js@1.9.17) - solid-js: 1.9.17 - solid-presence: 0.2.0(solid-js@1.9.17) - solid-prevent-scroll: 0.1.11(solid-js@1.9.17) - - '@kobalte/utils@0.9.2(solid-js@1.9.17)': - dependencies: - '@solid-primitives/event-listener': 2.4.6(solid-js@1.9.17) - '@solid-primitives/keyed': 1.5.3(solid-js@1.9.17) - '@solid-primitives/map': 0.4.13(solid-js@1.9.17) - '@solid-primitives/media': 2.3.6(solid-js@1.9.17) - '@solid-primitives/props': 3.2.4(solid-js@1.9.17) - '@solid-primitives/refs': 1.1.4(solid-js@1.9.17) - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - '@oxc-project/types@0.155.0': {} '@playwright/test@1.64.1': @@ -1869,78 +1643,6 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} - '@solid-primitives/event-listener@2.4.6(solid-js@1.9.17)': - dependencies: - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/keyed@1.5.3(solid-js@1.9.17)': - dependencies: - solid-js: 1.9.17 - - '@solid-primitives/map@0.4.13(solid-js@1.9.17)': - dependencies: - '@solid-primitives/trigger': 1.2.4(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/media@2.3.6(solid-js@1.9.17)': - dependencies: - '@solid-primitives/event-listener': 2.4.6(solid-js@1.9.17) - '@solid-primitives/rootless': 1.5.4(solid-js@1.9.17) - '@solid-primitives/static-store': 0.1.4(solid-js@1.9.17) - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/props@3.2.4(solid-js@1.9.17)': - dependencies: - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/refs@1.1.4(solid-js@1.9.17)': - dependencies: - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/resize-observer@2.2.0(solid-js@1.9.17)': - dependencies: - '@solid-primitives/event-listener': 2.4.6(solid-js@1.9.17) - '@solid-primitives/rootless': 1.5.4(solid-js@1.9.17) - '@solid-primitives/static-store': 0.1.4(solid-js@1.9.17) - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/rootless@1.5.4(solid-js@1.9.17)': - dependencies: - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/static-store@0.1.4(solid-js@1.9.17)': - dependencies: - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/storage@1.3.11(solid-js@1.9.17)': - dependencies: - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/transition-group@1.1.2(solid-js@1.9.17)': - dependencies: - solid-js: 1.9.17 - - '@solid-primitives/trigger@1.2.4(solid-js@1.9.17)': - dependencies: - '@solid-primitives/utils': 6.4.1(solid-js@1.9.17) - solid-js: 1.9.17 - - '@solid-primitives/utils@6.4.1(solid-js@1.9.17)': - dependencies: - solid-js: 1.9.17 - - '@swc/helpers@0.5.23': - dependencies: - tslib: 2.8.1 - '@tailwindcss/node@4.3.3': dependencies: '@jridgewell/remapping': 2.3.5 @@ -2011,38 +1713,8 @@ snapshots: '@tanstack/history@1.162.5': {} - '@tanstack/match-sorter-utils@9.2.6': - dependencies: - remove-accents: 0.5.0 - '@tanstack/query-core@5.104.5': {} - '@tanstack/query-devtools@5.104.5(csstype@3.2.3)': - dependencies: - '@kobalte/core': 0.13.14(solid-js@1.9.17) - '@solid-primitives/keyed': 1.5.3(solid-js@1.9.17) - '@solid-primitives/resize-observer': 2.2.0(solid-js@1.9.17) - '@solid-primitives/storage': 1.3.11(solid-js@1.9.17) - '@tanstack/match-sorter-utils': 9.2.6 - '@tanstack/query-core': 5.104.5 - clsx: 2.1.1 - goober: 2.1.19(csstype@3.2.3) - solid-js: 1.9.17 - solid-transition-group: 0.2.3(solid-js@1.9.17) - superjson: 2.2.6 - transitivePeerDependencies: - - csstype - - '@tanstack/react-query-devtools@5.104.5(@tanstack/react-query@5.104.5(@types/react@19.3.0)(react@19.3.1))(@types/react@19.3.0)(csstype@3.2.3)(react@19.3.1)': - dependencies: - '@tanstack/query-devtools': 5.104.5(csstype@3.2.3) - '@tanstack/react-query': 5.104.5(@types/react@19.3.0)(react@19.3.1) - react: 19.3.1 - optionalDependencies: - '@types/react': 19.3.0 - transitivePeerDependencies: - - csstype - '@tanstack/react-query@5.104.5(@types/react@19.3.0)(react@19.3.1)': dependencies: '@tanstack/query-core': 5.104.5 @@ -2050,17 +1722,6 @@ snapshots: optionalDependencies: '@types/react': 19.3.0 - '@tanstack/react-router-devtools@1.167.2(@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(@tanstack/router-core@1.171.39)(csstype@3.2.3)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': - dependencies: - '@tanstack/react-router': 1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1) - '@tanstack/router-devtools-core': 1.168.2(@tanstack/router-core@1.171.39)(csstype@3.2.3) - react: 19.3.1 - react-dom: 19.3.1(react@19.3.1) - optionalDependencies: - '@tanstack/router-core': 1.171.39 - transitivePeerDependencies: - - csstype - '@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': dependencies: '@tanstack/history': 1.162.5 @@ -2084,14 +1745,6 @@ snapshots: seroval: 1.6.12 seroval-plugins: 1.7.2(seroval@1.6.12) - '@tanstack/router-devtools-core@1.168.2(@tanstack/router-core@1.171.39)(csstype@3.2.3)': - dependencies: - '@tanstack/router-core': 1.171.39 - clsx: 2.1.1 - goober: 2.1.19(csstype@3.2.3) - optionalDependencies: - csstype: 3.2.3 - '@tanstack/router-generator@1.167.46': dependencies: '@babel/types': 7.29.11 @@ -2333,8 +1986,6 @@ snapshots: cookie-es@3.1.1: {} - copy-anything@4.1.5: {} - css-tree@3.2.1: dependencies: mdn-data: 2.27.1 @@ -2395,10 +2046,6 @@ snapshots: gensync@1.0.0-beta.2: {} - goober@2.1.19(csstype@3.2.3): - dependencies: - csstype: 3.2.3 - graceful-fs@4.2.11: {} html-encoding-sniffer@7.0.0: @@ -2620,8 +2267,6 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 - remove-accents@0.5.0: {} - require-from-string@2.0.2: {} rolldown@1.2.15: @@ -2653,38 +2298,12 @@ snapshots: semver@6.3.1: {} - seroval-plugins@1.6.12(seroval@1.6.12): - dependencies: - seroval: 1.6.12 - seroval-plugins@1.7.2(seroval@1.6.12): dependencies: seroval: 1.6.12 seroval@1.6.12: {} - solid-js@1.9.17: - dependencies: - csstype: 3.2.3 - seroval: 1.6.12 - seroval-plugins: 1.6.12(seroval@1.6.12) - - solid-presence@0.2.0(solid-js@1.9.17): - dependencies: - '@corvu/utils': 0.4.2(solid-js@1.9.17) - solid-js: 1.9.17 - - solid-prevent-scroll@0.1.11(solid-js@1.9.17): - dependencies: - '@corvu/utils': 0.4.2(solid-js@1.9.17) - solid-js: 1.9.17 - - solid-transition-group@0.2.3(solid-js@1.9.17): - dependencies: - '@solid-primitives/refs': 1.1.4(solid-js@1.9.17) - '@solid-primitives/transition-group': 1.1.2(solid-js@1.9.17) - solid-js: 1.9.17 - source-map-js@1.2.2: {} std-env@4.3.0: {} @@ -2693,10 +2312,6 @@ snapshots: dependencies: min-indent: 1.0.1 - superjson@2.2.6: - dependencies: - copy-anything: 4.1.5 - tailwindcss@4.3.3: {} tapable@2.3.3: {} @@ -2724,8 +2339,6 @@ snapshots: dependencies: punycode: 2.3.1 - tslib@2.8.1: {} - typescript@7.0.2: optionalDependencies: '@typescript/typescript-aix-ppc64': 7.0.2 diff --git a/web/pnpm-workspace.yaml b/web/pnpm-workspace.yaml index a8813294..4816a95d 100644 --- a/web/pnpm-workspace.yaml +++ b/web/pnpm-workspace.yaml @@ -17,6 +17,6 @@ overrides: seroval: ~1.6.11 # pnpm blocks dependency install/build scripts by default. List only the -# packages that legitimately need to run a build script during install. -onlyBuiltDependencies: - - esbuild +# packages that legitimately need to run a build script during install (none +# do since Vite 8 replaced esbuild with Rolldown). +onlyBuiltDependencies: [] diff --git a/web/src/api/email.ts b/web/src/api/email.ts index 51a00b7d..6c2a9eb7 100644 --- a/web/src/api/email.ts +++ b/web/src/api/email.ts @@ -233,9 +233,6 @@ export async function sendTestEmail(to?: string): Promise { /** An OAuth answer that carries the settings, and why Forge's old registration was not deleted. */ export type EmailSettingsWithWarning = EmailSettingsView & { warning?: string | null } -/** How the mailbox authorizes Forge. */ -export type OauthAuthorizeMethod = 'authorization_code' | 'device' | 'client_credentials' - /** A started device authorization: the code to enter, and where. */ export interface DeviceAuthorization { flow_id: string diff --git a/web/src/components/Breadcrumbs.tsx b/web/src/components/Breadcrumbs.tsx deleted file mode 100644 index 1a464a48..00000000 --- a/web/src/components/Breadcrumbs.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { PathCrumbs, type Crumb } from '~/components/ui' - -export type { Crumb } - -/** - * Folder-view breadcrumb trail. Items with a `to` render as router links; - * the final item is the current location and renders as plain text. - */ -export function Breadcrumbs({ items }: { items: Crumb[] }) { - return -} diff --git a/web/src/components/CopyButton.test.tsx b/web/src/components/CopyButton.test.tsx index 326d3a70..d147cc41 100644 --- a/web/src/components/CopyButton.test.tsx +++ b/web/src/components/CopyButton.test.tsx @@ -1,7 +1,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest' import { fireEvent, render, screen } from '@testing-library/react' -import { CommandSnippet, CopyButton } from './CopyButton' +import { CommandSnippet, CopyButton } from './ui' /** * Copy affordances: the command snippet and the compact digest button write diff --git a/web/src/components/CopyButton.tsx b/web/src/components/CopyButton.tsx deleted file mode 100644 index c2528dda..00000000 --- a/web/src/components/CopyButton.tsx +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Copy-to-clipboard affordances (a `docker login` / `docker pull` command, a - * manifest digest): the design system's `CommandSnippet` and `CopyButton`. - */ -export { CommandSnippet, CopyButton } from '~/components/ui' diff --git a/web/src/components/Paginator.tsx b/web/src/components/Paginator.tsx deleted file mode 100644 index 3c13f681..00000000 --- a/web/src/components/Paginator.tsx +++ /dev/null @@ -1 +0,0 @@ -export { Paginator } from '~/components/ui' diff --git a/web/src/components/RbacLabels.tsx b/web/src/components/RbacLabels.tsx index bf6b0b30..3d93c5fe 100644 --- a/web/src/components/RbacLabels.tsx +++ b/web/src/components/RbacLabels.tsx @@ -5,7 +5,6 @@ import { LEVEL_COVERS, type GrantView, type Level, - type RoleView, type SelectorView, } from '~/api/rbac' import { Notice, StatusBadge, type Tone } from '~/components/ui' @@ -115,22 +114,6 @@ export function SelectorLabel({ ) } -/** A role linked by name (or its id when not in the list). */ -export function RoleLabel({ - id, - roles, -}: { - id: number - roles: ReadonlyMap -}) { - const role = roles.get(id) - return ( - - {role?.name ?? `role #${id}`} - - ) -} - /** * A grant in words, for a confirmation that names what a deletion removes: * `write on nuget-internal (packages of acme)`. diff --git a/web/src/components/RepoFormatBadge.tsx b/web/src/components/RepoFormatBadge.tsx deleted file mode 100644 index fe7b9ce6..00000000 --- a/web/src/components/RepoFormatBadge.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { FormatTag, formatLabel } from '~/components/ui' - -export { formatLabel } - -/** - * The repository format (`nuget` | `docker` | `raw`) with its display - * name and a generic glyph. Other formats (other plugins) show their - * raw id, like `RepoKindBadge`. - */ -export function RepoFormatBadge({ format }: { format: string }) { - return -} diff --git a/web/src/components/RepoKindBadge.tsx b/web/src/components/RepoKindBadge.tsx deleted file mode 100644 index 6c52ee11..00000000 --- a/web/src/components/RepoKindBadge.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { KindBadge } from '~/components/ui' - -/** - * The repository kind (`hosted` | `proxy` | `group`) on its own tint. Unknown - * kinds render neutral so a future kind never renders untyped. - */ -export function RepoKindBadge({ kind }: { kind: string }) { - return -} diff --git a/web/src/components/ui/badges.tsx b/web/src/components/ui/badges.tsx index 560319d8..55b159ff 100644 --- a/web/src/components/ui/badges.tsx +++ b/web/src/components/ui/badges.tsx @@ -2,7 +2,6 @@ import type { ReactNode } from 'react' import clsx from 'clsx' import { Icon, type IconName } from './icons' -import { CopyButton } from './code' const KINDS = new Set(['hosted', 'proxy', 'group']) @@ -134,39 +133,3 @@ export function Version({ ) } -/** - * A content digest the Docker way (algorithm plus 12 hex characters), the - * full value as tooltip, with a copy button. `full` shows the whole digest - * with a faint tail. - */ -export function Digest({ - value, - length = 12, - full = false, - showAlgorithm = true, - copy = true, - copyLabel = 'Copy digest', - className, -}: { - value: string - length?: number - full?: boolean - showAlgorithm?: boolean - copy?: boolean - copyLabel?: string - className?: string -}) { - const i = value.indexOf(':') - const algo = i >= 0 ? value.slice(0, i + 1) : '' - const hex = i >= 0 ? value.slice(i + 1) : value - return ( - - - {showAlgorithm && algo && {algo}} - {hex.slice(0, length)} - {full && {hex.slice(length)}} - - {copy && } - - ) -} diff --git a/web/src/components/ui/icons.tsx b/web/src/components/ui/icons.tsx index 0272eb0c..f3307c38 100644 --- a/web/src/components/ui/icons.tsx +++ b/web/src/components/ui/icons.tsx @@ -115,9 +115,6 @@ const ICONS = { export type IconName = keyof typeof ICONS -/** The names of every icon, for previews and tests. */ -export const ICON_NAMES = Object.keys(ICONS) as IconName[] - /** * One icon. Decorative by default (`aria-hidden`); pass `title` only when the * icon carries meaning alone, and prefer a visible word. diff --git a/web/src/components/ui/index.ts b/web/src/components/ui/index.ts index 3026b943..00423d05 100644 --- a/web/src/components/ui/index.ts +++ b/web/src/components/ui/index.ts @@ -3,11 +3,10 @@ * `fg-*` classes of styles/forge-ui.css and draw every value from the tokens * in styles/tokens.css. */ -export { Avatar, Icon, ICON_NAMES, Logo, type IconName } from './icons' -export { Button, RouterAnchor, isAppPath, type ButtonProps, type ButtonVariant } from './button' +export { Avatar, Icon, Logo, type IconName } from './icons' +export { Button } from './button' export { Chip, - Digest, FormatTag, KindBadge, StatusBadge, @@ -23,7 +22,6 @@ export { CopyButton, CopyField, SecretOnce, - useCopy, } from './code' export { CellActions, @@ -56,16 +54,12 @@ export { TextareaField, TextField, type ChoiceCard, - type RadioOption, } from './forms' export { Columns, FormActions, Page, PageHeader, Panel, Toolbar } from './layout' export { Menu, Paginator, - PathCrumbs, SegmentedControl, Tabs, - type Crumb, type MenuItem, - type TabItem, } from './nav' diff --git a/web/src/styles/forge-ui.css b/web/src/styles/forge-ui.css index f4caeabc..f70334ed 100644 --- a/web/src/styles/forge-ui.css +++ b/web/src/styles/forge-ui.css @@ -19,7 +19,7 @@ /* Focus: one ring everywhere, 2px solid heat, 2px out; rail-heat inside the rail. */ .fg-btn:focus-visible, .fg-input:focus-visible, .fg-select:focus-visible, .fg-tab:focus-visible, .fg-copy:focus-visible, .fg-copyfield-btn:focus-visible, .fg-link:focus-visible, .fg-link-strong:focus-visible, .fg-crumbs a:focus-visible, .fg-notice-action:focus-visible, .fg-seg-item:focus-visible, - .fg-menu-item:focus-visible, .fg-toast-close:focus-visible, .fg-toast-action:focus-visible, .fg-dialog-close:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; } + .fg-menu-item:focus-visible, .fg-toast-close:focus-visible, .fg-dialog-close:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; } .fg-check-input:focus-visible + .fg-check-box, .fg-check-input:focus-visible + .fg-switch-track, .fg-choice-input:focus-visible ~ .fg-choice-top { outline: 2px solid var(--focus); outline-offset: 2px; } .fg-rail :focus-visible { outline: 2px solid var(--rail-heat); outline-offset: 2px; } @@ -92,9 +92,7 @@ .fg-version--unlisted .fg-version-core { color: var(--ink-faint); } .fg-version-latest { margin-left: 8px; padding: 0 6px; border-radius: var(--radius-xs); background: var(--heat-soft); color: var(--heat); font-family: var(--font-sans); font-size: 11px; line-height: 18px; font-weight: 600; } .fg-digest { display: inline-flex; align-items: center; gap: 4px; font-family: var(--font-mono); font-size: 12px; line-height: 16px; white-space: nowrap; } - .fg-digest-algo { color: var(--ink-faint); } .fg-digest-short { color: var(--ink); } - .fg-digest-rest { color: var(--ink-faint); white-space: normal; word-break: break-all; } .fg-copy { display: inline-flex; align-items: center; justify-content: center; gap: 4px; box-sizing: border-box; min-width: 24px; height: 24px; padding: 0 5px; border: 0; border-radius: var(--radius-xs); background: transparent; color: var(--ink-faint); font-family: var(--font-sans); font-size: 12px; line-height: 16px; font-weight: 500; cursor: pointer; } .fg-copy:hover { background: var(--surface-hover); color: var(--ink); } .fg-copy-done { color: var(--ok); } @@ -107,7 +105,6 @@ .fg-snippet-label { color: var(--ink-muted); font-size: 12px; line-height: 16px; font-weight: 500; } .fg-snippet-box { display: flex; align-items: flex-start; gap: var(--space-2); padding: 7px 6px 7px 12px; border: 1px solid var(--code-line); border-radius: var(--radius-sm); background: var(--code); } .fg-snippet-code { flex: 1; min-width: 0; padding-top: 2px; color: var(--code-ink); font-family: var(--font-mono); font-size: 13px; line-height: 20px; font-weight: 450; white-space: pre-wrap; overflow-wrap: anywhere; } - .fg-snippet-prompt { margin-right: 1ch; color: var(--code-muted); user-select: none; } .fg-code-ph { color: var(--code-accent); } .fg-codeblock { margin: 0; min-width: 0; overflow: hidden; border: 1px solid var(--code-line); border-radius: var(--radius-md); background: var(--code); } .fg-codeblock-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: 6px 6px 6px 12px; border-bottom: 1px solid var(--code-line); background: var(--code-raised); } @@ -209,10 +206,6 @@ .fg-rail .fg-logo-mark { fill: var(--rail-heat); } .fg-rail-brand { display: flex; align-items: center; height: 32px; padding: 0 6px; } .fg-rail-home { display: inline-flex; border-radius: var(--radius-sm); } - .fg-rail-jump { display: flex; align-items: center; gap: 8px; box-sizing: border-box; width: 100%; height: 34px; padding: 0 8px 0 10px; border: 1px solid var(--rail-line); border-radius: var(--radius-sm); background: transparent; color: var(--rail-muted); font-family: var(--font-sans); font-size: 13px; line-height: 20px; text-align: left; cursor: pointer; } - .fg-rail-jump:hover { background: var(--rail-raised); color: var(--rail-ink); } - .fg-rail-jump span { flex: 1; } - .fg-kbd--rail { border-color: var(--rail-line); background: var(--rail-raised); color: var(--rail-muted); } .fg-rail-sections { display: grid; gap: 20px; } .fg-rail-section { display: grid; gap: 4px; } .fg-rail-title { padding: 0 10px 2px; color: var(--rail-muted); font-size: 11px; line-height: 16px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; } @@ -318,13 +311,11 @@ .fg-toast-text { display: grid; flex: 1; gap: 2px; min-width: 0; padding-top: 2px; } .fg-toast-title { margin: 0; color: var(--ink); font-size: 14px; line-height: 20px; font-weight: 600; } .fg-toast-body { color: var(--ink-muted); font-size: 13px; line-height: 20px; } - .fg-toast-action { justify-self: start; margin-top: 4px; padding: 0; border: 0; background: transparent; color: var(--link); font-family: var(--font-sans); font-size: 13px; font-weight: 600; cursor: pointer; } .fg-toast-close { flex: none; display: grid; place-items: center; width: 28px; height: 28px; border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--ink-faint); cursor: pointer; } .fg-toast-close:hover { background: var(--surface-hover); color: var(--ink); } /* ---------- Dialog ---------- */ .fg-dialog-layer { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; padding: var(--space-4); } - .fg-dialog-layer--inline { position: relative; inset: auto; min-height: 100%; padding: var(--space-8) var(--space-4); } .fg-dialog-scrim { position: absolute; inset: 0; background: var(--scrim); } .fg-dialog { position: relative; display: grid; box-sizing: border-box; width: 480px; max-width: 100%; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); box-shadow: var(--shadow-lg); } .fg-dialog--wide { width: min(720px, calc(100vw - 2 * var(--space-4))); } @@ -357,7 +348,6 @@ .fg-cell-badges { display: inline-flex; flex-wrap: wrap; gap: 6px; vertical-align: middle; } .fg-chip { padding: 1px 6px; border-radius: var(--radius-xs); background: var(--surface-sunken); color: var(--ink-muted); font-family: var(--font-mono); font-size: 12px; line-height: 18px; white-space: nowrap; } .fg-cell-link { display: flex; flex-direction: column; min-width: 0; } - .fg-cell-name { color: var(--ink); font-weight: 600; } .fg-cell-user { display: inline-flex; align-items: center; gap: 10px; } .fg-link-strong { display: inline-flex; align-items: center; gap: 8px; color: var(--ink); font-weight: 600; text-decoration: none; } .fg-link-strong .fg-icon { color: var(--ink-faint); } diff --git a/web/tsconfig.tsbuildinfo b/web/tsconfig.tsbuildinfo deleted file mode 100644 index b3e7dcae..00000000 --- a/web/tsconfig.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"version":"7.0.2","root":["./src/main.tsx","./src/routeTree.gen.ts","./src/routes.ts","./src/vite-env.d.ts","./src/api/auth.ts","./src/api/cliLogin.ts","./src/api/email.ts","./src/api/images.ts","./src/api/imports.ts","./src/api/me.ts","./src/api/packages.ts","./src/api/raw.ts","./src/api/rbac.ts","./src/api/realms.ts","./src/api/repositories.ts","./src/api/retention.ts","./src/api/settings.ts","./src/api/system.ts","./src/api/tokens.ts","./src/api/users.test.ts","./src/api/users.ts","./src/components/AccessBadge.tsx","./src/components/AccessLevelFields.tsx","./src/components/AnonymousAccessPanel.tsx","./src/components/AppRail.tsx","./src/components/AuthCard.tsx","./src/components/Breadcrumbs.tsx","./src/components/ChartView.tsx","./src/components/CopyButton.test.tsx","./src/components/CopyButton.tsx","./src/components/DelayBadge.test.tsx","./src/components/DelayBadge.tsx","./src/components/DependencyGroups.tsx","./src/components/DockerConnect.tsx","./src/components/EmptyState.tsx","./src/components/ErrorState.tsx","./src/components/ImageDeleteDialog.tsx","./src/components/ImageTables.tsx","./src/components/PackageConnect.test.ts","./src/components/PackageConnect.tsx","./src/components/Paginator.tsx","./src/components/PriorityList.tsx","./src/components/ProxyCachePanel.tsx","./src/components/RawBrowser.tsx","./src/components/RbacLabels.tsx","./src/components/RealmForm.test.ts","./src/components/RealmForm.tsx","./src/components/RepoFormatBadge.tsx","./src/components/RepoKindBadge.tsx","./src/components/RepositoryForm.test.tsx","./src/components/RepositoryForm.tsx","./src/components/RetentionBadge.tsx","./src/components/RetentionPolicyForm.test.ts","./src/components/RetentionPolicyForm.tsx","./src/components/RoleDeleteConfirm.tsx","./src/components/RouteError.tsx","./src/components/SearchBox.tsx","./src/components/SelectorDeleteConfirm.tsx","./src/components/SelectorForm.tsx","./src/components/ShowOnceSecret.test.tsx","./src/components/ShowOnceSecret.tsx","./src/components/TokenBadges.test.tsx","./src/components/TokenBadges.tsx","./src/components/TokenCreateForm.tsx","./src/components/TokenScopeFields.tsx","./src/components/VersionTable.tsx","./src/components/ui/badges.tsx","./src/components/ui/button.tsx","./src/components/ui/code.tsx","./src/components/ui/data.tsx","./src/components/ui/feedback.tsx","./src/components/ui/forms.tsx","./src/components/ui/icons.tsx","./src/components/ui/index.ts","./src/components/ui/layout.tsx","./src/components/ui/nav.tsx","./src/lib/accounts.test.ts","./src/lib/accounts.ts","./src/lib/auth.test.ts","./src/lib/auth.ts","./src/lib/chunkReload.test.tsx","./src/lib/chunkReload.ts","./src/lib/config.ts","./src/lib/httpClient.test.ts","./src/lib/httpClient.ts","./src/lib/navigation.ts","./src/lib/oci.test.ts","./src/lib/oci.ts","./src/lib/queryClient.ts","./src/lib/returnTo.ts","./src/lib/search.test.ts","./src/lib/search.ts","./src/lib/theme.test.ts","./src/lib/theme.ts","./src/queries/useBrowseRepos.ts","./src/queries/useChart.ts","./src/queries/useEmail.ts","./src/queries/useImageDetail.ts","./src/queries/useImageSearch.ts","./src/queries/useImports.ts","./src/queries/useMe.ts","./src/queries/usePackageDetail.ts","./src/queries/usePackageSearch.ts","./src/queries/useRawListing.ts","./src/queries/useRbac.ts","./src/queries/useRealms.ts","./src/queries/useRepositories.ts","./src/queries/useRetention.ts","./src/queries/useSettings.ts","./src/queries/useSystem.ts","./src/queries/useTokens.ts","./src/queries/useUsers.ts","./src/routes/AdminLayout.tsx","./src/routes/AppLayout.tsx","./src/routes/Browse.test.tsx","./src/routes/Browse.tsx","./src/routes/CliLogin.test.tsx","./src/routes/CliLogin.tsx","./src/routes/ImageDetail.test.tsx","./src/routes/ImageDetail.tsx","./src/routes/Invite.tsx","./src/routes/Login.test.tsx","./src/routes/Login.tsx","./src/routes/PackageDetail.test.tsx","./src/routes/PackageDetail.tsx","./src/routes/RawBrowse.test.tsx","./src/routes/RepoBrowse.tsx","./src/routes/Tokens.test.tsx","./src/routes/Tokens.tsx","./src/routes/invite.test.tsx","./src/routes/root.tsx","./src/routes/routing.test.tsx","./src/routes/session.test.tsx","./src/routes/admin/AdminHome.tsx","./src/routes/admin/realms/Create.tsx","./src/routes/admin/realms/Edit.tsx","./src/routes/admin/realms/List.tsx","./src/routes/admin/realms/realms.test.tsx","./src/routes/admin/repositories/Create.tsx","./src/routes/admin/repositories/Edit.tsx","./src/routes/admin/repositories/GroupMembers.tsx","./src/routes/admin/repositories/Import.tsx","./src/routes/admin/repositories/List.tsx","./src/routes/admin/repositories/Retention.tsx","./src/routes/admin/repositories/TrustedPublishers.tsx","./src/routes/admin/repositories/imports.test.tsx","./src/routes/admin/repositories/repositories.test.tsx","./src/routes/admin/repositories/retention.test.tsx","./src/routes/admin/roles/Edit.tsx","./src/routes/admin/roles/List.tsx","./src/routes/admin/roles/roles.test.tsx","./src/routes/admin/selectors/Create.tsx","./src/routes/admin/selectors/Edit.tsx","./src/routes/admin/selectors/List.tsx","./src/routes/admin/selectors/selectors.test.tsx","./src/routes/admin/service-accounts/Create.tsx","./src/routes/admin/service-accounts/Edit.tsx","./src/routes/admin/service-accounts/List.tsx","./src/routes/admin/service-accounts/serviceAccounts.test.tsx","./src/routes/admin/settings/Email.tsx","./src/routes/admin/settings/RetentionSettings.tsx","./src/routes/admin/settings/Settings.tsx","./src/routes/admin/settings/email.test.tsx","./src/routes/admin/settings/retention-settings.test.tsx","./src/routes/admin/settings/settings.test.tsx","./src/routes/admin/system/System.tsx","./src/routes/admin/system/system.test.tsx","./src/routes/admin/users/Create.tsx","./src/routes/admin/users/Edit.tsx","./src/routes/admin/users/List.tsx","./src/routes/admin/users/userRoles.test.tsx","./src/routes/admin/users/users.test.tsx","./src/test/fakeRbacApi.ts","./src/test/renderApp.tsx","./src/test/text.ts","./vite.config.ts","./vitest.setup.ts"],"packageJsons":["./node_modules/.pnpm/@fontsource-variable+ibm-plex-sans@5.3.0/node_modules/@fontsource-variable/ibm-plex-sans/package.json","./node_modules/.pnpm/@fontsource-variable+jetbrains-mono@5.3.0/node_modules/@fontsource-variable/jetbrains-mono/package.json","./node_modules/.pnpm/@oxc-project+types@0.153.0/node_modules/@oxc-project/types/package.json","./node_modules/.pnpm/@rolldown+pluginutils@1.0.1/node_modules/@rolldown/pluginutils/package.json","./node_modules/.pnpm/@tailwindcss+vite@4.3.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@tailwindcss/vite/package.json","./node_modules/.pnpm/@tanstack+history@1.162.5/node_modules/@tanstack/history/package.json","./node_modules/.pnpm/@tanstack+query-core@5.104.3/node_modules/@tanstack/query-core/package.json","./node_modules/.pnpm/@tanstack+react-query@5.104.3_react@19.3.1/node_modules/@tanstack/react-query/package.json","./node_modules/.pnpm/@tanstack+react-router@1.170.45_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@tanstack/react-router/package.json","./node_modules/.pnpm/@tanstack+router-core@1.171.38/node_modules/@tanstack/router-core/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/router-plugin/package.json","./node_modules/.pnpm/@tanstack+virtual-file-routes@1.162.0/node_modules/@tanstack/virtual-file-routes/package.json","./node_modules/.pnpm/@testing-library+dom@10.4.1/node_modules/@testing-library/dom/package.json","./node_modules/.pnpm/@testing-library+jest-dom@7.0.1_@testing-library+dom@10.4.1_vitest@5.0.5_@types+node@26_0b6a06c8ca1e6ac8904c27cde4b58fae/node_modules/@testing-library/jest-dom/package.json","./node_modules/.pnpm/@testing-library+react@16.3.3_@testing-library+dom@10.4.1_@types+react-dom@19.3.0_@type_9cb2ebc1aa84bc4b8c235922926b17c0/node_modules/@testing-library/react/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/package.json","./node_modules/.pnpm/@types+aria-query@5.0.4/node_modules/@types/aria-query/package.json","./node_modules/.pnpm/@types+chai@5.2.3/node_modules/@types/chai/package.json","./node_modules/.pnpm/@types+deep-eql@4.0.2/node_modules/@types/deep-eql/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/package.json","./node_modules/.pnpm/@types+react-dom@19.3.0_@types+react@19.3.0/node_modules/@types/react-dom/package.json","./node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitejs/plugin-react/package.json","./node_modules/.pnpm/@vitest+mocker@5.0.5_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitest/mocker/package.json","./node_modules/.pnpm/aria-query@5.3.0/node_modules/aria-query/package.json","./node_modules/.pnpm/aria-query@5.3.2/node_modules/aria-query/package.json","./node_modules/.pnpm/assertion-error@2.0.1/node_modules/assertion-error/package.json","./node_modules/.pnpm/chai@6.3.0/node_modules/chai/package.json","./node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/package.json","./node_modules/.pnpm/csstype@3.2.3/node_modules/csstype/package.json","./node_modules/.pnpm/expect-type@1.4.0/node_modules/expect-type/package.json","./node_modules/.pnpm/jiti@2.7.0/node_modules/jiti/package.json","./node_modules/.pnpm/jsdom@30.1.3/node_modules/jsdom/package.json","./node_modules/.pnpm/lightningcss@1.33.0/node_modules/lightningcss/package.json","./node_modules/.pnpm/postcss@8.5.30/node_modules/postcss/package.json","./node_modules/.pnpm/pretty-format@27.5.1/node_modules/pretty-format/package.json","./node_modules/.pnpm/punycode@2.3.1/node_modules/punycode/package.json","./node_modules/.pnpm/react-dom@19.3.1_react@19.3.1/node_modules/react-dom/package.json","./node_modules/.pnpm/react@19.3.1/node_modules/react/package.json","./node_modules/.pnpm/rolldown@1.2.13/node_modules/rolldown/package.json","./node_modules/.pnpm/seroval@1.6.12/node_modules/seroval/package.json","./node_modules/.pnpm/source-map-js@1.2.2/node_modules/source-map-js/package.json","./node_modules/.pnpm/tinybench@6.2.2/node_modules/tinybench/package.json","./node_modules/.pnpm/undici-types@8.9.0/node_modules/undici-types/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vitest/package.json","./node_modules/.pnpm/zod@4.6.7/node_modules/zod/package.json","./node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/package.json","./node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/package.json","./node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/package.json","./package.json"],"missingPackageJsons":["./node_modules/.pnpm/@rolldown+pluginutils@1.0.1/node_modules/@rolldown/pluginutils/dist/filter/package.json","./node_modules/.pnpm/@rolldown+pluginutils@1.0.1/node_modules/@rolldown/pluginutils/dist/package.json","./node_modules/.pnpm/@tailwindcss+vite@4.3.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@tailwindcss/vite/dist/package.json","./node_modules/.pnpm/@tailwindcss+vite@4.3.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@tailwindcss/vite/node_modules/vite/package.json","./node_modules/.pnpm/@tanstack+history@1.162.5/node_modules/@tanstack/history/dist/esm/package.json","./node_modules/.pnpm/@tanstack+history@1.162.5/node_modules/@tanstack/history/dist/package.json","./node_modules/.pnpm/@tanstack+query-core@5.104.3/node_modules/@tanstack/query-core/build/modern/package.json","./node_modules/.pnpm/@tanstack+query-core@5.104.3/node_modules/@tanstack/query-core/build/package.json","./node_modules/.pnpm/@tanstack+react-query@5.104.3_react@19.3.1/node_modules/@tanstack/react-query/build/modern/package.json","./node_modules/.pnpm/@tanstack+react-query@5.104.3_react@19.3.1/node_modules/@tanstack/react-query/build/package.json","./node_modules/.pnpm/@tanstack+react-query@5.104.3_react@19.3.1/node_modules/react/jsx-runtime/package.json","./node_modules/.pnpm/@tanstack+react-router@1.170.45_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@tanstack/react-router/dist/esm/package.json","./node_modules/.pnpm/@tanstack+react-router@1.170.45_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@tanstack/react-router/dist/esm/ssr/package.json","./node_modules/.pnpm/@tanstack+react-router@1.170.45_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@tanstack/react-router/dist/package.json","./node_modules/.pnpm/@tanstack+react-router@1.170.45_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/react/jsx-runtime/package.json","./node_modules/.pnpm/@tanstack+router-core@1.171.38/node_modules/@tanstack/router-core/dist/esm/package.json","./node_modules/.pnpm/@tanstack+router-core@1.171.38/node_modules/@tanstack/router-core/dist/esm/ssr/package.json","./node_modules/.pnpm/@tanstack+router-core@1.171.38/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/package.json","./node_modules/.pnpm/@tanstack+router-core@1.171.38/node_modules/@tanstack/router-core/dist/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/dist/esm/filesystem/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/dist/esm/filesystem/physical/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/dist/esm/filesystem/virtual/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/dist/esm/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/dist/esm/plugin/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/dist/esm/transform/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/dist/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/node_modules/@tanstack/virtual-file-routes/package.json","./node_modules/.pnpm/@tanstack+router-generator@1.167.45/node_modules/@tanstack/router-generator/node_modules/zod/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@rsbuild/core/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/router-plugin/dist/esm/core/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/router-plugin/dist/esm/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/router-plugin/dist/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/router-plugin/node_modules/@tanstack/router-core/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/router-plugin/node_modules/@tanstack/router-generator/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/router-plugin/node_modules/@tanstack/virtual-file-routes/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/router-plugin/node_modules/vite/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/router-plugin/node_modules/zod/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/@tanstack/virtual-file-routes/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/vite-plugin-solid/package.json","./node_modules/.pnpm/@tanstack+router-plugin@1.168.47_@tanstack+react-router@1.170.45_react-dom@19.3.1_react_62bf9e8c870b8c2554520550c5339f26/node_modules/webpack/package.json","./node_modules/.pnpm/@tanstack+virtual-file-routes@1.162.0/node_modules/@tanstack/virtual-file-routes/dist/esm/package.json","./node_modules/.pnpm/@tanstack+virtual-file-routes@1.162.0/node_modules/@tanstack/virtual-file-routes/dist/package.json","./node_modules/.pnpm/@testing-library+dom@10.4.1/node_modules/@testing-library/dom/node_modules/aria-query/package.json","./node_modules/.pnpm/@testing-library+dom@10.4.1/node_modules/@testing-library/dom/node_modules/pretty-format/package.json","./node_modules/.pnpm/@testing-library+dom@10.4.1/node_modules/@testing-library/dom/types/package.json","./node_modules/.pnpm/@testing-library+jest-dom@7.0.1_@testing-library+dom@10.4.1_vitest@5.0.5_@types+node@26_0b6a06c8ca1e6ac8904c27cde4b58fae/node_modules/@testing-library/jest-dom/node_modules/@testing-library/dom/package.json","./node_modules/.pnpm/@testing-library+jest-dom@7.0.1_@testing-library+dom@10.4.1_vitest@5.0.5_@types+node@26_0b6a06c8ca1e6ac8904c27cde4b58fae/node_modules/@testing-library/jest-dom/node_modules/aria-query/package.json","./node_modules/.pnpm/@testing-library+jest-dom@7.0.1_@testing-library+dom@10.4.1_vitest@5.0.5_@types+node@26_0b6a06c8ca1e6ac8904c27cde4b58fae/node_modules/@testing-library/jest-dom/node_modules/jest/package.json","./node_modules/.pnpm/@testing-library+jest-dom@7.0.1_@testing-library+dom@10.4.1_vitest@5.0.5_@types+node@26_0b6a06c8ca1e6ac8904c27cde4b58fae/node_modules/@testing-library/jest-dom/node_modules/vitest/package.json","./node_modules/.pnpm/@testing-library+jest-dom@7.0.1_@testing-library+dom@10.4.1_vitest@5.0.5_@types+node@26_0b6a06c8ca1e6ac8904c27cde4b58fae/node_modules/@testing-library/jest-dom/types/package.json","./node_modules/.pnpm/@testing-library+jest-dom@7.0.1_@testing-library+dom@10.4.1_vitest@5.0.5_@types+node@26_0b6a06c8ca1e6ac8904c27cde4b58fae/node_modules/jest/package.json","./node_modules/.pnpm/@testing-library+react@16.3.3_@testing-library+dom@10.4.1_@types+react-dom@19.3.0_@type_9cb2ebc1aa84bc4b8c235922926b17c0/node_modules/@testing-library/react/types/package.json","./node_modules/.pnpm/@testing-library+react@16.3.3_@testing-library+dom@10.4.1_@types+react-dom@19.3.0_@type_9cb2ebc1aa84bc4b8c235922926b17c0/node_modules/@types/react-dom/client/package.json","./node_modules/.pnpm/@testing-library+react@16.3.3_@testing-library+dom@10.4.1_@types+react-dom@19.3.0_@type_9cb2ebc1aa84bc4b8c235922926b17c0/node_modules/@types/react-dom/test-utils/package.json","./node_modules/.pnpm/@testing-library+react@16.3.3_@testing-library+dom@10.4.1_@types+react-dom@19.3.0_@type_9cb2ebc1aa84bc4b8c235922926b17c0/node_modules/react-dom/client/package.json","./node_modules/.pnpm/@testing-library+react@16.3.3_@testing-library+dom@10.4.1_@types+react-dom@19.3.0_@type_9cb2ebc1aa84bc4b8c235922926b17c0/node_modules/react-dom/test-utils/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/clipboard/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/convenience/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/document/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/event/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/event/selection/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/keyboard/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/pointer/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/setup/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/system/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/system/pointer/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/utility/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/utils/click/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/utils/dataTransfer/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/utils/edit/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/utils/focus/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/utils/keyDef/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/utils/misc/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/utils/package.json","./node_modules/.pnpm/@testing-library+user-event@14.6.8_@testing-library+dom@10.4.1/node_modules/@testing-library/user-event/dist/types/utils/pointer/package.json","./node_modules/.pnpm/@types+chai@5.2.3/node_modules/deep-eql/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/assert/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/assert/strict/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/async_hooks/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/buffer/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/child_process/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/cluster/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/console/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/constants/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/crypto/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/dgram/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/diagnostics_channel/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/dns/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/dns/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/domain/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/events/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/fs/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/fs/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/http/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/http2/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/https/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/inspector/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/inspector/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/module/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/net/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/assert/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/dns/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/fs/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/inspector/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/path/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/readline/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/stream/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/test/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/timers/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/util/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/web-globals/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/node/zlib/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/os/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/path/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/path/posix/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/path/win32/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/perf_hooks/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/process/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/punycode/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/querystring/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/readline/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/readline/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/repl/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/stream/consumers/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/stream/iter/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/stream/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/stream/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/stream/web/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/string_decoder/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/timers/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/timers/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/tls/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/trace_events/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/tty/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/url/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/util/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/util/types/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/v8/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/vm/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/wasi/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/worker_threads/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/@types/zlib/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/assert/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/assert/strict/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/async_hooks/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/buffer/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/child_process/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/cluster/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/console/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/constants/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/crypto/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/dgram/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/diagnostics_channel/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/dns/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/dns/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/domain/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/events/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/fs/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/fs/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/http/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/http2/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/https/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/inspector/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/inspector/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/module/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/net/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/os/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/path/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/path/posix/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/path/win32/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/perf_hooks/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/process/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/punycode/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/querystring/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/readline/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/readline/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/repl/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/stream/consumers/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/stream/iter/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/stream/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/stream/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/stream/web/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/string_decoder/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/timers/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/timers/promises/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/tls/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/trace_events/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/tty/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/url/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/util/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/util/types/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/v8/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/vm/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/wasi/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/worker_threads/package.json","./node_modules/.pnpm/@types+node@26.6.5/node_modules/zlib/package.json","./node_modules/.pnpm/@types+react-dom@19.3.0_@types+react@19.3.0/node_modules/@types/react-dom/test-utils/package.json","./node_modules/.pnpm/@types+react-dom@19.3.0_@types+react@19.3.0/node_modules/react/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@rolldown/plugin-babel/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitejs/plugin-react/dist/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitejs/plugin-react/node_modules/@rolldown/plugin-babel/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitejs/plugin-react/node_modules/babel-plugin-react-compiler/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitejs/plugin-react/node_modules/oxc-transform-react/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitejs/plugin-react/node_modules/vite/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitejs/plugin-react/types/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/babel-plugin-react-compiler/package.json","./node_modules/.pnpm/@vitejs+plugin-react@6.1.2_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/oxc-transform-react/package.json","./node_modules/.pnpm/@vitest+mocker@5.0.5_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitest/mocker/dist/package.json","./node_modules/.pnpm/@vitest+mocker@5.0.5_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/msw/package.json","./node_modules/.pnpm/expect-type@1.4.0/node_modules/expect-type/dist/package.json","./node_modules/.pnpm/lightningcss@1.33.0/node_modules/lightningcss/node/package.json","./node_modules/.pnpm/node_modules/@rolldown/plugin-babel/package.json","./node_modules/.pnpm/node_modules/@tanstack/virtual-file-routes/package.json","./node_modules/.pnpm/node_modules/@types/assert/package.json","./node_modules/.pnpm/node_modules/@types/assert/strict/package.json","./node_modules/.pnpm/node_modules/@types/async_hooks/package.json","./node_modules/.pnpm/node_modules/@types/babel-plugin-react-compiler/package.json","./node_modules/.pnpm/node_modules/@types/buffer/package.json","./node_modules/.pnpm/node_modules/@types/child_process/package.json","./node_modules/.pnpm/node_modules/@types/cluster/package.json","./node_modules/.pnpm/node_modules/@types/console/package.json","./node_modules/.pnpm/node_modules/@types/constants/package.json","./node_modules/.pnpm/node_modules/@types/crypto/package.json","./node_modules/.pnpm/node_modules/@types/dgram/package.json","./node_modules/.pnpm/node_modules/@types/diagnostics_channel/package.json","./node_modules/.pnpm/node_modules/@types/dns/package.json","./node_modules/.pnpm/node_modules/@types/dns/promises/package.json","./node_modules/.pnpm/node_modules/@types/domain/package.json","./node_modules/.pnpm/node_modules/@types/esbuild/package.json","./node_modules/.pnpm/node_modules/@types/events/package.json","./node_modules/.pnpm/node_modules/@types/fs/package.json","./node_modules/.pnpm/node_modules/@types/fs/promises/package.json","./node_modules/.pnpm/node_modules/@types/http/package.json","./node_modules/.pnpm/node_modules/@types/http2/package.json","./node_modules/.pnpm/node_modules/@types/https/package.json","./node_modules/.pnpm/node_modules/@types/inspector/package.json","./node_modules/.pnpm/node_modules/@types/inspector/promises/package.json","./node_modules/.pnpm/node_modules/@types/jest/package.json","./node_modules/.pnpm/node_modules/@types/less/package.json","./node_modules/.pnpm/node_modules/@types/module/package.json","./node_modules/.pnpm/node_modules/@types/net/package.json","./node_modules/.pnpm/node_modules/@types/os/package.json","./node_modules/.pnpm/node_modules/@types/oxc-transform-react/package.json","./node_modules/.pnpm/node_modules/@types/path/package.json","./node_modules/.pnpm/node_modules/@types/path/posix/package.json","./node_modules/.pnpm/node_modules/@types/path/win32/package.json","./node_modules/.pnpm/node_modules/@types/perf_hooks/package.json","./node_modules/.pnpm/node_modules/@types/process/package.json","./node_modules/.pnpm/node_modules/@types/punycode/package.json","./node_modules/.pnpm/node_modules/@types/querystring/package.json","./node_modules/.pnpm/node_modules/@types/react/jsx-runtime/package.json","./node_modules/.pnpm/node_modules/@types/react/package.json","./node_modules/.pnpm/node_modules/@types/readline/package.json","./node_modules/.pnpm/node_modules/@types/readline/promises/package.json","./node_modules/.pnpm/node_modules/@types/repl/package.json","./node_modules/.pnpm/node_modules/@types/rolldown__plugin-babel/package.json","./node_modules/.pnpm/node_modules/@types/sass-embedded/package.json","./node_modules/.pnpm/node_modules/@types/sass/package.json","./node_modules/.pnpm/node_modules/@types/stream/consumers/package.json","./node_modules/.pnpm/node_modules/@types/stream/iter/package.json","./node_modules/.pnpm/node_modules/@types/stream/package.json","./node_modules/.pnpm/node_modules/@types/stream/promises/package.json","./node_modules/.pnpm/node_modules/@types/stream/web/package.json","./node_modules/.pnpm/node_modules/@types/string_decoder/package.json","./node_modules/.pnpm/node_modules/@types/stylus/package.json","./node_modules/.pnpm/node_modules/@types/tanstack__virtual-file-routes/package.json","./node_modules/.pnpm/node_modules/@types/terser/package.json","./node_modules/.pnpm/node_modules/@types/timers/package.json","./node_modules/.pnpm/node_modules/@types/timers/promises/package.json","./node_modules/.pnpm/node_modules/@types/tls/package.json","./node_modules/.pnpm/node_modules/@types/trace_events/package.json","./node_modules/.pnpm/node_modules/@types/tty/package.json","./node_modules/.pnpm/node_modules/@types/url/package.json","./node_modules/.pnpm/node_modules/@types/util/package.json","./node_modules/.pnpm/node_modules/@types/util/types/package.json","./node_modules/.pnpm/node_modules/@types/v8/package.json","./node_modules/.pnpm/node_modules/@types/vitejs__devtools/config/package.json","./node_modules/.pnpm/node_modules/@types/vitejs__devtools/package.json","./node_modules/.pnpm/node_modules/@types/vm/package.json","./node_modules/.pnpm/node_modules/@types/wasi/package.json","./node_modules/.pnpm/node_modules/@types/worker_threads/package.json","./node_modules/.pnpm/node_modules/@types/zlib/package.json","./node_modules/.pnpm/node_modules/@vitejs/devtools/config/package.json","./node_modules/.pnpm/node_modules/@vitejs/devtools/package.json","./node_modules/.pnpm/node_modules/assert/package.json","./node_modules/.pnpm/node_modules/assert/strict/package.json","./node_modules/.pnpm/node_modules/async_hooks/package.json","./node_modules/.pnpm/node_modules/babel-plugin-react-compiler/package.json","./node_modules/.pnpm/node_modules/buffer/package.json","./node_modules/.pnpm/node_modules/child_process/package.json","./node_modules/.pnpm/node_modules/cluster/package.json","./node_modules/.pnpm/node_modules/console/package.json","./node_modules/.pnpm/node_modules/constants/package.json","./node_modules/.pnpm/node_modules/crypto/package.json","./node_modules/.pnpm/node_modules/dgram/package.json","./node_modules/.pnpm/node_modules/diagnostics_channel/package.json","./node_modules/.pnpm/node_modules/dns/package.json","./node_modules/.pnpm/node_modules/dns/promises/package.json","./node_modules/.pnpm/node_modules/domain/package.json","./node_modules/.pnpm/node_modules/esbuild/package.json","./node_modules/.pnpm/node_modules/events/package.json","./node_modules/.pnpm/node_modules/fs/package.json","./node_modules/.pnpm/node_modules/fs/promises/package.json","./node_modules/.pnpm/node_modules/http/package.json","./node_modules/.pnpm/node_modules/http2/package.json","./node_modules/.pnpm/node_modules/https/package.json","./node_modules/.pnpm/node_modules/inspector/package.json","./node_modules/.pnpm/node_modules/inspector/promises/package.json","./node_modules/.pnpm/node_modules/jest/package.json","./node_modules/.pnpm/node_modules/less/package.json","./node_modules/.pnpm/node_modules/module/package.json","./node_modules/.pnpm/node_modules/net/package.json","./node_modules/.pnpm/node_modules/os/package.json","./node_modules/.pnpm/node_modules/oxc-transform-react/package.json","./node_modules/.pnpm/node_modules/path/package.json","./node_modules/.pnpm/node_modules/path/posix/package.json","./node_modules/.pnpm/node_modules/path/win32/package.json","./node_modules/.pnpm/node_modules/perf_hooks/package.json","./node_modules/.pnpm/node_modules/process/package.json","./node_modules/.pnpm/node_modules/querystring/package.json","./node_modules/.pnpm/node_modules/react/jsx-runtime/package.json","./node_modules/.pnpm/node_modules/react/package.json","./node_modules/.pnpm/node_modules/readline/package.json","./node_modules/.pnpm/node_modules/readline/promises/package.json","./node_modules/.pnpm/node_modules/repl/package.json","./node_modules/.pnpm/node_modules/sass-embedded/package.json","./node_modules/.pnpm/node_modules/sass/package.json","./node_modules/.pnpm/node_modules/stream/consumers/package.json","./node_modules/.pnpm/node_modules/stream/iter/package.json","./node_modules/.pnpm/node_modules/stream/package.json","./node_modules/.pnpm/node_modules/stream/promises/package.json","./node_modules/.pnpm/node_modules/stream/web/package.json","./node_modules/.pnpm/node_modules/string_decoder/package.json","./node_modules/.pnpm/node_modules/stylus/package.json","./node_modules/.pnpm/node_modules/terser/package.json","./node_modules/.pnpm/node_modules/timers/package.json","./node_modules/.pnpm/node_modules/timers/promises/package.json","./node_modules/.pnpm/node_modules/tls/package.json","./node_modules/.pnpm/node_modules/trace_events/package.json","./node_modules/.pnpm/node_modules/tty/package.json","./node_modules/.pnpm/node_modules/url/package.json","./node_modules/.pnpm/node_modules/util/package.json","./node_modules/.pnpm/node_modules/util/types/package.json","./node_modules/.pnpm/node_modules/v8/package.json","./node_modules/.pnpm/node_modules/vm/package.json","./node_modules/.pnpm/node_modules/wasi/package.json","./node_modules/.pnpm/node_modules/worker_threads/package.json","./node_modules/.pnpm/node_modules/zlib/package.json","./node_modules/.pnpm/postcss@8.5.30/node_modules/postcss/lib/package.json","./node_modules/.pnpm/postcss@8.5.30/node_modules/postcss/node_modules/source-map-js/package.json","./node_modules/.pnpm/pretty-format@27.5.1/node_modules/pretty-format/build/package.json","./node_modules/.pnpm/rolldown@1.2.13/node_modules/rolldown/dist/package.json","./node_modules/.pnpm/rolldown@1.2.13/node_modules/rolldown/dist/shared/package.json","./node_modules/.pnpm/seroval@1.6.12/node_modules/seroval/dist/package.json","./node_modules/.pnpm/tinybench@6.2.2/node_modules/tinybench/dist/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@types/esbuild/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@types/less/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@types/sass-embedded/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@types/sass/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@types/stylus/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@types/terser/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@types/vitejs__devtools/config/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@types/vitejs__devtools/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@vitejs/devtools/config/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/@vitejs/devtools/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/esbuild/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/less/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/rolldown/experimental/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/rolldown/filter/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/rolldown/parseAst/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/rolldown/plugins/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/rolldown/utils/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/sass-embedded/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/sass/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/stylus/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/sugarss/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/terser/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/tsx/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/dist/node/chunks/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/dist/node/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/dist/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/@vitejs/devtools/config/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/@vitejs/devtools/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/esbuild/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/less/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/lightningcss/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/postcss/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/rolldown/experimental/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/rolldown/filter/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/rolldown/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/rolldown/parseAst/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/rolldown/plugins/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/rolldown/utils/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/sass-embedded/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/sass/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/stylus/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/node_modules/terser/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/types/internal/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/vite/types/package.json","./node_modules/.pnpm/vite@8.3.4_@types+node@26.6.5_jiti@2.7.0/node_modules/yaml/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@edge-runtime/vm/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@opentelemetry/api/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitest/browser-playwright/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitest/browser-preview/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitest/browser-webdriverio/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitest/coverage-istanbul/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitest/coverage-v8/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/@vitest/ui/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/happy-dom/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vite/module-runner/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vitest/dist/chunks/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vitest/dist/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vitest/node_modules/@vitest/mocker/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vitest/node_modules/chai/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vitest/node_modules/expect-type/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vitest/node_modules/tinybench/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vitest/node_modules/vite/module-runner/package.json","./node_modules/.pnpm/vitest@5.0.5_@types+node@26.6.5_jsdom@30.1.3_vite@8.3.4_@types+node@26.6.5_jiti@2.7.0_/node_modules/vitest/node_modules/vite/package.json","./node_modules/@fontsource-variable/ibm-plex-sans/wght.css/package.json","./node_modules/@fontsource-variable/jetbrains-mono/wght.css/package.json","./node_modules/@rolldown/plugin-babel/package.json","./node_modules/@tanstack/router-plugin/vite/package.json","./node_modules/@testing-library/jest-dom/vitest/package.json","./node_modules/@types/assert/package.json","./node_modules/@types/assert/strict/package.json","./node_modules/@types/async_hooks/package.json","./node_modules/@types/babel-plugin-react-compiler/package.json","./node_modules/@types/buffer/package.json","./node_modules/@types/child_process/package.json","./node_modules/@types/cluster/package.json","./node_modules/@types/console/package.json","./node_modules/@types/constants/package.json","./node_modules/@types/crypto/package.json","./node_modules/@types/dgram/package.json","./node_modules/@types/diagnostics_channel/package.json","./node_modules/@types/dns/package.json","./node_modules/@types/dns/promises/package.json","./node_modules/@types/domain/package.json","./node_modules/@types/esbuild/package.json","./node_modules/@types/events/package.json","./node_modules/@types/fontsource-variable__ibm-plex-sans/package.json","./node_modules/@types/fontsource-variable__ibm-plex-sans/wght.css/package.json","./node_modules/@types/fontsource-variable__jetbrains-mono/package.json","./node_modules/@types/fontsource-variable__jetbrains-mono/wght.css/package.json","./node_modules/@types/fs/package.json","./node_modules/@types/fs/promises/package.json","./node_modules/@types/http/package.json","./node_modules/@types/http2/package.json","./node_modules/@types/https/package.json","./node_modules/@types/inspector/package.json","./node_modules/@types/inspector/promises/package.json","./node_modules/@types/jest/package.json","./node_modules/@types/less/package.json","./node_modules/@types/module/package.json","./node_modules/@types/net/package.json","./node_modules/@types/os/package.json","./node_modules/@types/oxc-transform-react/package.json","./node_modules/@types/path/package.json","./node_modules/@types/path/posix/package.json","./node_modules/@types/path/win32/package.json","./node_modules/@types/perf_hooks/package.json","./node_modules/@types/process/package.json","./node_modules/@types/punycode/package.json","./node_modules/@types/querystring/package.json","./node_modules/@types/react-dom/client/package.json","./node_modules/@types/react/jsx-runtime/package.json","./node_modules/@types/readline/package.json","./node_modules/@types/readline/promises/package.json","./node_modules/@types/repl/package.json","./node_modules/@types/rolldown__plugin-babel/package.json","./node_modules/@types/sass-embedded/package.json","./node_modules/@types/sass/package.json","./node_modules/@types/stream/consumers/package.json","./node_modules/@types/stream/iter/package.json","./node_modules/@types/stream/package.json","./node_modules/@types/stream/promises/package.json","./node_modules/@types/stream/web/package.json","./node_modules/@types/string_decoder/package.json","./node_modules/@types/stylus/package.json","./node_modules/@types/terser/package.json","./node_modules/@types/testing-library__jest-dom/package.json","./node_modules/@types/timers/package.json","./node_modules/@types/timers/promises/package.json","./node_modules/@types/tls/package.json","./node_modules/@types/trace_events/package.json","./node_modules/@types/tty/package.json","./node_modules/@types/url/package.json","./node_modules/@types/util/package.json","./node_modules/@types/util/types/package.json","./node_modules/@types/v8/package.json","./node_modules/@types/vite/client/package.json","./node_modules/@types/vitejs__devtools/config/package.json","./node_modules/@types/vitejs__devtools/package.json","./node_modules/@types/vitest/globals/package.json","./node_modules/@types/vm/package.json","./node_modules/@types/wasi/package.json","./node_modules/@types/worker_threads/package.json","./node_modules/@types/zlib/package.json","./node_modules/@vitejs/devtools/config/package.json","./node_modules/@vitejs/devtools/package.json","./node_modules/assert/package.json","./node_modules/assert/strict/package.json","./node_modules/async_hooks/package.json","./node_modules/babel-plugin-react-compiler/package.json","./node_modules/buffer/package.json","./node_modules/child_process/package.json","./node_modules/cluster/package.json","./node_modules/console/package.json","./node_modules/constants/package.json","./node_modules/crypto/package.json","./node_modules/dgram/package.json","./node_modules/diagnostics_channel/package.json","./node_modules/dns/package.json","./node_modules/dns/promises/package.json","./node_modules/domain/package.json","./node_modules/esbuild/package.json","./node_modules/events/package.json","./node_modules/fs/package.json","./node_modules/fs/promises/package.json","./node_modules/http/package.json","./node_modules/http2/package.json","./node_modules/https/package.json","./node_modules/inspector/package.json","./node_modules/inspector/promises/package.json","./node_modules/jest/package.json","./node_modules/less/package.json","./node_modules/module/package.json","./node_modules/net/package.json","./node_modules/os/package.json","./node_modules/oxc-transform-react/package.json","./node_modules/path/package.json","./node_modules/path/posix/package.json","./node_modules/path/win32/package.json","./node_modules/perf_hooks/package.json","./node_modules/process/package.json","./node_modules/punycode/package.json","./node_modules/querystring/package.json","./node_modules/react-dom/client/package.json","./node_modules/react/jsx-runtime/package.json","./node_modules/readline/package.json","./node_modules/readline/promises/package.json","./node_modules/repl/package.json","./node_modules/sass-embedded/package.json","./node_modules/sass/package.json","./node_modules/stream/consumers/package.json","./node_modules/stream/iter/package.json","./node_modules/stream/package.json","./node_modules/stream/promises/package.json","./node_modules/stream/web/package.json","./node_modules/string_decoder/package.json","./node_modules/stylus/package.json","./node_modules/terser/package.json","./node_modules/timers/package.json","./node_modules/timers/promises/package.json","./node_modules/tls/package.json","./node_modules/trace_events/package.json","./node_modules/tty/package.json","./node_modules/url/package.json","./node_modules/util/package.json","./node_modules/util/types/package.json","./node_modules/v8/package.json","./node_modules/vite/client/package.json","./node_modules/vitest/globals/package.json","./node_modules/vm/package.json","./node_modules/wasi/package.json","./node_modules/worker_threads/package.json","./node_modules/zlib/package.json"]} \ No newline at end of file