diff --git a/docs/administration/server-configuration.mdx b/docs/administration/server-configuration.mdx index bd444ed98..2d1efa140 100644 --- a/docs/administration/server-configuration.mdx +++ b/docs/administration/server-configuration.mdx @@ -38,7 +38,7 @@ url = "https://fabro.example.com/api/v1" [server.web] enabled = true -url = "https://fabro-web.example.com" +url = "https://fabro.example.com" [server.auth] methods = ["dev-token", "github"] @@ -127,10 +127,12 @@ Control the embedded SPA and browser-oriented routes. | Key | Description | Default | |---|---|---| | `enabled` | Serve the embedded SPA, `/auth/*`, and the web-only helper endpoints under `/api/v1` | `true` | -| `url` | External web UI URL used for OAuth redirects | none (no implicit derivation from `server.listen`) | +| `url` | Required single canonical origin for the server. The browser UI and `/auth/*` routes use this origin, and it must be an absolute `http(s)` URL. | `http://localhost:3000` | When `enabled = false`, the server still exposes the machine API and `/health`, but `/`, `/auth/*`, SPA client routes, `/api/v1/auth/me`, `/api/v1/setup/*`, and `/api/v1/demo/toggle` all return `404`. +`server.web.url` is not a secondary web host. Fabro supports a single public origin for API and web traffic. In local development that can be plain HTTP such as `http://localhost:3000` or `http://127.0.0.1:3000`. In production, operators are responsible for terminating HTTPS upstream. + ### `[server.auth]` section Configure how users authenticate with the server. diff --git a/docs/api-reference/fabro-api.yaml b/docs/api-reference/fabro-api.yaml index 57e9c9987..9eefde011 100644 --- a/docs/api-reference/fabro-api.yaml +++ b/docs/api-reference/fabro-api.yaml @@ -416,21 +416,6 @@ paths: schema: $ref: "#/components/schemas/ErrorResponse" - /api/v1/auth/cli/config: - get: - operationId: getCliAuthConfig - tags: [Discovery] - summary: CLI Auth Configuration - description: Returns whether CLI OAuth login is available for this server and which web origin should handle the browser flow. - security: [] - responses: - "200": - description: CLI authentication configuration - content: - application/json: - schema: - $ref: "#/components/schemas/CliAuthConfig" - # ── Runs ────────────────────────────────────────────────────────────── /api/v1/runs: @@ -5190,33 +5175,6 @@ components: description: Health status indicator. example: ok - CliAuthConfig: - description: Capability and routing information for CLI OAuth login. - type: object - required: - - enabled - - web_url - - methods - properties: - enabled: - type: boolean - description: Whether CLI OAuth login is currently available. - web_url: - type: ["string", "null"] - description: Canonical browser origin for the OAuth flow when enabled. - example: https://fabro.example.com - methods: - type: array - description: Authentication methods configured on the server. - items: - type: string - example: ["github", "dev-token"] - reason: - type: ["string", "null"] - description: > - Optional machine-readable reason when CLI OAuth login is unavailable. - Known values currently include `github_not_enabled` and `web_not_enabled`. - SecretType: description: The way a secret is consumed by the sandbox. type: string diff --git a/docs/plans/2026-04-19-003-feat-cli-auth-login-plan.md b/docs/plans/2026-04-19-003-feat-cli-auth-login-plan.md index e09b209a4..f67f8d206 100644 --- a/docs/plans/2026-04-19-003-feat-cli-auth-login-plan.md +++ b/docs/plans/2026-04-19-003-feat-cli-auth-login-plan.md @@ -24,14 +24,14 @@ We need per-user, per-device CLI credentials that are server-side revocable, sho - **R2.** Access credential is a short-lived (10 min) HS256 JWT; refresh credential is an opaque 32-byte secret rotated on every use with 30 d sliding expiry. (origin §Token model) - **R3.** Refresh-token rotation is atomic: two concurrent refreshes cannot both succeed. Reuse detection deletes the entire chain. (origin §Revocation semantics) - **R4.** Identity is OIDC-style `(idp_issuer, idp_subject)` — not GitHub username — forward-compatible with Google/GHES. `login` is display-only. (origin §Identity model) -- **R5.** Browser flow runs on `server.web.url`, not on the `--server` target. CLI discovers the canonical origin via `GET /api/v1/auth/cli/config` preflight. (origin §Architecture overview, §Canonical origin) -- **R6.** `fabro auth login` succeeds on servers reachable only over HTTPS or Unix socket (browser hits web_url; token endpoints use the CLI transport). (origin §Canonical origin) +- **R5.** `server.web.url` is the server's single canonical origin. `fabro auth login` opens the browser against the resolved HTTP(S) `--server` target directly; no `/api/v1/auth/cli/config` preflight exists. (origin §Architecture overview, §Canonical origin) +- **R6.** `fabro auth login` requires an HTTP(S) server target. Unix-socket targets use the local dev-token flow instead of browser OAuth. Plain HTTP is allowed; operator-managed TLS is a deployment concern. (origin §Canonical origin) - **R7.** Dev-token flow is unchanged. Bearer-priority order: `FABRO_DEV_TOKEN` env → `AuthStore` JWT → dev-token file fallback. (origin §CLI UX, §Bearer priority) - **R8.** Reactive auto-refresh triggers on 401 with `code == "access_token_expired"` in the `ApiError` envelope; refresh failures surface as "session expired — run `fabro auth login`". (origin §Bearer priority) - **R9.** Server-side errors in the browser flow reach the CLI via OAuth-style redirect to loopback (`?error=&state=&error_description=`) when `redirect_uri`+`state` have validated; plain HTML page otherwise. (origin §Browser-to-CLI error handoff) - **R10.** GitHub allowlist rejection at `/auth/callback/github` happens **before** a session is minted; `/auth/cli/resume` must forward the callback's `?error=` to the CLI loopback without checking session first. (origin §/auth/cli/resume algorithm) - **R11.** `SESSION_SECRET` is reused as an HKDF master; cookie and JWT keys are domain-separated subkeys. No new env vars. (origin §Settings and secrets) -- **R12.** `server.auth.methods=[github]` combined with `web.enabled=false` fails at server startup with a clear config error. Other "CLI login unavailable" states (github not in methods) are running-server states reported via preflight. (origin §Web mode and config validation) +- **R12.** `server.auth.methods=[github]` combined with `web.enabled=false` fails at server startup with a clear config error. When web is disabled and `/auth/*` is not mounted, CLI login is unsupported and `/auth/cli/start` returns `404`. (origin §Web mode and config validation) - **R13.** IP allowlist, when enabled, covers every new endpoint (no carve-outs). (origin §IP allowlist) - **R14.** `fabro auth status` runs fully offline against local state (no server call); `--json` emits structured output; credentials and their expiry windows are shown per server. (origin §CLI UX) - **R15.** Integration tests exercise the real `web_auth.rs` OAuth glue end-to-end against a black-box `twin-github` extended with OAuth endpoints, not via `#[cfg(test)]` session injection. (origin §Prerequisite: twin-github OAuth extension) @@ -44,7 +44,7 @@ Explicit non-goals for this plan (deferred to fast-follow work): - **Windows support for `fabro auth login` writes.** `fabro auth login` returns a clear error on Windows; users work around via WSL or dev-token. Dropped to avoid DPAPI/ACL complexity that doesn't clearly improve on the 0600 file baseline for the same-user threat model. Note: `fabro auth status` and `fabro auth logout` DO work on Windows (see R14 — status must remain cross-platform for dev-token detection and logged-out-state reporting). - **Idempotency grace on refresh.** Network failures during refresh-response delivery force re-login. A future grace window (if needed) must key by stable per-install identifier, not UA/source-IP. -- **`--browser-url` override for split-network topologies.** Browser always opens against `config.web_url` in v1. +- **`--browser-url` override for split-network topologies.** Browser always opens against the resolved HTTP(S) `--server` target in v1. - **Public `oauth_base_url` / `api_base_url` settings** for GHES / self-hosted GitHub. Test harness uses a test-only injection point; public settings land when GHES itself lands. - Device flow (`--device`). Same token model, different exchange endpoint. - OS keychain storage. Plain 0600 file is the v1 Unix storage baseline. @@ -105,7 +105,7 @@ Design-time external work was consolidated in the spec (OAuth 2.0 RFC 6749 §4.1 - **Reactive-only auto-refresh (no pre-flight).** CLI refreshes on 401 with `code == "access_token_expired"` and retries once. No clock-based pre-flight check. Avoids concurrent-refresh storms across parallel CLI invocations, removes clock-sync assumptions, and shrinks the refresh code path by half. Latency cost is at most one extra round-trip per ~10 min window of activity. - **HTTPS-or-loopback-or-unix-socket-only for refresh traffic, checked by URL parsing, not string matching.** CLI parses the server target as `url::Url`. Accepts: `scheme == "https"`; OR `scheme == "http"` with `url.host()` parsing to an `IpAddr` that `is_loopback()` returns true (covers `127.0.0.0/8`, `::1`, and `::ffff:127.0.0.1`); OR the Unix-socket target type. Rejects literal `localhost` (DNS-overridable), any host containing dots after a loopback prefix (e.g., `127.0.0.1.evil.com`), any encoded form (decimal `2130706433`, hex `0x7f000001`, octal). Surfaces an actionable error pointing at the scheme or host. Prevents silent refresh-token leaks over plaintext. - **`map_api_error_structured` wraps `progenitor_client::Error` into `ApiFailure { status, code, detail }`.** Existing `map_api_error` is refactored to call `map_api_error_structured` and discard `code`, reducing drift risk. Auto-refresh wrapper uses the structured helper. -- **OpenAPI-first for preflight.** `GET /api/v1/auth/cli/config` lands in `fabro-api.yaml` and regenerates the Rust+TS clients. Preflight response carries `reason` enum only (not `reason_description`) — the CLI renders user-facing text from the enum locally. The OAuth-style `/auth/cli/{token,refresh,logout}` endpoints are outside the canonical API surface (different envelope, different auth); they are **not** in the OpenAPI spec and are hand-wired. +- **No OpenAPI preflight surface.** The CLI constructs browser URLs from its resolved HTTP(S) target directly. The OAuth-style `/auth/cli/{token,refresh,logout}` endpoints remain outside the canonical API surface and are hand-wired. - **Browser URL always equals `config.web_url` in v1.** Split-network topologies (dockerized dev, VPN mismatches, SSH-plus-browser-on-different-hosts) are deferred to a fast-follow `--browser-url` flag. For v1, users whose `server.web.url` is not reachable from their browser cannot complete login; the preflight handler returns the exact URL the CLI will open so the failure mode is at least visible. ## Open Questions diff --git a/docs/plans/2026-04-20-001-fix-cli-server-same-host-assumptions-plan.md b/docs/plans/2026-04-20-001-fix-cli-server-same-host-assumptions-plan.md index c56a50d8c..ebdbecf5b 100644 --- a/docs/plans/2026-04-20-001-fix-cli-server-same-host-assumptions-plan.md +++ b/docs/plans/2026-04-20-001-fix-cli-server-same-host-assumptions-plan.md @@ -11,6 +11,8 @@ date: 2026-04-20 Tighten the CLI/server contract so an explicit `http(s)://...` target is always treated as a remote server, never as a disguised local daemon. This removes the remaining places where the CLI still derives remote behavior from local storage, local dev-token files, or colocated-network assumptions left over from the earlier same-host architecture. +Historical note (2026-04-21): the auth flow now also assumes a single origin. `fabro auth login` opens the browser flow on the resolved HTTP(S) target directly; the old `/api/v1/auth/cli/config` preflight no longer exists. + ## Problem Frame The codebase already moved most commands to a server-target model, but a few central helpers still collapse explicit remote targets back into local-machine state: diff --git a/docs/plans/2026-04-20-002-refactor-extract-fabro-client-crate-plan.md b/docs/plans/2026-04-20-002-refactor-extract-fabro-client-crate-plan.md index 04faa0652..4ce7dfb11 100644 --- a/docs/plans/2026-04-20-002-refactor-extract-fabro-client-crate-plan.md +++ b/docs/plans/2026-04-20-002-refactor-extract-fabro-client-crate-plan.md @@ -5,6 +5,8 @@ status: active date: 2026-04-20 --- +Historical note (2026-04-21): the follow-up auth-surface tightening removed `LoopbackClassification`, `target.loopback_classification()`, `ensure_refresh_target_transport`, and the plain-HTTP refresh rejection. References to those APIs below describe the planned state at the time, not the current implementation. + # refactor: Extract fabro-client crate and lift domain DTOs to fabro-types ## Overview diff --git a/docs/reference/architecture.mdx b/docs/reference/architecture.mdx index ff8015e71..32ee05428 100644 --- a/docs/reference/architecture.mdx +++ b/docs/reference/architecture.mdx @@ -39,7 +39,7 @@ Key server config options: | Setting | Description | |---|---| | `server.listen` | Bind transport: Unix socket or plain TCP listener | -| `server.api.url` / `server.web.url` | External HTTPS URLs advertised to clients | +| `server.api.url` / `server.web.url` | External API base URL and the single canonical browser/API origin | | `server.auth.methods` | Bootstrap auth methods: `dev-token`, `github`, or both | | `server.scheduler.max_concurrent_runs` | Scheduler concurrency limit (default 5) | | `[run.*]` | Defaults applied to every run (overridable per-run) | diff --git a/docs/reference/user-configuration.mdx b/docs/reference/user-configuration.mdx index 4f4f18a4c..bdbf8d0e4 100644 --- a/docs/reference/user-configuration.mdx +++ b/docs/reference/user-configuration.mdx @@ -257,6 +257,8 @@ fabro model list --server https://fabro.example.com/api/v1 An explicit `http(s)://...` target is always remote-by-contract. Fabro does not derive auth for that target from a local storage dir, an active local daemon record, or `~/.fabro/dev-token`. Use CLI OAuth (`fabro auth login --server ...`) or an explicit `FABRO_DEV_TOKEN` when you need remote auth. +`fabro auth login` only works with `type = "http"` targets. Unix-socket targets use the local dev-token flow instead of browser OAuth. Plain `http://...` targets are supported for local or trusted deployments; operators remain responsible for providing HTTPS anywhere real credentials cross an untrusted network. + `fabro exec` does not automatically use `[cli.target]`. It only routes model traffic through a Fabro server when you pass `--server` for that invocation. ## `[run.pull_request]` diff --git a/docs/superpowers/specs/2026-04-19-cli-auth-login-design.md b/docs/superpowers/specs/2026-04-19-cli-auth-login-design.md index 51134a087..73a9d1ad5 100644 --- a/docs/superpowers/specs/2026-04-19-cli-auth-login-design.md +++ b/docs/superpowers/specs/2026-04-19-cli-auth-login-design.md @@ -40,16 +40,14 @@ Identity is the OIDC-style composite `(idp_issuer, idp_subject)`, future-proof f No new auth primitives on the wire: bearer credentials ride `Authorization: Bearer `; web sessions continue to ride the `Cookie` header. The existing `jwt_auth.rs` extractor keeps reading session cookies where it already does, and the bearer-header validation is extended to distinguish (by prefix) dev-token vs JWT access token. -**Canonical origin.** All browser-visible CLI-flow URLs (`/auth/cli/start`, `/auth/cli/resume`, the chained `/auth/login/github` → `/auth/callback/github`) run against `server.web.url`, not against whatever `--server` URL the CLI was given. The existing OAuth flow is hard-coded to redirect to `{server.web.url}/auth/callback/github` (`web_auth.rs:339`), and `fabro_oauth_state` / the new `fabro_cli_flow` cookies are cookie-jar-bound to that origin. If the CLI target differs (e.g. `--server http://127.0.0.1:3000` with `server.web.url=https://fabro.example.com`, or a Unix-socket target), the browser flow still runs on `server.web.url`. The CLI discovers this origin via a new unauthenticated preflight endpoint `GET /api/v1/auth/cli/config` (see Server endpoints), called over the CLI's normal transport. The non-browser step (POST `/auth/cli/token`, `/auth/cli/refresh`, `/auth/cli/logout`) continues to use the CLI's normal transport and can therefore target a Unix socket. +**Canonical origin.** `server.web.url` is the single canonical origin for the server. The browser-visible CLI-flow URLs (`/auth/cli/start`, `/auth/cli/resume`, `/auth/login/github`, `/auth/callback/github`) all run on that same origin, and `fabro auth login` opens the browser against its resolved HTTP(S) `--server` target directly. Dual-origin API/web deployments and the old `/api/v1/auth/cli/config` preflight are no longer part of the design. Unix-socket targets do not support browser OAuth login; they use the local dev-token flow instead. **Web mode and config validation.** `/auth/*` only mounts when `server.web.enabled = true` (`server.rs:916-918`). The config-validity matrix: - `auth.methods = [..., "github", ...]` **and** `web.enabled = false` → **startup error**. These two settings contradict each other; the admin must pick one. -- `auth.methods` excludes `"github"` (regardless of `web.enabled`) → server starts normally. CLI login is not available; preflight `GET /api/v1/auth/cli/config` returns `enabled: false`. -- `web.enabled = false` with `"github"` also absent → server starts; `/auth/cli/*` routes don't mount; preflight (mounted on the always-available API router) returns `enabled: false`. -- `web.enabled = true` and `auth.methods` includes `"github"` → everything mounted; preflight returns `enabled: true`. - -The CLI always hits the preflight first and fails fast with an actionable message rather than opening a doomed browser. +- `auth.methods` excludes `"github"` (regardless of `web.enabled`) → server starts normally. Direct hits to `/auth/cli/start` redirect back to the validated CLI loopback with `error=github_not_configured`. +- `web.enabled = false` with `"github"` also absent → server starts; `/auth/cli/*` routes do not mount, so CLI login is unsupported and `/auth/cli/start` returns `404`. +- `web.enabled = true` and `auth.methods` includes `"github"` → the browser flow is mounted on the server origin and CLI login is available for HTTP(S) targets. **Browser-to-CLI error handoff.** Server-side failures during the browser flow (invalid PKCE params, ineligible session, allowlist rejection at callback) need to reach the terminal without devolving into a loopback-listener timeout. The contract, matching OAuth 2.0 RFC 6749 §4.1.2.1: diff --git a/lib/crates/fabro-cli/src/commands/auth/login.rs b/lib/crates/fabro-cli/src/commands/auth/login.rs index c7c85f42d..0419def51 100644 --- a/lib/crates/fabro-cli/src/commands/auth/login.rs +++ b/lib/crates/fabro-cli/src/commands/auth/login.rs @@ -1,9 +1,8 @@ use std::time::Duration; -use anyhow::{Context as _, Result, anyhow, bail}; +use anyhow::{Context as _, Result, bail}; use chrono::{DateTime, Utc}; -use fabro_api::types; -use fabro_client::{AuthEntry, AuthStore, StoredSubject, ensure_refresh_target_transport}; +use fabro_client::{AuthEntry, AuthStore, StoredSubject}; use fabro_http::header::CONTENT_TYPE; use fabro_types::settings::CliSettings; use fabro_types::settings::cli::CliLayer; @@ -55,16 +54,7 @@ pub(super) async fn login_command( { let ctx = CommandContext::base(printer, cli.clone(), cli_layer)?; let target = user_config::resolve_server_target(&args.server, ctx.machine_settings())?; - let config = fetch_cli_auth_config(&target).await?; - if !config.enabled { - bail!("{}", cli_auth_unavailable_message(config.reason.as_deref())); - } - - let web_url = config - .web_url - .as_deref() - .filter(|value| !value.is_empty()) - .ok_or_else(|| anyhow!("CLI login is not available on this server."))?; + let web_url = browser_origin(&target)?; let pkce = fabro_oauth::generate_pkce(); let state = fabro_oauth::generate_state(); let callback_path = "/callback"; @@ -96,8 +86,6 @@ pub(super) async fn login_command( } }; - ensure_refresh_target_transport(&target)?; - let tokens = exchange_cli_token(&target, &code, &pkce.verifier, &redirect_uri).await?; let entry = AuthEntry { access_token: tokens.access_token, @@ -121,15 +109,16 @@ pub(super) async fn login_command( } #[cfg(unix)] -async fn fetch_cli_auth_config(target: &ServerTarget) -> Result { - let (http_client, base_url) = target.build_public_http_client()?; - let client = fabro_api::ApiClient::new_with_client(&base_url, http_client); - client - .get_cli_auth_config() - .send() - .await - .map(progenitor_client::ResponseValue::into_inner) - .map_err(|err| anyhow!("{err}")) +fn browser_origin(target: &ServerTarget) -> Result<&str> { + if target.as_unix_socket_path().is_some() { + bail!( + "fabro auth login requires an HTTP(S) server target. Unix-socket targets use a dev-token instead. Pass --server http(s)://... or configure [cli.target] with an http/https URL." + ); + } + + target + .as_http_url() + .ok_or_else(|| anyhow::anyhow!("server target must be an http(s) URL")) } #[cfg(unix)] @@ -207,26 +196,20 @@ fn open_browser_or_print(browser_url: &str, no_browser: bool, printer: Printer) } } -fn cli_auth_unavailable_message(reason: Option<&str>) -> &'static str { - match reason { - Some("github_not_enabled") => { - "CLI login is not available on this server because GitHub login is not enabled." - } - Some("web_not_enabled") => { - "CLI login is not available on this server because the web UI is disabled." - } - _ => "CLI login is not available on this server.", - } -} - fn login_failure_message(error_code: &str, error_description: Option<&str>) -> String { match error_code { "github_session_required" => { "GitHub session required. Complete sign-in in the browser and try again.".to_string() } + "github_not_configured" => { + "The fabro server does not have GitHub login enabled. Ask the operator to enable it or use a dev-token.".to_string() + } "access_denied" => "Authorization denied.".to_string(), "unauthorized" => "Login not permitted.".to_string(), - "server_error" => "Could not complete GitHub sign-in.".to_string(), + "server_error" => error_description + .filter(|value| !value.is_empty()) + .unwrap_or("Could not complete GitHub sign-in.") + .to_string(), _ => error_description .filter(|value| !value.is_empty()) .unwrap_or("Could not complete login.") @@ -255,11 +238,10 @@ struct OAuthErrorBody { mod tests { use base64::Engine as _; use base64::engine::general_purpose::URL_SAFE_NO_PAD; - use fabro_client::LoopbackClassification; use insta::assert_snapshot; use sha2::{Digest, Sha256}; - use super::{build_browser_url, cli_auth_unavailable_message, login_failure_message}; + use super::{browser_origin, build_browser_url, login_failure_message}; use crate::user_config::ServerTarget; #[test] @@ -270,36 +252,16 @@ mod tests { } #[test] - fn browser_url_uses_web_origin_and_callback_params() { + fn browser_url_uses_server_target_origin_and_callback_params() { let url = build_browser_url( - "https://app.fabro.example", + "https://fabro.example", "http://127.0.0.1:41234/callback", "state-123", "challenge-abc", ) .unwrap(); - assert_snapshot!(url, @"https://app.fabro.example/auth/cli/start?redirect_uri=http%3A%2F%2F127.0.0.1%3A41234%2Fcallback&state=state-123&code_challenge=challenge-abc&code_challenge_method=S256"); - } - - #[test] - fn unavailable_reason_messages_cover_known_and_unknown_values() { - assert_eq!( - cli_auth_unavailable_message(Some("github_not_enabled")), - "CLI login is not available on this server because GitHub login is not enabled." - ); - assert_eq!( - cli_auth_unavailable_message(Some("web_not_enabled")), - "CLI login is not available on this server because the web UI is disabled." - ); - assert_eq!( - cli_auth_unavailable_message(Some("future_reason")), - "CLI login is not available on this server." - ); - assert_eq!( - cli_auth_unavailable_message(None), - "CLI login is not available on this server." - ); + assert_snapshot!(url, @"https://fabro.example/auth/cli/start?redirect_uri=http%3A%2F%2F127.0.0.1%3A41234%2Fcallback&state=state-123&code_challenge=challenge-abc&code_challenge_method=S256"); } #[test] @@ -317,21 +279,31 @@ mod tests { "Login not permitted." ); assert_eq!( - login_failure_message("server_error", Some("Could not complete GitHub sign-in")), - "Could not complete GitHub sign-in." + login_failure_message( + "github_not_configured", + Some("GitHub authentication is not enabled on this server") + ), + "The fabro server does not have GitHub login enabled. Ask the operator to enable it or use a dev-token." ); assert_eq!( - login_failure_message("future_code", Some("Future description")), - "Future description" + login_failure_message("server_error", Some("SESSION_SECRET is not configured")), + "SESSION_SECRET is not configured" ); } #[test] - fn token_transport_accepts_only_https_loopback_or_unix() { - let target = ServerTarget::http_url("https://fabro.example.com").unwrap(); - assert_eq!( - target.loopback_classification().unwrap(), - LoopbackClassification::Https + fn auth_login_accepts_http_target() { + let target = ServerTarget::http_url("http://fabro.example.com/api/v1").unwrap(); + assert_eq!(browser_origin(&target).unwrap(), "http://fabro.example.com"); + } + + #[test] + fn auth_login_rejects_unix_socket_target() { + let target = ServerTarget::unix_socket_path("/tmp/fabro.sock").unwrap(); + let err = browser_origin(&target).unwrap_err(); + assert!( + err.to_string() + .contains("fabro auth login requires an HTTP(S) server target") ); } } diff --git a/lib/crates/fabro-cli/tests/it/scenario/auth.rs b/lib/crates/fabro-cli/tests/it/scenario/auth.rs index 89776a39d..e2d8b0521 100644 --- a/lib/crates/fabro-cli/tests/it/scenario/auth.rs +++ b/lib/crates/fabro-cli/tests/it/scenario/auth.rs @@ -30,16 +30,6 @@ fn auth_login_refresh_logout_flow() { let server = MockServer::start(); let target = server_target(&server); - let config_mock = server.mock(|when, then| { - when.method(GET).path("/api/v1/auth/cli/config"); - then.status(200) - .header("Content-Type", "application/json") - .json_body(json!({ - "enabled": true, - "web_url": server.base_url(), - "methods": ["github"] - })); - }); let token_mock = server.mock(|when, then| { when.method(POST) .path("/auth/cli/token") @@ -61,7 +51,6 @@ fn auth_login_refresh_logout_flow() { "login output should confirm success:\n{}", String::from_utf8_lossy(&login_output.stderr) ); - config_mock.assert(); token_mock.assert(); let status = auth_status(&context, &target); @@ -167,16 +156,6 @@ fn auth_refresh_failure_clears_local_session() { "fabro_dev_abababababababababababababababababababababababababababababababab\n", ); - server.mock(|when, then| { - when.method(GET).path("/api/v1/auth/cli/config"); - then.status(200) - .header("Content-Type", "application/json") - .json_body(json!({ - "enabled": true, - "web_url": server.base_url(), - "methods": ["github"] - })); - }); server.mock(|when, then| { when.method(POST) .path("/auth/cli/token") @@ -289,6 +268,37 @@ fn auth_refresh_failure_clears_local_session() { auth_required_mock.assert(); } +#[test] +fn auth_login_rejects_unix_socket_target() { + let context = test_context!(); + let socket_path = context.temp_dir.join("fabro.sock"); + + let output = context + .command() + .args([ + "auth", + "login", + "--no-browser", + "--server", + socket_path.to_str().unwrap(), + ]) + .output() + .expect("auth login should execute"); + + assert!( + !output.status.success(), + "auth login should fail for unix-socket targets\nstdout:\n{}\nstderr:\n{}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + assert!( + String::from_utf8_lossy(&output.stderr) + .contains("fabro auth login requires an HTTP(S) server target"), + "unix-socket rejection should explain the transport requirement:\n{}", + String::from_utf8_lossy(&output.stderr) + ); +} + #[tokio::test(flavor = "multi_thread")] async fn auth_login_refresh_logout_flow_against_real_server_and_twin_github() { let context = test_context!(); @@ -303,22 +313,19 @@ async fn auth_login_refresh_logout_flow_against_real_server_and_twin_github() { String::from_utf8_lossy(&login_output.stderr) ); assert!( - browser_url.starts_with(&format!("{}/auth/cli/start", harness.web_base_url)), - "browser flow should open the configured web origin, got: {browser_url}" + browser_url.starts_with(&format!("{}/auth/cli/start", harness.api_base_url)), + "browser flow should open the server target origin, got: {browser_url}" ); - assert_ne!(harness.api_base_url, harness.web_base_url); let status = auth_status(&context, &target); assert_eq!(status["servers"].as_array().map(Vec::len), Some(1)); assert_eq!(status["servers"][0]["oauth_state"], "active"); assert_eq!(status["servers"][0]["login"], "octocat"); assert_eq!(status["servers"][0]["server"], harness.api_base_url); - assert!(harness.api_requests.contains("GET /api/v1/auth/cli/config")); - assert!(harness.web_requests.contains("GET /auth/cli/start")); - assert!(harness.web_requests.contains("GET /auth/cli/resume")); - assert!(harness.web_requests.contains("POST /auth/cli/resume")); assert!(harness.api_requests.contains("POST /auth/cli/token")); - assert!(!harness.web_requests.contains("POST /auth/cli/token")); + assert!(harness.api_requests.contains("GET /auth/cli/start")); + assert!(harness.api_requests.contains("GET /auth/cli/resume")); + assert!(harness.api_requests.contains("POST /auth/cli/resume")); harness.api_requests.clear(); let exec_output = context @@ -358,7 +365,7 @@ async fn auth_login_refresh_logout_flow_against_real_server_and_twin_github() { ); harness.api_requests.clear(); - expire_saved_access_token(&context, &harness.web_base_url); + expire_saved_access_token(&context, &harness.api_base_url); let expired_exec_output = context .exec_cmd() .args([ @@ -464,8 +471,8 @@ async fn auth_login_surfaces_access_denied_from_real_browser_flow() { let (login_output, browser_url) = complete_login_via_browser(&context, &target).await; assert!( - browser_url.starts_with(&format!("{}/auth/cli/start", harness.web_base_url)), - "browser flow should open the configured web origin, got: {browser_url}" + browser_url.starts_with(&format!("{}/auth/cli/start", harness.api_base_url)), + "browser flow should open the server target origin, got: {browser_url}" ); assert!( !login_output.status.success(), @@ -491,7 +498,7 @@ async fn auth_cli_start_ignores_dev_token_session_and_redirects_to_github_login( let client = no_redirect_browser_client(); let login_response = client - .post(format!("{}/auth/login/dev-token", harness.web_base_url)) + .post(format!("{}/auth/login/dev-token", harness.api_base_url)) .json(&json!({ "token": TEST_DEV_TOKEN })) .send() .await @@ -501,7 +508,7 @@ async fn auth_cli_start_ignores_dev_token_session_and_redirects_to_github_login( let response = client .get(format!( "{}/auth/cli/start?redirect_uri=http://127.0.0.1:4444/callback&state=abcdefghijklmnop&code_challenge=challenge&code_challenge_method=S256", - harness.web_base_url + harness.api_base_url )) .send() .await diff --git a/lib/crates/fabro-cli/tests/it/support/auth_harness.rs b/lib/crates/fabro-cli/tests/it/support/auth_harness.rs index b907cf442..a8a81b40b 100644 --- a/lib/crates/fabro-cli/tests/it/support/auth_harness.rs +++ b/lib/crates/fabro-cli/tests/it/support/auth_harness.rs @@ -43,12 +43,9 @@ pub(crate) const TEST_DEV_TOKEN: &str = pub(crate) struct RealAuthHarness { pub(crate) api_base_url: String, - pub(crate) web_base_url: String, api_server: RunningHttpServer, - web_server: RunningHttpServer, twin: fabro_test::TwinGitHub, pub(crate) api_requests: ListenerRequestLog, - pub(crate) web_requests: ListenerRequestLog, } impl RealAuthHarness { @@ -71,9 +68,8 @@ impl RealAuthHarness { let twin = fabro_test::TwinGitHub::start(github_state).await; let (api_listener, api_base_url) = bind_listener().await; - let (web_listener, web_base_url) = bind_listener().await; - let settings = auth_settings(&web_base_url, &github_client_id, auth_methods); + let settings = auth_settings(&api_base_url, &github_client_id, auth_methods); let resolved = resolve_server_from_file(&settings).expect("settings should resolve"); let dev_token = dev_token.map(str::to_string); let auth_mode = resolve_auth_mode_with_lookup(&resolved, |name| match name { @@ -105,22 +101,15 @@ impl RealAuthHarness { ); let api_requests = ListenerRequestLog::default(); - let web_requests = ListenerRequestLog::default(); - let api_server = RunningHttpServer::start(api_listener, router.clone(), &api_requests); - let web_server = RunningHttpServer::start(web_listener, router, &web_requests); + let api_server = RunningHttpServer::start(api_listener, router, &api_requests); wait_for_http_ready(&api_base_url).await; - wait_for_http_ready(&web_base_url).await; api_requests.clear(); - web_requests.clear(); Self { api_base_url, - web_base_url, api_server, - web_server, twin, api_requests, - web_requests, } } @@ -130,7 +119,6 @@ impl RealAuthHarness { pub(crate) async fn shutdown(self) { self.api_server.shutdown().await; - self.web_server.shutdown().await; self.twin.shutdown().await; } } @@ -354,7 +342,7 @@ async fn bind_listener() -> (TcpListener, String) { } fn auth_settings( - web_base_url: &str, + api_base_url: &str, github_client_id: &str, auth_methods: &[&str], ) -> fabro_types::settings::SettingsLayer { @@ -374,7 +362,7 @@ methods = [{auth_methods}] allowed_usernames = ["octocat"] [server.web] -url = "{web_base_url}" +url = "{api_base_url}" [server.integrations.github] client_id = "{github_client_id}" diff --git a/lib/crates/fabro-client/src/client.rs b/lib/crates/fabro-client/src/client.rs index 3cc165c28..9bb7873f9 100644 --- a/lib/crates/fabro-client/src/client.rs +++ b/lib/crates/fabro-client/src/client.rs @@ -25,7 +25,6 @@ use crate::error::{ ApiError, ApiFailure, classify_api_error, classify_http_response, convert_type, is_not_found_error, map_api_error, raw_response_failure_error, }; -use crate::loopback::LoopbackClassification; use crate::session::OAuthSession; use crate::target::ServerTarget; use crate::{AuthEntry, StoredSubject, sse}; @@ -355,8 +354,6 @@ impl Client { self.rebuild_with_fallback(oauth_session).await?; bail!("CLI session has expired. Run `fabro auth login` again."); } - ensure_refresh_target_transport(&oauth_session.target)?; - let (http_client, base_url) = oauth_session.target.build_public_http_client()?; let response = http_client .post(format!("{base_url}/auth/cli/refresh")) @@ -1307,21 +1304,6 @@ pub fn apply_bearer_token_auth( Ok(builder.default_headers(headers)) } -pub fn ensure_refresh_target_transport(target: &ServerTarget) -> Result<()> { - match target.loopback_classification()? { - LoopbackClassification::Https - | LoopbackClassification::LoopbackHttp - | LoopbackClassification::UnixSocket => Ok(()), - LoopbackClassification::Rejected => bail!(refresh_transport_error(target)), - } -} - -fn refresh_transport_error(target: &ServerTarget) -> String { - format!( - "Refusing to send refresh-token credentials over plaintext HTTP to a non-loopback host ({target}). Use HTTPS, or bind the server to 127.0.0.1 / ::1." - ) -} - fn non_zero_u64_from_u32(value: u32) -> Option { NonZeroU64::new(u64::from(value)) } @@ -1333,6 +1315,8 @@ fn non_zero_u64_from_usize(value: usize) -> Option { #[cfg(test)] mod tests { use chrono::Duration as ChronoDuration; + use tokio::io::{AsyncReadExt, AsyncWriteExt}; + use tokio::net::TcpListener; use super::*; use crate::AuthStore; @@ -1357,10 +1341,42 @@ mod tests { #[cfg(unix)] #[tokio::test] - async fn refresh_access_token_rejects_plain_http_non_loopback_targets() { + async fn refresh_access_token_allows_plain_http_targets() { let temp = tempfile::tempdir().unwrap(); let auth_store = AuthStore::new(temp.path().join("auth.json")); - let target = ServerTarget::http_url("http://fabro.example.com").unwrap(); + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let port = listener.local_addr().unwrap().port(); + let server = tokio::spawn(async move { + let (mut stream, _) = listener.accept().await.unwrap(); + let mut request = vec![0_u8; 4096]; + let read = stream.read(&mut request).await.unwrap(); + let request = String::from_utf8_lossy(&request[..read]); + assert!( + request.starts_with("POST /auth/cli/refresh HTTP/1.1"), + "unexpected refresh request: {request}" + ); + let body = serde_json::json!({ + "access_token": "access-refreshed", + "access_token_expires_at": (chrono::Utc::now() + ChronoDuration::minutes(10)).to_rfc3339(), + "refresh_token": "refresh-refreshed", + "refresh_token_expires_at": (chrono::Utc::now() + ChronoDuration::days(30)).to_rfc3339(), + "subject": { + "idp_issuer": "https://github.com", + "idp_subject": "12345", + "login": "octocat", + "name": "Name octocat", + "email": "octocat@example.com" + } + }) + .to_string(); + let response = format!( + "HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}", + body.len(), + body + ); + stream.write_all(response.as_bytes()).await.unwrap(); + }); + let target = ServerTarget::http_url(format!("http://localhost:{port}")).unwrap(); let entry = oauth_entry("octocat"); auth_store.put(&target, entry.clone()).unwrap(); @@ -1368,25 +1384,15 @@ mod tests { .target(target.clone()) .credential(Credential::OAuth(entry)) .oauth_session(OAuthSession::new(target.clone(), auth_store.clone())) - .transport( - "http://fabro.example.com", - fabro_http::HttpClientBuilder::new() - .no_proxy() - .build() - .unwrap(), - ) + .transport("http://localhost", fabro_http::test_http_client().unwrap()) .connect() .await .unwrap(); - let err = client - .refresh_access_token("access-octocat") - .await - .unwrap_err(); - assert!( - err.to_string() - .contains("Refusing to send refresh-token credentials over plaintext HTTP") - ); - assert!(auth_store.get(&target).unwrap().is_some()); + client.refresh_access_token("access-octocat").await.unwrap(); + let refreshed = auth_store.get(&target).unwrap().unwrap(); + assert_eq!(refreshed.access_token, "access-refreshed"); + assert_eq!(refreshed.refresh_token, "refresh-refreshed"); + server.abort(); } } diff --git a/lib/crates/fabro-client/src/lib.rs b/lib/crates/fabro-client/src/lib.rs index e8a78d380..a2d3e5278 100644 --- a/lib/crates/fabro-client/src/lib.rs +++ b/lib/crates/fabro-client/src/lib.rs @@ -4,22 +4,17 @@ pub mod auth_store; pub mod client; pub mod credential; pub mod error; -pub mod loopback; pub mod session; pub mod sse; pub mod target; pub use auth_store::{AuthEntry, AuthStore, AuthStoreError, LockError, StoredSubject}; -pub use client::{ - Client, RunEventStream, TransportConnector, apply_bearer_token_auth, - ensure_refresh_target_transport, -}; +pub use client::{Client, RunEventStream, TransportConnector, apply_bearer_token_auth}; pub use credential::{Credential, CredentialFallback}; pub use error::{ ApiError, ApiFailure, StructuredApiError, classify_api_error, classify_http_response, convert_type, is_not_found_error, map_api_error, parse_error_response_value, raw_response_failure_error, }; -pub use loopback::{LoopbackClassification, TargetSchemeError}; pub use session::OAuthSession; pub use target::ServerTarget; diff --git a/lib/crates/fabro-client/src/loopback.rs b/lib/crates/fabro-client/src/loopback.rs deleted file mode 100644 index cea27093f..000000000 --- a/lib/crates/fabro-client/src/loopback.rs +++ /dev/null @@ -1,208 +0,0 @@ -use std::net::IpAddr; - -use thiserror::Error; - -use crate::target::ServerTarget; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LoopbackClassification { - Https, - LoopbackHttp, - UnixSocket, - Rejected, -} - -#[derive(Debug, Error)] -pub enum TargetSchemeError { - #[error("invalid server URL `{value}`: {reason}")] - InvalidUrl { value: String, reason: String }, - #[error("unsupported server URL scheme `{scheme}`")] - UnsupportedScheme { scheme: String }, - #[error("server URL `{value}` is missing a host")] - MissingHost { value: String }, -} - -pub(crate) fn classify_target( - target: &ServerTarget, -) -> Result { - if target.is_unix_socket() { - Ok(LoopbackClassification::UnixSocket) - } else if let Some(api_url) = target.as_http_url() { - classify_http_target(api_url) - } else { - Err(TargetSchemeError::MissingHost { - value: target.to_string(), - }) - } -} - -fn classify_http_target(api_url: &str) -> Result { - let url = fabro_http::Url::parse(api_url).map_err(|source| TargetSchemeError::InvalidUrl { - value: api_url.to_string(), - reason: source.to_string(), - })?; - - match url.scheme() { - "https" => Ok(LoopbackClassification::Https), - "http" => { - if url.host_str().is_none() { - return Err(TargetSchemeError::MissingHost { - value: api_url.to_string(), - }); - } - if !url.username().is_empty() || url.password().is_some() { - return Ok(LoopbackClassification::Rejected); - } - let Some(authority) = raw_authority(api_url) else { - return Err(TargetSchemeError::MissingHost { - value: api_url.to_string(), - }); - }; - Ok(if raw_host_is_loopback_literal(authority) { - LoopbackClassification::LoopbackHttp - } else { - LoopbackClassification::Rejected - }) - } - scheme => Err(TargetSchemeError::UnsupportedScheme { - scheme: scheme.to_string(), - }), - } -} - -fn raw_authority(url: &str) -> Option<&str> { - let (_, remainder) = url.split_once("://")?; - let end = remainder - .find(|ch| ['/', '?', '#'].contains(&ch)) - .unwrap_or(remainder.len()); - Some(&remainder[..end]) -} - -fn raw_host_is_loopback_literal(authority: &str) -> bool { - if authority.contains('@') { - return false; - } - let Some(host) = raw_host(authority) else { - return false; - }; - match host.parse::().ok() { - Some(IpAddr::V4(ipv4)) => host.contains('.') && ipv4.is_loopback(), - Some(ip @ IpAddr::V6(_)) => ip_is_loopback(&ip), - None => false, - } -} - -fn raw_host(authority: &str) -> Option<&str> { - if authority.is_empty() { - return None; - } - if authority.starts_with('[') { - let end = authority.find(']')?; - let remainder = &authority[end + 1..]; - if !remainder.is_empty() && !remainder.starts_with(':') { - return None; - } - return Some(&authority[1..end]); - } - - let host = authority - .split_once(':') - .map_or(authority, |(host, _)| host); - if host.is_empty() { None } else { Some(host) } -} - -fn ip_is_loopback(ip: &IpAddr) -> bool { - match ip { - IpAddr::V4(ipv4) => ipv4.is_loopback(), - IpAddr::V6(ipv6) => { - ipv6.is_loopback() || ipv6.to_ipv4_mapped().is_some_and(|ip| ip.is_loopback()) - } - } -} - -#[cfg(test)] -mod tests { - use super::LoopbackClassification; - use crate::target::ServerTarget; - - #[test] - fn classifies_https_loopback_and_unix_targets() { - let cases = [ - ( - ServerTarget::http_url("https://fabro.example.com").unwrap(), - LoopbackClassification::Https, - ), - ( - ServerTarget::http_url("http://127.0.0.1:3000").unwrap(), - LoopbackClassification::LoopbackHttp, - ), - ( - ServerTarget::http_url("http://[::1]:3000").unwrap(), - LoopbackClassification::LoopbackHttp, - ), - ( - ServerTarget::http_url("http://[::ffff:127.0.0.1]:3000").unwrap(), - LoopbackClassification::LoopbackHttp, - ), - ( - ServerTarget::unix_socket_path("/tmp/fabro.sock").unwrap(), - LoopbackClassification::UnixSocket, - ), - ]; - - for (target, expected) in cases { - assert_eq!(target.loopback_classification().unwrap(), expected); - } - } - - #[test] - fn rejects_plain_http_non_loopback_targets() { - let cases = [ - "http://fabro.example.com", - "http://127.0.0.1.evil.com", - "http://127.0.0.1:1@attacker.com", - "http://localhost", - "http://localhost.evil.com", - ]; - - for api_url in cases { - let target = ServerTarget::http_url(api_url).unwrap(); - assert_eq!( - target.loopback_classification().unwrap(), - LoopbackClassification::Rejected - ); - } - } - - #[test] - fn rejects_obfuscated_ipv4_literals_at_parse_time() { - let cases = [ - "http://2130706433", // decimal integer - "http://0x7f000001", // hex integer - "http://0177.0.0.1", // octal dotted - "http://127.1", // two-part short - "http://127.0.1", // three-part short - "http://0x7f.0.0.1", // mixed hex/decimal - "http://127.00.0.1", // leading-zero octet - "http://127.0.0.001", // leading-zero octet - ]; - for api_url in cases { - assert!( - ServerTarget::http_url(api_url).is_err(), - "{api_url} should not parse as a server target" - ); - } - } - - #[test] - fn rejects_non_http_server_targets_at_parse_time() { - let error = "ftp://fabro.example.com" - .parse::() - .unwrap_err(); - assert!( - error - .to_string() - .contains("server target must be an http(s) URL or absolute Unix socket path") - ); - } -} diff --git a/lib/crates/fabro-client/src/target.rs b/lib/crates/fabro-client/src/target.rs index b590bcb0a..b76ae272c 100644 --- a/lib/crates/fabro-client/src/target.rs +++ b/lib/crates/fabro-client/src/target.rs @@ -4,8 +4,6 @@ use std::str::FromStr; use anyhow::{Result, bail}; -use crate::loopback::{LoopbackClassification, TargetSchemeError, classify_target}; - #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum ServerTarget { HttpUrl(CanonicalHttpUrl), @@ -74,10 +72,6 @@ impl ServerTarget { bail!("Unix-socket HTTP client is not supported on this platform") } } - - pub fn loopback_classification(&self) -> Result { - classify_target(self) - } } impl fmt::Display for ServerTarget { diff --git a/lib/crates/fabro-server/src/auth/cli_flow.rs b/lib/crates/fabro-server/src/auth/cli_flow.rs index 20370c680..36345cdc2 100644 --- a/lib/crates/fabro-server/src/auth/cli_flow.rs +++ b/lib/crates/fabro-server/src/auth/cli_flow.rs @@ -22,7 +22,7 @@ use tracing::{info, warn}; use url::{Host, Url}; use crate::auth::{self, AuthCode, ConsumeOutcome, JwtSubject, RefreshToken}; -use crate::jwt_auth::{AuthMode, ConfiguredAuth, auth_method_name}; +use crate::jwt_auth::{AuthMode, ConfiguredAuth}; use crate::server::AppState; use crate::web_auth::{SessionCookie, read_private_session}; @@ -44,16 +44,6 @@ struct OAuthErrorResponse<'a> { error_description: &'a str, } -#[derive(Serialize)] -struct CliAuthConfigResponse { - enabled: bool, - #[serde(rename = "web_url")] - web_url: Option, - methods: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - reason: Option<&'static str>, -} - #[derive(Deserialize)] struct CliStartParams { redirect_uri: Option, @@ -100,10 +90,6 @@ struct CliTokenResponse { subject: CliAuthSubjectResponse, } -pub(crate) fn api_routes() -> Router> { - Router::new().route("/auth/cli/config", get(config)) -} - pub(crate) fn web_routes() -> Router> { Router::new() .route("/cli/start", get(start)) @@ -113,42 +99,12 @@ pub(crate) fn web_routes() -> Router> { .route("/cli/logout", post(logout)) } -async fn config( - State(state): State>, - Extension(auth_mode): Extension, -) -> Json { - let methods = configured_methods(&auth_mode); - let settings = state.server_settings(); - let web_enabled = settings.web.enabled; - let web_url = resolved_web_url(state.as_ref()); - let github_enabled = methods.iter().any(|method| method == "github"); - let enabled = web_enabled && github_enabled; - let reason = if enabled { - None - } else if !web_enabled { - Some("web_not_enabled") - } else { - Some("github_not_enabled") - }; - - Json(CliAuthConfigResponse { - enabled, - web_url: enabled.then_some(web_url).flatten(), - methods, - reason, - }) -} - async fn start( State(state): State>, Extension(auth_mode): Extension, Query(params): Query, headers: HeaderMap, ) -> Response { - if !github_enabled(&auth_mode) { - return static_error_page(GITHUB_NOT_CONFIGURED); - } - let Some(redirect_uri) = params .redirect_uri .as_deref() @@ -164,6 +120,24 @@ async fn start( return static_error_page(INVALID_OR_MISSING_STATE); } + if !github_enabled(&auth_mode) { + return redirect_with_error( + &redirect_uri, + state_token, + "github_not_configured", + "GitHub authentication is not enabled on this server", + ); + } + + let Some(session_key) = state.session_key() else { + return redirect_with_error( + &redirect_uri, + state_token, + "server_error", + "SESSION_SECRET is not configured on this server", + ); + }; + let Some(code_challenge) = params.code_challenge.as_deref() else { return redirect_with_error( &redirect_uri, @@ -180,10 +154,6 @@ async fn start( "Invalid PKCE parameters", ); } - - let Some(session_key) = state.session_key() else { - return static_error_page(GITHUB_NOT_CONFIGURED); - }; let session = read_private_session(&headers, &session_key); let secure = session_cookie_secure(state.as_ref()); @@ -703,17 +673,6 @@ async fn logout( StatusCode::NO_CONTENT.into_response() } -fn configured_methods(auth_mode: &AuthMode) -> Vec { - match auth_mode { - AuthMode::Enabled(config) => config - .methods - .iter() - .map(|method| auth_method_name(*method).to_string()) - .collect(), - AuthMode::Disabled => Vec::new(), - } -} - fn github_enabled(auth_mode: &AuthMode) -> bool { matches!( auth_mode, @@ -739,14 +698,7 @@ fn github_auth_not_configured() -> Response { } fn resolved_web_url(state: &AppState) -> Option { - state - .server_settings() - .web - .url - .resolve(|name| std::env::var(name).ok()) - .ok() - .map(|resolved| resolved.value) - .filter(|value| !value.is_empty()) + state.canonical_origin().ok() } fn session_cookie_secure(state: &AppState) -> bool { @@ -1367,8 +1319,8 @@ mod tests { use uuid::Uuid; use super::{ - CliFlowCookie, add_cli_flow_cookie, api_routes, read_private_cli_flow, - user_agent_fingerprint, web_routes, + CliFlowCookie, add_cli_flow_cookie, read_private_cli_flow, user_agent_fingerprint, + web_routes, }; use crate::auth::{self, AuthCode, RefreshToken}; use crate::jwt_auth::{AuthMode, ConfiguredAuth}; @@ -1423,7 +1375,6 @@ mod tests { false, ); let app = axum::Router::new() - .nest("/api/v1", api_routes()) .nest("/auth", web_routes()) .layer(Extension(github_auth_mode())) .with_state(Arc::clone(&state)); diff --git a/lib/crates/fabro-server/src/auth/mod.rs b/lib/crates/fabro-server/src/auth/mod.rs index 5c597c358..14efe5d1e 100644 --- a/lib/crates/fabro-server/src/auth/mod.rs +++ b/lib/crates/fabro-server/src/auth/mod.rs @@ -4,7 +4,7 @@ mod jwt; mod keys; mod translate; -pub(crate) use cli_flow::{api_routes, web_routes}; +pub(crate) use cli_flow::web_routes; pub(crate) use fabro_store::{AuthCode, ConsumeOutcome, RefreshToken}; pub use github_endpoints::GithubEndpoints; pub(crate) use jwt::{JwtError, JwtSubject, issue, verify}; diff --git a/lib/crates/fabro-server/src/canonical_origin.rs b/lib/crates/fabro-server/src/canonical_origin.rs new file mode 100644 index 000000000..04fb2532c --- /dev/null +++ b/lib/crates/fabro-server/src/canonical_origin.rs @@ -0,0 +1,37 @@ +use fabro_types::settings::ServerSettings as ResolvedServerSettings; +use url::Url; + +use crate::server::EnvLookup; + +pub(crate) fn validate_canonical_origin( + resolved: &ResolvedServerSettings, + env_lookup: &EnvLookup, +) -> Result<(), String> { + resolve_canonical_origin(resolved, env_lookup).map(|_| ()) +} + +pub(crate) fn resolve_canonical_origin( + resolved: &ResolvedServerSettings, + env_lookup: &EnvLookup, +) -> Result { + let value = resolved + .web + .url + .resolve(|name| env_lookup(name)) + .map_err(|_| canonical_origin_error(&resolved.web.url.as_source()))? + .value; + + let parsed = Url::parse(&value).map_err(|_| canonical_origin_error(&value))?; + let scheme = parsed.scheme(); + if !matches!(scheme, "http" | "https") || parsed.host_str().is_none() { + return Err(canonical_origin_error(&value)); + } + + Ok(value) +} + +fn canonical_origin_error(value: &str) -> String { + format!( + "server.web.url is required and must be an absolute http(s) URL (got \"{value}\"). Set it in your settings file or via the FABRO_WEB_URL environment variable." + ) +} diff --git a/lib/crates/fabro-server/src/lib.rs b/lib/crates/fabro-server/src/lib.rs index c09a85a0f..f1a76af8f 100644 --- a/lib/crates/fabro-server/src/lib.rs +++ b/lib/crates/fabro-server/src/lib.rs @@ -10,6 +10,7 @@ pub mod auth; pub mod bind; +mod canonical_origin; pub mod csp; #[allow( clippy::wildcard_imports, diff --git a/lib/crates/fabro-server/src/serve.rs b/lib/crates/fabro-server/src/serve.rs index f6c27856b..24a8a684d 100644 --- a/lib/crates/fabro-server/src/serve.rs +++ b/lib/crates/fabro-server/src/serve.rs @@ -27,6 +27,7 @@ use tokio::time::interval; use tracing::{error, info, warn}; use crate::bind::{self, Bind, BindRequest}; +use crate::canonical_origin::validate_canonical_origin; use crate::github_webhooks::{TailscaleFunnelManager, WEBHOOK_ROUTE, WEBHOOK_SECRET_ENV}; use crate::ip_allowlist::{GitHubMetaResolver, IpAllowlistConfig, resolve_ip_allowlist_config}; use crate::jwt_auth::resolve_auth_mode_with_lookup; @@ -510,6 +511,8 @@ where build_artifact_object_store(&resolved_server_settings)?; let artifact_store = fabro_store::ArtifactStore::new(artifact_object_store, artifact_prefix); let env_lookup: EnvLookup = Arc::new(|name| std::env::var(name).ok()); + validate_canonical_origin(&resolved_server_settings, &env_lookup) + .map_err(anyhow::Error::msg)?; let state = build_app_state(AppStateConfig { settings: Arc::clone(&shared_settings), registry_factory_override: None, @@ -607,14 +610,8 @@ where .expect("config lock poisoned"); *cfg != effective }; - if changed { - match state_for_poll.replace_settings(effective) { - Ok(()) => info!("Server config reloaded"), - Err(error) => warn!( - error = %error, - "Failed to resolve reloaded server config, keeping previous" - ), - } + if changed && state_for_poll.replace_settings(effective).is_ok() { + info!("Server config reloaded"); } } Err(e) => { diff --git a/lib/crates/fabro-server/src/server.rs b/lib/crates/fabro-server/src/server.rs index 19ae6a41f..b2711cb95 100644 --- a/lib/crates/fabro-server/src/server.rs +++ b/lib/crates/fabro-server/src/server.rs @@ -108,6 +108,7 @@ use ulid::Ulid; use crate::auth::{self, GithubEndpoints, auth_translation_middleware, demo_routing_middleware}; use crate::bind::Bind; +use crate::canonical_origin::{resolve_canonical_origin, validate_canonical_origin}; use crate::error::ApiError; use crate::github_webhooks::{ WEBHOOK_ROUTE, WEBHOOK_SECRET_ENV, parse_event_metadata, verify_signature, @@ -575,6 +576,7 @@ pub struct AppState { pub(crate) settings: Arc>, pub(crate) server_settings: RwLock>, pub(crate) local_daemon_mode: bool, + pub(crate) env_lookup: EnvLookup, http_client: Option, shutting_down: AtomicBool, registry_factory_override: Option>, @@ -691,6 +693,17 @@ impl AppState { self.server_secrets.get(name) } + pub(crate) fn resolve_interp(&self, value: &InterpString) -> anyhow::Result { + value + .resolve(|name| (self.env_lookup)(name)) + .map(|resolved| resolved.value) + .map_err(anyhow::Error::from) + } + + pub(crate) fn canonical_origin(&self) -> Result { + resolve_canonical_origin(&self.server_settings(), &self.env_lookup) + } + pub(crate) fn session_key(&self) -> Option { self.server_secret("SESSION_SECRET") .and_then(|value| auth::derive_cookie_key(value.as_bytes()).ok()) @@ -780,6 +793,15 @@ impl AppState { .join("\n") ) })?); + let resolved_ref = Arc::as_ref(&resolved); + if let Err(error) = validate_canonical_origin(resolved_ref, &self.env_lookup) { + let error = anyhow::anyhow!(error); + warn!( + error = %error, + "Failed to resolve reloaded server config, keeping previous" + ); + return Err(error); + } *self.settings.write().expect("settings lock poisoned") = settings; *self @@ -965,12 +987,9 @@ pub fn build_router_with_options( let api_common = if web_enabled { Router::new() .route("/openapi.json", get(openapi_spec)) - .merge(auth::api_routes()) .merge(web_auth::api_routes()) } else { - Router::new() - .route("/openapi.json", get(openapi_spec)) - .merge(auth::api_routes()) + Router::new().route("/openapi.json", get(openapi_spec)) }; let demo_router = Router::new() @@ -2674,6 +2693,7 @@ pub(crate) fn build_app_state(config: AppStateConfig) -> anyhow::Result, + } + + #[derive(Default)] + struct LogCaptureVisitor { + fields: Vec<(String, String)>, + } + + impl Visit for LogCaptureVisitor { + fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) { + self.fields + .push((field.name().to_string(), format!("{value:?}"))); + } + } + + struct LogCaptureLayer { + events: StdArc>>, + } + + impl Layer for LogCaptureLayer { + fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) { + if event.metadata().target() != "fabro_server::server" { + return; + } + + let mut visitor = LogCaptureVisitor::default(); + event.record(&mut visitor); + self.events.lock().unwrap().push(LogCapture { + level: *event.metadata().level(), + target: event.metadata().target().to_string(), + fields: visitor.fields, + }); + } + } + + fn capture_logs(f: impl FnOnce() -> T) -> (T, StdArc>>) { + let events = StdArc::new(StdMutex::new(Vec::::new())); + let subscriber = Registry::default().with(LogCaptureLayer { + events: StdArc::clone(&events), + }); + let result = tracing::subscriber::with_default(subscriber, f); + (result, events) + } + + fn canonical_origin_settings(url: &str) -> SettingsLayer { + fabro_config::parse_settings_layer(&format!( + r#" +_version = 1 + +[server.web] +url = "{url}" +"# + )) + .expect("settings fixture should parse") + } + #[tokio::test] async fn resolved_settings_view_returns_internal_error_when_runtime_settings_stop_resolving() { let state = create_app_state(); @@ -7441,6 +7526,47 @@ type = "http" assert_status!(response, StatusCode::INTERNAL_SERVER_ERROR).await; } + #[test] + fn replace_settings_rejects_invalid_canonical_origin_and_keeps_previous_settings() { + for invalid in ["", "/relative/path", "ftp://fabro.example.com"] { + let state = create_app_state_with_env_lookup( + canonical_origin_settings("http://valid.example.com"), + 5, + { + let invalid = invalid.to_string(); + move |name| (name == "FABRO_WEB_URL").then(|| invalid.clone()) + }, + ); + + let (result, logs) = capture_logs(|| { + state.replace_settings(canonical_origin_settings("{{ env.FABRO_WEB_URL }}")) + }); + + let err = result.expect_err("invalid canonical origin should be rejected"); + assert!( + err.to_string() + .contains("server.web.url is required and must be an absolute http(s) URL"), + "unexpected error for {invalid}: {err}" + ); + assert_eq!( + state.canonical_origin().unwrap(), + "http://valid.example.com".to_string() + ); + + let logs = logs.lock().unwrap(); + assert!(logs.iter().any(|event| { + event.level == tracing::Level::WARN + && event.target == "fabro_server::server" + && event.fields.iter().any(|(name, value)| { + name == "message" + && value.contains( + "Failed to resolve reloaded server config, keeping previous", + ) + }) + })); + } + } + #[tokio::test] async fn create_secret_stores_file_secret_and_excludes_it_from_snapshot() { let state = create_app_state(); diff --git a/lib/crates/fabro-server/src/web_auth.rs b/lib/crates/fabro-server/src/web_auth.rs index 0ceb1170d..7018d6fc3 100644 --- a/lib/crates/fabro-server/src/web_auth.rs +++ b/lib/crates/fabro-server/src/web_auth.rs @@ -16,7 +16,9 @@ use serde_json::json; use tracing::{debug, error, info, warn}; use crate::auth::GithubEndpoints; -use crate::jwt_auth::{AuthMode, AuthenticatedSubject, auth_method_name, dev_token_matches}; +use crate::jwt_auth::{ + AuthMode, AuthenticatedService, AuthenticatedSubject, auth_method_name, dev_token_matches, +}; use crate::server::AppState; pub const SESSION_COOKIE_NAME: &str = "__fabro_session"; @@ -255,11 +257,8 @@ fn callback_error_redirect( } } -fn resolve_interp(value: &InterpString) -> anyhow::Result { - value - .resolve(|name| std::env::var(name).ok()) - .map(|resolved| resolved.value) - .map_err(anyhow::Error::from) +fn resolve_interp(state: &AppState, value: &InterpString) -> anyhow::Result { + state.resolve_interp(value) } fn auth_methods_from_mode(auth_mode: &AuthMode) -> Vec { @@ -386,7 +385,7 @@ async fn login_github( json!({"error": "GitHub App client_id is not configured"}), ); }; - let client_id = match resolve_interp(client_id) { + let client_id = match resolve_interp(state.as_ref(), client_id) { Ok(client_id) => client_id, Err(err) => { warn!(error = %err, "OAuth login failed: client_id could not be resolved"); @@ -396,7 +395,7 @@ async fn login_github( ); } }; - let web_url = match resolve_interp(&settings.web.url) { + let web_url = match resolve_interp(state.as_ref(), &settings.web.url) { Ok(web_url) => web_url, Err(err) => { warn!(error = %err, "OAuth login failed: server.web.url could not be resolved"); @@ -538,7 +537,7 @@ async fn callback_github( json!({"error": "GitHub App client_id is not configured"}), ); }; - let client_id = match resolve_interp(client_id) { + let client_id = match resolve_interp(state.as_ref(), client_id) { Ok(client_id) => client_id, Err(err) => { error!(error = %err, "OAuth callback failed: client_id could not be resolved"); @@ -555,7 +554,7 @@ async fn callback_github( json!({"error": "GITHUB_APP_CLIENT_SECRET is not configured"}), ); }; - let web_url = match resolve_interp(&settings.web.url) { + let web_url = match resolve_interp(state.as_ref(), &settings.web.url) { Ok(web_url) => web_url, Err(err) => { error!(error = %err, "OAuth callback failed: server.web.url could not be resolved"); @@ -820,6 +819,7 @@ async fn auth_me(subject: AuthenticatedSubject, headers: HeaderMap) -> Response } async fn toggle_demo( + _auth: AuthenticatedService, State(state): State>, Json(payload): Json, ) -> Response { diff --git a/lib/crates/fabro-server/tests/it/api/cli_auth_config.rs b/lib/crates/fabro-server/tests/it/api/cli_auth_config.rs deleted file mode 100644 index 6ed2ed774..000000000 --- a/lib/crates/fabro-server/tests/it/api/cli_auth_config.rs +++ /dev/null @@ -1,171 +0,0 @@ -use std::sync::Arc; - -use axum::body::Body; -use axum::http::{Request, StatusCode}; -use fabro_config::parse_settings_layer; -use fabro_server::ip_allowlist::IpAllowlistConfig; -use fabro_server::jwt_auth::{AuthMode, ConfiguredAuth}; -use fabro_server::server::{ - RouterOptions, build_router_with_options, create_app_state_with_options, -}; -use fabro_types::settings::ServerAuthMethod; -use tower::ServiceExt; - -use crate::helpers::body_json; - -fn settings(source: &str) -> fabro_types::settings::SettingsLayer { - parse_settings_layer(source).expect("fixture should parse") -} - -fn build_app( - settings: fabro_types::settings::SettingsLayer, - auth_mode: &AuthMode, - options: RouterOptions, -) -> axum::Router { - build_router_with_options( - create_app_state_with_options(settings, 5), - auth_mode, - Arc::new(IpAllowlistConfig::default()), - options, - ) -} - -#[tokio::test] -async fn cli_auth_config_reports_enabled_github_login() { - let app = build_app( - settings( - r#" -_version = 1 - -[server.auth] -methods = ["github"] - -[server.auth.github] -allowed_usernames = ["alice"] - -[server.web] -url = "https://fabro.example" - -[server.integrations.github] -client_id = "Iv1.test" -"#, - ), - &AuthMode::Enabled(ConfiguredAuth::new(vec![ServerAuthMethod::Github], None)), - RouterOptions::default(), - ); - - let response = app - .oneshot( - Request::builder() - .uri("/api/v1/auth/cli/config") - .body(Body::empty()) - .unwrap(), - ) - .await - .unwrap(); - - assert_eq!(response.status(), StatusCode::OK); - let body = body_json(response.into_body()).await; - assert_eq!( - body, - serde_json::json!({ - "enabled": true, - "web_url": "https://fabro.example", - "methods": ["github"] - }) - ); -} - -#[tokio::test] -async fn cli_auth_config_reports_github_not_enabled() { - let app = build_app( - settings( - r#" -_version = 1 - -[server.auth] -methods = ["dev-token"] -"#, - ), - &AuthMode::Enabled(ConfiguredAuth::new(vec![ServerAuthMethod::DevToken], None)), - RouterOptions::default(), - ); - - let response = app - .oneshot( - Request::builder() - .uri("/api/v1/auth/cli/config") - .body(Body::empty()) - .unwrap(), - ) - .await - .unwrap(); - - assert_eq!(response.status(), StatusCode::OK); - let body = body_json(response.into_body()).await; - assert_eq!( - body, - serde_json::json!({ - "enabled": false, - "web_url": null, - "methods": ["dev-token"], - "reason": "github_not_enabled" - }) - ); -} - -#[tokio::test] -async fn cli_auth_config_reports_web_not_enabled_and_api_mount_survives() { - let app = build_app( - settings( - r#" -_version = 1 - -[server.auth] -methods = ["dev-token"] - -[server.web] -enabled = false -"#, - ), - &AuthMode::Enabled(ConfiguredAuth::new(vec![ServerAuthMethod::DevToken], None)), - RouterOptions { - web_enabled: false, - ..RouterOptions::default() - }, - ); - - let config_response = app - .clone() - .oneshot( - Request::builder() - .uri("/api/v1/auth/cli/config") - .body(Body::empty()) - .unwrap(), - ) - .await - .unwrap(); - - assert_eq!(config_response.status(), StatusCode::OK); - let body = body_json(config_response.into_body()).await; - assert_eq!( - body, - serde_json::json!({ - "enabled": false, - "web_url": null, - "methods": ["dev-token"], - "reason": "web_not_enabled" - }) - ); - - let start_response = app - .oneshot( - Request::builder() - .uri("/auth/cli/start") - .body(Body::empty()) - .unwrap(), - ) - .await - .unwrap(); - assert_eq!(start_response.status(), StatusCode::NOT_FOUND); -} diff --git a/lib/crates/fabro-server/tests/it/api/mod.rs b/lib/crates/fabro-server/tests/it/api/mod.rs index ed6afbfd3..9bec16c6c 100644 --- a/lib/crates/fabro-server/tests/it/api/mod.rs +++ b/lib/crates/fabro-server/tests/it/api/mod.rs @@ -1,4 +1,3 @@ -mod cli_auth_config; mod cli_auth_token; mod docs; mod install; diff --git a/lib/crates/fabro-server/tests/it/api/routing.rs b/lib/crates/fabro-server/tests/it/api/routing.rs index df596c0ff..4deb779a5 100644 --- a/lib/crates/fabro-server/tests/it/api/routing.rs +++ b/lib/crates/fabro-server/tests/it/api/routing.rs @@ -4,9 +4,9 @@ use std::sync::Arc; use axum::body::Body; use axum::extract::ConnectInfo; use axum::http::{Method, Request, StatusCode}; -use fabro_config::parse_settings_layer; +use fabro_config::{parse_settings_layer, resolve_server_from_file}; use fabro_server::ip_allowlist::{IpAllowlist, IpAllowlistConfig}; -use fabro_server::jwt_auth::AuthMode; +use fabro_server::jwt_auth::{AuthMode, resolve_auth_mode_with_lookup}; use fabro_server::server::{ RouterOptions, build_router, build_router_with_options, create_app_state, create_app_state_with_options, @@ -16,6 +16,29 @@ use tower::ServiceExt; use crate::helpers::{checked_response, response_json, response_status, response_text}; +const DEV_TOKEN: &str = + "fabro_dev_abababababababababababababababababababababababababababababababab"; +const SESSION_SECRET: &str = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + +fn dev_token_enabled_auth_mode() -> AuthMode { + let settings = parse_settings_layer( + r#" +_version = 1 + +[server.auth] +methods = ["dev-token"] +"#, + ) + .expect("settings fixture should parse"); + let resolved = resolve_server_from_file(&settings).expect("settings should resolve"); + resolve_auth_mode_with_lookup(&resolved, |name| match name { + "SESSION_SECRET" => Some(SESSION_SECRET.to_string()), + "FABRO_DEV_TOKEN" => Some(DEV_TOKEN.to_string()), + _ => None, + }) + .expect("auth mode should resolve") +} + #[tokio::test] async fn old_unversioned_routes_return_404() { let app = build_router(create_app_state(), AuthMode::Disabled); @@ -215,6 +238,59 @@ async fn web_enabled_serves_web_only_routes() { .await; } +#[tokio::test] +async fn toggle_demo_rejects_unauthenticated_requests() { + let app = build_router(create_app_state(), dev_token_enabled_auth_mode()); + + let response = app + .oneshot( + Request::builder() + .method("POST") + .uri("/api/v1/demo/toggle") + .header("content-type", "application/json") + .body(Body::from(r#"{"enabled":true}"#)) + .unwrap(), + ) + .await + .unwrap(); + response_status( + response, + StatusCode::UNAUTHORIZED, + "POST /api/v1/demo/toggle without auth", + ) + .await; +} + +#[tokio::test] +async fn toggle_demo_allows_authenticated_requests() { + let app = build_router(create_app_state(), dev_token_enabled_auth_mode()); + + let response = checked_response( + app.oneshot( + Request::builder() + .method("POST") + .uri("/api/v1/demo/toggle") + .header("authorization", format!("Bearer {DEV_TOKEN}")) + .header("content-type", "application/json") + .body(Body::from(r#"{"enabled":true}"#)) + .unwrap(), + ) + .await + .unwrap(), + StatusCode::OK, + "POST /api/v1/demo/toggle with dev token", + ) + .await; + assert!( + response + .headers() + .get("set-cookie") + .and_then(|value| value.to_str().ok()) + .is_some_and(|value| value.contains("fabro-demo=1")), + "authenticated demo toggle should set the demo cookie" + ); +} + #[tokio::test] async fn security_headers_are_applied_to_all_responses() { let app = build_router(create_app_state(), AuthMode::Disabled); diff --git a/lib/crates/fabro-spa/assets/assets/chunk-7fpy4pmb.js b/lib/crates/fabro-spa/assets/assets/chunk-7fpy4pmb.js deleted file mode 100644 index 271497c14..000000000 --- a/lib/crates/fabro-spa/assets/assets/chunk-7fpy4pmb.js +++ /dev/null @@ -1 +0,0 @@ -import"./chunk-q07bg6gn.js";var e=Object.freeze(JSON.parse('{"name":"Pierre Dark","type":"dark","colors":{"editor.background":"#070707","editor.foreground":"#fbfbfb","foreground":"#fbfbfb","focusBorder":"#009fff","selection.background":"#19283c","editor.selectionBackground":"#009fff4d","editor.lineHighlightBackground":"#19283c8c","editorCursor.foreground":"#009fff","editorLineNumber.foreground":"#84848A","editorLineNumber.activeForeground":"#adadb1","editorIndentGuide.background":"#1F1F21","editorIndentGuide.activeBackground":"#2e2e30","diffEditor.insertedTextBackground":"#00cab11a","diffEditor.deletedTextBackground":"#ff2e3f1a","sideBar.background":"#141415","sideBar.foreground":"#adadb1","sideBar.border":"#070707","sideBarTitle.foreground":"#fbfbfb","sideBarSectionHeader.background":"#141415","sideBarSectionHeader.foreground":"#adadb1","sideBarSectionHeader.border":"#070707","activityBar.background":"#141415","activityBar.foreground":"#fbfbfb","activityBar.border":"#070707","activityBar.activeBorder":"#009fff","activityBarBadge.background":"#009fff","activityBarBadge.foreground":"#070707","titleBar.activeBackground":"#141415","titleBar.activeForeground":"#fbfbfb","titleBar.inactiveBackground":"#141415","titleBar.inactiveForeground":"#84848A","titleBar.border":"#070707","list.activeSelectionBackground":"#19283c99","list.activeSelectionForeground":"#fbfbfb","list.inactiveSelectionBackground":"#19283c73","list.hoverBackground":"#19283c59","list.focusOutline":"#009fff","tab.activeBackground":"#070707","tab.activeForeground":"#fbfbfb","tab.activeBorderTop":"#009fff","tab.inactiveBackground":"#141415","tab.inactiveForeground":"#84848A","tab.border":"#070707","editorGroupHeader.tabsBackground":"#141415","editorGroupHeader.tabsBorder":"#070707","panel.background":"#141415","panel.border":"#070707","panelTitle.activeBorder":"#009fff","panelTitle.activeForeground":"#fbfbfb","panelTitle.inactiveForeground":"#84848A","statusBar.background":"#141415","statusBar.foreground":"#adadb1","statusBar.border":"#070707","statusBar.noFolderBackground":"#141415","statusBar.debuggingBackground":"#ffca00","statusBar.debuggingForeground":"#070707","statusBarItem.remoteBackground":"#141415","statusBarItem.remoteForeground":"#adadb1","input.background":"#1F1F21","input.border":"#1F1F21","input.foreground":"#fbfbfb","input.placeholderForeground":"#79797F","dropdown.background":"#1F1F21","dropdown.border":"#1F1F21","dropdown.foreground":"#fbfbfb","button.background":"#009fff","button.foreground":"#070707","button.hoverBackground":"#0190e6","textLink.foreground":"#009fff","textLink.activeForeground":"#009fff","gitDecoration.addedResourceForeground":"#00cab1","gitDecoration.conflictingResourceForeground":"#ffca00","gitDecoration.modifiedResourceForeground":"#009fff","gitDecoration.deletedResourceForeground":"#ff2e3f","gitDecoration.untrackedResourceForeground":"#00cab1","gitDecoration.ignoredResourceForeground":"#84848A","terminal.titleForeground":"#adadb1","terminal.titleInactiveForeground":"#84848A","terminal.background":"#141415","terminal.foreground":"#adadb1","terminal.ansiBlack":"#141415","terminal.ansiRed":"#ff2e3f","terminal.ansiGreen":"#0dbe4e","terminal.ansiYellow":"#ffca00","terminal.ansiBlue":"#009fff","terminal.ansiMagenta":"#c635e4","terminal.ansiCyan":"#08c0ef","terminal.ansiWhite":"#c6c6c8","terminal.ansiBrightBlack":"#141415","terminal.ansiBrightRed":"#ff2e3f","terminal.ansiBrightGreen":"#0dbe4e","terminal.ansiBrightYellow":"#ffca00","terminal.ansiBrightBlue":"#009fff","terminal.ansiBrightMagenta":"#c635e4","terminal.ansiBrightCyan":"#08c0ef","terminal.ansiBrightWhite":"#c6c6c8"},"tokenColors":[{"scope":["comment","punctuation.definition.comment"],"settings":{"foreground":"#84848A"}},{"scope":"comment markup.link","settings":{"foreground":"#84848A"}},{"scope":["string","constant.other.symbol"],"settings":{"foreground":"#5ecc71"}},{"scope":["punctuation.definition.string.begin","punctuation.definition.string.end"],"settings":{"foreground":"#5ecc71"}},{"scope":["constant.numeric","constant.language.boolean"],"settings":{"foreground":"#68cdf2"}},{"scope":"constant","settings":{"foreground":"#ffd452"}},{"scope":"punctuation.definition.constant","settings":{"foreground":"#ffd452"}},{"scope":"constant.language","settings":{"foreground":"#68cdf2"}},{"scope":"variable.other.constant","settings":{"foreground":"#ffca00"}},{"scope":"keyword","settings":{"foreground":"#ff678d"}},{"scope":"keyword.control","settings":{"foreground":"#ff678d"}},{"scope":["storage","storage.type","storage.modifier"],"settings":{"foreground":"#ff678d"}},{"scope":"token.storage","settings":{"foreground":"#ff678d"}},{"scope":["keyword.operator.new","keyword.operator.expression.instanceof","keyword.operator.expression.typeof","keyword.operator.expression.void","keyword.operator.expression.delete","keyword.operator.expression.in","keyword.operator.expression.of","keyword.operator.expression.keyof"],"settings":{"foreground":"#ff678d"}},{"scope":"keyword.operator.delete","settings":{"foreground":"#ff678d"}},{"scope":["variable","identifier","meta.definition.variable"],"settings":{"foreground":"#ffa359"}},{"scope":["variable.other.readwrite","meta.object-literal.key","support.variable.property","support.variable.object.process","support.variable.object.node"],"settings":{"foreground":"#ffa359"}},{"scope":"variable.language","settings":{"foreground":"#ffca00"}},{"scope":"variable.parameter.function","settings":{"foreground":"#adadb1"}},{"scope":"function.parameter","settings":{"foreground":"#adadb1"}},{"scope":"variable.parameter","settings":{"foreground":"#adadb1"}},{"scope":"variable.parameter.function.language.python","settings":{"foreground":"#ffd452"}},{"scope":"variable.parameter.function.python","settings":{"foreground":"#ffd452"}},{"scope":["support.function","entity.name.function","meta.function-call","meta.require","support.function.any-method","variable.function"],"settings":{"foreground":"#9d6afb"}},{"scope":"keyword.other.special-method","settings":{"foreground":"#9d6afb"}},{"scope":"entity.name.function","settings":{"foreground":"#9d6afb"}},{"scope":"support.function.console","settings":{"foreground":"#9d6afb"}},{"scope":["support.type","entity.name.type","entity.name.class","storage.type"],"settings":{"foreground":"#d568ea"}},{"scope":["support.class","entity.name.type.class"],"settings":{"foreground":"#d568ea"}},{"scope":["entity.name.class","variable.other.class.js","variable.other.class.ts"],"settings":{"foreground":"#d568ea"}},{"scope":"entity.name.class.identifier.namespace.type","settings":{"foreground":"#d568ea"}},{"scope":"entity.name.type.namespace","settings":{"foreground":"#ffca00"}},{"scope":"entity.other.inherited-class","settings":{"foreground":"#d568ea"}},{"scope":"entity.name.namespace","settings":{"foreground":"#ffca00"}},{"scope":"keyword.operator","settings":{"foreground":"#79797F"}},{"scope":["keyword.operator.logical","keyword.operator.bitwise","keyword.operator.channel"],"settings":{"foreground":"#08c0ef"}},{"scope":["keyword.operator.arithmetic","keyword.operator.comparison","keyword.operator.relational","keyword.operator.increment","keyword.operator.decrement"],"settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.assignment","settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.assignment.compound","settings":{"foreground":"#ff678d"}},{"scope":["keyword.operator.assignment.compound.js","keyword.operator.assignment.compound.ts"],"settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.ternary","settings":{"foreground":"#ff678d"}},{"scope":"keyword.operator.optional","settings":{"foreground":"#ff678d"}},{"scope":"punctuation","settings":{"foreground":"#79797F"}},{"scope":"punctuation.separator.delimiter","settings":{"foreground":"#79797F"}},{"scope":"punctuation.separator.key-value","settings":{"foreground":"#79797F"}},{"scope":"punctuation.terminator","settings":{"foreground":"#79797F"}},{"scope":"meta.brace","settings":{"foreground":"#79797F"}},{"scope":"meta.brace.square","settings":{"foreground":"#79797F"}},{"scope":"meta.brace.round","settings":{"foreground":"#79797F"}},{"scope":"function.brace","settings":{"foreground":"#79797F"}},{"scope":["punctuation.definition.parameters","punctuation.definition.typeparameters"],"settings":{"foreground":"#79797F"}},{"scope":["punctuation.definition.block","punctuation.definition.tag"],"settings":{"foreground":"#79797F"}},{"scope":["meta.tag.tsx","meta.tag.jsx","meta.tag.js","meta.tag.ts"],"settings":{"foreground":"#79797F"}},{"scope":"keyword.operator.expression.import","settings":{"foreground":"#9d6afb"}},{"scope":"keyword.operator.module","settings":{"foreground":"#ff678d"}},{"scope":"support.type.object.console","settings":{"foreground":"#ffa359"}},{"scope":["support.module.node","support.type.object.module","entity.name.type.module"],"settings":{"foreground":"#ffca00"}},{"scope":"support.constant.math","settings":{"foreground":"#ffca00"}},{"scope":"support.constant.property.math","settings":{"foreground":"#ffd452"}},{"scope":"support.constant.json","settings":{"foreground":"#ffd452"}},{"scope":"support.type.object.dom","settings":{"foreground":"#08c0ef"}},{"scope":["support.variable.dom","support.variable.property.dom"],"settings":{"foreground":"#ffa359"}},{"scope":"support.variable.property.process","settings":{"foreground":"#ffd452"}},{"scope":"meta.property.object","settings":{"foreground":"#ffa359"}},{"scope":"variable.parameter.function.js","settings":{"foreground":"#ffa359"}},{"scope":["keyword.other.template.begin","keyword.other.template.end"],"settings":{"foreground":"#5ecc71"}},{"scope":["keyword.other.substitution.begin","keyword.other.substitution.end"],"settings":{"foreground":"#5ecc71"}},{"scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end"],"settings":{"foreground":"#ff678d"}},{"scope":"meta.template.expression","settings":{"foreground":"#79797F"}},{"scope":"punctuation.section.embedded","settings":{"foreground":"#ffa359"}},{"scope":"variable.interpolation","settings":{"foreground":"#ffa359"}},{"scope":["punctuation.section.embedded.begin","punctuation.section.embedded.end"],"settings":{"foreground":"#ff678d"}},{"scope":"punctuation.quasi.element","settings":{"foreground":"#ff678d"}},{"scope":["support.type.primitive.ts","support.type.builtin.ts","support.type.primitive.tsx","support.type.builtin.tsx"],"settings":{"foreground":"#d568ea"}},{"scope":"support.type.type.flowtype","settings":{"foreground":"#9d6afb"}},{"scope":"support.type.primitive","settings":{"foreground":"#d568ea"}},{"scope":"support.variable.magic.python","settings":{"foreground":"#ff6762"}},{"scope":"variable.parameter.function.language.special.self.python","settings":{"foreground":"#ffca00"}},{"scope":["punctuation.separator.period.python","punctuation.separator.element.python","punctuation.parenthesis.begin.python","punctuation.parenthesis.end.python"],"settings":{"foreground":"#79797F"}},{"scope":["punctuation.definition.arguments.begin.python","punctuation.definition.arguments.end.python","punctuation.separator.arguments.python","punctuation.definition.list.begin.python","punctuation.definition.list.end.python"],"settings":{"foreground":"#79797F"}},{"scope":"support.type.python","settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.logical.python","settings":{"foreground":"#ff678d"}},{"scope":"meta.function-call.generic.python","settings":{"foreground":"#9d6afb"}},{"scope":"constant.character.format.placeholder.other.python","settings":{"foreground":"#ffd452"}},{"scope":"meta.function.decorator.python","settings":{"foreground":"#9d6afb"}},{"scope":["support.token.decorator.python","meta.function.decorator.identifier.python"],"settings":{"foreground":"#08c0ef"}},{"scope":"storage.modifier.lifetime.rust","settings":{"foreground":"#79797F"}},{"scope":"support.function.std.rust","settings":{"foreground":"#9d6afb"}},{"scope":"entity.name.lifetime.rust","settings":{"foreground":"#ffca00"}},{"scope":"variable.language.rust","settings":{"foreground":"#ff6762"}},{"scope":"keyword.operator.misc.rust","settings":{"foreground":"#79797F"}},{"scope":"keyword.operator.sigil.rust","settings":{"foreground":"#ff678d"}},{"scope":"support.constant.core.rust","settings":{"foreground":"#ffd452"}},{"scope":["meta.function.c","meta.function.cpp"],"settings":{"foreground":"#ff6762"}},{"scope":["punctuation.section.block.begin.bracket.curly.cpp","punctuation.section.block.end.bracket.curly.cpp","punctuation.terminator.statement.c","punctuation.section.block.begin.bracket.curly.c","punctuation.section.block.end.bracket.curly.c","punctuation.section.parens.begin.bracket.round.c","punctuation.section.parens.end.bracket.round.c","punctuation.section.parameters.begin.bracket.round.c","punctuation.section.parameters.end.bracket.round.c"],"settings":{"foreground":"#79797F"}},{"scope":["keyword.operator.assignment.c","keyword.operator.comparison.c","keyword.operator.c","keyword.operator.increment.c","keyword.operator.decrement.c","keyword.operator.bitwise.shift.c"],"settings":{"foreground":"#ff678d"}},{"scope":["keyword.operator.assignment.cpp","keyword.operator.comparison.cpp","keyword.operator.cpp","keyword.operator.increment.cpp","keyword.operator.decrement.cpp","keyword.operator.bitwise.shift.cpp"],"settings":{"foreground":"#ff678d"}},{"scope":["punctuation.separator.c","punctuation.separator.cpp"],"settings":{"foreground":"#ff678d"}},{"scope":["support.type.posix-reserved.c","support.type.posix-reserved.cpp"],"settings":{"foreground":"#08c0ef"}},{"scope":["keyword.operator.sizeof.c","keyword.operator.sizeof.cpp"],"settings":{"foreground":"#ff678d"}},{"scope":"variable.c","settings":{"foreground":"#79797F"}},{"scope":["storage.type.annotation.java","storage.type.object.array.java"],"settings":{"foreground":"#ffca00"}},{"scope":"source.java","settings":{"foreground":"#ff6762"}},{"scope":["punctuation.section.block.begin.java","punctuation.section.block.end.java","punctuation.definition.method-parameters.begin.java","punctuation.definition.method-parameters.end.java","meta.method.identifier.java","punctuation.section.method.begin.java","punctuation.section.method.end.java","punctuation.terminator.java","punctuation.section.class.begin.java","punctuation.section.class.end.java","punctuation.section.inner-class.begin.java","punctuation.section.inner-class.end.java","meta.method-call.java","punctuation.section.class.begin.bracket.curly.java","punctuation.section.class.end.bracket.curly.java","punctuation.section.method.begin.bracket.curly.java","punctuation.section.method.end.bracket.curly.java","punctuation.separator.period.java","punctuation.bracket.angle.java","punctuation.definition.annotation.java","meta.method.body.java"],"settings":{"foreground":"#79797F"}},{"scope":"meta.method.java","settings":{"foreground":"#9d6afb"}},{"scope":["storage.modifier.import.java","storage.type.java","storage.type.generic.java"],"settings":{"foreground":"#ffca00"}},{"scope":"keyword.operator.instanceof.java","settings":{"foreground":"#ff678d"}},{"scope":"meta.definition.variable.name.java","settings":{"foreground":"#ff6762"}},{"scope":"token.variable.parameter.java","settings":{"foreground":"#79797F"}},{"scope":"import.storage.java","settings":{"foreground":"#ffca00"}},{"scope":"token.package.keyword","settings":{"foreground":"#ff678d"}},{"scope":"token.package","settings":{"foreground":"#79797F"}},{"scope":"token.storage.type.java","settings":{"foreground":"#ffca00"}},{"scope":"keyword.operator.assignment.go","settings":{"foreground":"#ffca00"}},{"scope":["keyword.operator.arithmetic.go","keyword.operator.address.go"],"settings":{"foreground":"#ff678d"}},{"scope":"entity.name.package.go","settings":{"foreground":"#ffca00"}},{"scope":["support.other.namespace.use.php","support.other.namespace.use-as.php","support.other.namespace.php","entity.other.alias.php","meta.interface.php"],"settings":{"foreground":"#ffca00"}},{"scope":"keyword.operator.error-control.php","settings":{"foreground":"#ff678d"}},{"scope":"keyword.operator.type.php","settings":{"foreground":"#ff678d"}},{"scope":["punctuation.section.array.begin.php","punctuation.section.array.end.php"],"settings":{"foreground":"#79797F"}},{"scope":["storage.type.php","meta.other.type.phpdoc.php","keyword.other.type.php","keyword.other.array.phpdoc.php"],"settings":{"foreground":"#ffca00"}},{"scope":["meta.function-call.php","meta.function-call.object.php","meta.function-call.static.php"],"settings":{"foreground":"#9d6afb"}},{"scope":["punctuation.definition.parameters.begin.bracket.round.php","punctuation.definition.parameters.end.bracket.round.php","punctuation.separator.delimiter.php","punctuation.section.scope.begin.php","punctuation.section.scope.end.php","punctuation.terminator.expression.php","punctuation.definition.arguments.begin.bracket.round.php","punctuation.definition.arguments.end.bracket.round.php","punctuation.definition.storage-type.begin.bracket.round.php","punctuation.definition.storage-type.end.bracket.round.php","punctuation.definition.array.begin.bracket.round.php","punctuation.definition.array.end.bracket.round.php","punctuation.definition.begin.bracket.round.php","punctuation.definition.end.bracket.round.php","punctuation.definition.begin.bracket.curly.php","punctuation.definition.end.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php","punctuation.definition.section.switch-block.start.bracket.curly.php","punctuation.definition.section.switch-block.begin.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php"],"settings":{"foreground":"#79797F"}},{"scope":["support.constant.ext.php","support.constant.std.php","support.constant.core.php","support.constant.parser-token.php"],"settings":{"foreground":"#ffd452"}},{"scope":["entity.name.goto-label.php","support.other.php"],"settings":{"foreground":"#9d6afb"}},{"scope":["keyword.operator.logical.php","keyword.operator.bitwise.php","keyword.operator.arithmetic.php"],"settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.regexp.php","settings":{"foreground":"#ff678d"}},{"scope":"keyword.operator.comparison.php","settings":{"foreground":"#08c0ef"}},{"scope":["keyword.operator.heredoc.php","keyword.operator.nowdoc.php"],"settings":{"foreground":"#ff678d"}},{"scope":"variable.other.class.php","settings":{"foreground":"#ff6762"}},{"scope":"invalid.illegal.non-null-typehinted.php","settings":{"foreground":"#f44747"}},{"scope":"variable.other.generic-type.haskell","settings":{"foreground":"#ff678d"}},{"scope":"storage.type.haskell","settings":{"foreground":"#ffd452"}},{"scope":"storage.type.cs","settings":{"foreground":"#ffca00"}},{"scope":"entity.name.variable.local.cs","settings":{"foreground":"#ff6762"}},{"scope":"entity.name.label.cs","settings":{"foreground":"#ffca00"}},{"scope":["entity.name.scope-resolution.function.call","entity.name.scope-resolution.function.definition"],"settings":{"foreground":"#ffca00"}},{"scope":["punctuation.definition.delayed.unison","punctuation.definition.list.begin.unison","punctuation.definition.list.end.unison","punctuation.definition.ability.begin.unison","punctuation.definition.ability.end.unison","punctuation.operator.assignment.as.unison","punctuation.separator.pipe.unison","punctuation.separator.delimiter.unison","punctuation.definition.hash.unison"],"settings":{"foreground":"#ff6762"}},{"scope":"support.constant.edge","settings":{"foreground":"#ff678d"}},{"scope":"support.type.prelude.elm","settings":{"foreground":"#08c0ef"}},{"scope":"support.constant.elm","settings":{"foreground":"#ffd452"}},{"scope":"entity.global.clojure","settings":{"foreground":"#ffca00"}},{"scope":"meta.symbol.clojure","settings":{"foreground":"#ff6762"}},{"scope":"constant.keyword.clojure","settings":{"foreground":"#08c0ef"}},{"scope":["meta.arguments.coffee","variable.parameter.function.coffee"],"settings":{"foreground":"#ff6762"}},{"scope":"storage.modifier.import.groovy","settings":{"foreground":"#ffca00"}},{"scope":"meta.method.groovy","settings":{"foreground":"#9d6afb"}},{"scope":"meta.definition.variable.name.groovy","settings":{"foreground":"#ff6762"}},{"scope":"meta.definition.class.inherited.classes.groovy","settings":{"foreground":"#5ecc71"}},{"scope":"support.variable.semantic.hlsl","settings":{"foreground":"#ffca00"}},{"scope":["support.type.texture.hlsl","support.type.sampler.hlsl","support.type.object.hlsl","support.type.object.rw.hlsl","support.type.fx.hlsl","support.type.object.hlsl"],"settings":{"foreground":"#ff678d"}},{"scope":["text.variable","text.bracketed"],"settings":{"foreground":"#ff6762"}},{"scope":["support.type.swift","support.type.vb.asp"],"settings":{"foreground":"#ffca00"}},{"scope":"meta.scope.prerequisites.makefile","settings":{"foreground":"#ff6762"}},{"scope":"source.makefile","settings":{"foreground":"#ffca00"}},{"scope":"source.ini","settings":{"foreground":"#5ecc71"}},{"scope":"constant.language.symbol.ruby","settings":{"foreground":"#08c0ef"}},{"scope":["function.parameter.ruby","function.parameter.cs"],"settings":{"foreground":"#79797F"}},{"scope":"constant.language.symbol.elixir","settings":{"foreground":"#08c0ef"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade","settings":{"foreground":"#ff678d"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade","settings":{"foreground":"#ff678d"}},{"scope":"entity.name.function.xi","settings":{"foreground":"#ffca00"}},{"scope":"entity.name.class.xi","settings":{"foreground":"#08c0ef"}},{"scope":"constant.character.character-class.regexp.xi","settings":{"foreground":"#ff6762"}},{"scope":"constant.regexp.xi","settings":{"foreground":"#ff678d"}},{"scope":"keyword.control.xi","settings":{"foreground":"#08c0ef"}},{"scope":"invalid.xi","settings":{"foreground":"#79797F"}},{"scope":"beginning.punctuation.definition.quote.markdown.xi","settings":{"foreground":"#5ecc71"}},{"scope":"beginning.punctuation.definition.list.markdown.xi","settings":{"foreground":"#84848A"}},{"scope":"constant.character.xi","settings":{"foreground":"#9d6afb"}},{"scope":"accent.xi","settings":{"foreground":"#9d6afb"}},{"scope":"wikiword.xi","settings":{"foreground":"#ffd452"}},{"scope":"constant.other.color.rgb-value.xi","settings":{"foreground":"#fbfbfb"}},{"scope":"punctuation.definition.tag.xi","settings":{"foreground":"#84848A"}},{"scope":["support.constant.property-value.scss","support.constant.property-value.css"],"settings":{"foreground":"#ffd452"}},{"scope":["keyword.operator.css","keyword.operator.scss","keyword.operator.less"],"settings":{"foreground":"#08c0ef"}},{"scope":["support.constant.color.w3c-standard-color-name.css","support.constant.color.w3c-standard-color-name.scss"],"settings":{"foreground":"#ffd452"}},{"scope":"punctuation.separator.list.comma.css","settings":{"foreground":"#79797F"}},{"scope":"support.type.vendored.property-name.css","settings":{"foreground":"#08c0ef"}},{"scope":"support.type.property-name.css","settings":{"foreground":"#08c0ef"}},{"scope":"support.type.property-name","settings":{"foreground":"#79797F"}},{"scope":"support.constant.property-value","settings":{"foreground":"#79797F"}},{"scope":"support.constant.font-name","settings":{"foreground":"#ffd452"}},{"scope":"entity.other.attribute-name.class.css","settings":{"foreground":"#61d5c0","fontStyle":"normal"}},{"scope":"entity.other.attribute-name.id","settings":{"foreground":"#9d6afb","fontStyle":"normal"}},{"scope":["entity.other.attribute-name.pseudo-element","entity.other.attribute-name.pseudo-class"],"settings":{"foreground":"#08c0ef"}},{"scope":"meta.selector","settings":{"foreground":"#ff678d"}},{"scope":"selector.sass","settings":{"foreground":"#ff6762"}},{"scope":"rgb-value","settings":{"foreground":"#08c0ef"}},{"scope":"inline-color-decoration rgb-value","settings":{"foreground":"#ffd452"}},{"scope":"less rgb-value","settings":{"foreground":"#ffd452"}},{"scope":"control.elements","settings":{"foreground":"#ffd452"}},{"scope":"keyword.operator.less","settings":{"foreground":"#ffd452"}},{"scope":"entity.name.tag","settings":{"foreground":"#ff6762"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#61d5c0","fontStyle":"normal"}},{"scope":"constant.character.entity","settings":{"foreground":"#ff6762"}},{"scope":"meta.tag","settings":{"foreground":"#79797F"}},{"scope":"invalid.illegal.bad-ampersand.html","settings":{"foreground":"#79797F"}},{"scope":"markup.heading","settings":{"foreground":"#ff6762"}},{"scope":["markup.heading punctuation.definition.heading","entity.name.section"],"settings":{"foreground":"#9d6afb"}},{"scope":"entity.name.section.markdown","settings":{"foreground":"#ff6762"}},{"scope":"punctuation.definition.heading.markdown","settings":{"foreground":"#ff6762"}},{"scope":"markup.heading.setext","settings":{"foreground":"#79797F"}},{"scope":["markup.heading.setext.1.markdown","markup.heading.setext.2.markdown"],"settings":{"foreground":"#ff6762"}},{"scope":["markup.bold","todo.bold"],"settings":{"foreground":"#ffd452"}},{"scope":"punctuation.definition.bold","settings":{"foreground":"#ffca00"}},{"scope":"punctuation.definition.bold.markdown","settings":{"foreground":"#ffd452"}},{"scope":["markup.italic","punctuation.definition.italic","todo.emphasis"],"settings":{"foreground":"#ff678d","fontStyle":"italic"}},{"scope":"emphasis md","settings":{"foreground":"#ff678d"}},{"scope":"markup.italic.markdown","settings":{"fontStyle":"italic"}},{"scope":["markup.underline.link.markdown","markup.underline.link.image.markdown"],"settings":{"foreground":"#ff678d"}},{"scope":["string.other.link.title.markdown","string.other.link.description.markdown"],"settings":{"foreground":"#9d6afb"}},{"scope":"punctuation.definition.metadata.markdown","settings":{"foreground":"#ff6762"}},{"scope":["markup.inline.raw.markdown","markup.inline.raw.string.markdown"],"settings":{"foreground":"#5ecc71"}},{"scope":"punctuation.definition.list.begin.markdown","settings":{"foreground":"#ff6762"}},{"scope":"punctuation.definition.list.markdown","settings":{"foreground":"#ff6762"}},{"scope":"beginning.punctuation.definition.list.markdown","settings":{"foreground":"#ff6762"}},{"scope":["punctuation.definition.string.begin.markdown","punctuation.definition.string.end.markdown"],"settings":{"foreground":"#ff6762"}},{"scope":"markup.quote.markdown","settings":{"foreground":"#84848A"}},{"scope":"keyword.other.unit","settings":{"foreground":"#ff6762"}},{"scope":"markup.changed.diff","settings":{"foreground":"#ffca00"}},{"scope":["meta.diff.header.from-file","meta.diff.header.to-file","punctuation.definition.from-file.diff","punctuation.definition.to-file.diff"],"settings":{"foreground":"#9d6afb"}},{"scope":"markup.inserted.diff","settings":{"foreground":"#5ecc71"}},{"scope":"markup.deleted.diff","settings":{"foreground":"#ff6762"}},{"scope":"string.regexp","settings":{"foreground":"#64d1db"}},{"scope":"constant.other.character-class.regexp","settings":{"foreground":"#ff6762"}},{"scope":"keyword.operator.quantifier.regexp","settings":{"foreground":"#ffd452"}},{"scope":"constant.character.escape","settings":{"foreground":"#68cdf2"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json","settings":{"foreground":"#ff6762"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string","settings":{"foreground":"#ff6762"}},{"scope":["source.json meta.structure.dictionary.json > value.json > string.quoted.json","source.json meta.structure.array.json > value.json > string.quoted.json","source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation","source.json meta.structure.array.json > value.json > string.quoted.json > punctuation"],"settings":{"foreground":"#5ecc71"}},{"scope":["source.json meta.structure.dictionary.json > constant.language.json","source.json meta.structure.array.json > constant.language.json"],"settings":{"foreground":"#08c0ef"}},{"scope":"support.type.property-name.json","settings":{"foreground":"#ff6762"}},{"scope":"support.type.property-name.json punctuation","settings":{"foreground":"#ff6762"}},{"scope":"punctuation.definition.block.sequence.item.yaml","settings":{"foreground":"#79797F"}},{"scope":"block.scope.end","settings":{"foreground":"#79797F"}},{"scope":"block.scope.begin","settings":{"foreground":"#79797F"}},{"scope":"token.info-token","settings":{"foreground":"#9d6afb"}},{"scope":"token.warn-token","settings":{"foreground":"#ffd452"}},{"scope":"token.error-token","settings":{"foreground":"#f44747"}},{"scope":"token.debug-token","settings":{"foreground":"#ff678d"}},{"scope":"invalid.illegal","settings":{"foreground":"#fbfbfb"}},{"scope":"invalid.broken","settings":{"foreground":"#fbfbfb"}},{"scope":"invalid.deprecated","settings":{"foreground":"#fbfbfb"}},{"scope":"invalid.unimplemented","settings":{"foreground":"#fbfbfb"}}],"semanticTokenColors":{"comment":"#84848A","string":"#5ecc71","number":"#68cdf2","regexp":"#64d1db","keyword":"#ff678d","variable":"#ffa359","parameter":"#adadb1","property":"#ffa359","function":"#9d6afb","method":"#9d6afb","type":"#d568ea","class":"#d568ea","namespace":"#ffca00","enumMember":"#08c0ef","variable.constant":"#ffd452","variable.defaultLibrary":"#ffca00"}}'));export{e as default}; diff --git a/lib/crates/fabro-spa/assets/assets/chunk-nghb2mxb.js b/lib/crates/fabro-spa/assets/assets/chunk-nghb2mxb.js deleted file mode 100644 index db154f1f0..000000000 --- a/lib/crates/fabro-spa/assets/assets/chunk-nghb2mxb.js +++ /dev/null @@ -1 +0,0 @@ -import"./chunk-q07bg6gn.js";var e=Object.freeze(JSON.parse('{"name":"Pierre Light","type":"light","colors":{"editor.background":"#ffffff","editor.foreground":"#070707","foreground":"#070707","focusBorder":"#009fff","selection.background":"#dfebff","editor.selectionBackground":"#009fff2e","editor.lineHighlightBackground":"#dfebff8c","editorCursor.foreground":"#009fff","editorLineNumber.foreground":"#84848A","editorLineNumber.activeForeground":"#6C6C71","editorIndentGuide.background":"#eeeeef","editorIndentGuide.activeBackground":"#dbdbdd","diffEditor.insertedTextBackground":"#00cab133","diffEditor.deletedTextBackground":"#ff2e3f33","sideBar.background":"#f8f8f8","sideBar.foreground":"#6C6C71","sideBar.border":"#eeeeef","sideBarTitle.foreground":"#070707","sideBarSectionHeader.background":"#f8f8f8","sideBarSectionHeader.foreground":"#6C6C71","sideBarSectionHeader.border":"#eeeeef","activityBar.background":"#f8f8f8","activityBar.foreground":"#070707","activityBar.border":"#eeeeef","activityBar.activeBorder":"#009fff","activityBarBadge.background":"#009fff","activityBarBadge.foreground":"#ffffff","titleBar.activeBackground":"#f8f8f8","titleBar.activeForeground":"#070707","titleBar.inactiveBackground":"#f8f8f8","titleBar.inactiveForeground":"#84848A","titleBar.border":"#eeeeef","list.activeSelectionBackground":"#dfebffcc","list.activeSelectionForeground":"#070707","list.inactiveSelectionBackground":"#dfebff73","list.hoverBackground":"#dfebff59","list.focusOutline":"#009fff","tab.activeBackground":"#ffffff","tab.activeForeground":"#070707","tab.activeBorderTop":"#009fff","tab.inactiveBackground":"#f8f8f8","tab.inactiveForeground":"#84848A","tab.border":"#eeeeef","editorGroupHeader.tabsBackground":"#f8f8f8","editorGroupHeader.tabsBorder":"#eeeeef","panel.background":"#f8f8f8","panel.border":"#eeeeef","panelTitle.activeBorder":"#009fff","panelTitle.activeForeground":"#070707","panelTitle.inactiveForeground":"#84848A","statusBar.background":"#f8f8f8","statusBar.foreground":"#6C6C71","statusBar.border":"#eeeeef","statusBar.noFolderBackground":"#f8f8f8","statusBar.debuggingBackground":"#ffca00","statusBar.debuggingForeground":"#ffffff","statusBarItem.remoteBackground":"#f8f8f8","statusBarItem.remoteForeground":"#6C6C71","input.background":"#f2f2f3","input.border":"#dbdbdd","input.foreground":"#070707","input.placeholderForeground":"#8E8E95","dropdown.background":"#f2f2f3","dropdown.border":"#dbdbdd","dropdown.foreground":"#070707","button.background":"#009fff","button.foreground":"#ffffff","button.hoverBackground":"#1aa9ff","textLink.foreground":"#009fff","textLink.activeForeground":"#009fff","gitDecoration.addedResourceForeground":"#00cab1","gitDecoration.conflictingResourceForeground":"#ffca00","gitDecoration.modifiedResourceForeground":"#009fff","gitDecoration.deletedResourceForeground":"#ff2e3f","gitDecoration.untrackedResourceForeground":"#00cab1","gitDecoration.ignoredResourceForeground":"#84848A","terminal.titleForeground":"#6C6C71","terminal.titleInactiveForeground":"#84848A","terminal.background":"#f8f8f8","terminal.foreground":"#6C6C71","terminal.ansiBlack":"#1F1F21","terminal.ansiRed":"#ff2e3f","terminal.ansiGreen":"#0dbe4e","terminal.ansiYellow":"#ffca00","terminal.ansiBlue":"#009fff","terminal.ansiMagenta":"#c635e4","terminal.ansiCyan":"#08c0ef","terminal.ansiWhite":"#c6c6c8","terminal.ansiBrightBlack":"#1F1F21","terminal.ansiBrightRed":"#ff2e3f","terminal.ansiBrightGreen":"#0dbe4e","terminal.ansiBrightYellow":"#ffca00","terminal.ansiBrightBlue":"#009fff","terminal.ansiBrightMagenta":"#c635e4","terminal.ansiBrightCyan":"#08c0ef","terminal.ansiBrightWhite":"#c6c6c8"},"tokenColors":[{"scope":["comment","punctuation.definition.comment"],"settings":{"foreground":"#84848A"}},{"scope":"comment markup.link","settings":{"foreground":"#84848A"}},{"scope":["string","constant.other.symbol"],"settings":{"foreground":"#199f43"}},{"scope":["punctuation.definition.string.begin","punctuation.definition.string.end"],"settings":{"foreground":"#199f43"}},{"scope":["constant.numeric","constant.language.boolean"],"settings":{"foreground":"#1ca1c7"}},{"scope":"constant","settings":{"foreground":"#d5a910"}},{"scope":"punctuation.definition.constant","settings":{"foreground":"#d5a910"}},{"scope":"constant.language","settings":{"foreground":"#1ca1c7"}},{"scope":"variable.other.constant","settings":{"foreground":"#d5a910"}},{"scope":"keyword","settings":{"foreground":"#fc2b73"}},{"scope":"keyword.control","settings":{"foreground":"#fc2b73"}},{"scope":["storage","storage.type","storage.modifier"],"settings":{"foreground":"#fc2b73"}},{"scope":"token.storage","settings":{"foreground":"#fc2b73"}},{"scope":["keyword.operator.new","keyword.operator.expression.instanceof","keyword.operator.expression.typeof","keyword.operator.expression.void","keyword.operator.expression.delete","keyword.operator.expression.in","keyword.operator.expression.of","keyword.operator.expression.keyof"],"settings":{"foreground":"#fc2b73"}},{"scope":"keyword.operator.delete","settings":{"foreground":"#fc2b73"}},{"scope":["variable","identifier","meta.definition.variable"],"settings":{"foreground":"#d47628"}},{"scope":["variable.other.readwrite","meta.object-literal.key","support.variable.property","support.variable.object.process","support.variable.object.node"],"settings":{"foreground":"#d47628"}},{"scope":"variable.language","settings":{"foreground":"#d5a910"}},{"scope":"variable.parameter.function","settings":{"foreground":"#79797F"}},{"scope":"function.parameter","settings":{"foreground":"#79797F"}},{"scope":"variable.parameter","settings":{"foreground":"#79797F"}},{"scope":"variable.parameter.function.language.python","settings":{"foreground":"#d5a910"}},{"scope":"variable.parameter.function.python","settings":{"foreground":"#d5a910"}},{"scope":["support.function","entity.name.function","meta.function-call","meta.require","support.function.any-method","variable.function"],"settings":{"foreground":"#7b43f8"}},{"scope":"keyword.other.special-method","settings":{"foreground":"#7b43f8"}},{"scope":"entity.name.function","settings":{"foreground":"#7b43f8"}},{"scope":"support.function.console","settings":{"foreground":"#7b43f8"}},{"scope":["support.type","entity.name.type","entity.name.class","storage.type"],"settings":{"foreground":"#c635e4"}},{"scope":["support.class","entity.name.type.class"],"settings":{"foreground":"#c635e4"}},{"scope":["entity.name.class","variable.other.class.js","variable.other.class.ts"],"settings":{"foreground":"#c635e4"}},{"scope":"entity.name.class.identifier.namespace.type","settings":{"foreground":"#c635e4"}},{"scope":"entity.name.type.namespace","settings":{"foreground":"#d5a910"}},{"scope":"entity.other.inherited-class","settings":{"foreground":"#c635e4"}},{"scope":"entity.name.namespace","settings":{"foreground":"#d5a910"}},{"scope":"keyword.operator","settings":{"foreground":"#79797F"}},{"scope":["keyword.operator.logical","keyword.operator.bitwise","keyword.operator.channel"],"settings":{"foreground":"#08c0ef"}},{"scope":["keyword.operator.arithmetic","keyword.operator.comparison","keyword.operator.relational","keyword.operator.increment","keyword.operator.decrement"],"settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.assignment","settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.assignment.compound","settings":{"foreground":"#fc2b73"}},{"scope":["keyword.operator.assignment.compound.js","keyword.operator.assignment.compound.ts"],"settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.ternary","settings":{"foreground":"#fc2b73"}},{"scope":"keyword.operator.optional","settings":{"foreground":"#fc2b73"}},{"scope":"punctuation","settings":{"foreground":"#79797F"}},{"scope":"punctuation.separator.delimiter","settings":{"foreground":"#79797F"}},{"scope":"punctuation.separator.key-value","settings":{"foreground":"#79797F"}},{"scope":"punctuation.terminator","settings":{"foreground":"#79797F"}},{"scope":"meta.brace","settings":{"foreground":"#79797F"}},{"scope":"meta.brace.square","settings":{"foreground":"#79797F"}},{"scope":"meta.brace.round","settings":{"foreground":"#79797F"}},{"scope":"function.brace","settings":{"foreground":"#79797F"}},{"scope":["punctuation.definition.parameters","punctuation.definition.typeparameters"],"settings":{"foreground":"#79797F"}},{"scope":["punctuation.definition.block","punctuation.definition.tag"],"settings":{"foreground":"#79797F"}},{"scope":["meta.tag.tsx","meta.tag.jsx","meta.tag.js","meta.tag.ts"],"settings":{"foreground":"#79797F"}},{"scope":"keyword.operator.expression.import","settings":{"foreground":"#7b43f8"}},{"scope":"keyword.operator.module","settings":{"foreground":"#fc2b73"}},{"scope":"support.type.object.console","settings":{"foreground":"#d47628"}},{"scope":["support.module.node","support.type.object.module","entity.name.type.module"],"settings":{"foreground":"#d5a910"}},{"scope":"support.constant.math","settings":{"foreground":"#d5a910"}},{"scope":"support.constant.property.math","settings":{"foreground":"#d5a910"}},{"scope":"support.constant.json","settings":{"foreground":"#d5a910"}},{"scope":"support.type.object.dom","settings":{"foreground":"#08c0ef"}},{"scope":["support.variable.dom","support.variable.property.dom"],"settings":{"foreground":"#d47628"}},{"scope":"support.variable.property.process","settings":{"foreground":"#d5a910"}},{"scope":"meta.property.object","settings":{"foreground":"#d47628"}},{"scope":"variable.parameter.function.js","settings":{"foreground":"#d47628"}},{"scope":["keyword.other.template.begin","keyword.other.template.end"],"settings":{"foreground":"#199f43"}},{"scope":["keyword.other.substitution.begin","keyword.other.substitution.end"],"settings":{"foreground":"#199f43"}},{"scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end"],"settings":{"foreground":"#fc2b73"}},{"scope":"meta.template.expression","settings":{"foreground":"#79797F"}},{"scope":"punctuation.section.embedded","settings":{"foreground":"#d47628"}},{"scope":"variable.interpolation","settings":{"foreground":"#d47628"}},{"scope":["punctuation.section.embedded.begin","punctuation.section.embedded.end"],"settings":{"foreground":"#fc2b73"}},{"scope":"punctuation.quasi.element","settings":{"foreground":"#fc2b73"}},{"scope":["support.type.primitive.ts","support.type.builtin.ts","support.type.primitive.tsx","support.type.builtin.tsx"],"settings":{"foreground":"#c635e4"}},{"scope":"support.type.type.flowtype","settings":{"foreground":"#7b43f8"}},{"scope":"support.type.primitive","settings":{"foreground":"#c635e4"}},{"scope":"support.variable.magic.python","settings":{"foreground":"#d52c36"}},{"scope":"variable.parameter.function.language.special.self.python","settings":{"foreground":"#d5a910"}},{"scope":["punctuation.separator.period.python","punctuation.separator.element.python","punctuation.parenthesis.begin.python","punctuation.parenthesis.end.python"],"settings":{"foreground":"#79797F"}},{"scope":["punctuation.definition.arguments.begin.python","punctuation.definition.arguments.end.python","punctuation.separator.arguments.python","punctuation.definition.list.begin.python","punctuation.definition.list.end.python"],"settings":{"foreground":"#79797F"}},{"scope":"support.type.python","settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.logical.python","settings":{"foreground":"#fc2b73"}},{"scope":"meta.function-call.generic.python","settings":{"foreground":"#7b43f8"}},{"scope":"constant.character.format.placeholder.other.python","settings":{"foreground":"#d5a910"}},{"scope":"meta.function.decorator.python","settings":{"foreground":"#7b43f8"}},{"scope":["support.token.decorator.python","meta.function.decorator.identifier.python"],"settings":{"foreground":"#08c0ef"}},{"scope":"storage.modifier.lifetime.rust","settings":{"foreground":"#79797F"}},{"scope":"support.function.std.rust","settings":{"foreground":"#7b43f8"}},{"scope":"entity.name.lifetime.rust","settings":{"foreground":"#d5a910"}},{"scope":"variable.language.rust","settings":{"foreground":"#d52c36"}},{"scope":"keyword.operator.misc.rust","settings":{"foreground":"#79797F"}},{"scope":"keyword.operator.sigil.rust","settings":{"foreground":"#fc2b73"}},{"scope":"support.constant.core.rust","settings":{"foreground":"#d5a910"}},{"scope":["meta.function.c","meta.function.cpp"],"settings":{"foreground":"#d52c36"}},{"scope":["punctuation.section.block.begin.bracket.curly.cpp","punctuation.section.block.end.bracket.curly.cpp","punctuation.terminator.statement.c","punctuation.section.block.begin.bracket.curly.c","punctuation.section.block.end.bracket.curly.c","punctuation.section.parens.begin.bracket.round.c","punctuation.section.parens.end.bracket.round.c","punctuation.section.parameters.begin.bracket.round.c","punctuation.section.parameters.end.bracket.round.c"],"settings":{"foreground":"#79797F"}},{"scope":["keyword.operator.assignment.c","keyword.operator.comparison.c","keyword.operator.c","keyword.operator.increment.c","keyword.operator.decrement.c","keyword.operator.bitwise.shift.c"],"settings":{"foreground":"#fc2b73"}},{"scope":["keyword.operator.assignment.cpp","keyword.operator.comparison.cpp","keyword.operator.cpp","keyword.operator.increment.cpp","keyword.operator.decrement.cpp","keyword.operator.bitwise.shift.cpp"],"settings":{"foreground":"#fc2b73"}},{"scope":["punctuation.separator.c","punctuation.separator.cpp"],"settings":{"foreground":"#fc2b73"}},{"scope":["support.type.posix-reserved.c","support.type.posix-reserved.cpp"],"settings":{"foreground":"#08c0ef"}},{"scope":["keyword.operator.sizeof.c","keyword.operator.sizeof.cpp"],"settings":{"foreground":"#fc2b73"}},{"scope":"variable.c","settings":{"foreground":"#79797F"}},{"scope":["storage.type.annotation.java","storage.type.object.array.java"],"settings":{"foreground":"#d5a910"}},{"scope":"source.java","settings":{"foreground":"#d52c36"}},{"scope":["punctuation.section.block.begin.java","punctuation.section.block.end.java","punctuation.definition.method-parameters.begin.java","punctuation.definition.method-parameters.end.java","meta.method.identifier.java","punctuation.section.method.begin.java","punctuation.section.method.end.java","punctuation.terminator.java","punctuation.section.class.begin.java","punctuation.section.class.end.java","punctuation.section.inner-class.begin.java","punctuation.section.inner-class.end.java","meta.method-call.java","punctuation.section.class.begin.bracket.curly.java","punctuation.section.class.end.bracket.curly.java","punctuation.section.method.begin.bracket.curly.java","punctuation.section.method.end.bracket.curly.java","punctuation.separator.period.java","punctuation.bracket.angle.java","punctuation.definition.annotation.java","meta.method.body.java"],"settings":{"foreground":"#79797F"}},{"scope":"meta.method.java","settings":{"foreground":"#7b43f8"}},{"scope":["storage.modifier.import.java","storage.type.java","storage.type.generic.java"],"settings":{"foreground":"#d5a910"}},{"scope":"keyword.operator.instanceof.java","settings":{"foreground":"#fc2b73"}},{"scope":"meta.definition.variable.name.java","settings":{"foreground":"#d52c36"}},{"scope":"token.variable.parameter.java","settings":{"foreground":"#79797F"}},{"scope":"import.storage.java","settings":{"foreground":"#d5a910"}},{"scope":"token.package.keyword","settings":{"foreground":"#fc2b73"}},{"scope":"token.package","settings":{"foreground":"#79797F"}},{"scope":"token.storage.type.java","settings":{"foreground":"#d5a910"}},{"scope":"keyword.operator.assignment.go","settings":{"foreground":"#d5a910"}},{"scope":["keyword.operator.arithmetic.go","keyword.operator.address.go"],"settings":{"foreground":"#fc2b73"}},{"scope":"entity.name.package.go","settings":{"foreground":"#d5a910"}},{"scope":["support.other.namespace.use.php","support.other.namespace.use-as.php","support.other.namespace.php","entity.other.alias.php","meta.interface.php"],"settings":{"foreground":"#d5a910"}},{"scope":"keyword.operator.error-control.php","settings":{"foreground":"#fc2b73"}},{"scope":"keyword.operator.type.php","settings":{"foreground":"#fc2b73"}},{"scope":["punctuation.section.array.begin.php","punctuation.section.array.end.php"],"settings":{"foreground":"#79797F"}},{"scope":["storage.type.php","meta.other.type.phpdoc.php","keyword.other.type.php","keyword.other.array.phpdoc.php"],"settings":{"foreground":"#d5a910"}},{"scope":["meta.function-call.php","meta.function-call.object.php","meta.function-call.static.php"],"settings":{"foreground":"#7b43f8"}},{"scope":["punctuation.definition.parameters.begin.bracket.round.php","punctuation.definition.parameters.end.bracket.round.php","punctuation.separator.delimiter.php","punctuation.section.scope.begin.php","punctuation.section.scope.end.php","punctuation.terminator.expression.php","punctuation.definition.arguments.begin.bracket.round.php","punctuation.definition.arguments.end.bracket.round.php","punctuation.definition.storage-type.begin.bracket.round.php","punctuation.definition.storage-type.end.bracket.round.php","punctuation.definition.array.begin.bracket.round.php","punctuation.definition.array.end.bracket.round.php","punctuation.definition.begin.bracket.round.php","punctuation.definition.end.bracket.round.php","punctuation.definition.begin.bracket.curly.php","punctuation.definition.end.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php","punctuation.definition.section.switch-block.start.bracket.curly.php","punctuation.definition.section.switch-block.begin.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php"],"settings":{"foreground":"#79797F"}},{"scope":["support.constant.ext.php","support.constant.std.php","support.constant.core.php","support.constant.parser-token.php"],"settings":{"foreground":"#d5a910"}},{"scope":["entity.name.goto-label.php","support.other.php"],"settings":{"foreground":"#7b43f8"}},{"scope":["keyword.operator.logical.php","keyword.operator.bitwise.php","keyword.operator.arithmetic.php"],"settings":{"foreground":"#08c0ef"}},{"scope":"keyword.operator.regexp.php","settings":{"foreground":"#fc2b73"}},{"scope":"keyword.operator.comparison.php","settings":{"foreground":"#08c0ef"}},{"scope":["keyword.operator.heredoc.php","keyword.operator.nowdoc.php"],"settings":{"foreground":"#fc2b73"}},{"scope":"variable.other.class.php","settings":{"foreground":"#d52c36"}},{"scope":"invalid.illegal.non-null-typehinted.php","settings":{"foreground":"#f44747"}},{"scope":"variable.other.generic-type.haskell","settings":{"foreground":"#fc2b73"}},{"scope":"storage.type.haskell","settings":{"foreground":"#d5a910"}},{"scope":"storage.type.cs","settings":{"foreground":"#d5a910"}},{"scope":"entity.name.variable.local.cs","settings":{"foreground":"#d52c36"}},{"scope":"entity.name.label.cs","settings":{"foreground":"#d5a910"}},{"scope":["entity.name.scope-resolution.function.call","entity.name.scope-resolution.function.definition"],"settings":{"foreground":"#d5a910"}},{"scope":["punctuation.definition.delayed.unison","punctuation.definition.list.begin.unison","punctuation.definition.list.end.unison","punctuation.definition.ability.begin.unison","punctuation.definition.ability.end.unison","punctuation.operator.assignment.as.unison","punctuation.separator.pipe.unison","punctuation.separator.delimiter.unison","punctuation.definition.hash.unison"],"settings":{"foreground":"#d52c36"}},{"scope":"support.constant.edge","settings":{"foreground":"#fc2b73"}},{"scope":"support.type.prelude.elm","settings":{"foreground":"#08c0ef"}},{"scope":"support.constant.elm","settings":{"foreground":"#d5a910"}},{"scope":"entity.global.clojure","settings":{"foreground":"#d5a910"}},{"scope":"meta.symbol.clojure","settings":{"foreground":"#d52c36"}},{"scope":"constant.keyword.clojure","settings":{"foreground":"#08c0ef"}},{"scope":["meta.arguments.coffee","variable.parameter.function.coffee"],"settings":{"foreground":"#d52c36"}},{"scope":"storage.modifier.import.groovy","settings":{"foreground":"#d5a910"}},{"scope":"meta.method.groovy","settings":{"foreground":"#7b43f8"}},{"scope":"meta.definition.variable.name.groovy","settings":{"foreground":"#d52c36"}},{"scope":"meta.definition.class.inherited.classes.groovy","settings":{"foreground":"#199f43"}},{"scope":"support.variable.semantic.hlsl","settings":{"foreground":"#d5a910"}},{"scope":["support.type.texture.hlsl","support.type.sampler.hlsl","support.type.object.hlsl","support.type.object.rw.hlsl","support.type.fx.hlsl","support.type.object.hlsl"],"settings":{"foreground":"#fc2b73"}},{"scope":["text.variable","text.bracketed"],"settings":{"foreground":"#d52c36"}},{"scope":["support.type.swift","support.type.vb.asp"],"settings":{"foreground":"#d5a910"}},{"scope":"meta.scope.prerequisites.makefile","settings":{"foreground":"#d52c36"}},{"scope":"source.makefile","settings":{"foreground":"#d5a910"}},{"scope":"source.ini","settings":{"foreground":"#199f43"}},{"scope":"constant.language.symbol.ruby","settings":{"foreground":"#08c0ef"}},{"scope":["function.parameter.ruby","function.parameter.cs"],"settings":{"foreground":"#79797F"}},{"scope":"constant.language.symbol.elixir","settings":{"foreground":"#08c0ef"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade","settings":{"foreground":"#fc2b73"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade","settings":{"foreground":"#fc2b73"}},{"scope":"entity.name.function.xi","settings":{"foreground":"#d5a910"}},{"scope":"entity.name.class.xi","settings":{"foreground":"#08c0ef"}},{"scope":"constant.character.character-class.regexp.xi","settings":{"foreground":"#d52c36"}},{"scope":"constant.regexp.xi","settings":{"foreground":"#fc2b73"}},{"scope":"keyword.control.xi","settings":{"foreground":"#08c0ef"}},{"scope":"invalid.xi","settings":{"foreground":"#79797F"}},{"scope":"beginning.punctuation.definition.quote.markdown.xi","settings":{"foreground":"#199f43"}},{"scope":"beginning.punctuation.definition.list.markdown.xi","settings":{"foreground":"#84848A"}},{"scope":"constant.character.xi","settings":{"foreground":"#7b43f8"}},{"scope":"accent.xi","settings":{"foreground":"#7b43f8"}},{"scope":"wikiword.xi","settings":{"foreground":"#d5a910"}},{"scope":"constant.other.color.rgb-value.xi","settings":{"foreground":"#070707"}},{"scope":"punctuation.definition.tag.xi","settings":{"foreground":"#84848A"}},{"scope":["support.constant.property-value.scss","support.constant.property-value.css"],"settings":{"foreground":"#d5a910"}},{"scope":["keyword.operator.css","keyword.operator.scss","keyword.operator.less"],"settings":{"foreground":"#08c0ef"}},{"scope":["support.constant.color.w3c-standard-color-name.css","support.constant.color.w3c-standard-color-name.scss"],"settings":{"foreground":"#d5a910"}},{"scope":"punctuation.separator.list.comma.css","settings":{"foreground":"#79797F"}},{"scope":"support.type.vendored.property-name.css","settings":{"foreground":"#08c0ef"}},{"scope":"support.type.property-name.css","settings":{"foreground":"#08c0ef"}},{"scope":"support.type.property-name","settings":{"foreground":"#79797F"}},{"scope":"support.constant.property-value","settings":{"foreground":"#79797F"}},{"scope":"support.constant.font-name","settings":{"foreground":"#d5a910"}},{"scope":"entity.other.attribute-name.class.css","settings":{"foreground":"#16a994","fontStyle":"normal"}},{"scope":"entity.other.attribute-name.id","settings":{"foreground":"#7b43f8","fontStyle":"normal"}},{"scope":["entity.other.attribute-name.pseudo-element","entity.other.attribute-name.pseudo-class"],"settings":{"foreground":"#08c0ef"}},{"scope":"meta.selector","settings":{"foreground":"#fc2b73"}},{"scope":"selector.sass","settings":{"foreground":"#d52c36"}},{"scope":"rgb-value","settings":{"foreground":"#08c0ef"}},{"scope":"inline-color-decoration rgb-value","settings":{"foreground":"#d5a910"}},{"scope":"less rgb-value","settings":{"foreground":"#d5a910"}},{"scope":"control.elements","settings":{"foreground":"#d5a910"}},{"scope":"keyword.operator.less","settings":{"foreground":"#d5a910"}},{"scope":"entity.name.tag","settings":{"foreground":"#d52c36"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#16a994","fontStyle":"normal"}},{"scope":"constant.character.entity","settings":{"foreground":"#d52c36"}},{"scope":"meta.tag","settings":{"foreground":"#79797F"}},{"scope":"invalid.illegal.bad-ampersand.html","settings":{"foreground":"#79797F"}},{"scope":"markup.heading","settings":{"foreground":"#d52c36"}},{"scope":["markup.heading punctuation.definition.heading","entity.name.section"],"settings":{"foreground":"#7b43f8"}},{"scope":"entity.name.section.markdown","settings":{"foreground":"#d52c36"}},{"scope":"punctuation.definition.heading.markdown","settings":{"foreground":"#d52c36"}},{"scope":"markup.heading.setext","settings":{"foreground":"#79797F"}},{"scope":["markup.heading.setext.1.markdown","markup.heading.setext.2.markdown"],"settings":{"foreground":"#d52c36"}},{"scope":["markup.bold","todo.bold"],"settings":{"foreground":"#d5a910"}},{"scope":"punctuation.definition.bold","settings":{"foreground":"#d5a910"}},{"scope":"punctuation.definition.bold.markdown","settings":{"foreground":"#d5a910"}},{"scope":["markup.italic","punctuation.definition.italic","todo.emphasis"],"settings":{"foreground":"#fc2b73","fontStyle":"italic"}},{"scope":"emphasis md","settings":{"foreground":"#fc2b73"}},{"scope":"markup.italic.markdown","settings":{"fontStyle":"italic"}},{"scope":["markup.underline.link.markdown","markup.underline.link.image.markdown"],"settings":{"foreground":"#fc2b73"}},{"scope":["string.other.link.title.markdown","string.other.link.description.markdown"],"settings":{"foreground":"#7b43f8"}},{"scope":"punctuation.definition.metadata.markdown","settings":{"foreground":"#d52c36"}},{"scope":["markup.inline.raw.markdown","markup.inline.raw.string.markdown"],"settings":{"foreground":"#199f43"}},{"scope":"punctuation.definition.list.begin.markdown","settings":{"foreground":"#d52c36"}},{"scope":"punctuation.definition.list.markdown","settings":{"foreground":"#d52c36"}},{"scope":"beginning.punctuation.definition.list.markdown","settings":{"foreground":"#d52c36"}},{"scope":["punctuation.definition.string.begin.markdown","punctuation.definition.string.end.markdown"],"settings":{"foreground":"#d52c36"}},{"scope":"markup.quote.markdown","settings":{"foreground":"#84848A"}},{"scope":"keyword.other.unit","settings":{"foreground":"#d52c36"}},{"scope":"markup.changed.diff","settings":{"foreground":"#d5a910"}},{"scope":["meta.diff.header.from-file","meta.diff.header.to-file","punctuation.definition.from-file.diff","punctuation.definition.to-file.diff"],"settings":{"foreground":"#7b43f8"}},{"scope":"markup.inserted.diff","settings":{"foreground":"#199f43"}},{"scope":"markup.deleted.diff","settings":{"foreground":"#d52c36"}},{"scope":"string.regexp","settings":{"foreground":"#17a5af"}},{"scope":"constant.other.character-class.regexp","settings":{"foreground":"#d52c36"}},{"scope":"keyword.operator.quantifier.regexp","settings":{"foreground":"#d5a910"}},{"scope":"constant.character.escape","settings":{"foreground":"#1ca1c7"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json","settings":{"foreground":"#d52c36"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string","settings":{"foreground":"#d52c36"}},{"scope":["source.json meta.structure.dictionary.json > value.json > string.quoted.json","source.json meta.structure.array.json > value.json > string.quoted.json","source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation","source.json meta.structure.array.json > value.json > string.quoted.json > punctuation"],"settings":{"foreground":"#199f43"}},{"scope":["source.json meta.structure.dictionary.json > constant.language.json","source.json meta.structure.array.json > constant.language.json"],"settings":{"foreground":"#08c0ef"}},{"scope":"support.type.property-name.json","settings":{"foreground":"#d52c36"}},{"scope":"support.type.property-name.json punctuation","settings":{"foreground":"#d52c36"}},{"scope":"punctuation.definition.block.sequence.item.yaml","settings":{"foreground":"#79797F"}},{"scope":"block.scope.end","settings":{"foreground":"#79797F"}},{"scope":"block.scope.begin","settings":{"foreground":"#79797F"}},{"scope":"token.info-token","settings":{"foreground":"#7b43f8"}},{"scope":"token.warn-token","settings":{"foreground":"#d5a910"}},{"scope":"token.error-token","settings":{"foreground":"#f44747"}},{"scope":"token.debug-token","settings":{"foreground":"#fc2b73"}},{"scope":"invalid.illegal","settings":{"foreground":"#070707"}},{"scope":"invalid.broken","settings":{"foreground":"#070707"}},{"scope":"invalid.deprecated","settings":{"foreground":"#070707"}},{"scope":"invalid.unimplemented","settings":{"foreground":"#070707"}}],"semanticTokenColors":{"comment":"#84848A","string":"#199f43","number":"#1ca1c7","regexp":"#17a5af","keyword":"#fc2b73","variable":"#d47628","parameter":"#79797F","property":"#d47628","function":"#7b43f8","method":"#7b43f8","type":"#c635e4","class":"#c635e4","namespace":"#d5a910","enumMember":"#08c0ef","variable.constant":"#d5a910","variable.defaultLibrary":"#d5a910"}}'));export{e as default}; diff --git a/lib/crates/fabro-spa/assets/assets/chunk-q2qv5qr4.js b/lib/crates/fabro-spa/assets/assets/chunk-q2qv5qr4.js new file mode 100644 index 000000000..8d5674785 --- /dev/null +++ b/lib/crates/fabro-spa/assets/assets/chunk-q2qv5qr4.js @@ -0,0 +1 @@ +import"./chunk-q07bg6gn.js";var b="pierre-dark",h="dark",q={"editor.background":"#070707","editor.foreground":"#fbfbfb",foreground:"#fbfbfb",focusBorder:"#009fff","selection.background":"#19283c","editor.selectionBackground":"#009fff4d","editor.lineHighlightBackground":"#19283c8c","editorCursor.foreground":"#009fff","editorLineNumber.foreground":"#84848A","editorLineNumber.activeForeground":"#adadb1","editorIndentGuide.background":"#39393c","editorIndentGuide.activeBackground":"#2e2e30","diffEditor.insertedTextBackground":"#00cab11a","diffEditor.deletedTextBackground":"#ff2e3f1a","sideBar.background":"#141415","sideBar.foreground":"#adadb1","sideBar.border":"#070707","sideBarTitle.foreground":"#fbfbfb","sideBarSectionHeader.background":"#141415","sideBarSectionHeader.foreground":"#adadb1","sideBarSectionHeader.border":"#070707","activityBar.background":"#141415","activityBar.foreground":"#fbfbfb","activityBar.border":"#070707","activityBar.activeBorder":"#009fff","activityBarBadge.background":"#009fff","activityBarBadge.foreground":"#070707","titleBar.activeBackground":"#141415","titleBar.activeForeground":"#fbfbfb","titleBar.inactiveBackground":"#141415","titleBar.inactiveForeground":"#84848A","titleBar.border":"#070707","list.activeSelectionBackground":"#19283c99","list.activeSelectionForeground":"#fbfbfb","list.inactiveSelectionBackground":"#19283c73","list.hoverBackground":"#19283c59","list.focusOutline":"#009fff","tab.activeBackground":"#070707","tab.activeForeground":"#fbfbfb","tab.activeBorderTop":"#009fff","tab.inactiveBackground":"#141415","tab.inactiveForeground":"#84848A","tab.border":"#070707","editorGroupHeader.tabsBackground":"#141415","editorGroupHeader.tabsBorder":"#070707","panel.background":"#141415","panel.border":"#070707","panelTitle.activeBorder":"#009fff","panelTitle.activeForeground":"#fbfbfb","panelTitle.inactiveForeground":"#84848A","statusBar.background":"#141415","statusBar.foreground":"#adadb1","statusBar.border":"#070707","statusBar.noFolderBackground":"#141415","statusBar.debuggingBackground":"#ffca00","statusBar.debuggingForeground":"#070707","statusBarItem.remoteBackground":"#141415","statusBarItem.remoteForeground":"#adadb1","input.background":"#1F1F21","input.border":"#424245","input.foreground":"#fbfbfb","input.placeholderForeground":"#79797F","dropdown.background":"#1F1F21","dropdown.border":"#424245","dropdown.foreground":"#fbfbfb","button.background":"#009fff","button.foreground":"#070707","button.hoverBackground":"#0190e6","textLink.foreground":"#009fff","textLink.activeForeground":"#009fff","gitDecoration.addedResourceForeground":"#00cab1","gitDecoration.conflictingResourceForeground":"#ffca00","gitDecoration.modifiedResourceForeground":"#009fff","gitDecoration.deletedResourceForeground":"#ff2e3f","gitDecoration.untrackedResourceForeground":"#00cab1","gitDecoration.ignoredResourceForeground":"#84848A","terminal.titleForeground":"#adadb1","terminal.titleInactiveForeground":"#84848A","terminal.background":"#141415","terminal.foreground":"#adadb1","terminal.ansiBlack":"#141415","terminal.ansiRed":"#ff2e3f","terminal.ansiGreen":"#0dbe4e","terminal.ansiYellow":"#ffca00","terminal.ansiBlue":"#009fff","terminal.ansiMagenta":"#c635e4","terminal.ansiCyan":"#08c0ef","terminal.ansiWhite":"#c6c6c8","terminal.ansiBrightBlack":"#141415","terminal.ansiBrightRed":"#ff2e3f","terminal.ansiBrightGreen":"#0dbe4e","terminal.ansiBrightYellow":"#ffca00","terminal.ansiBrightBlue":"#009fff","terminal.ansiBrightMagenta":"#c635e4","terminal.ansiBrightCyan":"#08c0ef","terminal.ansiBrightWhite":"#c6c6c8"},v=[{scope:["comment","punctuation.definition.comment"],settings:{foreground:"#84848A"}},{scope:"comment markup.link",settings:{foreground:"#84848A"}},{scope:["string","constant.other.symbol"],settings:{foreground:"#5ecc71"}},{scope:["punctuation.definition.string.begin","punctuation.definition.string.end"],settings:{foreground:"#5ecc71"}},{scope:["constant.numeric","constant.language.boolean"],settings:{foreground:"#68cdf2"}},{scope:"constant",settings:{foreground:"#ffd452"}},{scope:"punctuation.definition.constant",settings:{foreground:"#ffd452"}},{scope:"constant.language",settings:{foreground:"#68cdf2"}},{scope:"variable.other.constant",settings:{foreground:"#ffca00"}},{scope:"keyword",settings:{foreground:"#ff678d"}},{scope:"keyword.control",settings:{foreground:"#ff678d"}},{scope:["storage","storage.type","storage.modifier"],settings:{foreground:"#ff678d"}},{scope:"token.storage",settings:{foreground:"#ff678d"}},{scope:["keyword.operator.new","keyword.operator.expression.instanceof","keyword.operator.expression.typeof","keyword.operator.expression.void","keyword.operator.expression.delete","keyword.operator.expression.in","keyword.operator.expression.of","keyword.operator.expression.keyof"],settings:{foreground:"#ff678d"}},{scope:"keyword.operator.delete",settings:{foreground:"#ff678d"}},{scope:["variable","identifier","meta.definition.variable"],settings:{foreground:"#ffa359"}},{scope:["variable.other.readwrite","meta.object-literal.key","support.variable.property","support.variable.object.process","support.variable.object.node"],settings:{foreground:"#ffa359"}},{scope:"variable.language",settings:{foreground:"#ffca00"}},{scope:"variable.parameter.function",settings:{foreground:"#adadb1"}},{scope:"function.parameter",settings:{foreground:"#adadb1"}},{scope:"variable.parameter",settings:{foreground:"#adadb1"}},{scope:"variable.parameter.function.language.python",settings:{foreground:"#ffd452"}},{scope:"variable.parameter.function.python",settings:{foreground:"#ffd452"}},{scope:["support.function","entity.name.function","meta.function-call","meta.require","support.function.any-method","variable.function"],settings:{foreground:"#9d6afb"}},{scope:"keyword.other.special-method",settings:{foreground:"#9d6afb"}},{scope:"entity.name.function",settings:{foreground:"#9d6afb"}},{scope:"support.function.console",settings:{foreground:"#9d6afb"}},{scope:["support.type","entity.name.type","entity.name.class","storage.type"],settings:{foreground:"#d568ea"}},{scope:["support.class","entity.name.type.class"],settings:{foreground:"#d568ea"}},{scope:["entity.name.class","variable.other.class.js","variable.other.class.ts"],settings:{foreground:"#d568ea"}},{scope:"entity.name.class.identifier.namespace.type",settings:{foreground:"#d568ea"}},{scope:"entity.name.type.namespace",settings:{foreground:"#ffca00"}},{scope:"entity.other.inherited-class",settings:{foreground:"#d568ea"}},{scope:"entity.name.namespace",settings:{foreground:"#ffca00"}},{scope:"keyword.operator",settings:{foreground:"#79797F"}},{scope:["keyword.operator.logical","keyword.operator.bitwise","keyword.operator.channel"],settings:{foreground:"#08c0ef"}},{scope:["keyword.operator.arithmetic","keyword.operator.comparison","keyword.operator.relational","keyword.operator.increment","keyword.operator.decrement"],settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.assignment",settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.assignment.compound",settings:{foreground:"#ff678d"}},{scope:["keyword.operator.assignment.compound.js","keyword.operator.assignment.compound.ts"],settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.ternary",settings:{foreground:"#ff678d"}},{scope:"keyword.operator.optional",settings:{foreground:"#ff678d"}},{scope:"punctuation",settings:{foreground:"#79797F"}},{scope:"punctuation.separator.delimiter",settings:{foreground:"#79797F"}},{scope:"punctuation.separator.key-value",settings:{foreground:"#79797F"}},{scope:"punctuation.terminator",settings:{foreground:"#79797F"}},{scope:"meta.brace",settings:{foreground:"#79797F"}},{scope:"meta.brace.square",settings:{foreground:"#79797F"}},{scope:"meta.brace.round",settings:{foreground:"#79797F"}},{scope:"function.brace",settings:{foreground:"#79797F"}},{scope:["punctuation.definition.parameters","punctuation.definition.typeparameters"],settings:{foreground:"#79797F"}},{scope:["punctuation.definition.block","punctuation.definition.tag"],settings:{foreground:"#79797F"}},{scope:["meta.tag.tsx","meta.tag.jsx","meta.tag.js","meta.tag.ts"],settings:{foreground:"#79797F"}},{scope:"keyword.operator.expression.import",settings:{foreground:"#9d6afb"}},{scope:"keyword.operator.module",settings:{foreground:"#ff678d"}},{scope:"support.type.object.console",settings:{foreground:"#ffa359"}},{scope:["support.module.node","support.type.object.module","entity.name.type.module"],settings:{foreground:"#ffca00"}},{scope:"support.constant.math",settings:{foreground:"#ffca00"}},{scope:"support.constant.property.math",settings:{foreground:"#ffd452"}},{scope:"support.constant.json",settings:{foreground:"#ffd452"}},{scope:"support.type.object.dom",settings:{foreground:"#08c0ef"}},{scope:["support.variable.dom","support.variable.property.dom"],settings:{foreground:"#ffa359"}},{scope:"support.variable.property.process",settings:{foreground:"#ffd452"}},{scope:"meta.property.object",settings:{foreground:"#ffa359"}},{scope:"variable.parameter.function.js",settings:{foreground:"#ffa359"}},{scope:["keyword.other.template.begin","keyword.other.template.end"],settings:{foreground:"#5ecc71"}},{scope:["keyword.other.substitution.begin","keyword.other.substitution.end"],settings:{foreground:"#5ecc71"}},{scope:["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end"],settings:{foreground:"#ff678d"}},{scope:"meta.template.expression",settings:{foreground:"#79797F"}},{scope:"punctuation.section.embedded",settings:{foreground:"#ffa359"}},{scope:"variable.interpolation",settings:{foreground:"#ffa359"}},{scope:["punctuation.section.embedded.begin","punctuation.section.embedded.end"],settings:{foreground:"#ff678d"}},{scope:"punctuation.quasi.element",settings:{foreground:"#ff678d"}},{scope:["support.type.primitive.ts","support.type.builtin.ts","support.type.primitive.tsx","support.type.builtin.tsx"],settings:{foreground:"#d568ea"}},{scope:"support.type.type.flowtype",settings:{foreground:"#9d6afb"}},{scope:"support.type.primitive",settings:{foreground:"#d568ea"}},{scope:"support.variable.magic.python",settings:{foreground:"#ff6762"}},{scope:"variable.parameter.function.language.special.self.python",settings:{foreground:"#ffca00"}},{scope:["punctuation.separator.period.python","punctuation.separator.element.python","punctuation.parenthesis.begin.python","punctuation.parenthesis.end.python"],settings:{foreground:"#79797F"}},{scope:["punctuation.definition.arguments.begin.python","punctuation.definition.arguments.end.python","punctuation.separator.arguments.python","punctuation.definition.list.begin.python","punctuation.definition.list.end.python"],settings:{foreground:"#79797F"}},{scope:"support.type.python",settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.logical.python",settings:{foreground:"#ff678d"}},{scope:"meta.function-call.generic.python",settings:{foreground:"#9d6afb"}},{scope:"constant.character.format.placeholder.other.python",settings:{foreground:"#ffd452"}},{scope:"meta.function.decorator.python",settings:{foreground:"#9d6afb"}},{scope:["support.token.decorator.python","meta.function.decorator.identifier.python"],settings:{foreground:"#08c0ef"}},{scope:"storage.modifier.lifetime.rust",settings:{foreground:"#79797F"}},{scope:"support.function.std.rust",settings:{foreground:"#9d6afb"}},{scope:"entity.name.lifetime.rust",settings:{foreground:"#ffca00"}},{scope:"variable.language.rust",settings:{foreground:"#ff6762"}},{scope:"keyword.operator.misc.rust",settings:{foreground:"#79797F"}},{scope:"keyword.operator.sigil.rust",settings:{foreground:"#ff678d"}},{scope:"support.constant.core.rust",settings:{foreground:"#ffd452"}},{scope:["meta.function.c","meta.function.cpp"],settings:{foreground:"#ff6762"}},{scope:["punctuation.section.block.begin.bracket.curly.cpp","punctuation.section.block.end.bracket.curly.cpp","punctuation.terminator.statement.c","punctuation.section.block.begin.bracket.curly.c","punctuation.section.block.end.bracket.curly.c","punctuation.section.parens.begin.bracket.round.c","punctuation.section.parens.end.bracket.round.c","punctuation.section.parameters.begin.bracket.round.c","punctuation.section.parameters.end.bracket.round.c"],settings:{foreground:"#79797F"}},{scope:["keyword.operator.assignment.c","keyword.operator.comparison.c","keyword.operator.c","keyword.operator.increment.c","keyword.operator.decrement.c","keyword.operator.bitwise.shift.c"],settings:{foreground:"#ff678d"}},{scope:["keyword.operator.assignment.cpp","keyword.operator.comparison.cpp","keyword.operator.cpp","keyword.operator.increment.cpp","keyword.operator.decrement.cpp","keyword.operator.bitwise.shift.cpp"],settings:{foreground:"#ff678d"}},{scope:["punctuation.separator.c","punctuation.separator.cpp"],settings:{foreground:"#ff678d"}},{scope:["support.type.posix-reserved.c","support.type.posix-reserved.cpp"],settings:{foreground:"#08c0ef"}},{scope:["keyword.operator.sizeof.c","keyword.operator.sizeof.cpp"],settings:{foreground:"#ff678d"}},{scope:"variable.c",settings:{foreground:"#79797F"}},{scope:["storage.type.annotation.java","storage.type.object.array.java"],settings:{foreground:"#ffca00"}},{scope:"source.java",settings:{foreground:"#ff6762"}},{scope:["punctuation.section.block.begin.java","punctuation.section.block.end.java","punctuation.definition.method-parameters.begin.java","punctuation.definition.method-parameters.end.java","meta.method.identifier.java","punctuation.section.method.begin.java","punctuation.section.method.end.java","punctuation.terminator.java","punctuation.section.class.begin.java","punctuation.section.class.end.java","punctuation.section.inner-class.begin.java","punctuation.section.inner-class.end.java","meta.method-call.java","punctuation.section.class.begin.bracket.curly.java","punctuation.section.class.end.bracket.curly.java","punctuation.section.method.begin.bracket.curly.java","punctuation.section.method.end.bracket.curly.java","punctuation.separator.period.java","punctuation.bracket.angle.java","punctuation.definition.annotation.java","meta.method.body.java"],settings:{foreground:"#79797F"}},{scope:"meta.method.java",settings:{foreground:"#9d6afb"}},{scope:["storage.modifier.import.java","storage.type.java","storage.type.generic.java"],settings:{foreground:"#ffca00"}},{scope:"keyword.operator.instanceof.java",settings:{foreground:"#ff678d"}},{scope:"meta.definition.variable.name.java",settings:{foreground:"#ff6762"}},{scope:"token.variable.parameter.java",settings:{foreground:"#79797F"}},{scope:"import.storage.java",settings:{foreground:"#ffca00"}},{scope:"token.package.keyword",settings:{foreground:"#ff678d"}},{scope:"token.package",settings:{foreground:"#79797F"}},{scope:"token.storage.type.java",settings:{foreground:"#ffca00"}},{scope:"keyword.operator.assignment.go",settings:{foreground:"#ffca00"}},{scope:["keyword.operator.arithmetic.go","keyword.operator.address.go"],settings:{foreground:"#ff678d"}},{scope:"entity.name.package.go",settings:{foreground:"#ffca00"}},{scope:["support.other.namespace.use.php","support.other.namespace.use-as.php","support.other.namespace.php","entity.other.alias.php","meta.interface.php"],settings:{foreground:"#ffca00"}},{scope:"keyword.operator.error-control.php",settings:{foreground:"#ff678d"}},{scope:"keyword.operator.type.php",settings:{foreground:"#ff678d"}},{scope:["punctuation.section.array.begin.php","punctuation.section.array.end.php"],settings:{foreground:"#79797F"}},{scope:["storage.type.php","meta.other.type.phpdoc.php","keyword.other.type.php","keyword.other.array.phpdoc.php"],settings:{foreground:"#ffca00"}},{scope:["meta.function-call.php","meta.function-call.object.php","meta.function-call.static.php"],settings:{foreground:"#9d6afb"}},{scope:["punctuation.definition.parameters.begin.bracket.round.php","punctuation.definition.parameters.end.bracket.round.php","punctuation.separator.delimiter.php","punctuation.section.scope.begin.php","punctuation.section.scope.end.php","punctuation.terminator.expression.php","punctuation.definition.arguments.begin.bracket.round.php","punctuation.definition.arguments.end.bracket.round.php","punctuation.definition.storage-type.begin.bracket.round.php","punctuation.definition.storage-type.end.bracket.round.php","punctuation.definition.array.begin.bracket.round.php","punctuation.definition.array.end.bracket.round.php","punctuation.definition.begin.bracket.round.php","punctuation.definition.end.bracket.round.php","punctuation.definition.begin.bracket.curly.php","punctuation.definition.end.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php","punctuation.definition.section.switch-block.start.bracket.curly.php","punctuation.definition.section.switch-block.begin.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php"],settings:{foreground:"#79797F"}},{scope:["support.constant.ext.php","support.constant.std.php","support.constant.core.php","support.constant.parser-token.php"],settings:{foreground:"#ffd452"}},{scope:["entity.name.goto-label.php","support.other.php"],settings:{foreground:"#9d6afb"}},{scope:["keyword.operator.logical.php","keyword.operator.bitwise.php","keyword.operator.arithmetic.php"],settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.regexp.php",settings:{foreground:"#ff678d"}},{scope:"keyword.operator.comparison.php",settings:{foreground:"#08c0ef"}},{scope:["keyword.operator.heredoc.php","keyword.operator.nowdoc.php"],settings:{foreground:"#ff678d"}},{scope:"variable.other.class.php",settings:{foreground:"#ff6762"}},{scope:"invalid.illegal.non-null-typehinted.php",settings:{foreground:"#f44747"}},{scope:"variable.other.generic-type.haskell",settings:{foreground:"#ff678d"}},{scope:"storage.type.haskell",settings:{foreground:"#ffd452"}},{scope:"storage.type.cs",settings:{foreground:"#ffca00"}},{scope:"entity.name.variable.local.cs",settings:{foreground:"#ff6762"}},{scope:"entity.name.label.cs",settings:{foreground:"#ffca00"}},{scope:["entity.name.scope-resolution.function.call","entity.name.scope-resolution.function.definition"],settings:{foreground:"#ffca00"}},{scope:["punctuation.definition.delayed.unison","punctuation.definition.list.begin.unison","punctuation.definition.list.end.unison","punctuation.definition.ability.begin.unison","punctuation.definition.ability.end.unison","punctuation.operator.assignment.as.unison","punctuation.separator.pipe.unison","punctuation.separator.delimiter.unison","punctuation.definition.hash.unison"],settings:{foreground:"#ff6762"}},{scope:"support.constant.edge",settings:{foreground:"#ff678d"}},{scope:"support.type.prelude.elm",settings:{foreground:"#08c0ef"}},{scope:"support.constant.elm",settings:{foreground:"#ffd452"}},{scope:"entity.global.clojure",settings:{foreground:"#ffca00"}},{scope:"meta.symbol.clojure",settings:{foreground:"#ff6762"}},{scope:"constant.keyword.clojure",settings:{foreground:"#08c0ef"}},{scope:["meta.arguments.coffee","variable.parameter.function.coffee"],settings:{foreground:"#ff6762"}},{scope:"storage.modifier.import.groovy",settings:{foreground:"#ffca00"}},{scope:"meta.method.groovy",settings:{foreground:"#9d6afb"}},{scope:"meta.definition.variable.name.groovy",settings:{foreground:"#ff6762"}},{scope:"meta.definition.class.inherited.classes.groovy",settings:{foreground:"#5ecc71"}},{scope:"support.variable.semantic.hlsl",settings:{foreground:"#ffca00"}},{scope:["support.type.texture.hlsl","support.type.sampler.hlsl","support.type.object.hlsl","support.type.object.rw.hlsl","support.type.fx.hlsl","support.type.object.hlsl"],settings:{foreground:"#ff678d"}},{scope:["text.variable","text.bracketed"],settings:{foreground:"#ff6762"}},{scope:["support.type.swift","support.type.vb.asp"],settings:{foreground:"#ffca00"}},{scope:"meta.scope.prerequisites.makefile",settings:{foreground:"#ff6762"}},{scope:"source.makefile",settings:{foreground:"#ffca00"}},{scope:"source.ini",settings:{foreground:"#5ecc71"}},{scope:"constant.language.symbol.ruby",settings:{foreground:"#08c0ef"}},{scope:["function.parameter.ruby","function.parameter.cs"],settings:{foreground:"#79797F"}},{scope:"constant.language.symbol.elixir",settings:{foreground:"#08c0ef"}},{scope:"text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade",settings:{foreground:"#ff678d"}},{scope:"text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade",settings:{foreground:"#ff678d"}},{scope:"entity.name.function.xi",settings:{foreground:"#ffca00"}},{scope:"entity.name.class.xi",settings:{foreground:"#08c0ef"}},{scope:"constant.character.character-class.regexp.xi",settings:{foreground:"#ff6762"}},{scope:"constant.regexp.xi",settings:{foreground:"#ff678d"}},{scope:"keyword.control.xi",settings:{foreground:"#08c0ef"}},{scope:"invalid.xi",settings:{foreground:"#79797F"}},{scope:"beginning.punctuation.definition.quote.markdown.xi",settings:{foreground:"#5ecc71"}},{scope:"beginning.punctuation.definition.list.markdown.xi",settings:{foreground:"#84848A"}},{scope:"constant.character.xi",settings:{foreground:"#9d6afb"}},{scope:"accent.xi",settings:{foreground:"#9d6afb"}},{scope:"wikiword.xi",settings:{foreground:"#ffd452"}},{scope:"constant.other.color.rgb-value.xi",settings:{foreground:"#ffffff"}},{scope:"punctuation.definition.tag.xi",settings:{foreground:"#84848A"}},{scope:["support.constant.property-value.scss","support.constant.property-value.css"],settings:{foreground:"#ffd452"}},{scope:["keyword.operator.css","keyword.operator.scss","keyword.operator.less"],settings:{foreground:"#08c0ef"}},{scope:["support.constant.color.w3c-standard-color-name.css","support.constant.color.w3c-standard-color-name.scss"],settings:{foreground:"#ffd452"}},{scope:"punctuation.separator.list.comma.css",settings:{foreground:"#79797F"}},{scope:"support.type.vendored.property-name.css",settings:{foreground:"#08c0ef"}},{scope:"support.type.property-name.css",settings:{foreground:"#08c0ef"}},{scope:"support.type.property-name",settings:{foreground:"#79797F"}},{scope:"support.constant.property-value",settings:{foreground:"#79797F"}},{scope:"support.constant.font-name",settings:{foreground:"#ffd452"}},{scope:"entity.other.attribute-name.class.css",settings:{foreground:"#61d5c0",fontStyle:"normal"}},{scope:"entity.other.attribute-name.id",settings:{foreground:"#9d6afb",fontStyle:"normal"}},{scope:["entity.other.attribute-name.pseudo-element","entity.other.attribute-name.pseudo-class"],settings:{foreground:"#08c0ef"}},{scope:"meta.selector",settings:{foreground:"#ff678d"}},{scope:"selector.sass",settings:{foreground:"#ff6762"}},{scope:"rgb-value",settings:{foreground:"#08c0ef"}},{scope:"inline-color-decoration rgb-value",settings:{foreground:"#ffd452"}},{scope:"less rgb-value",settings:{foreground:"#ffd452"}},{scope:"control.elements",settings:{foreground:"#ffd452"}},{scope:"keyword.operator.less",settings:{foreground:"#ffd452"}},{scope:"entity.name.tag",settings:{foreground:"#ff6762"}},{scope:"entity.other.attribute-name",settings:{foreground:"#61d5c0",fontStyle:"normal"}},{scope:"constant.character.entity",settings:{foreground:"#ff6762"}},{scope:"meta.tag",settings:{foreground:"#79797F"}},{scope:"invalid.illegal.bad-ampersand.html",settings:{foreground:"#79797F"}},{scope:"markup.heading",settings:{foreground:"#ff6762"}},{scope:["markup.heading punctuation.definition.heading","entity.name.section"],settings:{foreground:"#9d6afb"}},{scope:"entity.name.section.markdown",settings:{foreground:"#ff6762"}},{scope:"punctuation.definition.heading.markdown",settings:{foreground:"#ff6762"}},{scope:"markup.heading.setext",settings:{foreground:"#79797F"}},{scope:["markup.heading.setext.1.markdown","markup.heading.setext.2.markdown"],settings:{foreground:"#ff6762"}},{scope:["markup.bold","todo.bold"],settings:{foreground:"#ffd452"}},{scope:"punctuation.definition.bold",settings:{foreground:"#ffca00"}},{scope:"punctuation.definition.bold.markdown",settings:{foreground:"#ffd452"}},{scope:["markup.italic","punctuation.definition.italic","todo.emphasis"],settings:{foreground:"#ff678d",fontStyle:"italic"}},{scope:"emphasis md",settings:{foreground:"#ff678d"}},{scope:"markup.italic.markdown",settings:{fontStyle:"italic"}},{scope:["markup.underline.link.markdown","markup.underline.link.image.markdown"],settings:{foreground:"#ff678d"}},{scope:["string.other.link.title.markdown","string.other.link.description.markdown"],settings:{foreground:"#9d6afb"}},{scope:"punctuation.definition.metadata.markdown",settings:{foreground:"#ff6762"}},{scope:["markup.inline.raw.markdown","markup.inline.raw.string.markdown"],settings:{foreground:"#5ecc71"}},{scope:"punctuation.definition.list.begin.markdown",settings:{foreground:"#ff6762"}},{scope:"punctuation.definition.list.markdown",settings:{foreground:"#ff6762"}},{scope:"beginning.punctuation.definition.list.markdown",settings:{foreground:"#ff6762"}},{scope:["punctuation.definition.string.begin.markdown","punctuation.definition.string.end.markdown"],settings:{foreground:"#ff6762"}},{scope:"markup.quote.markdown",settings:{foreground:"#84848A"}},{scope:"keyword.other.unit",settings:{foreground:"#ff6762"}},{scope:"markup.changed.diff",settings:{foreground:"#ffca00"}},{scope:["meta.diff.header.from-file","meta.diff.header.to-file","punctuation.definition.from-file.diff","punctuation.definition.to-file.diff"],settings:{foreground:"#9d6afb"}},{scope:"markup.inserted.diff",settings:{foreground:"#5ecc71"}},{scope:"markup.deleted.diff",settings:{foreground:"#ff6762"}},{scope:"string.regexp",settings:{foreground:"#64d1db"}},{scope:"constant.other.character-class.regexp",settings:{foreground:"#ff6762"}},{scope:"keyword.operator.quantifier.regexp",settings:{foreground:"#ffd452"}},{scope:"constant.character.escape",settings:{foreground:"#68cdf2"}},{scope:"source.json meta.structure.dictionary.json > string.quoted.json",settings:{foreground:"#ff6762"}},{scope:"source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string",settings:{foreground:"#ff6762"}},{scope:["source.json meta.structure.dictionary.json > value.json > string.quoted.json","source.json meta.structure.array.json > value.json > string.quoted.json","source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation","source.json meta.structure.array.json > value.json > string.quoted.json > punctuation"],settings:{foreground:"#5ecc71"}},{scope:["source.json meta.structure.dictionary.json > constant.language.json","source.json meta.structure.array.json > constant.language.json"],settings:{foreground:"#08c0ef"}},{scope:"support.type.property-name.json",settings:{foreground:"#ff6762"}},{scope:"support.type.property-name.json punctuation",settings:{foreground:"#ff6762"}},{scope:"punctuation.definition.block.sequence.item.yaml",settings:{foreground:"#79797F"}},{scope:"block.scope.end",settings:{foreground:"#79797F"}},{scope:"block.scope.begin",settings:{foreground:"#79797F"}},{scope:"token.info-token",settings:{foreground:"#9d6afb"}},{scope:"token.warn-token",settings:{foreground:"#ffd452"}},{scope:"token.error-token",settings:{foreground:"#f44747"}},{scope:"token.debug-token",settings:{foreground:"#ff678d"}},{scope:"invalid.illegal",settings:{foreground:"#ffffff"}},{scope:"invalid.broken",settings:{foreground:"#ffffff"}},{scope:"invalid.deprecated",settings:{foreground:"#ffffff"}},{scope:"invalid.unimplemented",settings:{foreground:"#ffffff"}}],w={comment:"#84848A",string:"#5ecc71",number:"#68cdf2",regexp:"#64d1db",keyword:"#ff678d",variable:"#ffa359",parameter:"#adadb1",property:"#ffa359",function:"#9d6afb",method:"#9d6afb",type:"#d568ea",class:"#d568ea",namespace:"#ffca00",enumMember:"#08c0ef","variable.constant":"#ffd452","variable.defaultLibrary":"#ffca00"},x={name:b,type:h,colors:q,tokenColors:v,semanticTokenColors:w};export{h as type,v as tokenColors,w as semanticTokenColors,b as name,x as default,q as colors}; diff --git a/lib/crates/fabro-spa/assets/assets/chunk-tqzz87j8.js b/lib/crates/fabro-spa/assets/assets/chunk-tqzz87j8.js new file mode 100644 index 000000000..b56d27055 --- /dev/null +++ b/lib/crates/fabro-spa/assets/assets/chunk-tqzz87j8.js @@ -0,0 +1 @@ +import"./chunk-q07bg6gn.js";var b="pierre-light",q="light",v={"editor.background":"#ffffff","editor.foreground":"#070707",foreground:"#070707",focusBorder:"#009fff","selection.background":"#dfebff","editor.selectionBackground":"#009fff2e","editor.lineHighlightBackground":"#dfebff8c","editorCursor.foreground":"#009fff","editorLineNumber.foreground":"#84848A","editorLineNumber.activeForeground":"#6C6C71","editorIndentGuide.background":"#eeeeef","editorIndentGuide.activeBackground":"#dbdbdd","diffEditor.insertedTextBackground":"#00cab133","diffEditor.deletedTextBackground":"#ff2e3f33","sideBar.background":"#f8f8f8","sideBar.foreground":"#6C6C71","sideBar.border":"#eeeeef","sideBarTitle.foreground":"#070707","sideBarSectionHeader.background":"#f8f8f8","sideBarSectionHeader.foreground":"#6C6C71","sideBarSectionHeader.border":"#eeeeef","activityBar.background":"#f8f8f8","activityBar.foreground":"#070707","activityBar.border":"#eeeeef","activityBar.activeBorder":"#009fff","activityBarBadge.background":"#009fff","activityBarBadge.foreground":"#ffffff","titleBar.activeBackground":"#f8f8f8","titleBar.activeForeground":"#070707","titleBar.inactiveBackground":"#f8f8f8","titleBar.inactiveForeground":"#84848A","titleBar.border":"#eeeeef","list.activeSelectionBackground":"#dfebffcc","list.activeSelectionForeground":"#070707","list.inactiveSelectionBackground":"#dfebff73","list.hoverBackground":"#dfebff59","list.focusOutline":"#009fff","tab.activeBackground":"#ffffff","tab.activeForeground":"#070707","tab.activeBorderTop":"#009fff","tab.inactiveBackground":"#f8f8f8","tab.inactiveForeground":"#84848A","tab.border":"#eeeeef","editorGroupHeader.tabsBackground":"#f8f8f8","editorGroupHeader.tabsBorder":"#eeeeef","panel.background":"#f8f8f8","panel.border":"#eeeeef","panelTitle.activeBorder":"#009fff","panelTitle.activeForeground":"#070707","panelTitle.inactiveForeground":"#84848A","statusBar.background":"#f8f8f8","statusBar.foreground":"#6C6C71","statusBar.border":"#eeeeef","statusBar.noFolderBackground":"#f8f8f8","statusBar.debuggingBackground":"#ffca00","statusBar.debuggingForeground":"#ffffff","statusBarItem.remoteBackground":"#f8f8f8","statusBarItem.remoteForeground":"#6C6C71","input.background":"#f2f2f3","input.border":"#dbdbdd","input.foreground":"#070707","input.placeholderForeground":"#8E8E95","dropdown.background":"#f2f2f3","dropdown.border":"#dbdbdd","dropdown.foreground":"#070707","button.background":"#009fff","button.foreground":"#ffffff","button.hoverBackground":"#1aa9ff","textLink.foreground":"#009fff","textLink.activeForeground":"#009fff","gitDecoration.addedResourceForeground":"#00cab1","gitDecoration.conflictingResourceForeground":"#ffca00","gitDecoration.modifiedResourceForeground":"#009fff","gitDecoration.deletedResourceForeground":"#ff2e3f","gitDecoration.untrackedResourceForeground":"#00cab1","gitDecoration.ignoredResourceForeground":"#84848A","terminal.titleForeground":"#6C6C71","terminal.titleInactiveForeground":"#84848A","terminal.background":"#f8f8f8","terminal.foreground":"#6C6C71","terminal.ansiBlack":"#1F1F21","terminal.ansiRed":"#ff2e3f","terminal.ansiGreen":"#0dbe4e","terminal.ansiYellow":"#ffca00","terminal.ansiBlue":"#009fff","terminal.ansiMagenta":"#c635e4","terminal.ansiCyan":"#08c0ef","terminal.ansiWhite":"#c6c6c8","terminal.ansiBrightBlack":"#1F1F21","terminal.ansiBrightRed":"#ff2e3f","terminal.ansiBrightGreen":"#0dbe4e","terminal.ansiBrightYellow":"#ffca00","terminal.ansiBrightBlue":"#009fff","terminal.ansiBrightMagenta":"#c635e4","terminal.ansiBrightCyan":"#08c0ef","terminal.ansiBrightWhite":"#c6c6c8"},w=[{scope:["comment","punctuation.definition.comment"],settings:{foreground:"#84848A"}},{scope:"comment markup.link",settings:{foreground:"#84848A"}},{scope:["string","constant.other.symbol"],settings:{foreground:"#199f43"}},{scope:["punctuation.definition.string.begin","punctuation.definition.string.end"],settings:{foreground:"#199f43"}},{scope:["constant.numeric","constant.language.boolean"],settings:{foreground:"#1ca1c7"}},{scope:"constant",settings:{foreground:"#d5a910"}},{scope:"punctuation.definition.constant",settings:{foreground:"#d5a910"}},{scope:"constant.language",settings:{foreground:"#1ca1c7"}},{scope:"variable.other.constant",settings:{foreground:"#d5a910"}},{scope:"keyword",settings:{foreground:"#fc2b73"}},{scope:"keyword.control",settings:{foreground:"#fc2b73"}},{scope:["storage","storage.type","storage.modifier"],settings:{foreground:"#fc2b73"}},{scope:"token.storage",settings:{foreground:"#fc2b73"}},{scope:["keyword.operator.new","keyword.operator.expression.instanceof","keyword.operator.expression.typeof","keyword.operator.expression.void","keyword.operator.expression.delete","keyword.operator.expression.in","keyword.operator.expression.of","keyword.operator.expression.keyof"],settings:{foreground:"#fc2b73"}},{scope:"keyword.operator.delete",settings:{foreground:"#fc2b73"}},{scope:["variable","identifier","meta.definition.variable"],settings:{foreground:"#d47628"}},{scope:["variable.other.readwrite","meta.object-literal.key","support.variable.property","support.variable.object.process","support.variable.object.node"],settings:{foreground:"#d47628"}},{scope:"variable.language",settings:{foreground:"#d5a910"}},{scope:"variable.parameter.function",settings:{foreground:"#79797F"}},{scope:"function.parameter",settings:{foreground:"#79797F"}},{scope:"variable.parameter",settings:{foreground:"#79797F"}},{scope:"variable.parameter.function.language.python",settings:{foreground:"#d5a910"}},{scope:"variable.parameter.function.python",settings:{foreground:"#d5a910"}},{scope:["support.function","entity.name.function","meta.function-call","meta.require","support.function.any-method","variable.function"],settings:{foreground:"#7b43f8"}},{scope:"keyword.other.special-method",settings:{foreground:"#7b43f8"}},{scope:"entity.name.function",settings:{foreground:"#7b43f8"}},{scope:"support.function.console",settings:{foreground:"#7b43f8"}},{scope:["support.type","entity.name.type","entity.name.class","storage.type"],settings:{foreground:"#c635e4"}},{scope:["support.class","entity.name.type.class"],settings:{foreground:"#c635e4"}},{scope:["entity.name.class","variable.other.class.js","variable.other.class.ts"],settings:{foreground:"#c635e4"}},{scope:"entity.name.class.identifier.namespace.type",settings:{foreground:"#c635e4"}},{scope:"entity.name.type.namespace",settings:{foreground:"#d5a910"}},{scope:"entity.other.inherited-class",settings:{foreground:"#c635e4"}},{scope:"entity.name.namespace",settings:{foreground:"#d5a910"}},{scope:"keyword.operator",settings:{foreground:"#79797F"}},{scope:["keyword.operator.logical","keyword.operator.bitwise","keyword.operator.channel"],settings:{foreground:"#08c0ef"}},{scope:["keyword.operator.arithmetic","keyword.operator.comparison","keyword.operator.relational","keyword.operator.increment","keyword.operator.decrement"],settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.assignment",settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.assignment.compound",settings:{foreground:"#fc2b73"}},{scope:["keyword.operator.assignment.compound.js","keyword.operator.assignment.compound.ts"],settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.ternary",settings:{foreground:"#fc2b73"}},{scope:"keyword.operator.optional",settings:{foreground:"#fc2b73"}},{scope:"punctuation",settings:{foreground:"#79797F"}},{scope:"punctuation.separator.delimiter",settings:{foreground:"#79797F"}},{scope:"punctuation.separator.key-value",settings:{foreground:"#79797F"}},{scope:"punctuation.terminator",settings:{foreground:"#79797F"}},{scope:"meta.brace",settings:{foreground:"#79797F"}},{scope:"meta.brace.square",settings:{foreground:"#79797F"}},{scope:"meta.brace.round",settings:{foreground:"#79797F"}},{scope:"function.brace",settings:{foreground:"#79797F"}},{scope:["punctuation.definition.parameters","punctuation.definition.typeparameters"],settings:{foreground:"#79797F"}},{scope:["punctuation.definition.block","punctuation.definition.tag"],settings:{foreground:"#79797F"}},{scope:["meta.tag.tsx","meta.tag.jsx","meta.tag.js","meta.tag.ts"],settings:{foreground:"#79797F"}},{scope:"keyword.operator.expression.import",settings:{foreground:"#7b43f8"}},{scope:"keyword.operator.module",settings:{foreground:"#fc2b73"}},{scope:"support.type.object.console",settings:{foreground:"#d47628"}},{scope:["support.module.node","support.type.object.module","entity.name.type.module"],settings:{foreground:"#d5a910"}},{scope:"support.constant.math",settings:{foreground:"#d5a910"}},{scope:"support.constant.property.math",settings:{foreground:"#d5a910"}},{scope:"support.constant.json",settings:{foreground:"#d5a910"}},{scope:"support.type.object.dom",settings:{foreground:"#08c0ef"}},{scope:["support.variable.dom","support.variable.property.dom"],settings:{foreground:"#d47628"}},{scope:"support.variable.property.process",settings:{foreground:"#d5a910"}},{scope:"meta.property.object",settings:{foreground:"#d47628"}},{scope:"variable.parameter.function.js",settings:{foreground:"#d47628"}},{scope:["keyword.other.template.begin","keyword.other.template.end"],settings:{foreground:"#199f43"}},{scope:["keyword.other.substitution.begin","keyword.other.substitution.end"],settings:{foreground:"#199f43"}},{scope:["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end"],settings:{foreground:"#fc2b73"}},{scope:"meta.template.expression",settings:{foreground:"#79797F"}},{scope:"punctuation.section.embedded",settings:{foreground:"#d47628"}},{scope:"variable.interpolation",settings:{foreground:"#d47628"}},{scope:["punctuation.section.embedded.begin","punctuation.section.embedded.end"],settings:{foreground:"#fc2b73"}},{scope:"punctuation.quasi.element",settings:{foreground:"#fc2b73"}},{scope:["support.type.primitive.ts","support.type.builtin.ts","support.type.primitive.tsx","support.type.builtin.tsx"],settings:{foreground:"#c635e4"}},{scope:"support.type.type.flowtype",settings:{foreground:"#7b43f8"}},{scope:"support.type.primitive",settings:{foreground:"#c635e4"}},{scope:"support.variable.magic.python",settings:{foreground:"#d52c36"}},{scope:"variable.parameter.function.language.special.self.python",settings:{foreground:"#d5a910"}},{scope:["punctuation.separator.period.python","punctuation.separator.element.python","punctuation.parenthesis.begin.python","punctuation.parenthesis.end.python"],settings:{foreground:"#79797F"}},{scope:["punctuation.definition.arguments.begin.python","punctuation.definition.arguments.end.python","punctuation.separator.arguments.python","punctuation.definition.list.begin.python","punctuation.definition.list.end.python"],settings:{foreground:"#79797F"}},{scope:"support.type.python",settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.logical.python",settings:{foreground:"#fc2b73"}},{scope:"meta.function-call.generic.python",settings:{foreground:"#7b43f8"}},{scope:"constant.character.format.placeholder.other.python",settings:{foreground:"#d5a910"}},{scope:"meta.function.decorator.python",settings:{foreground:"#7b43f8"}},{scope:["support.token.decorator.python","meta.function.decorator.identifier.python"],settings:{foreground:"#08c0ef"}},{scope:"storage.modifier.lifetime.rust",settings:{foreground:"#79797F"}},{scope:"support.function.std.rust",settings:{foreground:"#7b43f8"}},{scope:"entity.name.lifetime.rust",settings:{foreground:"#d5a910"}},{scope:"variable.language.rust",settings:{foreground:"#d52c36"}},{scope:"keyword.operator.misc.rust",settings:{foreground:"#79797F"}},{scope:"keyword.operator.sigil.rust",settings:{foreground:"#fc2b73"}},{scope:"support.constant.core.rust",settings:{foreground:"#d5a910"}},{scope:["meta.function.c","meta.function.cpp"],settings:{foreground:"#d52c36"}},{scope:["punctuation.section.block.begin.bracket.curly.cpp","punctuation.section.block.end.bracket.curly.cpp","punctuation.terminator.statement.c","punctuation.section.block.begin.bracket.curly.c","punctuation.section.block.end.bracket.curly.c","punctuation.section.parens.begin.bracket.round.c","punctuation.section.parens.end.bracket.round.c","punctuation.section.parameters.begin.bracket.round.c","punctuation.section.parameters.end.bracket.round.c"],settings:{foreground:"#79797F"}},{scope:["keyword.operator.assignment.c","keyword.operator.comparison.c","keyword.operator.c","keyword.operator.increment.c","keyword.operator.decrement.c","keyword.operator.bitwise.shift.c"],settings:{foreground:"#fc2b73"}},{scope:["keyword.operator.assignment.cpp","keyword.operator.comparison.cpp","keyword.operator.cpp","keyword.operator.increment.cpp","keyword.operator.decrement.cpp","keyword.operator.bitwise.shift.cpp"],settings:{foreground:"#fc2b73"}},{scope:["punctuation.separator.c","punctuation.separator.cpp"],settings:{foreground:"#fc2b73"}},{scope:["support.type.posix-reserved.c","support.type.posix-reserved.cpp"],settings:{foreground:"#08c0ef"}},{scope:["keyword.operator.sizeof.c","keyword.operator.sizeof.cpp"],settings:{foreground:"#fc2b73"}},{scope:"variable.c",settings:{foreground:"#79797F"}},{scope:["storage.type.annotation.java","storage.type.object.array.java"],settings:{foreground:"#d5a910"}},{scope:"source.java",settings:{foreground:"#d52c36"}},{scope:["punctuation.section.block.begin.java","punctuation.section.block.end.java","punctuation.definition.method-parameters.begin.java","punctuation.definition.method-parameters.end.java","meta.method.identifier.java","punctuation.section.method.begin.java","punctuation.section.method.end.java","punctuation.terminator.java","punctuation.section.class.begin.java","punctuation.section.class.end.java","punctuation.section.inner-class.begin.java","punctuation.section.inner-class.end.java","meta.method-call.java","punctuation.section.class.begin.bracket.curly.java","punctuation.section.class.end.bracket.curly.java","punctuation.section.method.begin.bracket.curly.java","punctuation.section.method.end.bracket.curly.java","punctuation.separator.period.java","punctuation.bracket.angle.java","punctuation.definition.annotation.java","meta.method.body.java"],settings:{foreground:"#79797F"}},{scope:"meta.method.java",settings:{foreground:"#7b43f8"}},{scope:["storage.modifier.import.java","storage.type.java","storage.type.generic.java"],settings:{foreground:"#d5a910"}},{scope:"keyword.operator.instanceof.java",settings:{foreground:"#fc2b73"}},{scope:"meta.definition.variable.name.java",settings:{foreground:"#d52c36"}},{scope:"token.variable.parameter.java",settings:{foreground:"#79797F"}},{scope:"import.storage.java",settings:{foreground:"#d5a910"}},{scope:"token.package.keyword",settings:{foreground:"#fc2b73"}},{scope:"token.package",settings:{foreground:"#79797F"}},{scope:"token.storage.type.java",settings:{foreground:"#d5a910"}},{scope:"keyword.operator.assignment.go",settings:{foreground:"#d5a910"}},{scope:["keyword.operator.arithmetic.go","keyword.operator.address.go"],settings:{foreground:"#fc2b73"}},{scope:"entity.name.package.go",settings:{foreground:"#d5a910"}},{scope:["support.other.namespace.use.php","support.other.namespace.use-as.php","support.other.namespace.php","entity.other.alias.php","meta.interface.php"],settings:{foreground:"#d5a910"}},{scope:"keyword.operator.error-control.php",settings:{foreground:"#fc2b73"}},{scope:"keyword.operator.type.php",settings:{foreground:"#fc2b73"}},{scope:["punctuation.section.array.begin.php","punctuation.section.array.end.php"],settings:{foreground:"#79797F"}},{scope:["storage.type.php","meta.other.type.phpdoc.php","keyword.other.type.php","keyword.other.array.phpdoc.php"],settings:{foreground:"#d5a910"}},{scope:["meta.function-call.php","meta.function-call.object.php","meta.function-call.static.php"],settings:{foreground:"#7b43f8"}},{scope:["punctuation.definition.parameters.begin.bracket.round.php","punctuation.definition.parameters.end.bracket.round.php","punctuation.separator.delimiter.php","punctuation.section.scope.begin.php","punctuation.section.scope.end.php","punctuation.terminator.expression.php","punctuation.definition.arguments.begin.bracket.round.php","punctuation.definition.arguments.end.bracket.round.php","punctuation.definition.storage-type.begin.bracket.round.php","punctuation.definition.storage-type.end.bracket.round.php","punctuation.definition.array.begin.bracket.round.php","punctuation.definition.array.end.bracket.round.php","punctuation.definition.begin.bracket.round.php","punctuation.definition.end.bracket.round.php","punctuation.definition.begin.bracket.curly.php","punctuation.definition.end.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php","punctuation.definition.section.switch-block.start.bracket.curly.php","punctuation.definition.section.switch-block.begin.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php"],settings:{foreground:"#79797F"}},{scope:["support.constant.ext.php","support.constant.std.php","support.constant.core.php","support.constant.parser-token.php"],settings:{foreground:"#d5a910"}},{scope:["entity.name.goto-label.php","support.other.php"],settings:{foreground:"#7b43f8"}},{scope:["keyword.operator.logical.php","keyword.operator.bitwise.php","keyword.operator.arithmetic.php"],settings:{foreground:"#08c0ef"}},{scope:"keyword.operator.regexp.php",settings:{foreground:"#fc2b73"}},{scope:"keyword.operator.comparison.php",settings:{foreground:"#08c0ef"}},{scope:["keyword.operator.heredoc.php","keyword.operator.nowdoc.php"],settings:{foreground:"#fc2b73"}},{scope:"variable.other.class.php",settings:{foreground:"#d52c36"}},{scope:"invalid.illegal.non-null-typehinted.php",settings:{foreground:"#f44747"}},{scope:"variable.other.generic-type.haskell",settings:{foreground:"#fc2b73"}},{scope:"storage.type.haskell",settings:{foreground:"#d5a910"}},{scope:"storage.type.cs",settings:{foreground:"#d5a910"}},{scope:"entity.name.variable.local.cs",settings:{foreground:"#d52c36"}},{scope:"entity.name.label.cs",settings:{foreground:"#d5a910"}},{scope:["entity.name.scope-resolution.function.call","entity.name.scope-resolution.function.definition"],settings:{foreground:"#d5a910"}},{scope:["punctuation.definition.delayed.unison","punctuation.definition.list.begin.unison","punctuation.definition.list.end.unison","punctuation.definition.ability.begin.unison","punctuation.definition.ability.end.unison","punctuation.operator.assignment.as.unison","punctuation.separator.pipe.unison","punctuation.separator.delimiter.unison","punctuation.definition.hash.unison"],settings:{foreground:"#d52c36"}},{scope:"support.constant.edge",settings:{foreground:"#fc2b73"}},{scope:"support.type.prelude.elm",settings:{foreground:"#08c0ef"}},{scope:"support.constant.elm",settings:{foreground:"#d5a910"}},{scope:"entity.global.clojure",settings:{foreground:"#d5a910"}},{scope:"meta.symbol.clojure",settings:{foreground:"#d52c36"}},{scope:"constant.keyword.clojure",settings:{foreground:"#08c0ef"}},{scope:["meta.arguments.coffee","variable.parameter.function.coffee"],settings:{foreground:"#d52c36"}},{scope:"storage.modifier.import.groovy",settings:{foreground:"#d5a910"}},{scope:"meta.method.groovy",settings:{foreground:"#7b43f8"}},{scope:"meta.definition.variable.name.groovy",settings:{foreground:"#d52c36"}},{scope:"meta.definition.class.inherited.classes.groovy",settings:{foreground:"#199f43"}},{scope:"support.variable.semantic.hlsl",settings:{foreground:"#d5a910"}},{scope:["support.type.texture.hlsl","support.type.sampler.hlsl","support.type.object.hlsl","support.type.object.rw.hlsl","support.type.fx.hlsl","support.type.object.hlsl"],settings:{foreground:"#fc2b73"}},{scope:["text.variable","text.bracketed"],settings:{foreground:"#d52c36"}},{scope:["support.type.swift","support.type.vb.asp"],settings:{foreground:"#d5a910"}},{scope:"meta.scope.prerequisites.makefile",settings:{foreground:"#d52c36"}},{scope:"source.makefile",settings:{foreground:"#d5a910"}},{scope:"source.ini",settings:{foreground:"#199f43"}},{scope:"constant.language.symbol.ruby",settings:{foreground:"#08c0ef"}},{scope:["function.parameter.ruby","function.parameter.cs"],settings:{foreground:"#79797F"}},{scope:"constant.language.symbol.elixir",settings:{foreground:"#08c0ef"}},{scope:"text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade",settings:{foreground:"#fc2b73"}},{scope:"text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade",settings:{foreground:"#fc2b73"}},{scope:"entity.name.function.xi",settings:{foreground:"#d5a910"}},{scope:"entity.name.class.xi",settings:{foreground:"#08c0ef"}},{scope:"constant.character.character-class.regexp.xi",settings:{foreground:"#d52c36"}},{scope:"constant.regexp.xi",settings:{foreground:"#fc2b73"}},{scope:"keyword.control.xi",settings:{foreground:"#08c0ef"}},{scope:"invalid.xi",settings:{foreground:"#79797F"}},{scope:"beginning.punctuation.definition.quote.markdown.xi",settings:{foreground:"#199f43"}},{scope:"beginning.punctuation.definition.list.markdown.xi",settings:{foreground:"#84848A"}},{scope:"constant.character.xi",settings:{foreground:"#7b43f8"}},{scope:"accent.xi",settings:{foreground:"#7b43f8"}},{scope:"wikiword.xi",settings:{foreground:"#d5a910"}},{scope:"constant.other.color.rgb-value.xi",settings:{foreground:"#ffffff"}},{scope:"punctuation.definition.tag.xi",settings:{foreground:"#84848A"}},{scope:["support.constant.property-value.scss","support.constant.property-value.css"],settings:{foreground:"#d5a910"}},{scope:["keyword.operator.css","keyword.operator.scss","keyword.operator.less"],settings:{foreground:"#08c0ef"}},{scope:["support.constant.color.w3c-standard-color-name.css","support.constant.color.w3c-standard-color-name.scss"],settings:{foreground:"#d5a910"}},{scope:"punctuation.separator.list.comma.css",settings:{foreground:"#79797F"}},{scope:"support.type.vendored.property-name.css",settings:{foreground:"#08c0ef"}},{scope:"support.type.property-name.css",settings:{foreground:"#08c0ef"}},{scope:"support.type.property-name",settings:{foreground:"#79797F"}},{scope:"support.constant.property-value",settings:{foreground:"#79797F"}},{scope:"support.constant.font-name",settings:{foreground:"#d5a910"}},{scope:"entity.other.attribute-name.class.css",settings:{foreground:"#16a994",fontStyle:"normal"}},{scope:"entity.other.attribute-name.id",settings:{foreground:"#7b43f8",fontStyle:"normal"}},{scope:["entity.other.attribute-name.pseudo-element","entity.other.attribute-name.pseudo-class"],settings:{foreground:"#08c0ef"}},{scope:"meta.selector",settings:{foreground:"#fc2b73"}},{scope:"selector.sass",settings:{foreground:"#d52c36"}},{scope:"rgb-value",settings:{foreground:"#08c0ef"}},{scope:"inline-color-decoration rgb-value",settings:{foreground:"#d5a910"}},{scope:"less rgb-value",settings:{foreground:"#d5a910"}},{scope:"control.elements",settings:{foreground:"#d5a910"}},{scope:"keyword.operator.less",settings:{foreground:"#d5a910"}},{scope:"entity.name.tag",settings:{foreground:"#d52c36"}},{scope:"entity.other.attribute-name",settings:{foreground:"#16a994",fontStyle:"normal"}},{scope:"constant.character.entity",settings:{foreground:"#d52c36"}},{scope:"meta.tag",settings:{foreground:"#79797F"}},{scope:"invalid.illegal.bad-ampersand.html",settings:{foreground:"#79797F"}},{scope:"markup.heading",settings:{foreground:"#d52c36"}},{scope:["markup.heading punctuation.definition.heading","entity.name.section"],settings:{foreground:"#7b43f8"}},{scope:"entity.name.section.markdown",settings:{foreground:"#d52c36"}},{scope:"punctuation.definition.heading.markdown",settings:{foreground:"#d52c36"}},{scope:"markup.heading.setext",settings:{foreground:"#79797F"}},{scope:["markup.heading.setext.1.markdown","markup.heading.setext.2.markdown"],settings:{foreground:"#d52c36"}},{scope:["markup.bold","todo.bold"],settings:{foreground:"#d5a910"}},{scope:"punctuation.definition.bold",settings:{foreground:"#d5a910"}},{scope:"punctuation.definition.bold.markdown",settings:{foreground:"#d5a910"}},{scope:["markup.italic","punctuation.definition.italic","todo.emphasis"],settings:{foreground:"#fc2b73",fontStyle:"italic"}},{scope:"emphasis md",settings:{foreground:"#fc2b73"}},{scope:"markup.italic.markdown",settings:{fontStyle:"italic"}},{scope:["markup.underline.link.markdown","markup.underline.link.image.markdown"],settings:{foreground:"#fc2b73"}},{scope:["string.other.link.title.markdown","string.other.link.description.markdown"],settings:{foreground:"#7b43f8"}},{scope:"punctuation.definition.metadata.markdown",settings:{foreground:"#d52c36"}},{scope:["markup.inline.raw.markdown","markup.inline.raw.string.markdown"],settings:{foreground:"#199f43"}},{scope:"punctuation.definition.list.begin.markdown",settings:{foreground:"#d52c36"}},{scope:"punctuation.definition.list.markdown",settings:{foreground:"#d52c36"}},{scope:"beginning.punctuation.definition.list.markdown",settings:{foreground:"#d52c36"}},{scope:["punctuation.definition.string.begin.markdown","punctuation.definition.string.end.markdown"],settings:{foreground:"#d52c36"}},{scope:"markup.quote.markdown",settings:{foreground:"#84848A"}},{scope:"keyword.other.unit",settings:{foreground:"#d52c36"}},{scope:"markup.changed.diff",settings:{foreground:"#d5a910"}},{scope:["meta.diff.header.from-file","meta.diff.header.to-file","punctuation.definition.from-file.diff","punctuation.definition.to-file.diff"],settings:{foreground:"#7b43f8"}},{scope:"markup.inserted.diff",settings:{foreground:"#199f43"}},{scope:"markup.deleted.diff",settings:{foreground:"#d52c36"}},{scope:"string.regexp",settings:{foreground:"#17a5af"}},{scope:"constant.other.character-class.regexp",settings:{foreground:"#d52c36"}},{scope:"keyword.operator.quantifier.regexp",settings:{foreground:"#d5a910"}},{scope:"constant.character.escape",settings:{foreground:"#1ca1c7"}},{scope:"source.json meta.structure.dictionary.json > string.quoted.json",settings:{foreground:"#d52c36"}},{scope:"source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string",settings:{foreground:"#d52c36"}},{scope:["source.json meta.structure.dictionary.json > value.json > string.quoted.json","source.json meta.structure.array.json > value.json > string.quoted.json","source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation","source.json meta.structure.array.json > value.json > string.quoted.json > punctuation"],settings:{foreground:"#199f43"}},{scope:["source.json meta.structure.dictionary.json > constant.language.json","source.json meta.structure.array.json > constant.language.json"],settings:{foreground:"#08c0ef"}},{scope:"support.type.property-name.json",settings:{foreground:"#d52c36"}},{scope:"support.type.property-name.json punctuation",settings:{foreground:"#d52c36"}},{scope:"punctuation.definition.block.sequence.item.yaml",settings:{foreground:"#79797F"}},{scope:"block.scope.end",settings:{foreground:"#79797F"}},{scope:"block.scope.begin",settings:{foreground:"#79797F"}},{scope:"token.info-token",settings:{foreground:"#7b43f8"}},{scope:"token.warn-token",settings:{foreground:"#d5a910"}},{scope:"token.error-token",settings:{foreground:"#f44747"}},{scope:"token.debug-token",settings:{foreground:"#fc2b73"}},{scope:"invalid.illegal",settings:{foreground:"#ffffff"}},{scope:"invalid.broken",settings:{foreground:"#ffffff"}},{scope:"invalid.deprecated",settings:{foreground:"#ffffff"}},{scope:"invalid.unimplemented",settings:{foreground:"#ffffff"}}],x={comment:"#84848A",string:"#199f43",number:"#1ca1c7",regexp:"#17a5af",keyword:"#fc2b73",variable:"#d47628",parameter:"#79797F",property:"#d47628",function:"#7b43f8",method:"#7b43f8",type:"#c635e4",class:"#c635e4",namespace:"#d5a910",enumMember:"#08c0ef","variable.constant":"#d5a910","variable.defaultLibrary":"#d5a910"},z={name:b,type:q,colors:v,tokenColors:w,semanticTokenColors:x};export{q as type,w as tokenColors,x as semanticTokenColors,b as name,z as default,v as colors}; diff --git a/lib/crates/fabro-spa/assets/assets/entry-q11nrnd3.js b/lib/crates/fabro-spa/assets/assets/entry-q11nrnd3.js deleted file mode 100644 index 9a5faddae..000000000 --- a/lib/crates/fabro-spa/assets/assets/entry-q11nrnd3.js +++ /dev/null @@ -1,2402 +0,0 @@ -import{X as h,Y as D3,Z as p5,_ as x}from"./chunk-q07bg6gn.js";var J0=D3((Pa,YU)=>{(function(){function Z(y,Y0){Object.defineProperty(z.prototype,y,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",Y0[0],Y0[1])}})}function Y(y){if(y===null||typeof y!=="object")return null;return y=B1&&y[B1]||y["@@iterator"],typeof y==="function"?y:null}function Q(y,Y0){y=(y=y.constructor)&&(y.displayName||y.name)||"ReactClass";var F0=y+"."+Y0;R0[F0]||(console.error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.",Y0,y),R0[F0]=!0)}function z(y,Y0,F0){this.props=y,this.context=Y0,this.refs=n5,this.updater=F0||C1}function q(){}function B(y,Y0,F0){this.props=y,this.context=Y0,this.refs=n5,this.updater=F0||C1}function W(){}function $(y){return""+y}function U(y){try{$(y);var Y0=!1}catch(k0){Y0=!0}if(Y0){Y0=console;var F0=Y0.error,L0=typeof Symbol==="function"&&Symbol.toStringTag&&y[Symbol.toStringTag]||y.constructor.name||"Object";return F0.call(Y0,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",L0),$(y)}}function M(y){if(y==null)return null;if(typeof y==="function")return y.$$typeof===t6?null:y.displayName||y.name||null;if(typeof y==="string")return y;switch(y){case z0:return"Fragment";case q0:return"Profiler";case f:return"StrictMode";case i0:return"Suspense";case H0:return"SuspenseList";case L1:return"Activity"}if(typeof y==="object")switch(typeof y.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),y.$$typeof){case n:return"Portal";case M0:return y.displayName||"Context";case N0:return(y._context.displayName||"Context")+".Consumer";case I0:var Y0=y.render;return y=y.displayName,y||(y=Y0.displayName||Y0.name||"",y=y!==""?"ForwardRef("+y+")":"ForwardRef"),y;case l0:return Y0=y.displayName||null,Y0!==null?Y0:M(y.type)||"Memo";case t0:Y0=y._payload,y=y._init;try{return M(y(Y0))}catch(F0){}}return null}function w(y){if(y===z0)return"<>";if(typeof y==="object"&&y!==null&&y.$$typeof===t0)return"<...>";try{var Y0=M(y);return Y0?"<"+Y0+">":"<...>"}catch(F0){return"<...>"}}function O(){var y=W1.A;return y===null?null:y.getOwner()}function _(){return Error("react-stack-top-frame")}function F(y){if(w4.call(y,"key")){var Y0=Object.getOwnPropertyDescriptor(y,"key").get;if(Y0&&Y0.isReactWarning)return!1}return y.key!==void 0}function P(y,Y0){function F0(){P6||(P6=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",Y0))}F0.isReactWarning=!0,Object.defineProperty(y,"key",{get:F0,configurable:!0})}function R(){var y=M(this.type);return c4[y]||(c4[y]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),y=this.props.ref,y!==void 0?y:null}function v(y,Y0,F0,L0,k0,Y1){var x0=F0.ref;return y={$$typeof:$0,type:y,key:Y0,props:F0,_owner:L0},(x0!==void 0?x0:null)!==null?Object.defineProperty(y,"ref",{enumerable:!1,get:R}):Object.defineProperty(y,"ref",{enumerable:!1,value:null}),y._store={},Object.defineProperty(y._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(y,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(y,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:k0}),Object.defineProperty(y,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:Y1}),Object.freeze&&(Object.freeze(y.props),Object.freeze(y)),y}function L(y,Y0){return Y0=v(y.type,Y0,y.props,y._owner,y._debugStack,y._debugTask),y._store&&(Y0._store.validated=y._store.validated),Y0}function T(y){C(y)?y._store&&(y._store.validated=1):typeof y==="object"&&y!==null&&y.$$typeof===t0&&(y._payload.status==="fulfilled"?C(y._payload.value)&&y._payload.value._store&&(y._payload.value._store.validated=1):y._store&&(y._store.validated=1))}function C(y){return typeof y==="object"&&y!==null&&y.$$typeof===$0}function E(y){var Y0={"=":"=0",":":"=2"};return"$"+y.replace(/[=:]/g,function(F0){return Y0[F0]})}function b(y,Y0){return typeof y==="object"&&y!==null&&y.key!=null?(U(y.key),E(""+y.key)):Y0.toString(36)}function S(y){switch(y.status){case"fulfilled":return y.value;case"rejected":throw y.reason;default:switch(typeof y.status==="string"?y.then(W,W):(y.status="pending",y.then(function(Y0){y.status==="pending"&&(y.status="fulfilled",y.value=Y0)},function(Y0){y.status==="pending"&&(y.status="rejected",y.reason=Y0)})),y.status){case"fulfilled":return y.value;case"rejected":throw y.reason}}throw y}function j(y,Y0,F0,L0,k0){var Y1=typeof y;if(Y1==="undefined"||Y1==="boolean")y=null;var x0=!1;if(y===null)x0=!0;else switch(Y1){case"bigint":case"string":case"number":x0=!0;break;case"object":switch(y.$$typeof){case $0:case n:x0=!0;break;case t0:return x0=y._init,j(x0(y._payload),Y0,F0,L0,k0)}}if(x0){x0=y,k0=k0(x0);var Q1=L0===""?"."+b(x0,0):L0;return w1(k0)?(F0="",Q1!=null&&(F0=Q1.replace(Z7,"$&/")+"/"),j(k0,Y0,F0,"",function(O5){return O5})):k0!=null&&(C(k0)&&(k0.key!=null&&(x0&&x0.key===k0.key||U(k0.key)),F0=L(k0,F0+(k0.key==null||x0&&x0.key===k0.key?"":(""+k0.key).replace(Z7,"$&/")+"/")+Q1),L0!==""&&x0!=null&&C(x0)&&x0.key==null&&x0._store&&!x0._store.validated&&(F0._store.validated=2),k0=F0),Y0.push(k0)),1}if(x0=0,Q1=L0===""?".":L0+":",w1(y))for(var j0=0;j0 import('./MyComponent')) - -Did you accidentally put curly braces around the import?`,Y0),"default"in Y0||console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s - -Your code should look like: - const MyComponent = lazy(() => import('./MyComponent'))`,Y0),Y0.default;throw y._result}function k(){var y=W1.H;return y===null&&console.error(`Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: -1. You might have mismatching versions of React and the renderer (such as React DOM) -2. You might be breaking the Rules of Hooks -3. You might have more than one copy of React in the same app -See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.`),y}function o(){W1.asyncTransitions--}function X0(y){if(N4===null)try{var Y0=("require"+Math.random()).slice(0,7);N4=(YU&&YU[Y0]).call(YU,"timers").setImmediate}catch(F0){N4=function(L0){$2===!1&&($2=!0,typeof MessageChannel>"u"&&console.error("This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning."));var k0=new MessageChannel;k0.port1.onmessage=L0,k0.port2.postMessage(void 0)}}return N4(y)}function W0(y){return 1 ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"))}),{then:function(j0,O5){k0=!0,x0.then(function(q5){if(e(Y0,F0),F0===0){try{Z0(L0),X0(function(){return c(q5,j0,O5)})}catch(e5){W1.thrownErrors.push(e5)}if(0 ...)"))}),W1.actQueue=null),0W1.recentlyCreatedOwnerStacks++;return v(y,k0,L0,O(),j0?Error("react-stack-top-frame"):x2,j0?S1(w(y)):V6)},Pa.createRef=function(){var y={current:null};return Object.seal(y),y},Pa.forwardRef=function(y){y!=null&&y.$$typeof===l0?console.error("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...))."):typeof y!=="function"?console.error("forwardRef requires a render function but was given %s.",y===null?"null":typeof y):y.length!==0&&y.length!==2&&console.error("forwardRef render functions accept exactly two parameters: props and ref. %s",y.length===1?"Did you forget to use the ref parameter?":"Any additional parameter will be undefined."),y!=null&&y.defaultProps!=null&&console.error("forwardRef render functions do not support defaultProps. Did you accidentally pass a React component?");var Y0={$$typeof:I0,render:y},F0;return Object.defineProperty(Y0,"displayName",{enumerable:!1,configurable:!0,get:function(){return F0},set:function(L0){F0=L0,y.name||y.displayName||(Object.defineProperty(y,"name",{value:L0}),y.displayName=L0)}}),Y0},Pa.isValidElement=C,Pa.lazy=function(y){y={_status:-1,_result:y};var Y0={$$typeof:t0,_payload:y,_init:s},F0={name:"lazy",start:-1,end:-1,value:null,owner:null,debugStack:Error("react-stack-top-frame"),debugTask:console.createTask?console.createTask("lazy()"):null};return y._ioInfo=F0,Y0._debugInfo=[{awaited:F0}],Y0},Pa.memo=function(y,Y0){y==null&&console.error("memo: The first argument must be a component. Instead received: %s",y===null?"null":typeof y),Y0={$$typeof:l0,type:y,compare:Y0===void 0?null:Y0};var F0;return Object.defineProperty(Y0,"displayName",{enumerable:!1,configurable:!0,get:function(){return F0},set:function(L0){F0=L0,y.name||y.displayName||(Object.defineProperty(y,"name",{value:L0}),y.displayName=L0)}}),Y0},Pa.startTransition=function(y){var Y0=W1.T,F0={};F0._updatedFibers=new Set,W1.T=F0;try{var L0=y(),k0=W1.S;k0!==null&&k0(F0,L0),typeof L0==="object"&&L0!==null&&typeof L0.then==="function"&&(W1.asyncTransitions++,L0.then(o,o),L0.then(W,v5))}catch(Y1){v5(Y1)}finally{Y0===null&&F0._updatedFibers&&(y=F0._updatedFibers.size,F0._updatedFibers.clear(),10{(function(){function Z(){if(E=!1,g){var c=Va.unstable_now();o=c;var Z0=!0;try{Z:{T=!1,C&&(C=!1,S(s),s=-1),L=!0;var $0=v;try{Y:{B(c);for(R=Q(_);R!==null&&!(R.expirationTime>c&&$());){var n=R.callback;if(typeof n==="function"){R.callback=null,v=R.priorityLevel;var z0=n(R.expirationTime<=c);if(c=Va.unstable_now(),typeof z0==="function"){R.callback=z0,B(c),Z0=!0;break Y}R===Q(_)&&z(_),B(c)}else z(_);R=Q(_)}if(R!==null)Z0=!0;else{var f=Q(F);f!==null&&U(W,f.startTime-c),Z0=!1}}break Z}finally{R=null,v=$0,L=!1}Z0=void 0}}finally{Z0?X0():g=!1}}}function Y(c,Z0){var $0=c.length;c.push(Z0);Z:for(;0<$0;){var n=$0-1>>>1,z0=c[n];if(0>>1;nq(N0,$0))M0q(I0,N0)?(c[n]=I0,c[M0]=$0,n=M0):(c[n]=N0,c[q0]=$0,n=q0);else if(M0q(I0,$0))c[n]=I0,c[M0]=$0,n=M0;else break Z}}return Z0}function q(c,Z0){var $0=c.sortIndex-Z0.sortIndex;return $0!==0?$0:c.id-Z0.id}function B(c){for(var Z0=Q(F);Z0!==null;){if(Z0.callback===null)z(F);else if(Z0.startTime<=c)z(F),Z0.sortIndex=Z0.expirationTime,Y(_,Z0);else break;Z0=Q(F)}}function W(c){if(C=!1,B(c),!T)if(Q(_)!==null)T=!0,g||(g=!0,X0());else{var Z0=Q(F);Z0!==null&&U(W,Z0.startTime-c)}}function $(){return E?!0:Va.unstable_now()-oc||125n?(c.sortIndex=$0,Y(F,c),Q(_)===null&&c===Q(F)&&(C?(S(s),s=-1):C=!0,U(W,$0-n))):(c.sortIndex=z0,Y(_,c),T||L||(T=!0,g||(g=!0,X0()))),c},Va.unstable_shouldYield=$,Va.unstable_wrapCallback=function(c){var Z0=v;return function(){var $0=v;v=Z0;try{return c.apply(this,arguments)}finally{v=$0}}},typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop==="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())})()});var uI=D3((Ra)=>{var mF=h(J0());(function(){function Z(){}function Y(w){return""+w}function Q(w,O,_){var F=3` tag.%s',_),typeof w==="string"&&typeof O==="object"&&O!==null&&typeof O.as==="string"){_=O.as;var F=z(_,O.crossOrigin);$.d.L(w,_,{crossOrigin:F,integrity:typeof O.integrity==="string"?O.integrity:void 0,nonce:typeof O.nonce==="string"?O.nonce:void 0,type:typeof O.type==="string"?O.type:void 0,fetchPriority:typeof O.fetchPriority==="string"?O.fetchPriority:void 0,referrerPolicy:typeof O.referrerPolicy==="string"?O.referrerPolicy:void 0,imageSrcSet:typeof O.imageSrcSet==="string"?O.imageSrcSet:void 0,imageSizes:typeof O.imageSizes==="string"?O.imageSizes:void 0,media:typeof O.media==="string"?O.media:void 0})}},Ra.preloadModule=function(w,O){var _="";typeof w==="string"&&w||(_+=" The `href` argument encountered was "+q(w)+"."),O!==void 0&&typeof O!=="object"?_+=" The `options` argument encountered was "+q(O)+".":O&&("as"in O)&&typeof O.as!=="string"&&(_+=" The `as` option encountered was "+q(O.as)+"."),_&&console.error('ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `` tag.%s',_),typeof w==="string"&&(O?(_=z(O.as,O.crossOrigin),$.d.m(w,{as:typeof O.as==="string"&&O.as!=="script"?O.as:void 0,crossOrigin:_,integrity:typeof O.integrity==="string"?O.integrity:void 0})):$.d.m(w))},Ra.requestFormReset=function(w){$.d.r(w)},Ra.unstable_batchedUpdates=function(w,O){return w(O)},Ra.useFormState=function(w,O,_){return W().useFormState(w,O,_)},Ra.useFormStatus=function(){return W().useHostTransitionStatus()},Ra.version="19.2.4",typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop==="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())})()});var b3=D3((vQ0,pI)=>{var La=h(uI());pI.exports=La});var cI=D3((Ta)=>{var a1=h(mI()),aQ=h(J0()),uF=h(b3());(function(){function Z(J,X){for(J=J.memoizedState;J!==null&&0=X.length)return G;var H=X[K],N=T2(J)?J.slice():E1({},J);return N[H]=Y(J[H],X,K+1,G),N}function Q(J,X,K){if(X.length!==K.length)console.warn("copyWithRename() expects paths of the same length");else{for(var G=0;G_8?console.error("Unexpected pop."):(X!==__[_8]&&console.error("Unexpected Fiber popped."),J.current=O_[_8],O_[_8]=null,__[_8]=null,_8--)}function W0(J,X,K){_8++,O_[_8]=J.current,__[_8]=K,J.current=X}function e(J){return J===null&&console.error("Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."),J}function c(J,X){W0(I9,X,J),W0(aq,J,J),W0(E9,null,J);var K=X.nodeType;switch(K){case 9:case 11:K=K===9?"#document":"#fragment",X=(X=X.documentElement)?(X=X.namespaceURI)?RD(X):j8:j8;break;default:if(K=X.tagName,X=X.namespaceURI)X=RD(X),X=LD(X,K);else switch(K){case"svg":X=lQ;break;case"math":X=sG;break;default:X=j8}}K=K.toLowerCase(),K=OT(null,K),K={context:X,ancestorInfo:K},X0(E9,J),W0(E9,K,J)}function Z0(J){X0(E9,J),X0(aq,J),X0(I9,J)}function $0(){return e(E9.current)}function n(J){J.memoizedState!==null&&W0(t$,J,J);var X=e(E9.current),K=J.type,G=LD(X.context,K);K=OT(X.ancestorInfo,K),G={context:G,ancestorInfo:K},X!==G&&(W0(aq,J,J),W0(E9,G,J))}function z0(J){aq.current===J&&(X0(E9,J),X0(aq,J)),t$.current===J&&(X0(t$,J),hK._currentValue=IY)}function f(){}function q0(){if(sq===0){Zb=console.log,Yb=console.info,Jb=console.warn,Qb=console.error,Xb=console.group,zb=console.groupCollapsed,qb=console.groupEnd;var J={configurable:!0,enumerable:!0,value:f,writable:!0};Object.defineProperties(console,{info:J,log:J,warn:J,error:J,group:J,groupCollapsed:J,groupEnd:J})}sq++}function N0(){if(sq--,sq===0){var J={configurable:!0,enumerable:!0,writable:!0};Object.defineProperties(console,{log:E1({},J,{value:Zb}),info:E1({},J,{value:Yb}),warn:E1({},J,{value:Jb}),error:E1({},J,{value:Qb}),group:E1({},J,{value:Xb}),groupCollapsed:E1({},J,{value:zb}),groupEnd:E1({},J,{value:qb})})}0>sq&&console.error("disabledDepth fell below zero. This is a bug in React. Please file an issue.")}function M0(J){var X=Error.prepareStackTrace;if(Error.prepareStackTrace=void 0,J=J.stack,Error.prepareStackTrace=X,J.startsWith(`Error: react-stack-top-frame -`)&&(J=J.slice(29)),X=J.indexOf(` -`),X!==-1&&(J=J.slice(X+1)),X=J.indexOf("react_stack_bottom_frame"),X!==-1&&(X=J.lastIndexOf(` -`,X)),X!==-1)J=J.slice(0,X);else return"";return J}function I0(J){if(F_===void 0)try{throw Error()}catch(K){var X=K.stack.trim().match(/\n( *(at )?)/);F_=X&&X[1]||"",Kb=-1)":-1A||I[N]!==a[A]){var i=` -`+I[N].replace(" at new "," at ");return J.displayName&&i.includes("")&&(i=i.replace("",J.displayName)),typeof J==="function"&&P_.set(J,i),i}while(1<=N&&0<=A);break}}}finally{A_=!1,U0.H=G,N0(),Error.prepareStackTrace=K}return I=(I=J?J.displayName||J.name:"")?I0(I):"",typeof J==="function"&&P_.set(J,I),I}function H0(J,X){switch(J.tag){case 26:case 27:case 5:return I0(J.type);case 16:return I0("Lazy");case 13:return J.child!==X&&X!==null?I0("Suspense Fallback"):I0("Suspense");case 19:return I0("SuspenseList");case 0:case 15:return i0(J.type,!1);case 11:return i0(J.type.render,!1);case 1:return i0(J.type,!0);case 31:return I0("Activity");default:return""}}function l0(J){try{var X="",K=null;do{X+=H0(J,K);var G=J._debugInfo;if(G)for(var H=G.length-1;0<=H;H--){var N=G[H];if(typeof N.name==="string"){var A=X;Z:{var{name:V,env:D,debugLocation:I}=N;if(I!=null){var a=M0(I),i=a.lastIndexOf(` -`),p=i===-1?a:a.slice(i+1);if(p.indexOf(V)!==-1){var K0=` -`+p;break Z}}K0=I0(V+(D?" ["+D+"]":""))}X=A+K0}}K=J,J=J.return}while(J);return X}catch(T0){return` -Error generating stack: `+T0.message+` -`+T0.stack}}function t0(J){return(J=J?J.displayName||J.name:"")?I0(J):""}function L1(){if(T4===null)return null;var J=T4._debugOwner;return J!=null?s(J):null}function B1(){if(T4===null)return"";var J=T4;try{var X="";switch(J.tag===6&&(J=J.return),J.tag){case 26:case 27:case 5:X+=I0(J.type);break;case 13:X+=I0("Suspense");break;case 19:X+=I0("SuspenseList");break;case 31:X+=I0("Activity");break;case 30:case 0:case 15:case 1:J._debugOwner||X!==""||(X+=t0(J.type));break;case 11:J._debugOwner||X!==""||(X+=t0(J.type.render))}for(;J;)if(typeof J.tag==="number"){var K=J;J=K._debugOwner;var G=K._debugStack;if(J&&G){var H=M0(G);H!==""&&(X+=` -`+H)}}else if(J.debugStack!=null){var N=J.debugStack;(J=J.owner)&&N&&(X+=` -`+M0(N))}else break;var A=X}catch(V){A=` -Error generating stack: `+V.message+` -`+V.stack}return A}function R0(J,X,K,G,H,N,A){var V=T4;C1(J);try{return J!==null&&J._debugTask?J._debugTask.run(X.bind(null,K,G,H,N,A)):X(K,G,H,N,A)}finally{C1(V)}throw Error("runWithFiberInDEV should never be called in production. This is a bug in React.")}function C1(J){U0.getCurrentStack=J===null?null:B1,_3=!1,T4=J}function Q5(J){return typeof Symbol==="function"&&Symbol.toStringTag&&J[Symbol.toStringTag]||J.constructor.name||"Object"}function n5(J){try{return N5(J),!1}catch(X){return!0}}function N5(J){return""+J}function w1(J,X){if(n5(J))return console.error("The provided `%s` attribute is an unsupported type %s. This value must be coerced to a string before using it here.",X,Q5(J)),N5(J)}function t6(J,X){if(n5(J))return console.error("The provided `%s` CSS property is an unsupported type %s. This value must be coerced to a string before using it here.",X,Q5(J)),N5(J)}function W1(J){if(n5(J))return console.error("Form field values (value, checked, defaultValue, or defaultChecked props) must be strings, not %s. This value must be coerced to a string before using it here.",Q5(J)),N5(J)}function w4(J){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u")return!1;var X=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(X.isDisabled)return!0;if(!X.supportsFiber)return console.error("The installed version of React DevTools is too old and will not work with the current version of React. Please update React DevTools. https://react.dev/link/react-devtools"),!0;try{MQ=X.inject(J),F7=X}catch(K){console.error("React instrumentation encountered an error: %o.",K)}return X.checkDCE?!0:!1}function S1(J){if(typeof hl==="function"&&gl(J),F7&&typeof F7.setStrictMode==="function")try{F7.setStrictMode(MQ,J)}catch(X){F3||(F3=!0,console.error("React instrumentation encountered an error: %o",X))}}function P6(J){return J>>>=0,J===0?32:31-(ml(J)/ul|0)|0}function e2(J){var X=J&42;if(X!==0)return X;switch(J&-J){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return J&261888;case 262144:case 524288:case 1048576:case 2097152:return J&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return J&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return console.error("Should have found matching lanes. This is a bug in React."),J}}function c4(J,X,K){var G=J.pendingLanes;if(G===0)return 0;var H=0,N=J.suspendedLanes,A=J.pingedLanes;J=J.warmLanes;var V=G&134217727;return V!==0?(G=V&~N,G!==0?H=e2(G):(A&=V,A!==0?H=e2(A):K||(K=V&~J,K!==0&&(H=e2(K))))):(V=G&~N,V!==0?H=e2(V):A!==0?H=e2(A):K||(K=G&~J,K!==0&&(H=e2(K)))),H===0?0:X!==0&&X!==H&&(X&N)===0&&(N=H&-H,K=X&-X,N>=K||N===32&&(K&4194048)!==0)?X:H}function x2(J,X){return(J.pendingLanes&~(J.suspendedLanes&~J.pingedLanes)&X)===0}function V6(J,X){switch(J){case 1:case 2:case 4:case 8:case 64:return X+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return X+5000;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return console.error("Should have found matching lanes. This is a bug in React."),-1}}function R6(){var J=ZG;return ZG<<=1,(ZG&62914560)===0&&(ZG=4194304),J}function Z7(J){for(var X=[],K=0;31>K;K++)X.push(J);return X}function v5(J,X){J.pendingLanes|=X,X!==268435456&&(J.suspendedLanes=0,J.pingedLanes=0,J.warmLanes=0)}function $2(J,X,K,G,H,N){var A=J.pendingLanes;J.pendingLanes=K,J.suspendedLanes=0,J.pingedLanes=0,J.warmLanes=0,J.expiredLanes&=K,J.entangledLanes&=K,J.errorRecoveryDisabledLanes&=K,J.shellSuspendCounter=0;var{entanglements:V,expirationTimes:D,hiddenUpdates:I}=J;for(K=A&~K;0"u")return null;try{return J.activeElement||J.body}catch(X){return J.body}}function S0(J){return J.replace(rl,function(X){return"\\"+X.charCodeAt(0).toString(16)+" "})}function c0(J,X){X.checked===void 0||X.defaultChecked===void 0||Mb||(console.error("%s contains an input of type %s with both checked and defaultChecked props. Input elements must be either controlled or uncontrolled (specify either the checked prop, or the defaultChecked prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://react.dev/link/controlled-components",L1()||"A component",X.type),Mb=!0),X.value===void 0||X.defaultValue===void 0||Ub||(console.error("%s contains an input of type %s with both value and defaultValue props. Input elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://react.dev/link/controlled-components",L1()||"A component",X.type),Ub=!0)}function r0(J,X,K,G,H,N,A,V){if(J.name="",A!=null&&typeof A!=="function"&&typeof A!=="symbol"&&typeof A!=="boolean"?(w1(A,"type"),J.type=A):J.removeAttribute("type"),X!=null)if(A==="number"){if(X===0&&J.value===""||J.value!=X)J.value=""+t(X)}else J.value!==""+t(X)&&(J.value=""+t(X));else A!=="submit"&&A!=="reset"||J.removeAttribute("value");X!=null?d0(J,A,t(X)):K!=null?d0(J,A,t(K)):G!=null&&J.removeAttribute("value"),H==null&&N!=null&&(J.defaultChecked=!!N),H!=null&&(J.checked=H&&typeof H!=="function"&&typeof H!=="symbol"),V!=null&&typeof V!=="function"&&typeof V!=="symbol"&&typeof V!=="boolean"?(w1(V,"name"),J.name=""+t(V)):J.removeAttribute("name")}function J1(J,X,K,G,H,N,A,V){if(N!=null&&typeof N!=="function"&&typeof N!=="symbol"&&typeof N!=="boolean"&&(w1(N,"type"),J.type=N),X!=null||K!=null){if(!(N!=="submit"&&N!=="reset"||X!==void 0&&X!==null)){P0(J);return}K=K!=null?""+t(K):"",X=X!=null?""+t(X):K,V||X===J.value||(J.value=X),J.defaultValue=X}G=G!=null?G:H,G=typeof G!=="function"&&typeof G!=="symbol"&&!!G,J.checked=V?J.checked:!!G,J.defaultChecked=!!G,A!=null&&typeof A!=="function"&&typeof A!=="symbol"&&typeof A!=="boolean"&&(w1(A,"name"),J.name=A),P0(J)}function d0(J,X,K){X==="number"&&y0(J.ownerDocument)===J||J.defaultValue===""+K||(J.defaultValue=""+K)}function p1(J,X){X.value==null&&(typeof X.children==="object"&&X.children!==null?aQ.Children.forEach(X.children,function(K){K==null||typeof K==="string"||typeof K==="number"||typeof K==="bigint"||wb||(wb=!0,console.error("Cannot infer the option value of complex children. Pass a `value` prop or use a plain string as children to