commit caa0e4225fa0673b22b1e62373a92d0bba80350f Author: Pedro Faria da Costa Date: Sun Jul 5 21:27:12 2026 +0100 initial import diff --git a/.cta.json b/.cta.json new file mode 100644 index 0000000..0402e19 --- /dev/null +++ b/.cta.json @@ -0,0 +1,19 @@ +{ + "projectName": "quarkshologridledger", + "mode": "file-router", + "typescript": true, + "packageManager": "npm", + "includeExamples": false, + "tailwind": true, + "addOnOptions": {}, + "envVarValues": {}, + "git": true, + "install": true, + "routerOnly": false, + "version": 1, + "framework": "react", + "chosenAddOns": [ + "eslint", + "nitro" + ] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8b25bb5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local +.env +.nitro +.tanstack +.wrangler +.output +.vinxi +__unconfig* +todos.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..00b5278 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.watcherExclude": { + "**/routeTree.gen.ts": true + }, + "search.exclude": { + "**/routeTree.gen.ts": true + }, + "files.readonlyInclude": { + "**/routeTree.gen.ts": true + } +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..45d2c24 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +.PHONY: build run clean help infra-up infra-down infra-logs run-engine run-web + +# Command Variables +DOCKER_COMPOSE=docker compose +GO=go +NPM=npm + +## infra-up: Start Valkey and Redis Insight containers in the background +infra-up: + $(DOCKER_COMPOSE) up -d + +## infra-down: Stop Valkey and Redis Insight containers +infra-down: + $(DOCKER_COMPOSE) down + +## infra-logs: Follow logs of the infrastructure containers +infra-logs: + $(DOCKER_COMPOSE) logs -f + +## run-engine: Build and run the Tongo Core backend engine daemon +run-engine: + $(MAKE) -C tongo-core run + +## run-web: Run the TanStack Start frontend web terminal dev server +run-web: + cd web-terminal && $(NPM) run dev + +## clean: Stop containers and clean all build artifacts and volumes +clean: infra-down + $(MAKE) -C tongo-core clean + $(DOCKER_COMPOSE) down -v + +## help: Show this help +help: + @grep -E '^## ' Makefile | sed 's/## //' | column -t -s ':' diff --git a/README.md b/README.md new file mode 100644 index 0000000..4bbb0a2 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# 🌌 Quark's Holo-Grid Ledger + +Welcome to the **Holo-Grid Ledger** β€” an authentic, plaintext terminal-style sportsbook application built for the Star Trek-inspired galactic economy. + +--- + +## πŸ› Project Architecture + +This repository is organized as a clean monorepo: + +- **[`web-terminal/`](file:///Users/pedro/code/github.com/costap/quarkshologridledger/web-terminal)**: The frontend user interface built with **TanStack Start**, **Vite**, **Valkey**, and **Tailwind CSS**. It renders high-density VT100-style console dashboards. +- **[`tongo-core/`](file:///Users/pedro/code/github.com/costap/quarkshologridledger/tongo-core)**: The high-performance Go simulation and probability engine. It runs as a background daemon, streaming active match telemetry and live odds directly to the Valkey cache. +- **[`data-source/`](file:///Users/pedro/code/github.com/costap/quarkshologridledger/data-source)**: Static definition registry ([`taxonomy.yaml`](file:///Users/pedro/code/github.com/costap/quarkshologridledger/data-source/taxonomy.yaml)) containing quadrants, factions, venues, and market templates. +- **[`reference/`](file:///Users/pedro/code/github.com/costap/quarkshologridledger/reference)**: Architectural references and blueprint documents for components and the simulation engine. + +--- + +## πŸ›  Getting Started + +### 1. Start Infrastructure (Valkey & Redis Insight) +The sportsbook relies on Valkey as a shared memory layer, and Redis Insight provides a GUI for database inspection. + +```bash +# Start Valkey and Redis Insight in the background +make infra-up + +# View logs +make infra-logs + +# Stop infrastructure +make infra-down +``` + +Valkey will run on `localhost:6379`, and Redis Insight will be accessible at `http://localhost:5540`. + +### 2. Start the Simulation Engine +Go to the Go backend folder and start the engine daemon: + +```bash +make run-engine +``` + +### 3. Start the Web Terminal UI +Go to the frontend folder, install dependencies, and start the Vite dev server: + +```bash +make run-web +``` + +Visit the console at `http://localhost:3000`. + +--- + +## πŸ“œ Ferengi Code of Conduct +> "The riskier the road, the greater the profit." β€” Rule of Acquisition #62 diff --git a/data-source/taxonomy.yaml b/data-source/taxonomy.yaml new file mode 100644 index 0000000..dc33bdf --- /dev/null +++ b/data-source/taxonomy.yaml @@ -0,0 +1,1056 @@ +# ╔══════════════════════════════════════════════════════════════════════════╗ +# β•‘ QUARK'S HOLO-GRID LEDGER β€” GALACTIC TAXONOMY REGISTRY β•‘ +# β•‘ Classification: SUBSPACE OPEN β€” All Patrons Welcome β•‘ +# β•‘ Last Calibrated: Stardate 79421.6 β•‘ +# β•‘ β•‘ +# β•‘ This file is the MASTER TEMPLATE LIBRARY for the Go ingestion engine. β•‘ +# β•‘ It defines WHAT exists (factions, arenas, bet types). β•‘ +# β•‘ The engine decides WHO fights WHERE and writes live data to Valkey. β•‘ +# β•‘ β•‘ +# β•‘ "Every quadrant has a price. Every sector has odds. β•‘ +# β•‘ And every faction... well, they all owe me latinum." β€” Quark β•‘ +# β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• + +# ───────────────────────────────────────────────────────────────────────── +# QUADRANTS β€” The four galactic league divisions +# +# Sportsbook Analogy: Sport Category / League +# e.g. "Alpha Quadrant" = "Premier League" +# +# Each quadrant contains its resident factions (teams/contenders). +# The Go engine pairs factions within or across quadrants to generate +# live match events. +# ───────────────────────────────────────────────────────────────────────── + +quadrants: + + # ══════════════════════════════════════ + # ALPHA QUADRANT β€” The Political Arena + # Stable markets, deep liquidity, diplomatic intrigue + # ══════════════════════════════════════ + + - id: "alpha" + name: "Alpha Quadrant" + designation: "QUADRANT-Ξ±" + color_code: "#34d399" + description: > + Seat of the Federation and the Ferengi Alliance. The most watched + league in the galaxy β€” high-profile matchups, massive betting volumes, + and constant diplomatic drama. Think of it as the galaxy's Premier + League. Every patron has an opinion on Alpha Quadrant odds. + base_volatility: 0.42 + factions: + + - id: "starfleet" + name: "Starfleet Command" + abbreviation: "SFC" + type: "defensive" + homeworld: "Earth (Sol III)" + color_code: "#34d399" + emblem_glyph: "β—†" + base_shield_strength: 92 + base_attack_power: 65 + base_evasion: 50 + tactical_profile: > + Elite shield technology and adaptable tactics. Starfleet + excels at absorbing punishment and finding last-minute + tactical solutions. The galaxy's most clutch performers β€” + never count them out, even at 10% shields. + rivalry_modifiers: + borg: 1.35 # Historical nemesis β€” inflated odds drama + cardassians: 1.15 # Border tension premium + romulans: 1.20 # Cold war intensity + + - id: "ferengi" + name: "Ferengi Alliance" + abbreviation: "FER" + type: "tactical" + homeworld: "Ferenginar" + color_code: "#fbbf24" + emblem_glyph: "β‚²" + base_shield_strength: 45 + base_attack_power: 35 + base_evasion: 78 + tactical_profile: > + Weak in direct combat but masters of misdirection, bribery, + and strategic retreat. Ferengi ships flee at the first sign + of real danger β€” but they always seem to profit somehow. + The ultimate "fade the public" play. + rivalry_modifiers: + klingons: 1.10 # Klingons despise cowardice + cardassians: 1.05 # Trade disputes + + - id: "cardassians" + name: "Cardassian Union" + abbreviation: "CRD" + type: "tactical" + homeworld: "Cardassia Prime" + color_code: "#94a3b8" + emblem_glyph: "β–Ό" + base_shield_strength: 70 + base_attack_power: 72 + base_evasion: 55 + tactical_profile: > + Disciplined, resource-efficient military with excellent + intelligence networks. Post-war Cardassians fight with + desperate cunning. Their Obsidian Order remnants feed + disinformation that distorts pre-match analysis. + rivalry_modifiers: + starfleet: 1.15 # Border grudge match + bajorans: 1.40 # Occupation-era hatred β€” maximum drama + dominion: 1.25 # Betrayal premium + + - id: "bajorans" + name: "Bajoran Militia" + abbreviation: "BAJ" + type: "defensive" + homeworld: "Bajor" + color_code: "#fb923c" + emblem_glyph: "☼" + base_shield_strength: 55 + base_attack_power: 48 + base_evasion: 60 + tactical_profile: > + Guerrilla fighters forged in decades of occupation. Individually + outmatched but fiercely determined. Prophet-intervention events + can swing any engagement without warning. The galaxy's most + unpredictable underdog. + rivalry_modifiers: + cardassians: 1.40 # The Occupation β€” blood feud + dominion: 1.30 # Wormhole guardians vs conquerors + + - id: "tholians" + name: "Tholian Assembly" + abbreviation: "THL" + type: "tactical" + homeworld: "Tholia" + color_code: "#f472b6" + emblem_glyph: "β—‡" + base_shield_strength: 80 + base_attack_power: 60 + base_evasion: 30 + tactical_profile: > + Crystalline entities that deploy energy web traps to immobilize + opponents. Slow but devastating when they establish grid + coverage. Web deployment events can instantly freeze shield + regeneration β€” a market-halting mechanic. + rivalry_modifiers: + starfleet: 1.10 # Territorial disputes + + - id: "breen" + name: "Breen Confederacy" + abbreviation: "BRN" + type: "aggressive" + homeworld: "Breen (coordinates classified)" + color_code: "#e2e8f0" + emblem_glyph: "❄" + base_shield_strength: 68 + base_attack_power: 82 + base_evasion: 45 + tactical_profile: > + Enigmatic warriors wielding energy-dampening weapons that + can disable opponent shields in a single volley. A pure + alpha-strike faction β€” if their opening salvo connects, + the fight is over. If it misses, they're vulnerable. + Binary outcomes make them a parlay favorite. + rivalry_modifiers: + starfleet: 1.20 # Chin'toka ambush grudge + klingons: 1.15 # Warrior pride clash + + # ══════════════════════════════════════ + # BETA QUADRANT β€” The Warrior's Ring + # High volatility, honor-bound combat, blood feuds + # ══════════════════════════════════════ + + - id: "beta" + name: "Beta Quadrant" + designation: "QUADRANT-Ξ²" + color_code: "#f87171" + description: > + The warrior's league. Klingon honor duels and Romulan shadow games + create the most violent and unpredictable matchups in the galaxy. + Markets swing hard on honor declarations and cloaking ambushes. + High-risk, high-reward β€” exactly how Quark likes it. + base_volatility: 0.78 + factions: + + - id: "klingons" + name: "Klingon Empire" + abbreviation: "KLG" + type: "aggressive" + homeworld: "Qo'noS" + color_code: "#ef4444" + emblem_glyph: "βš”" + base_shield_strength: 60 + base_attack_power: 95 + base_evasion: 35 + tactical_profile: > + Pure aggression. Klingon warriors charge headfirst into + battle screaming for Sto-vo-kor. Devastating opening + salvos but shields degrade rapidly under sustained fire. + The quintessential "front-runner" β€” dominant when ahead, + catastrophic when behind. Bat'leth duels create sudden + commander-loss events that crash their entire line. + rivalry_modifiers: + romulans: 1.30 # Ancient blood enemies + starfleet: 1.15 # Grudging respect / rivalry + gorn: 1.20 # Territorial border wars + + - id: "romulans" + name: "Romulan Star Empire" + abbreviation: "ROM" + type: "infiltrator" + homeworld: "Rator III (provisional)" + color_code: "#22d3ee" + emblem_glyph: "β—ˆ" + base_shield_strength: 72 + base_attack_power: 70 + base_evasion: 85 + tactical_profile: > + Masters of cloaking technology and deception. Romulans + never engage unless the odds are stacked in their favor. + Cloaking events create "information blackout" periods where + live telemetry goes dark β€” markets suspend until decloaking. + The Tal Shiar routinely feeds false data to manipulate lines. + rivalry_modifiers: + klingons: 1.30 # Khitomer massacre β€” eternal feud + starfleet: 1.20 # Neutral Zone tension + dominion: 1.15 # Omarion Nebula revenge + + - id: "gorn" + name: "Gorn Hegemony" + abbreviation: "GRN" + type: "aggressive" + homeworld: "Gornar" + color_code: "#84cc16" + emblem_glyph: "β–²" + base_shield_strength: 85 + base_attack_power: 80 + base_evasion: 20 + tactical_profile: > + Reptilian heavy-hitters with slow but massively armored + vessels. Gorn ships absorb incredible punishment and + deliver devastating broadsides. Terrible against fast + opponents, dominant against anything that stands and + trades blows. The "power forward" of galactic combat. + rivalry_modifiers: + klingons: 1.20 # Border skirmishes + starfleet: 1.10 # Cestus III incident + + - id: "orions" + name: "Orion Syndicate" + abbreviation: "ORI" + type: "infiltrator" + homeworld: "Orion (Rigel VII)" + color_code: "#4ade80" + emblem_glyph: "⊘" + base_shield_strength: 40 + base_attack_power: 55 + base_evasion: 90 + tactical_profile: > + Criminal syndicate operating pirate fleets and smuggling + networks. Orions fight dirty β€” sabotage, bribery, and + surprise attacks from unexpected vectors. Low raw power + but extremely difficult to pin down. Their matches always + have "special incident" side markets. + rivalry_modifiers: + starfleet: 1.10 # Law vs crime + ferengi: 1.05 # Competing underworld interests + + # ══════════════════════════════════════ + # GAMMA QUADRANT β€” The Dominion's Domain + # Extreme volatility, shapeshifter interference, thin markets + # ══════════════════════════════════════ + + - id: "gamma" + name: "Gamma Quadrant" + designation: "QUADRANT-Ξ³" + color_code: "#a78bfa" + description: > + Dominion-controlled space beyond the Bajoran Wormhole. Markets + are exotic, thin, and routinely manipulated by Changeling + infiltrators. The odds are never what they seem. Cross-quadrant + bets carry a mandatory wormhole transit surcharge. + base_volatility: 0.91 + factions: + + - id: "dominion" + name: "The Dominion" + abbreviation: "DOM" + type: "swarm" + homeworld: "Founders' Homeworld" + color_code: "#a78bfa" + emblem_glyph: "β—‰" + base_shield_strength: 75 + base_attack_power: 88 + base_evasion: 40 + tactical_profile: > + Jem'Hadar shock troops backed by Vorta tactical coordination. + The Dominion overwhelms with numbers and suicidal aggression. + Ketracel-white supply levels directly affect combat performance + β€” supply disruption events create massive odds swings. They + never retreat. They never surrender. + rivalry_modifiers: + starfleet: 1.35 # The Dominion War + bajorans: 1.30 # Wormhole control + cardassians: 1.25 # Betrayed allies + klingons: 1.20 # Chin'toka theater + + - id: "karemma" + name: "Karemma Trade Ministry" + abbreviation: "KRM" + type: "defensive" + homeworld: "Karemma" + color_code: "#fcd34d" + emblem_glyph: "β—Š" + base_shield_strength: 50 + base_attack_power: 30 + base_evasion: 65 + tactical_profile: > + Merchants, not warriors. Karemma ships are heavily shielded + trade vessels repurposed for combat. Their defense is + surprisingly robust but offense is anemic. The ultimate + "under" play β€” matches involving Karemma tend to be low + kinetic yield affairs. + rivalry_modifiers: + dominion: 1.05 # Reluctant subjects + + - id: "dosi" + name: "Dosi Consortium" + abbreviation: "DOS" + type: "aggressive" + homeworld: "Dosi Prime" + color_code: "#f97316" + emblem_glyph: "β–¬" + base_shield_strength: 55 + base_attack_power: 75 + base_evasion: 50 + tactical_profile: > + Ferocious warrior-merchants who negotiate with disruptor + pistols on the table. Dosi combat is fast, brutal, and + decisive. Short matches with explosive kinetic yields. + The "over" specialist of the Gamma Quadrant. + rivalry_modifiers: + ferengi: 1.15 # Trade rivalry + karemma: 1.10 # Commercial competitors + + - id: "hunters" + name: "Tosk Hunters" + abbreviation: "TSK" + type: "infiltrator" + homeworld: "Unknown (Gamma Quadrant)" + color_code: "#a3e635" + emblem_glyph: "βŠ•" + base_shield_strength: 45 + base_attack_power: 70 + base_evasion: 80 + tactical_profile: > + Bred to hunt the Tosk, these trackers bring relentless + pursuit tactics to fleet combat. Exceptional at locating + and eliminating cloaked or evasive targets. Their matches + are long attrition affairs with sudden decisive kills. + The anti-Romulan specialist. + rivalry_modifiers: + romulans: 1.25 # Cloaking hunter vs cloaking prey + + # ══════════════════════════════════════ + # DELTA QUADRANT β€” The Deep Frontier + # Maximum volatility, alien tech, extinction-level events + # ══════════════════════════════════════ + + - id: "delta" + name: "Delta Quadrant" + designation: "QUADRANT-Ξ΄" + color_code: "#38bdf8" + description: > + The deep frontier. Borg space, Hirogen hunting grounds, and + uncharted anomalies. Sparse markets with enormous premiums. + Data feeds are delayed and unreliable. Only accessible via + subspace relay. Not for the faint of lobes. + base_volatility: 0.95 + factions: + + - id: "borg" + name: "The Borg Collective" + abbreviation: "BRG" + type: "swarm" + homeworld: "Unicomplex (Primary Nexus)" + color_code: "#38bdf8" + emblem_glyph: "β–ˆ" + base_shield_strength: 95 + base_attack_power: 90 + base_evasion: 15 + tactical_profile: > + Resistance is futile. The Collective adapts to weapon + frequencies in real-time β€” sustained damage becomes less + effective each tick. Overwhelming force with adaptive + defenses. The galaxy's apex predator. Only defeats come + from exploiting their hive-mind dependency. When a Queen + is present, all stats receive a 15% bonus. + rivalry_modifiers: + starfleet: 1.35 # Wolf 359 / First Contact + species8472: 1.50 # The only faction that terrifies the Borg + + - id: "species8472" + name: "Species 8472 (Undine)" + abbreviation: "S84" + type: "aggressive" + homeworld: "Fluidic Space" + color_code: "#86efac" + emblem_glyph: "∞" + base_shield_strength: 99 + base_attack_power: 99 + base_evasion: 70 + tactical_profile: > + Extra-dimensional bio-ships with technology beyond + anything in normal space. A single bio-ship can destroy + a Borg cube. Their appearance in any match creates + instant market panic and odds collapse. The ultimate + "black swan" faction β€” rarely seen, always devastating. + rivalry_modifiers: + borg: 1.50 # The existential threat + starfleet: 1.20 # Scorched-earth distrust + + - id: "hirogen" + name: "Hirogen Hunters" + abbreviation: "HRG" + type: "aggressive" + homeworld: "Nomadic (Relay Network)" + color_code: "#a3a3a3" + emblem_glyph: "βŠ—" + base_shield_strength: 65 + base_attack_power: 85 + base_evasion: 55 + tactical_profile: > + Apex hunters who fight for glory and trophies, not + territory. Hirogen vessels are fast, heavily armed + pursuit craft. They specialize in isolating and + destroying single targets. Weak in fleet-scale + engagements but lethal in single-combat scenarios. + rivalry_modifiers: + klingons: 1.25 # Hunter vs warrior β€” marquee matchup + species8472: 1.30 # The ultimate hunt + + - id: "kazon" + name: "Kazon Order" + abbreviation: "KZN" + type: "aggressive" + homeworld: "Nomadic (Sect territories)" + color_code: "#d97706" + emblem_glyph: "β•³" + base_shield_strength: 40 + base_attack_power: 60 + base_evasion: 45 + tactical_profile: > + Fractured into rival sects (Ogla, Nistrim, Relora, Pommar). + Individually weak but occasionally muster combined sect + fleets for major engagements. The Delta Quadrant's + "relegation candidate" β€” always the underdog, but sect + unification events can suddenly make them competitive. + rivalry_modifiers: + hirogen: 1.10 # Prey animals + starfleet: 1.05 # Voyager grudge + + - id: "vidiians" + name: "Vidiian Sodality" + abbreviation: "VID" + type: "tactical" + homeworld: "Vidiia Prime" + color_code: "#6ee7b7" + emblem_glyph: "☀" + base_shield_strength: 60 + base_attack_power: 50 + base_evasion: 55 + tactical_profile: > + Post-Phage survivors with advanced bio-medical technology. + Vidiian weapons drain opponent crew effectiveness over time β€” + a slow bleed that accumulates across long engagements. + Favored in drawn-out matches, vulnerable to early blitzes. + rivalry_modifiers: + kazon: 1.10 # Territorial neighbors + +# ───────────────────────────────────────────────────────────────────────── +# MARKET TEMPLATES β€” Standard betting line generators +# +# Sportsbook Analogy: Bet Types +# The Go engine hydrates these templates with faction names and +# sector-specific modifiers to create live betting lines. +# +# Each template defines the structural "shape" of a bet. +# The engine substitutes {home} and {away} with actual faction names. +# ───────────────────────────────────────────────────────────────────────── + +market_templates: + + - id: "match-winner" + name: "Combat Resolution β€” Moneyline" + description: "Straight-up win/loss prediction. The bread and butter." + category: "primary" + selections: + - type: "home-win" + suffix: "Decisive Victory" + base_price: 2.00 + - type: "away-win" + suffix: "Decisive Victory" + base_price: 2.00 + + - id: "shield-breach" + name: "First Shield Breach" + description: "Which faction's shields fail to zero first?" + category: "primary" + selections: + - type: "home-breach-first" + suffix: "Shields Collapse First" + base_price: 1.90 + - type: "away-breach-first" + suffix: "Shields Collapse First" + base_price: 1.90 + + - id: "kinetic-over-under" + name: "Total Kinetic Yield" + description: "Over/Under on combined energy released during engagement." + category: "primary" + selections: + - type: "over" + name: "Over 8.5 Terawatts" + base_price: 1.85 + - type: "under" + name: "Under 8.5 Terawatts" + base_price: 1.85 + + - id: "shield-handicap" + name: "Shield Capacity Handicap" + description: "Spread bet on shield differential at engagement end." + category: "secondary" + selections: + - type: "home-spread" + name: "Home -15.5 Shield Points" + base_price: 1.90 + - type: "away-spread" + name: "Away +15.5 Shield Points" + base_price: 1.90 + + - id: "total-shield-damage" + name: "Total Shield Damage Dealt" + description: "Combined shield points stripped from both factions." + category: "secondary" + selections: + - type: "over" + name: "Over 120.5 Shield Points Destroyed" + base_price: 1.85 + - type: "under" + name: "Under 120.5 Shield Points Destroyed" + base_price: 1.95 + + - id: "engagement-duration" + name: "Engagement Duration" + description: "How long the combat lasts before resolution." + category: "secondary" + selections: + - type: "over" + name: "Over 24.5 Cycles" + base_price: 1.80 + - type: "under" + name: "Under 24.5 Cycles" + base_price: 2.00 + + - id: "comeback-special" + name: "Comeback Victory" + description: "Faction trails by 30+ shield points then wins. High premium." + category: "exotic" + selections: + - type: "home-comeback" + suffix: "Comeback from 30+ Deficit" + base_price: 5.50 + - type: "away-comeback" + suffix: "Comeback from 30+ Deficit" + base_price: 5.50 + + - id: "perfect-defense" + name: "Perfect Defense" + description: "A faction wins without shields dropping below 50%." + category: "exotic" + selections: + - type: "home-perfect" + suffix: "Wins with Shields Above 50%" + base_price: 3.20 + - type: "away-perfect" + suffix: "Wins with Shields Above 50%" + base_price: 3.20 + + - id: "mutual-destruction" + name: "Mutual Destruction" + description: "Both factions' shields reach zero. Extremely rare." + category: "exotic" + selections: + - type: "yes" + name: "Both Shields Reach 0%" + base_price: 12.00 + - type: "no" + name: "At Least One Faction Survives" + base_price: 1.05 + + - id: "subspace-event" + name: "Subspace Anomaly Interference" + description: "Will a random subspace event disrupt the engagement?" + category: "exotic" + selections: + - type: "anomaly-occurs" + name: "Anomaly Detected During Match" + base_price: 4.50 + - type: "clean-engagement" + name: "No Anomaly Interference" + base_price: 1.18 + +# ───────────────────────────────────────────────────────────────────────── +# SECTOR POOL β€” Match venue locations (stadiums/arenas) +# +# Sportsbook Analogy: Stadiums / Venues +# The Go engine picks a sector from this pool, assigns two factions, +# hydrates market templates, and pushes a live event into Valkey. +# +# Each sector has environmental modifiers that affect combat mechanics: +# - shield_modifier: Multiplier on all shield values in this sector +# - damage_modifier: Multiplier on all attack damage in this sector +# - evasion_modifier: Multiplier on evasion chances +# - special_event_chance: Probability of a subspace anomaly per tick +# ───────────────────────────────────────────────────────────────────────── + +sector_pool: + + # ── ALPHA QUADRANT VENUES ── + + - id: "sector-001" + name: "Sector 001 β€” Earth Orbital Array" + quadrant: "alpha" + coordinates: "21.4Ξ± Γ— 08.7Ξ²" + description: > + The most defended sector in the galaxy. Starfleet's home turf. + Maximum shield infrastructure gives a defensive advantage. + shield_modifier: 1.15 + damage_modifier: 0.90 + evasion_modifier: 1.00 + special_event_chance: 0.02 + status: "ACTIVE" + tags: ["core", "federation-home", "high-defense"] + + - id: "wolf-359" + name: "Wolf 359 β€” Memorial Perimeter" + quadrant: "alpha" + coordinates: "14.8Ξ± Γ— 03.2Ξ²" + description: > + Site of the devastating Borg incursion. Wreckage debris creates + navigational hazards that reduce evasion. Historically cursed + ground β€” strange energy readings boost anomaly chances. + shield_modifier: 0.95 + damage_modifier: 1.10 + evasion_modifier: 0.80 + special_event_chance: 0.12 + status: "ACTIVE" + tags: ["memorial", "debris-field", "high-anomaly"] + + - id: "bajor-wormhole" + name: "Bajor Sector β€” Deep Space Nine" + quadrant: "alpha" + coordinates: "37.2Ξ± Γ— 19.1Ξ²" + description: > + The wormhole approach corridor. Gravitational fluctuations from + the Celestial Temple create unpredictable shield harmonics. + Prophet-intervention events are unique to this sector. + shield_modifier: 1.00 + damage_modifier: 1.05 + evasion_modifier: 0.90 + special_event_chance: 0.18 + status: "ACTIVE" + tags: ["wormhole", "ds9", "prophet-events", "cross-quadrant"] + + - id: "badlands" + name: "The Badlands β€” Plasma Storm Zone" + quadrant: "alpha" + coordinates: "34.1Ξ± Γ— 22.8Ξ²" + description: > + Treacherous plasma storms wreak havoc on shields and sensors. + Massively increased damage and anomaly rates. The most + chaotic arena in the Alpha Quadrant β€” Quark's favorite. + shield_modifier: 0.70 + damage_modifier: 1.30 + evasion_modifier: 0.60 + special_event_chance: 0.35 + status: "ACTIVE" + tags: ["hazard", "plasma-storms", "high-damage", "chaotic"] + + - id: "vulcan-grid" + name: "Vulcan Sector β€” T'Khasi Defense Grid" + quadrant: "alpha" + coordinates: "16.5Ξ± Γ— 11.3Ξ²" + description: > + Logical, orderly, and precisely calibrated. Vulcan defense + satellites provide enhanced shield regeneration to all + combatants. The "safe" arena β€” low volatility, tight lines. + shield_modifier: 1.20 + damage_modifier: 0.85 + evasion_modifier: 1.00 + special_event_chance: 0.03 + status: "ACTIVE" + tags: ["safe", "shield-boost", "low-volatility"] + + - id: "ferenginar-orbit" + name: "Ferenginar Orbit β€” Commerce Ring" + quadrant: "alpha" + coordinates: "42.7Ξ± Γ— 15.4Ξ²" + description: > + The Ferengi charge hazard premiums for combat in their space. + Perpetual rain interference from the surface degrades sensor + accuracy. Betting volumes are always highest here. + shield_modifier: 1.00 + damage_modifier: 1.00 + evasion_modifier: 0.85 + special_event_chance: 0.08 + status: "ACTIVE" + tags: ["commerce", "ferengi-home", "sensor-interference"] + + - id: "cardassia-rebuild" + name: "Cardassia Sector β€” Reconstruction Zone" + quadrant: "alpha" + coordinates: "35.9Ξ± Γ— 24.6Ξ²" + description: > + Orbital debris from the Dominion War bombardment creates a + dangerous arena. Weapons platforms still drift online + occasionally, dealing random damage to both sides. + shield_modifier: 0.85 + damage_modifier: 1.15 + evasion_modifier: 0.75 + special_event_chance: 0.20 + status: "ACTIVE" + tags: ["post-war", "debris", "random-damage"] + + - id: "tholian-border" + name: "Tholian Border β€” Web Perimeter" + quadrant: "alpha" + coordinates: "48.1Ξ± Γ— 06.3Ξ²" + description: > + Ambient Tholian web energy slows all vessels and disrupts + evasive maneuvers. Shields fluctuate unpredictably near + crystalline energy nodes. Market-halting web events possible. + shield_modifier: 0.90 + damage_modifier: 1.05 + evasion_modifier: 0.50 + special_event_chance: 0.22 + status: "ACTIVE" + tags: ["web-hazard", "evasion-killer", "market-halt-risk"] + + # ── BETA QUADRANT VENUES ── + + - id: "qonos-arena" + name: "Qo'noS Sector β€” The Warrior's Ring" + quadrant: "beta" + coordinates: "08.3Ξ² Γ— 27.1Ξ±" + description: > + The Klingon homeworld arena. Combat here is brutal and fast. + Enhanced weapons yield and reduced shield efficiency β€” the + Klingons demand blood, not patience. + shield_modifier: 0.80 + damage_modifier: 1.25 + evasion_modifier: 0.95 + special_event_chance: 0.08 + status: "ACTIVE" + tags: ["klingon-home", "high-damage", "fast-matches"] + + - id: "neutral-zone" + name: "The Neutral Zone β€” Dead Buffer" + quadrant: "beta" + coordinates: "12.0Ξ² Γ— 30.0Ξ±" + description: > + The demilitarized corridor between Federation and Romulan space. + Sensor grids from both sides create enhanced evasion detection. + Cloaking devices are 30% less effective here. + shield_modifier: 1.05 + damage_modifier: 1.00 + evasion_modifier: 1.15 + special_event_chance: 0.05 + status: "ACTIVE" + tags: ["dmz", "anti-cloak", "surveillance"] + + - id: "khitomer" + name: "Khitomer Sector β€” Accord Grid" + quadrant: "beta" + coordinates: "10.4Ξ² Γ— 25.8Ξ±" + description: > + Historic treaty site. Balanced arena with no environmental + advantages. Diplomatic significance means any combat here + draws maximum viewership and betting volume. + shield_modifier: 1.00 + damage_modifier: 1.00 + evasion_modifier: 1.00 + special_event_chance: 0.05 + status: "ACTIVE" + tags: ["neutral", "high-profile", "balanced"] + + - id: "narendra-3" + name: "Narendra III β€” Honor's Edge" + quadrant: "beta" + coordinates: "14.2Ξ² Γ— 29.6Ξ±" + description: > + Site of the Enterprise-C's legendary sacrifice. Temporal + anomaly residue creates occasional time-distortion events + that can reset shield levels mid-combat. Extremely exotic. + shield_modifier: 1.00 + damage_modifier: 1.10 + evasion_modifier: 0.90 + special_event_chance: 0.25 + status: "ACTIVE" + tags: ["temporal-anomaly", "honor-history", "shield-reset-events"] + + - id: "rura-penthe" + name: "Rura Penthe β€” The Gulag Perimeter" + quadrant: "beta" + coordinates: "06.1Ξ² Γ— 31.7Ξ±" + description: > + The frozen prison asteroid's orbital space. Extreme cold + degrades shield harmonics. Klingon defense platforms add + random area damage. A brutal, unforgiving arena. + shield_modifier: 0.75 + damage_modifier: 1.20 + evasion_modifier: 0.85 + special_event_chance: 0.15 + status: "ACTIVE" + tags: ["prison", "cold-hazard", "area-damage"] + + - id: "azati-prime" + name: "Azati Prime β€” Delphic Expanse Remnant" + quadrant: "beta" + coordinates: "25.3Ξ² Γ— 44.0Ξ±" + description: > + Spatial anomalies from the collapsed Delphic Expanse still + linger here. Random physics distortions can invert shield + polarity, turning defense into vulnerability. The wildest + arena in Beta space. + shield_modifier: 0.85 + damage_modifier: 1.15 + evasion_modifier: 0.70 + special_event_chance: 0.30 + status: "ACTIVE" + tags: ["spatial-anomalies", "polarity-inversion", "wild"] + + - id: "gornar-orbit" + name: "Gornar Orbit β€” Hegemony Arena" + quadrant: "beta" + coordinates: "22.5Ξ² Γ— 38.2Ξ±" + description: > + The Gorn homeworld's massive gravity well favors heavy, + slow vessels. Enhanced shield regeneration for high-mass + ships. A punishing arena for light raiders. + shield_modifier: 1.10 + damage_modifier: 1.00 + evasion_modifier: 0.75 + special_event_chance: 0.06 + status: "ACTIVE" + tags: ["gorn-home", "high-gravity", "heavy-ship-advantage"] + + # ── GAMMA QUADRANT VENUES ── + + - id: "idran-terminus" + name: "Idran Sector β€” Wormhole Terminus" + quadrant: "gamma" + coordinates: "02.1Ξ³ Γ— 70.4Ξ²" + description: > + The Gamma side of the wormhole. Gravitational tides from the + passage create fluctuating shield resonances. First contact + point for all cross-quadrant expeditions. + shield_modifier: 0.95 + damage_modifier: 1.05 + evasion_modifier: 0.85 + special_event_chance: 0.15 + status: "ACTIVE" + tags: ["wormhole-exit", "gravitational-tides", "cross-quadrant"] + + - id: "omarion-nebula" + name: "Omarion Nebula β€” Graveyard Drift" + quadrant: "gamma" + coordinates: "38.9Ξ³ Γ— 85.7Ξ²" + description: > + Wreckage of 150 Tal Shiar and Obsidian Order warships. Dense + debris dramatically reduces evasion but provides excellent + cover for ambush tactics. Radiation spikes damage shields. + shield_modifier: 0.80 + damage_modifier: 1.20 + evasion_modifier: 0.55 + special_event_chance: 0.20 + status: "ACTIVE" + tags: ["battle-graveyard", "debris-dense", "ambush-terrain"] + + - id: "kurill-prime" + name: "Kurill Prime β€” Vorta Command Grid" + quadrant: "gamma" + coordinates: "31.7Ξ³ Γ— 82.4Ξ²" + description: > + Dominion administrative hub. Vorta tactical satellites provide + enhanced sensor data to all combatants. Clean arena with + excellent telemetry β€” rare for the Gamma Quadrant. + shield_modifier: 1.05 + damage_modifier: 1.00 + evasion_modifier: 1.10 + special_event_chance: 0.04 + status: "ACTIVE" + tags: ["dominion-admin", "clean-data", "enhanced-sensors"] + + - id: "dosi-crucible" + name: "Dosi Territory β€” The Crucible" + quadrant: "gamma" + coordinates: "25.3Ξ³ Γ— 79.6Ξ²" + description: > + Dosi combat arenas are surrounded by merchant observation + platforms. Enhanced weapon systems from arms dealers' demo + units increase damage across the board. Short, violent matches. + shield_modifier: 0.90 + damage_modifier: 1.30 + evasion_modifier: 1.00 + special_event_chance: 0.10 + status: "ACTIVE" + tags: ["arms-dealing", "enhanced-weapons", "short-matches"] + + - id: "founders-approach" + name: "Founders' Nebula β€” Outer Approach" + quadrant: "gamma" + coordinates: "42.1Ξ³ Γ— 87.5Ξ²" + description: > + The outermost navigable approach to the Founders' homeworld. + Changeling defense systems create random shapeshifting interference + that can swap faction identities on sensor displays. Maximum chaos. + shield_modifier: 0.85 + damage_modifier: 1.10 + evasion_modifier: 0.60 + special_event_chance: 0.40 + status: "ACTIVE" + tags: ["changeling-interference", "identity-swap", "maximum-chaos"] + + # ── DELTA QUADRANT VENUES ── + + - id: "grid-325" + name: "Grid 325 β€” Borg Patrol Corridor" + quadrant: "delta" + coordinates: "75.1Ξ΄ Γ— 84.6Ξ³" + description: > + Active Borg patrol zone. Residual assimilation nanoprobes in + the subspace field slowly degrade all shields over time. + Matches here have a ticking clock β€” fight fast or be absorbed. + shield_modifier: 0.75 + damage_modifier: 1.10 + evasion_modifier: 0.90 + special_event_chance: 0.18 + status: "ACTIVE" + tags: ["borg-territory", "shield-degradation", "ticking-clock"] + + - id: "hirogen-relay" + name: "Hirogen Relay Nexus β€” The Deep Web" + quadrant: "delta" + coordinates: "68.3Ξ΄ Γ— 77.9Ξ³" + description: > + Hub of the ancient communications relay network. Excellent + data transmission quality β€” the best telemetry in the Delta + Quadrant. Balanced combat environment with clear sensor reads. + shield_modifier: 1.00 + damage_modifier: 1.00 + evasion_modifier: 1.05 + special_event_chance: 0.06 + status: "ACTIVE" + tags: ["relay-hub", "clean-telemetry", "balanced"] + + - id: "nekrit-expanse" + name: "Nekrit Expanse β€” The Void" + quadrant: "delta" + coordinates: "60.7Ξ΄ Γ— 70.2Ξ³" + description: > + Vast, empty space at the edge of known territory. No environmental + modifiers β€” pure faction-vs-faction with zero interference. The + "laboratory" arena for testing raw combat power. + shield_modifier: 1.00 + damage_modifier: 1.00 + evasion_modifier: 1.00 + special_event_chance: 0.01 + status: "ACTIVE" + tags: ["void", "neutral", "pure-combat", "laboratory"] + + - id: "fluidic-rift" + name: "Fluidic Space Rift β€” Dimensional Breach" + quadrant: "delta" + coordinates: "88.2Ξ΄ Γ— 95.1Ξ³" + description: > + A tear between normal space and fluidic space. Bio-electric + energy from the rift supercharges all weapons but destabilizes + shield harmonics. The most extreme arena in the galaxy. + Species 8472 home advantage applies here. + shield_modifier: 0.60 + damage_modifier: 1.50 + evasion_modifier: 0.80 + special_event_chance: 0.35 + status: "ACTIVE" + tags: ["dimensional", "extreme", "bio-electric", "s8472-home"] + + - id: "devore-checkpoint" + name: "Devore Imperium β€” Inspection Gauntlet" + quadrant: "delta" + coordinates: "58.4Ξ΄ Γ— 66.1Ξ³" + description: > + Devore sensor sweeps periodically reveal all cloaked vessels. + Anti-telepathy fields disrupt psionic faction abilities. + A specialized arena that hard-counters infiltrator types. + shield_modifier: 1.00 + damage_modifier: 1.05 + evasion_modifier: 0.70 + special_event_chance: 0.12 + status: "ACTIVE" + tags: ["anti-cloak", "anti-psionic", "inspection"] + + - id: "caretaker-array" + name: "Caretaker's Array β€” Ocampa Orbit" + quadrant: "delta" + coordinates: "45.6Ξ΄ Γ— 55.3Ξ³" + description: > + Remnants of the Caretaker's technology still pulse with + displacement energy. Random transport events can teleport + combatants to unexpected positions, negating tactical + formations. The ultimate equalizer arena. + shield_modifier: 1.00 + damage_modifier: 1.00 + evasion_modifier: 0.80 + special_event_chance: 0.28 + status: "ACTIVE" + tags: ["displacement", "random-transport", "equalizer", "voyager-origin"] + + - id: "void-region" + name: "The Void β€” Absolute Darkness" + quadrant: "delta" + coordinates: "63.5Ξ΄ Γ— 73.8Ξ³" + description: > + A massive region of space with no stars, no resources, and + no escape. Ships trapped here fight with increasing desperation + as power reserves drain. Shield and damage modifiers degrade + each tick β€” the ultimate endurance test. + shield_modifier: 0.90 + damage_modifier: 0.90 + evasion_modifier: 0.90 + special_event_chance: 0.08 + status: "ACTIVE" + tags: ["void", "power-drain", "endurance", "degrading-modifiers"] + +# ───────────────────────────────────────────────────────────────────────── +# REGISTRY METADATA +# ───────────────────────────────────────────────────────────────────────── + +registry_metadata: + version: "2.0.0" + last_updated: "Stardate 79421.6" + total_quadrants: 4 + total_factions: 20 + total_sectors: 30 + total_market_templates: 10 + classification: "SUBSPACE OPEN" + curator: "Quark, Son of Keldar, Licensed Gamma Quadrant Bookmaker" + advisory: > + All odds and market descriptions are for entertainment purposes only + under Ferengi Commerce Authority License #QHL-7742-DS9. The house + reserves the right to adjust spreads, suspend markets, and deny + service to any patron displaying prophetic abilities, temporal + displacement, or Q Continuum affiliation. Rule of Acquisition #109: + "Dignity and an empty sack is worth the sack." diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d703900 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3.8' + +services: + valkey: + image: valkey/valkey:8.0 + container_name: tongo-valkey + ports: + - "6379:6379" + volumes: + - valkey_data:/data + restart: always + + redisinsight: + image: redis/redisinsight:latest + container_name: tongo-redisinsight + ports: + - "5540:5540" + volumes: + - redisinsight_data:/db + depends_on: + - valkey + restart: always + +volumes: + valkey_data: + redisinsight_data: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..5d7e631 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +allowBuilds: + unrs-resolver: set this to true or false diff --git a/reference/ENGINE.md b/reference/ENGINE.md new file mode 100644 index 0000000..560c5e3 --- /dev/null +++ b/reference/ENGINE.md @@ -0,0 +1,989 @@ +# Simulation Engine Architecture: Quark's Holo-Grid Ledger + +> **Status**: Design Analysis β€” Pre-Implementation +> **Author**: Engine Architecture Team +> **Dependencies**: `data-source/taxonomy.yaml`, Go 1.22+, Valkey 8.x + +--- + +## 1. Engine Overview + +The simulation engine is a **Go-based daemon** that reads the static taxonomy, generates live match events on a rolling schedule, simulates tick-by-tick combat, calculates real-time probabilities for all market types, and pushes continuous state updates into Valkey for the TanStack Start frontend to consume. + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ SIMULATION ENGINE β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚SCHEDULER β”‚β†’ β”‚MATCHMAKERβ”‚β†’ β”‚SIMULATOR β”‚β†’ β”‚PROBABILITYβ”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ (tick) β”‚ β”‚ ENGINE β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ EVENT β”‚ β”‚ MARKET β”‚ β”‚ +β”‚ β”‚GENERATOR β”‚ β”‚ UPDATER β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ VALKEY β”‚ β”‚ +β”‚ β”‚ WRITER β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Engine Modules + +| Module | Responsibility | Frequency | +|--------|---------------|-----------| +| **Scheduler** | Manages match lifecycle: create, run, resolve, retire | Every 30s check | +| **Matchmaker** | Pairs factions, picks venues, generates initial markets | On match creation | +| **Simulator** | Runs one combat tick per active match | Every 2s per match | +| **Event Generator** | Rolls for random in-match events | Every tick | +| **Probability Engine** | Recalculates all market odds from current state | Every tick | +| **Market Updater** | Applies probability β†’ price conversion + margin | Every tick | +| **Valkey Writer** | Serializes & pushes atomic state updates to cache | Every tick | + +--- + +## 2. Match Lifecycle + +Every match (sector engagement) follows a deterministic state machine: + +``` + SCHEDULED ──────► PRE-MATCH ──────► LIVE ──────► RESOLVING ──────► SETTLED + β”‚ β”‚ β”‚ β”‚ β”‚ + β”‚ T-60s before β”‚ Markets open β”‚ Combat ticks β”‚ Winner found β”‚ Markets paid + β”‚ match start β”‚ initial odds β”‚ odds moving β”‚ final odds β”‚ match archived + β”‚ β”‚ set from β”‚ events fire β”‚ locked β”‚ + β”‚ β”‚ faction stats β”‚ β”‚ β”‚ + β–Ό β–Ό β–Ό β–Ό β–Ό + Announced to Betslip accepts Live telemetry 3-tick cooldown Removed from + frontend index wagers streaming no new bets active index +``` + +### Lifecycle Timing + +| Phase | Duration | Markets | Description | +|-------|----------|---------|-------------| +| `SCHEDULED` | 30–90s | Closed | Match announced, factions & venue visible, no betting | +| `PRE_MATCH` | 60s | Open (pre-match odds) | Initial odds calculated, pre-match wagers accepted | +| `LIVE` | 60–150 ticks (2–5 min) | Open (live odds) | Active combat simulation, odds shift each tick | +| `RESOLVING` | 3 ticks (6s) | **Suspended** | Winner determined, final state locked, dramatic pause | +| `SETTLED` | 10s | Closed (final) | Results committed, markets graded, match archived | + +### Concurrent Match Capacity + +The engine should maintain a **rolling window** of active matches: + +```go +const ( + TargetActiveMatches = 8 // Aim for 8 concurrent live matches + MaxActiveMatches = 12 // Hard cap + MinActiveMatches = 4 // Trigger new match creation if below + MatchCreationCooldown = 15 // Seconds between new match spawns +) +``` + +The scheduler continuously checks: if `active < MinActiveMatches`, create new matches until `TargetActiveMatches` is reached. This guarantees the frontend always has events to display across all quadrants. + +--- + +## 3. Matchmaker β€” Pairing Algorithm + +The matchmaker selects two factions and a venue for each new engagement. + +### 3.1 Faction Pairing Rules + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PAIRING PROBABILITY WEIGHTS β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Same-quadrant matchup β”‚ 60% chance β”‚ +β”‚ Cross-quadrant matchup β”‚ 30% chance β”‚ +β”‚ Cross-quadrant (distant) β”‚ 10% chance β”‚ +β”‚ (Alpha↔Delta, Beta↔Gamma) β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +**Constraints:** +- A faction cannot appear in more than 2 simultaneous active matches +- Repeat matchups (same two factions) require a 3-match cooldown +- Rivalry matchups (high rivalry_modifier) get a 2x selection weight boost β€” they're marquee events + +### 3.2 Venue Selection + +```go +func SelectVenue(home, away FactionDef, taxonomy Taxonomy) SectorPoolItem { + // 1. Prefer venues in the home faction's quadrant (60%) + // 2. Neutral venues from either faction's quadrant (30%) + // 3. Random venue from any quadrant (10%) + + // Weight boost for thematic venues: + // - If home faction is Klingon and venue is "qonos-arena" β†’ 3x weight + // - If matchup has rivalry_modifier > 1.20 β†’ prefer "high-profile" tagged venues + + // Environmental modifiers from the venue apply to the entire match +} +``` + +### 3.3 Initial Odds Calculation + +Pre-match odds derive from **faction combat stats + venue modifiers + rivalry premium**: + +```go +func CalculatePreMatchOdds(home, away FactionDef, venue SectorPoolItem) float64 { + // 1. Calculate effective power ratings + homePower := (float64(home.BaseShield) * venue.ShieldModifier * 0.4) + + (float64(home.BaseAttack) * venue.DamageModifier * 0.4) + + (float64(home.BaseEvasion) * venue.EvasionModifier * 0.2) + + awayPower := (float64(away.BaseShield) * venue.ShieldModifier * 0.4) + + (float64(away.BaseAttack) * venue.DamageModifier * 0.4) + + (float64(away.BaseEvasion) * venue.EvasionModifier * 0.2) + + // 2. Convert power differential to probability via logistic function + diff := homePower - awayPower + homeProb := 1.0 / (1.0 + math.Exp(-diff / ScalingFactor)) + + // 3. Apply rivalry modifier (inflates drama, widens spread) + rivalryMod := home.RivalryModifiers[away.ID] // e.g., 1.35 + // Rivalry pushes odds away from 50/50 β€” makes favorites more favored + + // 4. Convert probability to decimal odds + homeOdds := 1.0 / homeProb + awayOdds := 1.0 / (1.0 - homeProb) + + // 5. Apply house margin (overround) + // Target: 105-108% overround (realistic sportsbook margin) + margin := 1.06 + homeOdds = homeOdds / margin + awayOdds = awayOdds / margin + + return homeOdds // (and awayOdds) +} +``` + +--- + +## 4. Combat Simulator β€” The Tick Loop + +Every 2 seconds, each active match processes one **combat tick**. + +### 4.1 Tick Sequence + +``` +FOR each active match: + β”‚ + β”œβ”€ 1. RESOLVE ACTIVE EFFECTS + β”‚ └─ Process lingering buffs/debuffs from prior events + β”‚ + β”œβ”€ 2. CALCULATE EFFECTIVE STATS + β”‚ β”œβ”€ Base stats Γ— venue modifiers Γ— active effects + β”‚ └─ Factor in type advantages (aggressive vs defensive, etc.) + β”‚ + β”œβ”€ 3. COMBAT EXCHANGE + β”‚ β”œβ”€ Both factions attack simultaneously + β”‚ β”œβ”€ Roll hit/miss for each (attack_power vs opponent evasion) + β”‚ β”œβ”€ Calculate damage dealt (if hit) + β”‚ β”œβ”€ Apply damage to opponent shields + β”‚ └─ Accumulate kinetic_yield (total energy released) + β”‚ + β”œβ”€ 4. EVENT ROLL + β”‚ β”œβ”€ Roll against venue.special_event_chance + β”‚ β”œβ”€ Roll against faction-specific event triggers + β”‚ └─ If event fires β†’ apply effects, log to event stream + β”‚ + β”œβ”€ 5. CHECK WIN CONDITIONS + β”‚ β”œβ”€ Shield collapse (one faction hits 0%) + β”‚ β”œβ”€ Mutual destruction (both hit 0% same tick) + β”‚ └─ Time limit (max ticks reached β†’ highest shields wins) + β”‚ + β”œβ”€ 6. RECALCULATE ALL MARKET PROBABILITIES + β”‚ └─ Feed current state to probability engine + β”‚ + └─ 7. PUSH TO VALKEY + └─ Atomic JSON state update +``` + +### 4.2 Combat Resolution Math + +```go +type TickResult struct { + HomeDamageDealt float64 + AwayDamageDealt float64 + HomeShieldsAfter float64 + AwayShieldsAfter float64 + KineticYieldDelta float64 + EventFired *MatchEvent // nil if no event +} + +func ResolveCombatTick(match *LiveMatch) TickResult { + home := &match.Factions.Home + away := &match.Factions.Away + venue := match.Venue + + // Effective stats = base Γ— venue modifier Γ— active effects + homeAttack := float64(home.EffectiveAttack) * venue.DamageModifier + awayAttack := float64(away.EffectiveAttack) * venue.DamageModifier + homeEvasion := float64(home.EffectiveEvasion) * venue.EvasionModifier + awayEvasion := float64(away.EffectiveEvasion) * venue.EvasionModifier + + // Hit chance = attacker_power / (attacker_power + defender_evasion) + // This creates a natural 0-1 probability range + homeHitChance := homeAttack / (homeAttack + awayEvasion) + awayHitChance := awayAttack / (awayAttack + homeEvasion) + + // Roll for hits + var homeDmg, awayDmg float64 + if rand.Float64() < homeHitChance { + // Home hits away β€” damage = base * random(0.6, 1.4) variance + homeDmg = homeAttack * (0.6 + rand.Float64()*0.8) * 0.1 // Scale to shield % + } + if rand.Float64() < awayHitChance { + awayDmg = awayAttack * (0.6 + rand.Float64()*0.8) * 0.1 + } + + // Apply type advantage multipliers + homeDmg *= TypeAdvantage(home.Type, away.Type) + awayDmg *= TypeAdvantage(away.Type, home.Type) + + // Apply damage to shields (clamped to 0-100) + away.ShieldCapacity = clamp(away.ShieldCapacity - homeDmg, 0, 100) + home.ShieldCapacity = clamp(home.ShieldCapacity - awayDmg, 0, 100) + + // Accumulate kinetic yield (total energy released = total damage dealt) + kineticDelta := homeDmg + awayDmg + match.KineticYield += kineticDelta + + return TickResult{ + HomeDamageDealt: homeDmg, + AwayDamageDealt: awayDmg, + HomeShieldsAfter: home.ShieldCapacity, + AwayShieldsAfter: away.ShieldCapacity, + KineticYieldDelta: kineticDelta, + } +} +``` + +### 4.3 Type Advantage Matrix + +Combat types create a rock-paper-scissors dynamic: + +``` + DEFENDER + aggressive defensive tactical infiltrator swarm +ATTACKER β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +aggressiveβ”‚ 1.00 0.80 1.20 1.30 0.90 β”‚ +defensive β”‚ 1.20 1.00 0.90 0.80 1.10 β”‚ +tactical β”‚ 0.80 1.10 1.00 1.20 1.00 β”‚ +infiltratrβ”‚ 0.70 1.20 0.80 1.00 1.30 β”‚ +swarm β”‚ 1.10 0.90 1.00 0.70 1.00 β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Key interactions: + aggressive β†’ infiltrator: 1.30 (brute force overwhelms trickery) + defensive β†’ aggressive: 1.20 (shields absorb the charge) + infiltratorβ†’ defensive: 1.20 (bypasses shield walls) + tactical β†’ aggressive: counterplay + swarm β†’ infiltrator: 0.70 (can't find them all) + infiltratorβ†’ swarm: 1.30 (surgical strikes on hive nodes) +``` + +--- + +## 5. Random Event System + +Events inject narrative drama and create sudden odds shifts β€” the equivalent of a red card, injury, or weather delay in real sports. + +### 5.1 Event Architecture + +```go +type MatchEvent struct { + ID string // Unique event instance ID + TemplateID string // Reference to event template + Name string // Display name + Description string // Narrative text for UI feed + Tick int // When it fired + Category EventCategory // combat | environmental | faction | market + Effects []EventEffect // Stat modifications + Duration int // Ticks the effect lasts (0 = instant) + Severity string // minor | major | critical +} + +type EventEffect struct { + Target string // "home" | "away" | "both" | "market" + Stat string // "shield" | "attack" | "evasion" | "price" + Operation string // "add" | "multiply" | "set" + Value float64 +} +``` + +### 5.2 Event Categories & Templates + +#### COMBAT EVENTS (triggered by combat state) + +| Event | Trigger | Effect | Duration | Severity | +|-------|---------|--------|----------|----------| +| **Critical Hit** | 5% per hit | 3Γ— damage on this hit | Instant | minor | +| **Shield Harmonics Failure** | When shields < 30% | Shields drop additional 10% | Instant | major | +| **Weapons Overload** | 3% per tick | Attacker deals 2Γ— but takes 5% self-damage | Instant | major | +| **Emergency Shield Reroute** | When shields < 15% | Restore 20% shields, disable attack for 3 ticks | 3 ticks | critical | +| **Hull Breach** | When shields hit 0% for first time | Shields cannot regenerate above 25% | Permanent | critical | + +#### ENVIRONMENTAL EVENTS (triggered by venue) + +| Event | Base Chance | Venue Tags | Effect | Duration | +|-------|-------------|------------|--------|----------| +| **Plasma Storm Surge** | venue.special_event_chance | plasma-storms | Both shields βˆ’15% | Instant | +| **Gravitational Anomaly** | venue.special_event_chance Γ— 0.5 | any | Both evasion Γ—0.5 | 5 ticks | +| **Subspace Rift** | venue.special_event_chance Γ— 0.3 | temporal-anomaly | Random shield reset (both set to random 40-80%) | Instant | +| **Sensor Blackout** | venue.special_event_chance Γ— 0.4 | sensor-interference | All markets SUSPENDED | 3 ticks | +| **Debris Impact** | venue.special_event_chance Γ— 0.6 | debris-field, debris-dense | Random faction takes 8-15% shield damage | Instant | +| **Energy Dampening Field** | venue.special_event_chance Γ— 0.2 | energy-dampening | Both attack Γ—0.6 | 4 ticks | + +#### FACTION-SPECIFIC EVENTS (triggered by faction type) + +| Event | Faction(s) | Trigger | Effect | +|-------|-----------|---------|--------| +| **Borg Adaptation** | `borg` | After taking 3 consecutive hits | Incoming damage Γ—0.5 for 5 ticks | +| **Cloaking Ambush** | `romulans` | 8% per tick when shields > 60% | Next attack deals 2.5Γ— damage, market suspends 1 tick | +| **Honor Duel Challenge** | `klingons` | When losing by 20+ shield points | Attack Γ—1.5, shields stop regenerating | +| **Prophet Intervention** | `bajorans` | 3% per tick | Shields restored to 70%, all markets suspended 2 ticks | +| **Energy Dampening Weapon** | `breen` | Once per match, 15% trigger | Opponent shields instantly halved | +| **Tholian Web Deployment** | `tholians` | When shields > 50% | Opponent evasion set to 0 for 4 ticks | +| **Ketracel Supply Drop** | `dominion` | When shields < 40% | All stats Γ—1.3 for 6 ticks | +| **Ferengi Tactical Retreat** | `ferengi` | When shields < 25% | Evasion Γ—3 for 3 ticks (hard to finish off) | +| **Species 8472 Bio-Pulse** | `species8472` | 10% per tick | Ignores shields, deals 20% direct damage | +| **Changeling Sabotage** | `dominion` (away only) | 5% per tick | Home faction attack Γ—0.7 for 3 ticks | + +#### MARKET EVENTS (triggered by odds state) + +| Event | Trigger | Effect | +|-------|---------|--------| +| **Subspace Interruption** | Shield swing > 25% in single tick | ALL markets suspended for 2 ticks | +| **Odds Avalanche** | One faction's moneyline crosses 5.00 | Exotic markets (comeback, mutual destruction) repriced with tighter odds | +| **Dead Heat Protocol** | Both shields within 5% and tick > 60% of max | Duration market prices collapse; match-winner market widens | + +### 5.3 Event Execution Flow + +```go +func (engine *Engine) RollForEvents(match *LiveMatch, tickResult TickResult) []MatchEvent { + var events []MatchEvent + + // 1. Environmental event roll + if rand.Float64() < match.Venue.SpecialEventChance { + event := engine.pickEnvironmentalEvent(match.Venue) + events = append(events, event) + } + + // 2. Faction-specific event checks + for _, side := range []string{"home", "away"} { + faction := match.GetFaction(side) + for _, template := range engine.factionEvents[faction.Type] { + if template.CheckTrigger(match, side, tickResult) { + if rand.Float64() < template.Probability { + event := template.Instantiate(match, side) + events = append(events, event) + } + } + } + } + + // 3. Combat state events + if tickResult.HomeDamageDealt > 0 && rand.Float64() < 0.05 { + events = append(events, CriticalHitEvent("home")) + } + + // 4. Market disruption checks + shieldSwing := math.Abs(tickResult.HomeShieldsAfter - tickResult.AwayShieldsAfter) + if shieldSwing > 25 { + events = append(events, SubspaceInterruptionEvent()) + } + + // Apply all event effects + for _, event := range events { + engine.applyEventEffects(match, event) + } + + return events +} +``` + +--- + +## 6. Probability Engine β€” The Core Odds Machine + +This is the heart of the sportsbook. Every tick, after combat resolution and event processing, all market probabilities must be recalculated from the current match state. + +### 6.1 Design Principles + +1. **Probabilities are derived, not stored** β€” odds are always computed from the current state vector, never carried forward from previous ticks +2. **Overround is applied last** β€” compute fair probability first, then apply house margin +3. **Suspension trumps calculation** β€” if a market event has suspended a market, skip recalculation until the suspension lifts +4. **Odds floor/ceiling** β€” No market selection can go below 1.01 or above 51.00 + +### 6.2 Match State Vector + +Every probability calculation takes this state as input: + +```go +type MatchState struct { + HomeShields float64 // 0-100 + AwayShields float64 // 0-100 + HomeFactionType string // aggressive, defensive, etc. + AwayFactionType string + HomeBaseStats [3]int // shield, attack, evasion + AwayBaseStats [3]int + KineticYield float64 // Cumulative energy released + CurrentTick int // How far into the match + MaxTicks int // Match duration limit + ActiveEffects []Effect // Lingering buffs/debuffs + VenueModifiers Venue // Environmental modifiers + EventLog []Event // History (for conditional markets) +} +``` + +### 6.3 Market-Specific Probability Models + +#### MODEL A: Match Winner (Moneyline) + +The most important market. Uses a **logistic regression model** on shield differential, weighted by time remaining. + +```go +func ProbabilityMatchWinner(state MatchState) (homeProb, awayProb float64) { + // Shield differential (positive = home advantage) + shieldDiff := state.HomeShields - state.AwayShields + + // Time factor: early ticks β†’ differential matters less + // Late ticks β†’ differential matters more (less time to recover) + tickProgress := float64(state.CurrentTick) / float64(state.MaxTicks) + timeFactor := 0.5 + (tickProgress * 1.5) // Ranges 0.5 β†’ 2.0 + + // Stat advantage: inherent faction strength difference + homePower := effectivePower(state.HomeBaseStats, state.VenueModifiers) + awayPower := effectivePower(state.AwayBaseStats, state.VenueModifiers) + statDiff := (homePower - awayPower) * 0.1 // Scaled down + + // Combined signal + signal := (shieldDiff * timeFactor * 0.05) + statDiff + + // Logistic function β†’ probability + homeProb = 1.0 / (1.0 + math.Exp(-signal)) + + // Edge case: if one side is at 0 shields + if state.HomeShields <= 0 { homeProb = 0.0 } + if state.AwayShields <= 0 { homeProb = 1.0 } + + // Clamp to avoid absurd odds + homeProb = clamp(homeProb, 0.02, 0.98) + awayProb = 1.0 - homeProb + + return homeProb, awayProb +} +``` + +**Behavior examples:** +| State | Home P | Away P | Home Odds | Away Odds | +|-------|--------|--------|-----------|-----------| +| Start (both 100%) | 0.50 | 0.50 | 2.00 | 2.00 | +| Home 80%, Away 60%, tick 25% | 0.58 | 0.42 | 1.72 | 2.38 | +| Home 45%, Away 70%, tick 50% | 0.30 | 0.70 | 3.33 | 1.43 | +| Home 20%, Away 65%, tick 80% | 0.08 | 0.92 | 12.50 | 1.09 | +| Home 5%, Away 50%, tick 90% | 0.03 | 0.97 | 33.33 | 1.03 | + +#### MODEL B: Total Kinetic Yield (Over/Under) + +Projects final total kinetic yield from current rate and remaining time. + +```go +func ProbabilityKineticYield(state MatchState, line float64) (overProb, underProb float64) { + // Current rate of energy release per tick + ticksElapsed := max(state.CurrentTick, 1) + currentRate := state.KineticYield / float64(ticksElapsed) + + // Project remaining yield + remainingTicks := float64(state.MaxTicks - state.CurrentTick) + projectedTotal := state.KineticYield + (currentRate * remainingTicks) + + // Variance decreases as match progresses (more certainty) + variance := (1.0 - float64(state.CurrentTick)/float64(state.MaxTicks)) * 3.0 + variance = max(variance, 0.3) // Minimum uncertainty + + // Normal CDF approximation + z := (line - projectedTotal) / variance + underProb = normalCDF(z) + overProb = 1.0 - underProb + + // Clamp + overProb = clamp(overProb, 0.02, 0.98) + underProb = 1.0 - overProb + + return overProb, underProb +} +``` + +#### MODEL C: First Shield Breach + +Predicts which faction's shields hit zero first based on damage rate trajectories. + +```go +func ProbabilityFirstBreach(state MatchState) (homeFirstProb, awayFirstProb float64) { + // If one already breached + if state.HomeShields <= 0 && state.AwayShields > 0 { return 1.0, 0.0 } + if state.AwayShields <= 0 && state.HomeShields > 0 { return 0.0, 1.0 } + if state.HomeShields <= 0 && state.AwayShields <= 0 { return 0.5, 0.5 } + + // Estimate ticks to breach for each + homeDamageRate := estimateDamageRate("away_to_home", state) // damage per tick to home + awayDamageRate := estimateDamageRate("home_to_away", state) // damage per tick to away + + homeTicksToBreach := state.HomeShields / max(homeDamageRate, 0.01) + awayTicksToBreach := state.AwayShields / max(awayDamageRate, 0.01) + + // Faction with fewer ticks to breach is more likely to breach first + total := homeTicksToBreach + awayTicksToBreach + homeFirstProb = awayTicksToBreach / total // Inverted: if away takes longer, home breaches first more likely... wait + // Actually: if home has fewer ticks to breach, home breaches first + homeFirstProb = 1.0 - (homeTicksToBreach / total) + awayFirstProb = 1.0 - homeFirstProb + + return clamp(homeFirstProb, 0.02, 0.98), clamp(awayFirstProb, 0.02, 0.98) +} +``` + +#### MODEL D: Engagement Duration (Over/Under Cycles) + +```go +func ProbabilityDuration(state MatchState, line float64) (overProb, underProb float64) { + // Estimate remaining ticks based on shield drain rates + avgDrainRate := estimateAverageDrainRate(state) // Combined shield loss per tick + avgShieldsRemaining := (state.HomeShields + state.AwayShields) / 2.0 + + estimatedRemainingTicks := avgShieldsRemaining / max(avgDrainRate, 0.1) + estimatedTotalTicks := float64(state.CurrentTick) + estimatedRemainingTicks + + // If already past the line, it's definitely over + if float64(state.CurrentTick) >= line { + return 1.0, 0.0 + } + + // Normal CDF on projected total vs line + variance := estimatedRemainingTicks * 0.3 + z := (line - estimatedTotalTicks) / max(variance, 0.1) + underProb = normalCDF(z) + overProb = 1.0 - underProb + + return clamp(overProb, 0.02, 0.98), clamp(underProb, 0.02, 0.98) +} +``` + +#### MODEL E: Comeback Victory + +```go +func ProbabilityComeback(state MatchState, deficitThreshold float64) (homeComeback, awayComeback float64) { + // Check if the deficit condition has been met historically + homeMaxDeficit := trackMaxDeficit(state.EventLog, "home") + awayMaxDeficit := trackMaxDeficit(state.EventLog, "away") + + homeDeficitMet := homeMaxDeficit >= deficitThreshold + awayDeficitMet := awayMaxDeficit >= deficitThreshold + + if !homeDeficitMet && !awayDeficitMet { + // Need both: P(reach deficit) Γ— P(win from deficit) + // This is very rare β†’ long odds + homeComeback = 0.05 // ~5% base, adjusted by state + awayComeback = 0.05 + } else { + // Deficit was met β€” now it's "just" a win probability from behind + if homeDeficitMet { + homeWinProb, _ := ProbabilityMatchWinner(state) + homeComeback = homeWinProb * 0.8 // Discount for comeback difficulty + } + if awayDeficitMet { + _, awayWinProb := ProbabilityMatchWinner(state) + awayComeback = awayWinProb * 0.8 + } + } + + return clamp(homeComeback, 0.02, 0.50), clamp(awayComeback, 0.02, 0.50) +} +``` + +#### MODEL F: Mutual Destruction + +```go +func ProbabilityMutualDestruction(state MatchState) float64 { + // Both shields need to reach 0 on the same tick + // More likely when shields are close together and both low + shieldDiff := math.Abs(state.HomeShields - state.AwayShields) + avgShields := (state.HomeShields + state.AwayShields) / 2.0 + + // Base probability is very low + baseProb := 0.01 + + // Increases when shields are similar (small diff) + similarityBoost := 1.0 + (20.0 - min(shieldDiff, 20.0)) / 20.0 * 3.0 + + // Increases when both shields are low + lowShieldBoost := 1.0 + if avgShields < 30 { + lowShieldBoost = 1.0 + (30.0 - avgShields) / 30.0 * 5.0 + } + + prob := baseProb * similarityBoost * lowShieldBoost + return clamp(prob, 0.005, 0.30) +} +``` + +#### MODEL G: Subspace Anomaly + +```go +func ProbabilitySubspaceAnomaly(state MatchState) (anomalyProb, cleanProb float64) { + // Geometric distribution: P(at least one event in remaining ticks) + remainingTicks := state.MaxTicks - state.CurrentTick + perTickChance := state.VenueModifiers.SpecialEventChance + + // Has an anomaly already occurred? + alreadyOccurred := hasAnomalyOccurred(state.EventLog) + if alreadyOccurred { + return 1.0, 0.0 // Already happened β†’ "yes" is certain + } + + // P(no anomaly in remaining ticks) = (1 - p)^n + cleanProb = math.Pow(1.0 - perTickChance, float64(remainingTicks)) + anomalyProb = 1.0 - cleanProb + + return clamp(anomalyProb, 0.02, 0.98), clamp(cleanProb, 0.02, 0.98) +} +``` + +### 6.4 Probability β†’ Price Conversion + +```go +func ProbabilityToPrice(prob float64, margin float64) float64 { + // Fair odds + fairOdds := 1.0 / prob + + // Apply house margin (overround) + // margin = 1.06 means 106% book (6% house edge) + adjustedOdds := fairOdds / margin + + // Apply floor/ceiling + adjustedOdds = clamp(adjustedOdds, 1.01, 51.00) + + // Round to 2 decimal places + return math.Round(adjustedOdds * 100) / 100 +} +``` + +### 6.5 Overround Strategy + +The house margin varies by market category: + +| Category | Target Overround | Rationale | +|----------|-----------------|-----------| +| Primary (moneyline, O/U) | 105–106% | High liquidity, competitive odds | +| Secondary (handicap, duration) | 107–108% | Moderate liquidity | +| Exotic (comeback, mutual dest.) | 110–115% | Low liquidity, high variance, more house edge | + +--- + +## 7. Valkey Data Schema + +### 7.1 Key Structure + +``` +sector:telemetry:{match_id} β†’ Full match JSON state (HSET) +sector:events:{match_id} β†’ Capped event log, last 20 events (LIST) +sector:index:active β†’ Set of active match IDs (SET) +sector:index:quadrant:{q_id} β†’ Active match IDs in quadrant (SET) +sector:schedule:upcoming β†’ Upcoming match announcements (SORTED SET by start time) +global:stats β†’ Engine statistics (HASH) +``` + +### 7.2 Match Telemetry Payload (JSON pushed to Valkey) + +This is the exact JSON the TanStack Start frontend receives: + +```json +{ + "id": "wolf-359-a7f3", + "name": "Wolf 359 β€” Memorial Perimeter", + "quadrant": "alpha", + "status": "LIVE", + "tick": 42, + "maxTicks": 90, + "kinetic_yield": 14.7, + "venue": { + "id": "wolf-359", + "name": "Wolf 359 β€” Memorial Perimeter", + "tags": ["memorial", "debris-field", "high-anomaly"] + }, + "factions": { + "home": { + "id": "starfleet", + "name": "Starfleet Command", + "abbreviation": "SFC", + "type": "defensive", + "glyph": "β—†", + "colorCode": "#34d399", + "shieldCapacity": 62, + "effectiveAttack": 58, + "effectiveEvasion": 40, + "activeEffects": [] + }, + "away": { + "id": "borg", + "name": "The Borg Collective", + "abbreviation": "BRG", + "type": "swarm", + "glyph": "β–ˆ", + "colorCode": "#38bdf8", + "shieldCapacity": 71, + "effectiveAttack": 99, + "effectiveEvasion": 12, + "activeEffects": [ + { "name": "Borg Adaptation", "remainingTicks": 3, "effect": "damage_taken_x0.5" } + ] + } + }, + "markets": [ + { + "id": "wolf-359-a7f3-moneyline-home", + "templateId": "match-winner", + "name": "Starfleet Command Decisive Victory", + "category": "primary", + "price": 2.85, + "previousPrice": 2.70, + "trend": "up", + "status": "OPEN", + "impliedProbability": 0.351 + }, + { + "id": "wolf-359-a7f3-moneyline-away", + "templateId": "match-winner", + "name": "The Borg Collective Decisive Victory", + "category": "primary", + "price": 1.48, + "previousPrice": 1.52, + "trend": "down", + "status": "OPEN", + "impliedProbability": 0.676 + }, + { + "id": "wolf-359-a7f3-ky-over", + "templateId": "kinetic-over-under", + "name": "Over 8.5 Terawatts", + "category": "primary", + "price": 1.35, + "previousPrice": 1.40, + "trend": "down", + "status": "OPEN", + "impliedProbability": 0.741 + } + ], + "recentEvents": [ + { + "tick": 38, + "name": "Borg Adaptation", + "description": "The Collective adapts to Starfleet phaser frequencies. Incoming damage reduced by 50%.", + "severity": "major" + }, + { + "tick": 31, + "name": "Debris Impact", + "description": "Wolf 359 wreckage collides with Borg cube. Shields -12%.", + "severity": "minor" + } + ] +} +``` + +### 7.3 Event Log Entry (LPUSH to sector:events:{match_id}) + +```json +{ + "tick": 38, + "timestamp": "2024-01-15T10:30:42Z", + "name": "Borg Adaptation", + "category": "faction", + "severity": "major", + "description": "The Collective adapts to Starfleet phaser frequencies. Incoming damage reduced by 50%.", + "effects": [ + { "target": "away", "stat": "damage_taken", "operation": "multiply", "value": 0.5, "duration": 5 } + ], + "marketImpact": { + "suspendedMarkets": [], + "significantPriceChanges": ["wolf-359-a7f3-moneyline-home", "wolf-359-a7f3-moneyline-away"] + } +} +``` + +--- + +## 8. Go Engine File Structure + +``` +ingestion-engine/ +β”œβ”€β”€ main.go # Entry point: init, taxonomy load, main loop +β”œβ”€β”€ go.mod +β”œβ”€β”€ go.sum +β”œβ”€β”€ config/ +β”‚ β”œβ”€β”€ taxonomy.go # YAML parsing & taxonomy types +β”‚ └── constants.go # Tuning knobs (tick rate, max matches, etc.) +β”œβ”€β”€ engine/ +β”‚ β”œβ”€β”€ scheduler.go # Match lifecycle state machine +β”‚ β”œβ”€β”€ matchmaker.go # Faction pairing & venue selection +β”‚ β”œβ”€β”€ simulator.go # Combat tick resolution +β”‚ β”œβ”€β”€ events.go # Random event generation & application +β”‚ β”œβ”€β”€ probability.go # All probability models (A through G) +β”‚ β”œβ”€β”€ markets.go # Market hydration, pricing, suspension +β”‚ └── type_advantage.go # Combat type interaction matrix +β”œβ”€β”€ models/ +β”‚ β”œβ”€β”€ match.go # LiveMatch, MatchState structs +β”‚ β”œβ”€β”€ faction.go # FactionState, ActiveEffect structs +β”‚ β”œβ”€β”€ market.go # Market, MarketSelection structs +β”‚ └── event.go # MatchEvent, EventEffect structs +└── cache/ + β”œβ”€β”€ valkey.go # Valkey client wrapper + └── serializer.go # JSON payload assembly +``` + +--- + +## 9. Main Loop Pseudocode + +```go +func main() { + // 1. Load taxonomy + taxonomy := config.LoadTaxonomy("../data-source/taxonomy.yaml") + + // 2. Connect to Valkey + valkeyClient := cache.NewValkeyClient("localhost:6379") + + // 3. Initialize engine + engine := engine.NewEngine(taxonomy, valkeyClient) + + // 4. Seed initial matches + engine.Scheduler.SeedMatches(TargetActiveMatches) + + // 5. Main tick loop (every 2 seconds) + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + + for range ticker.C { + // A. Scheduler: check for matches to create/retire + engine.Scheduler.Tick() + + // B. For each active match, run one combat tick + for _, match := range engine.Scheduler.ActiveMatches() { + switch match.Status { + case "PRE_MATCH": + // Just update countdown timer, no combat + engine.UpdatePreMatchCountdown(match) + + case "LIVE": + // Run full tick cycle + tickResult := engine.Simulator.ResolveTick(match) + events := engine.EventGenerator.Roll(match, tickResult) + engine.Probability.RecalculateAll(match) + engine.Markets.UpdatePrices(match) + + case "RESOLVING": + // Cooldown ticks β€” no combat, markets suspended + engine.Simulator.ResolveCountdown(match) + + case "SETTLED": + // Grade markets, archive, remove from active + engine.Scheduler.SettleMatch(match) + continue + } + + // Push state to Valkey + engine.Cache.PushMatchState(match) + engine.Cache.PushEventLog(match) + } + + // C. Update active index + engine.Cache.UpdateActiveIndex(engine.Scheduler.ActiveMatches()) + + log.Println(">> Tick complete. Active matches:", len(engine.Scheduler.ActiveMatches())) + } +} +``` + +--- + +## 10. Tuning Knobs & Configuration + +All magic numbers should be extractable constants: + +```go +// config/constants.go + +// Tick timing +const TickInterval = 2 * time.Second + +// Match lifecycle +const TargetActiveMatches = 8 +const MaxActiveMatches = 12 +const MinActiveMatches = 4 +const PreMatchDuration = 30 // ticks (60s) +const MinMatchDuration = 60 // ticks (2 min) +const MaxMatchDuration = 150 // ticks (5 min) +const ResolvingDuration = 3 // ticks (6s) + +// Combat +const DamageScalingFactor = 0.1 // Converts raw attack to shield % +const DamageVarianceLow = 0.6 // Min damage multiplier +const DamageVarianceHigh = 1.4 // Max damage multiplier +const CriticalHitChance = 0.05 // 5% per hit +const CriticalHitMultiplier = 3.0 + +// Probability +const LogisticScalingFactor = 20.0 // Controls sigmoid steepness +const MinProbability = 0.02 // Floor (max odds ~50.00) +const MaxProbability = 0.98 // Ceiling (min odds ~1.02) +const MinPrice = 1.01 +const MaxPrice = 51.00 + +// Margins +const PrimaryMarketMargin = 1.06 // 106% overround +const SecondaryMarketMargin = 1.075 +const ExoticMarketMargin = 1.12 + +// Matchmaking +const SameQuadrantWeight = 0.60 +const CrossQuadrantWeight = 0.30 +const DistantQuadrantWeight = 0.10 +const MaxSimultaneousAppearances = 2 +const RepeatMatchupCooldown = 3 +const RivalrySelectionBoost = 2.0 +``` + +--- + +## 11. Edge Cases & Failure Modes + +| Scenario | Handling | +|----------|----------| +| **Both shields hit 0 on same tick** | Mutual Destruction β€” market graded as "yes", match winner is a draw (both moneylines voided/refunded) | +| **Match hits max tick limit** | Higher shields wins. If tied, compare cumulative damage dealt. If still tied, draw. | +| **Valkey connection lost** | Engine continues simulating in memory, buffers state, reconnects with exponential backoff. On reconnect, flush all buffered states. | +| **All factions in cooldown** | Reduce cooldown timers by 1, create cross-quadrant match with least-recently-used factions | +| **Event chain causes instant kill** | Shield floor of 1% for first 10 ticks (grace period). After that, instant kills are valid. | +| **Price oscillation (rapid up/down)** | Apply 3-tick moving average smoothing to price output. Raw probability still updates instantly. | +| **Probability model disagrees with state** | State always wins. If shields are 0, P(win) = 0 regardless of model output. Hard overrides > model. | + +--- + +## 12. Future Extensibility + +| Feature | Approach | +|---------|----------| +| **Accumulator / Parlay bets** | Multiply implied probabilities across selections from different matches. Apply accumulator margin premium. | +| **Match history / form** | Track last N results per faction in Valkey sorted set. Feed into pre-match odds as a "form" modifier. | +| **Tournament mode** | Bracket of 8/16 factions. Winners advance. Outright winner market across the tournament. | +| **Player props (crew members)** | Add crew member sub-entities to factions with individual stats. Create crew-level markets. | +| **Live commentary feed** | Event log already structured. Add a natural language template engine to generate commentary strings. | +| **Seasonal rankings** | Track faction W/L/D records. Create league table. End-of-season markets (champion, relegation). | diff --git a/reference/FRONTEND.md b/reference/FRONTEND.md new file mode 100644 index 0000000..ac9fa53 --- /dev/null +++ b/reference/FRONTEND.md @@ -0,0 +1,765 @@ +# Frontend Architecture: Quark's Holo-Grid Ledger + +> **Status**: Design Analysis β€” Pre-Implementation +> **Dependencies**: `reference/ENGINE.md`, `data-source/taxonomy.yaml`, `AGENTS.md` +> **Framework**: TanStack Start + TanStack Router (file-based routing) + +--- + +## 1. Layout Topology + +The application uses a fixed-viewport, three-column terminal layout defined in `__root.tsx`. The root shell is persistent β€” only the center column swaps content via ``. + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ [=] QUARK'S HOLO-GRID LEDGER // SUB-NET RECEPTOR STARDATE: 54201.3 β”‚ +β”‚ BALANCE: 4,250.00 GPL β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ β”‚ β”‚ +β”‚ LEFT PANEL β”‚ CENTER PANEL β”‚ RIGHT PANEL β”‚ +β”‚ col-span-3 β”‚ col-span-6 β”‚ col-span-3 β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ Navigation β”‚ β”‚ Betslip β”‚ +β”‚ Sidebar β”‚ (route content) β”‚ Sidecar β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ 240px-ish β”‚ flex-1 β”‚ 280px-ish β”‚ +β”‚ β”‚ β”‚ β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ SYSTEM RUNTIME: OK // CORE MODULES ACTIVE TANSTACK + VITE β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Responsive Breakpoints + +``` +DESKTOP (β‰₯1280px): [col-3 Sidebar] [col-6 Main] [col-3 Betslip] +TABLET (768-1279): [col-2 Sidebar] [col-7 Main] [col-3 Betslip] (sidebar compressed) +MOBILE (<768): [Full-width Main] + bottom tab bar + slide-up betslip +``` + +On mobile, the sidebar collapses into a **bottom navigation bar** with 5 terminal command buttons, and the betslip becomes a pull-up sheet triggered from the bar. + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ QUARK'S HOLO-GRID LEDGER 4,250 GPL β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ MAIN CONTENT β”‚ +β”‚ (full-width) β”‚ +β”‚ β”‚ +β”‚ β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ GRID β”‚ ALPHA β”‚ BETA β”‚ SLIP β”‚ LEDGER β”‚ +β”‚ β—ˆ β”‚ Ξ± β”‚ Ξ² β”‚ β‚² β”‚ β–€ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## 2. Navigation Sidebar (Left Panel) + +The sidebar is the primary navigation interface. It must feel like a hardware command console β€” numbered entries, hierarchical quadrant trees, and live status indicators. + +### 2.1 Sidebar Sections + +``` +╔══════════════════════════════════╗ +β•‘ [ SYSTEM ARRAY ] Quadrants β•‘ +╠══════════════════════════════════╣ +β•‘ β•‘ +β•‘ > GRID OVERVIEW [00] β•‘ ← Link to / +β•‘ β•‘ +β•‘ ═══════════════════════════════ β•‘ +β•‘ > LIVE ENGAGEMENTS β•‘ ← Section header +β•‘ β•‘ +β•‘ β–Ύ ALPHA QUADRANT [Ξ±] β•‘ ← Collapsible quadrant group +β•‘ β”œβ”€ β—†SFC vs β–ˆBRG ●LIVE β•‘ ← Active match (link to /quadrants/{id}) +β•‘ β”‚ 62% β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘ 71% β•‘ ← Inline shield bars +β•‘ β”œβ”€ β–ΌCRD vs ☼BAJ ●LIVE β•‘ +β•‘ β”‚ 48% β–ˆβ–ˆβ–ˆβ–‘β–‘β–‘ 55% β•‘ +β•‘ └─ βš”KLG vs β—ˆROM β—‹PRE β•‘ ← Pre-match (different indicator) +β•‘ β•‘ +β•‘ β–Έ BETA QUADRANT [Ξ²] β•‘ ← Collapsed quadrant +β•‘ 2 active β•‘ +β•‘ β•‘ +β•‘ β–Έ GAMMA QUADRANT [Ξ³] β•‘ +β•‘ 1 active β•‘ +β•‘ β•‘ +β•‘ β–Έ DELTA QUADRANT [Ξ΄] β•‘ +β•‘ 3 active β•‘ +β•‘ β•‘ +β•‘ ═══════════════════════════════ β•‘ +β•‘ > STATION ARCHIVES β•‘ ← Section header +β•‘ β•‘ +β•‘ [01] Wager Ledger β•‘ ← Link to /ledger +β•‘ [02] Faction Registry β•‘ ← Link to /registry/factions +β•‘ [03] Venue Database β•‘ ← Link to /registry/venues +β•‘ [04] Transmission Schedule β•‘ ← Link to /schedule +β•‘ β•‘ +β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• +``` + +### 2.2 Live Match Items + +Each match in the sidebar should show at a glance: +- Faction glyphs and abbreviations (e.g., `β—†SFC vs β–ˆBRG`) +- Match status indicator: `●LIVE` (pulsing green) / `β—‹PRE` (amber) / `β—‰RES` (red) +- Compact shield capacity bars (optional, space permitting) +- Clicking navigates to `/quadrants/{sectorId}?quadrant=Alpha¤cy=Latinum` + +### 2.3 Sidebar Data Source + +The sidebar reads from the `sector:index:active` Valkey set via a **server function** that returns all active match summaries. It polls at the same 2s interval as match telemetry. + +```tsx +// Server function: returns lightweight match summaries for sidebar +const getActiveMatchIndex = createServerFn({ method: 'GET' }) + .handler(async () => { + const matchIds = await valkey.smembers('sector:index:active') + // For each match, read just the fields needed for sidebar rendering + // (id, name, quadrant, status, factions.home.abbreviation, factions.away.abbreviation, + // factions.home.shieldCapacity, factions.away.shieldCapacity) + return summaries + }) +``` + +--- + +## 3. Route Map + +### 3.1 File-Based Route Structure + +``` +src/routes/ +β”œβ”€β”€ __root.tsx # Shell layout (header, sidebar, betslip, footer) +β”œβ”€β”€ index.tsx # Grid Overview / Dashboard +β”œβ”€β”€ quadrants/ +β”‚ β”œβ”€β”€ index.tsx # Quadrant listing (all matches, filterable) +β”‚ └── $sectorId.tsx # Live match detail (the main event page) +β”œβ”€β”€ ledger/ +β”‚ β”œβ”€β”€ index.tsx # Wager Ledger overview (active + recent settled) +β”‚ β”œβ”€β”€ active.tsx # Active/open wagers only +β”‚ └── settled.tsx # Settled/graded wagers history +β”œβ”€β”€ registry/ +β”‚ β”œβ”€β”€ factions.tsx # Faction directory (all teams) +β”‚ β”œβ”€β”€ factions.$factionId.tsx # Faction detail (stats, form, history) +β”‚ β”œβ”€β”€ venues.tsx # Venue directory (all sectors) +β”‚ └── venues.$venueId.tsx # Venue detail (modifiers, match history) +└── schedule.tsx # Upcoming match schedule +``` + +### 3.2 Route Definitions with Validated Search Params + +Every route enforces typed search params via Zod validators per AGENTS.md Rule A. + +```tsx +// ─── / (Grid Overview Dashboard) ─── +export const Route = createFileRoute('/')({ + validateSearch: z.object({ + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(), + currency: z.enum(['Latinum', 'Credits']).default('Latinum'), + }), +}) + +// ─── /quadrants (Quadrant Match Listing) ─── +export const Route = createFileRoute('/quadrants/')({ + validateSearch: z.object({ + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(), + status: z.enum(['LIVE', 'PRE_MATCH', 'RESOLVING', 'all']).default('all'), + currency: z.enum(['Latinum', 'Credits']).default('Latinum'), + sort: z.enum(['shields', 'yield', 'newest', 'ending']).default('newest'), + }), +}) + +// ─── /quadrants/$sectorId (Live Match Detail) ─── +export const Route = createFileRoute('/quadrants/$sectorId')({ + validateSearch: z.object({ + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']), + currency: z.enum(['Latinum', 'Credits']).default('Latinum'), + marketCategory: z.enum(['primary', 'secondary', 'exotic', 'all']).default('all'), + }), +}) + +// ─── /ledger (Wager Ledger) ─── +export const Route = createFileRoute('/ledger/')({ + validateSearch: z.object({ + status: z.enum(['active', 'settled', 'all']).default('all'), + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(), + currency: z.enum(['Latinum', 'Credits']).default('Latinum'), + page: z.number().default(1), + }), +}) + +// ─── /registry/factions (Faction Directory) ─── +export const Route = createFileRoute('/registry/factions')({ + validateSearch: z.object({ + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(), + type: z.enum(['aggressive', 'defensive', 'tactical', 'infiltrator', 'swarm']).optional(), + sort: z.enum(['name', 'attack', 'shield', 'evasion', 'winrate']).default('name'), + }), +}) + +// ─── /registry/venues (Venue Directory) ─── +export const Route = createFileRoute('/registry/venues')({ + validateSearch: z.object({ + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(), + sort: z.enum(['name', 'shield_mod', 'damage_mod', 'chaos']).default('name'), + }), +}) + +// ─── /schedule (Upcoming Matches) ─── +export const Route = createFileRoute('/schedule')({ + validateSearch: z.object({ + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(), + currency: z.enum(['Latinum', 'Credits']).default('Latinum'), + }), +}) +``` + +--- + +## 4. Page Designs + +### 4.1 Grid Overview Dashboard (`/`) + +The landing page β€” a high-density terminal dashboard showing all active engagements at a glance. + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ [ CONSOLE TERMINAL ] Active Feeds β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ > SUBSPACE BROADCAST β€” LIVE ENGAGEMENTS ACROSS ALL QUADRANTS β”‚ +β”‚ ════════════════════════════════════════════════════════════ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€ FILTER ─────────────────────────────────────────────────┐ β”‚ +β”‚ β”‚ [ALL] [Ξ± ALPHA] [Ξ² BETA] [Ξ³ GAMMA] [Ξ΄ DELTA] β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ SECTOR 001 β€” EARTH ORBITAL ARRAY ●LIVE Ξ± β”‚ β”‚ +β”‚ β”‚ β—† Starfleet Command 62% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘ VS β”‚ β”‚ +β”‚ β”‚ β–ˆ Borg Collective 71% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘ β”‚ β”‚ +β”‚ β”‚ ────────────────────────────────────────────────── β”‚ β”‚ +β”‚ β”‚ KY: 14.7 TW TICK: 42/90 ODDS: SFC 2.85 | BRG 1.48 β”‚ +β”‚ β”‚ β–Έ 6 MARKETS OPEN [VIEW] β†’ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ THE BADLANDS β€” PLASMA STORM ZONE ●LIVE Ξ± β”‚ β”‚ +β”‚ β”‚ β–Ό Cardassian Union 48% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘ VS β”‚ β”‚ +β”‚ β”‚ ☼ Bajoran Militia 55% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘ β”‚ β”‚ +β”‚ β”‚ ────────────────────────────────────────────────── β”‚ β”‚ +β”‚ β”‚ KY: 8.2 TW TICK: 31/75 ODDS: CRD 2.10 | BAJ 1.72 β”‚ +β”‚ β”‚ β–Έ 8 MARKETS OPEN [VIEW] β†’ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ NARENDRA III β€” HONOR'S EDGE β—‹PRE Ξ² β”‚ β”‚ +β”‚ β”‚ βš” Klingon Empire VS β”‚ β”‚ +β”‚ β”‚ β—ˆ Romulan Star Empire β”‚ β”‚ +β”‚ β”‚ ────────────────────────────────────────────────── β”‚ β”‚ +β”‚ β”‚ COMMENCING IN: 00:47 PRE-MATCH ODDS AVAILABLE β”‚ β”‚ +β”‚ β”‚ β–Έ 4 MARKETS OPEN [VIEW] β†’ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€ LIVE TICKER ──────────────────────────────────────────┐ β”‚ +β”‚ β”‚ 14:32 Borg Adaptation triggered β€” Damage reduced 50% β”‚ β”‚ +β”‚ β”‚ 14:30 Critical Hit! Starfleet deals 3Γ— damage β”‚ β”‚ +β”‚ β”‚ 14:28 Bajor: Prophet Intervention β€” Markets SUSPENDED β”‚ β”‚ +β”‚ β”‚ 14:25 New match: Klingons vs Romulans @ Narendra III β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +**Key features:** +- Match summary cards with inline shield bars and headline odds +- Quadrant filter tabs (search param `?quadrant=alpha`) +- Live event ticker scrolling recent events from ALL active matches +- Pre-match cards show countdown timer instead of combat data +- Each card links to `/quadrants/$sectorId` + +### 4.2 Match Detail Page (`/quadrants/$sectorId`) + +The most important page β€” full live match view with all markets. + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ [ ENGAGEMENT MATRIX ] Wolf 359 β€” Memorial Perimeter β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ β”Œβ”€ VERSUS ARENA ────────────────────────────────────────────┐ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β—† STARFLEET COMMAND β–ˆ BORG COLLECTIVE β”‚ β”‚ +β”‚ β”‚ [SFC] [BRG] β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ SHIELDS 62% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘ 71% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘ SHIELDS β”‚ β”‚ +β”‚ β”‚ ATTACK 58 99 ATTACK β”‚ β”‚ +β”‚ β”‚ EVASION 40 12 EVASION β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ ─────────── ✦ VS ✦ ────────── β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ KINETIC YIELD: 14.7 TW TICK: 42 / 90 β”‚ β”‚ +β”‚ β”‚ VENUE: Wolf 359 [debris-field, high-anomaly] β”‚ β”‚ +β”‚ β”‚ SHIELD MOD: 0.95 DMG MOD: 1.10 EVA MOD: 0.80 β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€ ACTIVE EFFECTS ──────────────────────────────────────────┐ β”‚ +β”‚ β”‚ ⚑ BORG ADAPTATION (BRG) β€” Incoming damage Γ—0.5 [3/5] β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€ FILTER ───────────────────────────────────────────────────┐ β”‚ +β”‚ β”‚ [ALL] [PRIMARY] [SECONDARY] [EXOTIC] β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€ MARKETS ─────────────────────────────────────────────────┐ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ COMBAT RESOLUTION β€” MONEYLINE [primary] β”‚ β”‚ +β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ +β”‚ β”‚ β”‚ β—† Starfleet Victory β”‚ β–ˆ Borg Assimilation β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ [2.85] β–² β”‚ [1.48] β–Ό β”‚ β”‚ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ FIRST SHIELD BREACH [primary] β”‚ β”‚ +β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ +β”‚ β”‚ β”‚ β—† SFC Shields First β”‚ β–ˆ BRG Shields First β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ [1.65] β–Ό β”‚ [2.20] β–² β”‚ β”‚ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ TOTAL KINETIC YIELD [primary] β”‚ β”‚ +β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ +β”‚ β”‚ β”‚ Over 8.5 TW β”‚ Under 8.5 TW β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ [1.35] β–Ό β”‚ [3.10] β–² β”‚ β”‚ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ COMEBACK VICTORY [exotic] β”‚ β”‚ +β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ +β”‚ β”‚ β”‚ β—† SFC 30+ Comeback β”‚ β–ˆ BRG 30+ Comeback β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ [5.50] β”‚ [8.20] β–² β”‚ β”‚ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ MUTUAL DESTRUCTION [exotic] β”‚ β”‚ +β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ +β”‚ β”‚ β”‚ Both Shields 0% β”‚ Survivor β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ [12.00] β”‚ [1.05] β”‚ β”‚ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€ ENGAGEMENT LOG ──────────────────────────────────────────┐ β”‚ +β”‚ β”‚ [T42] β—† Starfleet fires β€” HIT β€” 4.2% shield damage β”‚ β”‚ +β”‚ β”‚ [T42] β–ˆ Borg fires β€” MISS β€” Evasion successful β”‚ β”‚ +β”‚ β”‚ [T38] ⚑ EVENT: Borg Adaptation β€” Incoming dmg Γ—0.5 β”‚ β”‚ +β”‚ β”‚ [T35] β—† Starfleet fires β€” CRIT β€” 12.6% shield damage β”‚ β”‚ +β”‚ β”‚ [T31] πŸŒ€ EVENT: Debris Impact β€” BRG shields -12% β”‚ β”‚ +β”‚ β”‚ [T28] β–ˆ Borg fires β€” HIT β€” 6.1% shield damage β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +**Key features:** +- Versus arena header with full faction stats, shield bars, and active effects +- Venue modifier display (so bettors understand the environment) +- Market category filter tabs (search param `?marketCategory=primary`) +- Each market selection is a clickable button that adds to betslip +- Price trend indicators (β–² up / β–Ό down) with color coding +- Engagement log showing tick-by-tick combat events +- Market suspension overlay when `SUBSPACE INTERRUPTION` event fires + +### 4.3 Betslip Sidecar (Right Panel β€” always visible) + +The betslip is NOT a route β€” it's a persistent panel in the root layout, managed via React context or a lightweight client store. + +``` +╔══════════════════════════════════╗ +β•‘ [ WAGER SLIP ] Secure Link β•‘ +╠══════════════════════════════════╣ +β•‘ β•‘ +β•‘ SELECTIONS (2) β•‘ +β•‘ ════════════════════════════ β•‘ +β•‘ β•‘ +β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘ +β•‘ β”‚ Wolf 359 β€” SFC vs BRG β”‚ β•‘ +β•‘ β”‚ β—† Starfleet Victory β”‚ β•‘ +β•‘ β”‚ [2.85] [Γ—] β”‚ β•‘ +β•‘ β”‚ STAKE: [___25.00___] GPL β”‚ β•‘ +β•‘ β”‚ RETURN: 71.25 GPL β”‚ β•‘ +β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β•‘ +β•‘ β•‘ +β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘ +β•‘ β”‚ Badlands β€” CRD vs BAJ β”‚ β•‘ +β•‘ β”‚ Over 8.5 Terawatts β”‚ β•‘ +β•‘ β”‚ [1.85] [Γ—] β”‚ β•‘ +β•‘ β”‚ STAKE: [___10.00___] GPL β”‚ β•‘ +β•‘ β”‚ RETURN: 18.50 GPL β”‚ β•‘ +β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β•‘ +β•‘ β•‘ +β•‘ ═══════════════════════════════ β•‘ +β•‘ SINGLES TOTAL STAKE: 35.00 β•‘ +β•‘ POTENTIAL RETURN: 89.75 β•‘ +β•‘ β•‘ +β•‘ ─── ACCUMULATOR ────────────── β•‘ +β•‘ COMBINED ODDS: [5.27] β•‘ +β•‘ ACCA STAKE: [________] GPL β•‘ +β•‘ ACCA RETURN: 0.00 GPL β•‘ +β•‘ β•‘ +β•‘ ═══════════════════════════════ β•‘ +β•‘ β•‘ +β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β•‘ +β•‘ β”‚ β–Ά TRANSMIT WAGER β—€ β”‚ β•‘ +β•‘ β”‚ Rule of Acquisition #62 β”‚ β•‘ +β•‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β•‘ +β•‘ β•‘ +β•‘ ─── RECENT TRANSMISSIONS ───── β•‘ +β•‘ βœ“ SFC Victory @ 2.40 +36.00 β•‘ +β•‘ βœ— Over 8.5 TW @ 1.85 -10.00 β•‘ +β•‘ β—‹ BRG Victory @ 1.48 PENDING β•‘ +β•‘ β•‘ +β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• +``` + +**Key features:** +- Selections added by clicking market buttons on any match page +- Individual stake inputs per selection (singles) +- Accumulator option with combined odds +- Live price updates β€” if odds change while in betslip, show oldβ†’new with flash +- Odds lock warning if price moves significantly +- Recent bet results at the bottom +- Persistent across route changes (React context, not URL state) + +### 4.4 Wager Ledger (`/ledger`) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ [ WAGER LEDGER ] Transaction Archive β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ β”Œβ”€ FILTER ───────────────────────────────────────────────────┐ β”‚ +β”‚ β”‚ [ALL] [ACTIVE] [SETTLED] Quadrant: [ALL β–Ύ] β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€ ACCOUNT SUMMARY ─────────────────────────────────────────┐ β”‚ +β”‚ β”‚ BALANCE: 4,250.00 GPL ACTIVE RISK: 285.00 GPL β”‚ β”‚ +β”‚ β”‚ SESSION P/L: +127.50 GPL β–² β”‚ β”‚ +β”‚ β”‚ WIN RATE: 58% (14/24) AVG ODDS: 2.15 β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ ─── ACTIVE WAGERS ──────────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ #W-0042 Wolf 359 β€” SFC vs BRG ●LIVE Ξ± β”‚ β”‚ +β”‚ β”‚ Selection: β—† Starfleet Victory β”‚ β”‚ +β”‚ β”‚ Odds Taken: 2.85 Stake: 25.00 GPL β”‚ β”‚ +β”‚ β”‚ Current Odds: 3.10 Potential: 71.25 GPL β”‚ β”‚ +β”‚ β”‚ Status: OPEN β€” Shields: SFC 62% | BRG 71% β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ ─── SETTLED WAGERS ─────────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ #W-0039 Qo'noS Arena β€” KLG vs GRN βœ“ WON Ξ² β”‚ β”‚ +β”‚ β”‚ Selection: βš” Klingon Victory β”‚ β”‚ +β”‚ β”‚ Odds: 1.65 Stake: 30.00 Return: 49.50 GPL +19.50 β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ #W-0037 Badlands β€” CRD vs BAJ βœ— LOST Ξ± β”‚ β”‚ +β”‚ β”‚ Selection: Over 8.5 TW β”‚ β”‚ +β”‚ β”‚ Odds: 1.85 Stake: 10.00 Return: 0.00 GPL -10.00 β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### 4.5 Faction Registry (`/registry/factions`) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ [ FACTION REGISTRY ] Combatant Database β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ β”Œβ”€ FILTER ───────────────────────────────────────────────────┐ β”‚ +β”‚ β”‚ Quadrant: [ALL β–Ύ] Type: [ALL β–Ύ] Sort: [NAME β–Ύ] β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ GLYPH FACTION QDR TYPE SHD ATK EVA β”‚ +β”‚ ═════ ═══════════════════ ═══ ═══════════ ═══ ═══ ═══ β”‚ +β”‚ β—† Starfleet Command Ξ± defensive 92 65 50 β”‚ +β”‚ β–ˆ Borg Collective Ξ΄ swarm 95 90 15 β”‚ +β”‚ βš” Klingon Empire Ξ² aggressive 60 95 35 β”‚ +β”‚ β—ˆ Romulan Star Empire Ξ² infiltrator 72 70 85 β”‚ +β”‚ β—‰ The Dominion Ξ³ swarm 75 88 40 β”‚ +β”‚ ∞ Species 8472 Ξ΄ aggressive 99 99 70 β”‚ +β”‚ ... β”‚ +β”‚ β”‚ +β”‚ Click a faction row to view detailed profile β†’ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +Clicking a faction row navigates to `/registry/factions/$factionId`, which shows: +- Full tactical profile text +- Rivalry modifiers table +- Active matches this faction is in +- Recent match history (W/L record) +- Type advantage breakdown + +### 4.6 Venue Database (`/registry/venues`) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ [ VENUE DATABASE ] Sector Pool Registry β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ VENUE QDR SHDΓ— DMGΓ— EVAΓ— ANOMALY β”‚ +β”‚ ═══════════════════════ ════ ═════ ═════ ═════ ════════ β”‚ +β”‚ Fluidic Space Rift Ξ΄ 0.60 1.50 0.80 35% !!! β”‚ +β”‚ The Badlands Ξ± 0.70 1.30 0.60 35% !!! β”‚ +β”‚ Founders' Approach Ξ³ 0.85 1.10 0.60 40% !!! β”‚ +β”‚ Qo'noS Arena Ξ² 0.80 1.25 0.95 8% β”‚ +β”‚ Vulcan Defense Grid Ξ± 1.20 0.85 1.00 3% β”‚ +β”‚ Nekrit Expanse Ξ΄ 1.00 1.00 1.00 1% β”‚ +β”‚ ... β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### 4.7 Match Schedule (`/schedule`) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ [ TRANSMISSION SCHEDULE ] Upcoming Engagements β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ ─── SCHEDULED (starting soon) ──────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ T-47s Narendra III β€” Honor's Edge [Ξ²] β”‚ β”‚ +β”‚ β”‚ βš” Klingon Empire vs β—ˆ Romulan Star Empire β”‚ β”‚ +β”‚ β”‚ Rivalry: 1.30 β€” MARQUEE MATCHUP β”‚ β”‚ +β”‚ β”‚ Pre-match odds available at T-60s β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ T-2m Gornar Orbit β€” Hegemony Arena [Ξ²] β”‚ β”‚ +β”‚ β”‚ β–² Gorn Hegemony vs ⊘ Orion Syndicate β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ ─── RECENTLY SETTLED ───────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ SETTLED Vulcan Grid β€” T'Khasi Defense Grid [Ξ±] β”‚ β”‚ +β”‚ β”‚ β—† Starfleet Command 68% vs β‚² Ferengi 0% β”‚ β”‚ +β”‚ β”‚ RESULT: Starfleet Victory β€” 72 ticks β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## 5. Component Architecture + +Per AGENTS.md, route files contain only configuration. All visual markup lives in components. + +### 5.1 Component Map + +``` +src/components/ +β”œβ”€β”€ ascii/ # Low-level visual primitives +β”‚ β”œβ”€β”€ AsciiPanel.tsx # Bordered panel container (EXISTS) +β”‚ β”œβ”€β”€ ShieldBar.tsx # Horizontal shield capacity bar +β”‚ β”œβ”€β”€ PriceTag.tsx # Odds display with trend indicator +β”‚ β”œβ”€β”€ StatusBadge.tsx # LIVE/PRE/RESOLVING/SETTLED indicator +β”‚ β”œβ”€β”€ TerminalLine.tsx # Decorative separator line +β”‚ β”œβ”€β”€ BlinkingCursor.tsx # Animated cursor for loading states +β”‚ β”œβ”€β”€ TickProgress.tsx # Match progress bar (tick X / maxTicks) +β”‚ └── GlyphIcon.tsx # Faction glyph renderer with color +β”‚ +β”œβ”€β”€ panels/ # Domain feature views (large composites) +β”‚ β”œβ”€β”€ NavigationMenu.tsx # Left sidebar navigation (EXISTS) +β”‚ β”œβ”€β”€ BetslipSidecar.tsx # Right sidebar betslip +β”‚ β”œβ”€β”€ MatchCard.tsx # Summary card for dashboard grid +β”‚ β”œβ”€β”€ VersusArena.tsx # Full faction-vs-faction header +β”‚ β”œβ”€β”€ MarketGrid.tsx # All markets for a match +β”‚ β”œβ”€β”€ MarketSelection.tsx # Single clickable odds button +β”‚ β”œβ”€β”€ EngagementLog.tsx # Scrolling event log for a match +β”‚ β”œβ”€β”€ LiveTicker.tsx # Global event feed (dashboard) +β”‚ β”œβ”€β”€ FactionTable.tsx # Sortable faction directory table +β”‚ β”œβ”€β”€ VenueTable.tsx # Sortable venue directory table +β”‚ β”œβ”€β”€ FactionProfile.tsx # Detailed faction stats view +β”‚ β”œβ”€β”€ WagerCard.tsx # Single bet display (active or settled) +β”‚ β”œβ”€β”€ AccountSummary.tsx # Balance, P/L, win rate stats +β”‚ β”œβ”€β”€ ScheduleCard.tsx # Upcoming/settled match card +β”‚ └── QuadrantFilterBar.tsx # Reusable quadrant filter tabs +β”‚ +└── providers/ # Client state providers + β”œβ”€β”€ BetslipProvider.tsx # Betslip selection state (React Context) + └── CurrencyProvider.tsx # Active currency preference +``` + +### 5.2 Route β†’ Component Mapping + +Routes stay thin (AGENTS.md compliance). Heavy rendering delegates to panel components. + +```tsx +// src/routes/quadrants/$sectorId.tsx β€” THIN ROUTE FILE +export const Route = createFileRoute('/quadrants/$sectorId')({ + validateSearch: z.object({ + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']), + currency: z.enum(['Latinum', 'Credits']).default('Latinum'), + marketCategory: z.enum(['primary', 'secondary', 'exotic', 'all']).default('all'), + }), + loader: async ({ params }) => { + const snapshot = await getCachedSectorData({ input: params.sectorId }) + return { snapshot } + }, + component: MatchDetailView, // ← delegates to panel +}) + +// The actual MatchDetailView component lives in src/components/panels/ +// It composes: VersusArena + MarketGrid + EngagementLog +``` + +--- + +## 6. Data Flow & Server Functions + +### 6.1 Server Function Registry + +``` +src/server/ +β”œβ”€β”€ db/ +β”‚ └── valkeyConnector.ts # Valkey client instance +└── functions/ + β”œβ”€β”€ getActiveMatchIndex.ts # All active match summaries (sidebar) + β”œβ”€β”€ getMatchTelemetry.ts # Full match state for detail page + β”œβ”€β”€ getUpcomingSchedule.ts # Scheduled matches + β”œβ”€β”€ getSettledMatches.ts # Recently settled results + β”œβ”€β”€ getFactionRegistry.ts # Static faction data from taxonomy + β”œβ”€β”€ getVenueRegistry.ts # Static venue data from taxonomy + └── submitWager.ts # Place a bet (write to Valkey) +``` + +### 6.2 Polling Strategy + +| Data | Interval | Source | Route | +|------|----------|--------|-------| +| Active match index (sidebar) | 2s | `sector:index:active` | `__root.tsx` (always) | +| Match telemetry (detail page) | 2s | `sector:telemetry:{id}` | `/quadrants/$sectorId` | +| Match events (detail page) | 2s | `sector:events:{id}` | `/quadrants/$sectorId` | +| Dashboard match cards | 2s | All active telemetry | `/` | +| Schedule | 10s | `sector:schedule:upcoming` | `/schedule` | +| Faction/venue registry | Static | `taxonomy.yaml` (cached) | `/registry/*` | +| Betslip price updates | 2s | Individual market keys | `BetslipSidecar` | + +### 6.3 SSR + Client Hydration Pattern + +```tsx +// Pattern for all live data routes: + +// 1. Loader runs on server β€” fetches initial snapshot from Valkey +loader: async ({ params }) => { + return await getCachedSectorData({ input: params.sectorId }) +}, + +// 2. Component hydrates with loader data, then starts client polling +function MatchDetailView() { + const initialData = Route.useLoaderData() + + const { data } = useQuery({ + queryKey: ['telemetry', sectorId], + queryFn: () => getCachedSectorData({ input: sectorId }), + initialData, // SSR data used immediately + refetchInterval: 2000, // Client polls every 2s after hydration + }) +} +``` + +--- + +## 7. Client State Management + +Only two pieces of state live on the client (not URL, not server): + +### 7.1 Betslip State (React Context) + +```tsx +interface BetslipSelection { + matchId: string + matchName: string + marketId: string + selectionName: string + price: number // Price when added + currentPrice: number // Live price (updated by polling) + stake: number // User-entered stake + factionGlyph: string +} + +interface BetslipState { + selections: BetslipSelection[] + addSelection: (sel: BetslipSelection) => void + removeSelection: (marketId: string) => void + updateStake: (marketId: string, stake: number) => void + clearAll: () => void + accumulatorStake: number + setAccumulatorStake: (stake: number) => void +} +``` + +### 7.2 Currency Preference + +Currency is tracked in URL search params (`?currency=Latinum`) per AGENTS.md deterministic URL state rule β€” NOT in client state. The `CurrencyProvider` simply reads from the URL. + +--- + +## 8. Route Transition Map + +```mermaid +graph TD + ROOT["__root.tsx
(always rendered)"] + + DASH["/ Dashboard
Grid Overview"] + QUAD_LIST["/quadrants
Filtered Match List"] + MATCH["/quadrants/$sectorId
Live Match Detail"] + + LEDGER["/ledger
Wager Overview"] + ACTIVE["/ledger/active
Open Wagers"] + SETTLED["/ledger/settled
Settled History"] + + FACTIONS["/registry/factions
All Factions"] + FACTION_D["/registry/factions/$id
Faction Profile"] + VENUES["/registry/venues
All Venues"] + VENUE_D["/registry/venues/$id
Venue Profile"] + + SCHED["/schedule
Upcoming Matches"] + + ROOT --> DASH + ROOT --> QUAD_LIST + ROOT --> MATCH + ROOT --> LEDGER + ROOT --> SCHED + ROOT --> FACTIONS + ROOT --> VENUES + + DASH -->|"click match card"| MATCH + QUAD_LIST -->|"click match"| MATCH + SCHED -->|"click scheduled"| MATCH + + LEDGER --> ACTIVE + LEDGER --> SETTLED + ACTIVE -->|"click match ref"| MATCH + + FACTIONS --> FACTION_D + FACTION_D -->|"click active match"| MATCH + VENUES --> VENUE_D + VENUE_D -->|"click active match"| MATCH + + MATCH -->|"click market selection"| BETSLIP["Betslip (context, not route)"] + + style MATCH fill:#34d399,color:#000 + style BETSLIP fill:#fbbf24,color:#000 + style DASH fill:#38bdf8,color:#000 +``` diff --git a/reference/PROJECT.md b/reference/PROJECT.md new file mode 100644 index 0000000..ee2ab7c --- /dev/null +++ b/reference/PROJECT.md @@ -0,0 +1,584 @@ +Here is a complete, self-containedΒ `REFERENCE.md`Β file that captures the entire system architecture. It bridges your plaintext TanStack Start frontend with a high-performanceΒ **Go-based data loader**Β streaming rawΒ **YAML telemetry**Β into aΒ **Valkey**Β cache (the open-source, high-performance successor to Redis). + +You can save this file locally to use as your architectural blueprint. + +### `REFERENCE.md` + +Markdown + +```` +# Architectural Reference: Quark's Holo-Grid Ledger + +This document serves as the absolute technical reference for the intergalactic terminal sportsbook. The architecture uses a three-tier design to handle high-frequency data streams safely and efficiently: +1. **Data Layer**: Flat YAML configuration files mimicking raw sub-atomic telemetry. +2. **Ingestion Layer (Go)**: A high-performance Go routine that parses YAML files and pushes records continuously into a Valkey cache instance. +3. **Application Layer (TanStack Start)**: A type-safe, server-rendered frontend pulling directly from Valkey via server functions and background synchronization hooks. + +--- + +## 1. System Topology + +```mermaid +graph LR + subgraph Data Layer + A[(telemetry.yaml)] + + subgraph Ingestion Layer + B[Go Ingestion Worker] + end + subgraph Cache Layer + C[(Valkey Cache Instance)] + end + subgraph Presentation Layer + D[TanStack Start SSR Server] --> E[Browser Terminal UI] + end + + A --> B + B -- HSET / LPUSH --> C + C -- READ --> D +```` + +## 2. Data Layer: Telemetry YAML Layout + +Place these static definition assets under theΒ `./data-source/`Β directory root. + +### File:Β `./data-source/sectors.yaml` + +YAML + +``` +sectors: + - id: "sector-001" + name: "Sector 001 (Earth Array)" + quadrant: "Alpha" + initial_shield_capacity: 100 + kinetic_yield: 4.2 + status: "LIVE" + markets: + - id: "s1-over" + name: "Kinetic Yield Over 8.5 TW" + initial_price: 1.85 + - id: "s1-under" + name: "Kinetic Yield Under 8.5 TW" + initial_price: 1.95 + + - id: "wolf-359" + name: "Wolf 359 Outpost" + quadrant: "Alpha" + initial_shield_capacity: 34 + kinetic_yield: 12.8 + status: "LIVE" + markets: + - id: "w359-fail" + name: "Total Shield Failure" + initial_price: 1.40 + - id: "w359-hold" + name: "Defenses Hold Perimeter" + initial_price: 2.80 +``` + +## 3. Ingestion Layer: Go Worker Utility + +This Go engine handles parsing the local YAML file, calculating artificial odds fluctuations, and writing live JSON payloads directly intoΒ **Valkey**Β using standard Redis protocol definitions via theΒ `go-redis/v9`Β driver. + +### File:Β `./ingestion-engine/main.go` + +Go + +``` +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "math/rand" + "os" + "time" + + "[github.com/redis/go-redis/v9](https://github.com/redis/go-redis/v9)" + "gopkg.in/yaml.v3" +) + +type Market struct { + ID string `yaml:"id" json:"id"` + Name string `yaml:"name" json:"name"` + Price float64 `yaml:"initial_price" json:"price"` + Trend string `json:"trend"` +} + +type Sector struct { + ID string `yaml:"id" json:"id"` + Name string `yaml:"name" json:"name"` + Quadrant string `yaml:"quadrant" json:"quadrant"` + ShieldCapacity int `yaml:"initial_shield_capacity" json:"shieldCapacity"` + KineticYield float64 `yaml:"kinetic_yield" json:"kinetic_yield"` + Status string `yaml:"status" json:"status"` + Markets []Market `yaml:"markets" json:"markets"` +} + +type Config struct { + Sectors []Sector `yaml:"sectors"` +} + +var ctx = context.Background() + +func main() { + // 1. Connect to Valkey (Using standard Redis protocol port 6379) + valkeyClient := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // Default empty + DB: 0, // Default DB + }) + + // Test connection + if err := valkeyClient.Ping(ctx).Err(); err != nil { + log.Fatalf("Critical: Could not resolve Valkey connection: %v", err) + } + fmt.Println("> Subspace Comms Link to Valkey established.") + + // 2. Read and parse the YAML file + yamlFile, err := os.ReadFile("../data-source/sectors.yaml") + if err != nil { + log.Fatalf("Error reading target file definitions: %v", err) + } + + var config Config + if err := yaml.Unmarshal(yamlFile, &config); err != nil { + log.Fatalf("Error parsing configuration details: %v", err) + } + + // 3. Fire the Ingestion Loop Simulation + ticker := time.NewTicker(2000 * time.Millisecond) + defer ticker.Stop() + + fmt.Println("> Telemetry engine loop initiated. Streaming telemetry logs...") + + for range ticker.C { + for i := range config.Sectors { + sector := &config.Sectors[i] + + // Fluctuate shield capacities artificially + shieldChange := rand.Intn(5) - 2 // -2 to +2 + sector.ShieldCapacity += shieldChange + if sector.ShieldCapacity > 100 { + sector.ShieldCapacity = 100 + } else if sector.ShieldCapacity < 0 { + sector.ShieldCapacity = 0 + } + + // Modulate marker coefficients + for j := range sector.Markets { + market := §or.Markets[j] + priceShift := (rand.Float64() * 0.2) - 0.1 // -0.10 to +0.10 + oldPrice := market.Price + market.Price = oldPrice + priceShift + + if market.Price < 1.05 { + market.Price = 1.05 + } + + if market.Price > oldPrice { + market.Trend = "up" + } else if market.Price < oldPrice { + market.Trend = "down" + } else { + market.Trend = "stable" + } + } + + // Marshall state to absolute JSON for application caching efficiency + jsonPayload, err := json.Marshal(sector) + if err != nil { + log.Printf("Error marshalling schema object: %v", err) + continue + } + + // Push atomic updates directly into Valkey hash set + key := fmt.Sprintf("sector:telemetry:%s", sector.ID) + err = valkeyClient.Set(ctx, key, jsonPayload, 0).Err() + if err != nil { + log.Printf("Valkey stream pipeline transmission error: %v", err) + } + } + log.Println(">> Atomic telemetry matrix block sent to Valkey pipeline cluster.") + } +} +``` + +## 4. Application Layer: Reading from Valkey in TanStack Start + +Your frontend reads directly from the cache pool inside server execution limits. This guarantees sub-millisecond data delivery times to the rendering layer. + +First, make sure you have standard client integration parameters ready (`npm i ioredis`). + +### File:Β `./src/server/db/valkeyConnector.ts` + +TypeScript + +``` +import Redis from 'ioredis' + +// Connect to local Valkey instance over port 6379 +export const valkey = new Redis({ + host: '127.0.0.1', + port: 6379, +}) + +export async function fetchLiveSectorFromCache(sectorId: string) { + const data = await valkey.get(`sector:telemetry:${sectorId}`) + if (!data) return null + return JSON.parse(data) +} +``` + +### File:Β `./src/routes/quadrants/$sectorId.tsx` + +TypeScript + +``` +import { createFileRoute } from '@tanstack/react-router' +import { useQuery } from '@tanstack/react-query' +import { fetchLiveSectorFromCache } from '../../server/db/valkeyConnector' +import { createServerFn } from '@tanstack/react-start' + +// Server RPC definition boundary +const getCachedSectorData = createServerFn({ method: 'GET' }) + .input(String) + .handler(async ({ input: sectorId }) => { + return await fetchLiveSectorFromCache(sectorId) + }) + +export const Route = createFileRoute('/quadrants/$sectorId')({ + loader: async ({ params }) => { + const initialSnapshot = await getCachedSectorData({ input: params.sectorId }) + return { initialSnapshot } + }, + component: TerminalGridPane, +}) + +function TerminalGridPane() { + const { initialSnapshot } = Route.useLoaderData() + const { sectorId } = Route.useParams() + + // High-frequency client polling strategy linking right back to Valkey keyspaces + const { data: sector } = useQuery({ + queryKey: ['live-telemetry', sectorId], + queryFn: () => getCachedSectorData({ input: sectorId }), + initialData: initialSnapshot, + refetchInterval: 2000, + }) + + if (!sector) return
> ERROR: MATRIX SYNC COMPROMISED
+ + return ( +
+

> COGNITIVE STREAM: {sector.name}

+
+

QUADRANT TELEMETRY: {sector.quadrant}

+

SHIELD EFFICIENCY: {sector.shieldCapacity}%

+
+ + {/* Dynamic Betting Selections Render */} +
+ {sector.markets.map((m: any) => ( + + ))} +
+
+ ) +} +``` + +To bring factions into your data, you just need to explicitly name the two competing forces inside yourΒ **Sectors**. In a sportsbook, these are yourΒ **Home Team**Β andΒ **Away Team**Β (or Competitor A and Competitor B). + +By adding aΒ `factions`Β object to your data model, your Go engine can calculate specific tactical advantages, and your TanStack Start frontend can render a trueΒ _"Versus"_Β scoreboard layout. + +Here is how you inject factions across your entire architecture. + +## 1. Update the Data Layer (`data-source/sectors.yaml`) + +Add aΒ `factions`Β object to each sector inside your YAML file. Give each faction a clear name and track their individual shield capacities separately instead of having just one global shield score. + +YAML + +``` +sectors: + - id: "sector-001" + name: "Sector 001 (Earth Array)" + quadrant: "Alpha" + kinetic_yield: 4.2 + status: "LIVE" + factions: + home: + name: "Starfleet Command" + shield_capacity: 100 + away: + name: "The Borg Collective" + shield_capacity: 100 + markets: + - id: "s1-home-win" + name: "Starfleet Victory" + initial_price: 2.10 + - id: "s1-away-win" + name: "Borg Assimilation" + initial_price: 1.65 +``` + +## 2. Update the Go Ingestion Engine (`main.go`) + +Now, update your Go structs to parse these factions, and modify the engine loop so the factions actively damage each other's shields. + +Go + +``` +type Faction struct { + Name string `yaml:"name" json:"name"` + ShieldCapacity int `yaml:"shield_capacity" json:"shieldCapacity"` +} + +type FactionsSchema struct { + Home Faction `yaml:"home" json:"home"` + Away Faction `yaml:"away" json:"away"` +} + +type Sector struct { + ID string `yaml:"id" json:"id"` + Name string `yaml:"name" json:"name"` + Quadrant string `yaml:"quadrant" json:"quadrant"` + KineticYield float64 `yaml:"kinetic_yield" json:"kinetic_yield"` + Status string `yaml:"status" json:"status"` + Factions FactionsSchema `yaml:"factions" json:"factions"` + Markets []Market `yaml:"markets" json:"markets"` +} + +// Inside the background loop, simulate combat between the factions: +for i := range config.Sectors { + sector := &config.Sectors[i] + + // Randomly choose which faction takes a hit this tick + if rand.Float64() > 0.5 { + sector.Factions.Home.ShieldCapacity -= rand.Intn(8) // Borg fires on Starfleet + } else { + sector.Factions.Away.ShieldCapacity -= rand.Intn(5) // Starfleet fires on Borg + } + + // Clamp values between 0 and 100 + if sector.Factions.Home.ShieldCapacity < 0 { sector.Factions.Home.ShieldCapacity = 0 } + if sector.Factions.Away.ShieldCapacity < 0 { sector.Factions.Away.ShieldCapacity = 0 } + + // Dynamically shift odds based on who has higher shields + for j := range sector.Markets { + market := §or.Markets[j] + // If Home shields drop below Away shields, increase Home odds multiplier (underdog status) + if sector.Factions.Home.ShieldCapacity < sector.Factions.Away.ShieldCapacity { + if market.ID == "s1-home-win" { market.Price += 0.05 } + } + } +} +``` + +## 3. Render the Confrontation in the UI (`$sectorId.tsx`) + +Now that Valkey is serving the detailed faction data, you can build a plaintext split-panel scoreboard at the top of your main grid layout. + +TypeScript + +``` +function SectorConsoleView() { + const { sectorId } = Route.useParams() + const { data: sector } = useQuery({ + queryKey: ['live-telemetry', sectorId], + queryFn: () => getCachedSectorData({ input: sectorId }), + refetchInterval: 2000, + }) + + if (!sector) return
> ACCESSING SYSTEM NET...
+ + return ( +
+ {/* Dynamic Versus Arena Header */} +
+
ENGAGEMENT MATRIX // {sector.name}
+ +
+ {/* Home Faction */} +
+ {sector.factions.home.name} + SHD: {sector.factions.home.shieldCapacity}% +
+ + {/* VS Divider */} +
VS
+ + {/* Away Faction */} +
+ {sector.factions.away.name} + SHD: {sector.factions.away.shieldCapacity}% +
+
+ + {/* Global Match Clock / Energy Tracker */} +
+ TOTAL ENERGY RELEASED: + {sector.kinetic_yield.toFixed(1)} TW +
+
+ + {/* Markets Selection Grid sits underneath this header view */} +
+ ) +} +``` + +Here is your consolidated, terminal-ready command dictionary mapping ourΒ **Star Trek Telemetry**Β to standardΒ **Sportsbook Architecture**: + +| **Space-Grid Term** | **Real-World Sportsbook Translation** | **Practical Example** | +| ------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| **Quadrant** | **Sport Category / League** | _Alpha Quadrant_Β (Matches your top-level category menu, like filtering for Premier League or NBA). | +| **Sector** | **Individual Match / Fixture** | _Sector 001_Β orΒ _Wolf 359_Β (The active "game page" where an event is currently happening). | +| **Factions** | **Teams / Contenders** | _Starfleet Command (Home)_Β vs.Β _The Borg Collective (Away)_Β (The competitors squaring off inside the arena). | +| **Shield Capacity** | **Live Defensive Metric / Health** | _Starfleet Shields: 74%_Β (Acts like an active match timeline indicator, showing which side is taking damage or losing control). | +| **Kinetic Yield** | **Live In-Play Match Score** | _14.2 Terawatts released_Β (The cumulative scoreboard counter that grows as action happens, like total points scored). | +| **Market** | **Betting Line / Wager Type** | _Faction Victory_Β orΒ _Total Kinetic Yield Over/Under_Β (The explicit proposal lines a user risks their Latinum on). | +| **Latinum** | **Account Balance Base Currency** | _Gold-Pressed Latinum_Β (The account balance backing your betslip tokens). | +| **Subspace Interruption** | **Odds Change Suspended Lockout** | _Market Suspended_Β (The background Valkey cache triggers an automatic input lockout when a sudden scoring event happens). | + +To generate a continuous, realistic stream of sports matches (Sectors) and betting options (Markets), you shouldn't hardcode individual events. Instead, you need a stable, staticΒ **Taxonomy Base Data**Β file. + +Think of this base taxonomy file as a template library. Your Go ingestion engine will read this library, pick two opposing factions, assign them a sector arena, and generate the live match data dynamically. + +Here is the structured YAML blueprint for your taxonomy database and how the generation engine maps it out. + +## 1. The Core Taxonomy Configuration (`data-source/taxonomy.yaml`) + +This file holds your static master rules. It defines what factions exist, which quadrants they belong to, their natural rivalries, and standard betting templates. + +YAML + +``` +# data-source/taxonomy.yaml + +quadrants: + - id: "alpha" + name: "Alpha Quadrant" + factions: + - id: "starfleet" + name: "Starfleet Command" + type: "defensive" + - id: "borg" + name: "The Borg Collective" + type: "aggressive" + - id: "cardassians" + name: "Cardassian Union" + type: "tactical" + + - id: "beta" + name: "Beta Quadrant" + factions: + - id: "klingons" + name: "Klingon Empire" + type: "aggressive" + - id: "romulans" + name: "Romulan Star Empire" + type: "tactical" + +# Standard templates used by the generator to instantiate structural betting lines +market_templates: + - id: "match-outcomes" + name: "Combat Resolution" + selections: + - type: "home-win" + suffix: "Decisive Victory" + - type: "away-win" + suffix: "Decisive Victory" + + - id: "kinetic-over-under" + name: "Total Kinetic Yield" + selections: + - type: "over" + name: "Over 8.5 Terawatts" + base_price: 1.85 + - type: "under" + name: "Under 8.5 Terawatts" + base_price: 1.85 + +# A list of location names the engine can pick to host matches +sector_pool: + - id: "wolf-359" + name: "Wolf 359 Outpost" + quadrant: "alpha" + - id: "sector-001" + name: "Sector 001 (Earth Core)" + quadrant: "alpha" + - id: "narendra-3" + name: "Narendra III Outpost" + quadrant: "beta" +``` + +## 2. The Generation Blueprint: From Rules to Live Data + +When your Go ingestion engine spins up, it loops through this taxonomy file to generate actual live events using an instantiation pattern: + +Plaintext + +``` + [ TAXONOMY DEFINITION ] + β”‚ + β–Ό (Go Generator Engine) + 1. Pick Location: "Wolf 359" (Alpha) + 2. Pick Home Faction: "Starfleet Command" + 3. Pick Away Faction: "The Borg Collective" + 4. Hydrate Market Templates: Substitute Faction names into strings + β”‚ + β–Ό + [ LIVE VALKEY DATA STRUCTURE ] +``` + +## 3. The Go Generation Logic (Conceptual Snippet) + +This is how your Go ingestion worker takes the abstract templates fromΒ `taxonomy.yaml`Β and handles generating real live event instances: + +Go + +``` +// Psuedocode for the Go template instantiation loop +func GenerateLiveEvent(location SectorPoolItem, home Faction, away Faction, templates []MarketTemplate) Sector { + var generatedMarkets []Market + + for _, tmpl := range templates { + if tmpl.ID == "match-outcomes" { + generatedMarkets = append(generatedMarkets, Market{ + ID: location.ID + "-moneyline-home", + Name: home.Name + " " + tmpl.Selections[0].Suffix, // "Starfleet Command Decisive Victory" + Price: 2.00, // Balanced starting base odds + }) + generatedMarkets = append(generatedMarkets, Market{ + ID: location.ID + "-moneyline-away", + Name: away.Name + " " + tmpl.Selections[1].Suffix, // "The Borg Collective Decisive Victory" + Price: 1.80, // Borg slight favorite based on aggressive profile + }) + } + } + + return Sector{ + ID: location.ID, + Name: location.Name, + Quadrant: location.Quadrant, + Status: "LIVE", + Factions: FactionsSchema{ + Home: FactionState{Name: home.Name, ShieldCapacity: 100}, + Away: FactionState{Name: away.Name, ShieldCapacity: 100}, + }, + Markets: generatedMarkets, + } +} +``` + +By organizing your database logic this way, you can add new teams (factions) or new stadiums (sectors) directly to yourΒ `taxonomy.yaml`Β file without altering a single line of your Go simulation logic or your TanStack Start React components. Everything down the wire becomes purely data-driven! \ No newline at end of file diff --git a/tongo-core/Makefile b/tongo-core/Makefile new file mode 100644 index 0000000..9d7560d --- /dev/null +++ b/tongo-core/Makefile @@ -0,0 +1,36 @@ +.PHONY: build run validate test clean fmt lint + +BINARY_NAME=tongo +GO=go + +## build: Compile the Tongo Core binary +build: + $(GO) build -o bin/$(BINARY_NAME) ./cmd/tongo + +## run: Build and run the simulation daemon +run: build + ./bin/$(BINARY_NAME) serve + +## validate: Validate the taxonomy configuration +validate: build + ./bin/$(BINARY_NAME) validate + +## test: Run all tests +test: + $(GO) test ./... -v + +## clean: Remove build artifacts +clean: + rm -rf bin/ + +## fmt: Format all Go source files +fmt: + $(GO) fmt ./... + +## lint: Run go vet +lint: + $(GO) vet ./... + +## help: Show this help +help: + @grep -E '^## ' Makefile | sed 's/## //' | column -t -s ':' diff --git a/tongo-core/README.md b/tongo-core/README.md new file mode 100644 index 0000000..3511b15 --- /dev/null +++ b/tongo-core/README.md @@ -0,0 +1,47 @@ +# 🎰 TONGO CORE + +Tongo Core is the Star Trek-inspired live simulation and probability engine powering **Quark's Holo-Grid Ledger**. It operates as a background daemon, simulating active space-grid combat, generating random in-play events, recalculating live market odds, and writing JSON telemetry directly to Valkey for client-side consumption. + +--- + +## πŸ› Architecture: Onion Clean Architecture + +The engine uses a strict clean architecture (onion pattern) with clean separation between layers: + +- **Domain Layer (`internal/domain/`)**: Pure domain models (`entity/`) and output/input interface definitions (`port/`). Free of external frameworks or dependencies. +- **Application Layer (`internal/application/`)**: Application services coordinating domain logic (match scheduling, combat resolution, probability calculation, markets). +- **Infrastructure Layer (`internal/infrastructure/`)**: Concrete implementations of ports (Valkey adapter, YAML loader, Viper config). + +--- + +## πŸš€ Getting Started + +### Prerequisites + +- Go 1.23+ +- Valkey or Redis running on port 6379 + +### Commands + +Run using the `Makefile`: + +```bash +# Build the binary +make build + +# Run the simulation daemon +make run + +# Validate taxonomy config +make validate + +# Run tests +make test +``` + +### CLI Interface + +Direct CLI commands: +- `tongo serve`: Start the simulation engine daemon. +- `tongo validate`: Parse and check structure of `taxonomy.yaml`. +- `tongo version`: Display current version. diff --git a/tongo-core/bin/tongo b/tongo-core/bin/tongo new file mode 100755 index 0000000..2e5dc1f Binary files /dev/null and b/tongo-core/bin/tongo differ diff --git a/tongo-core/cmd/tongo/cli/root.go b/tongo-core/cmd/tongo/cli/root.go new file mode 100644 index 0000000..fb3506c --- /dev/null +++ b/tongo-core/cmd/tongo/cli/root.go @@ -0,0 +1,24 @@ +package cli + +import ( + "os" + + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "tongo", + Short: "Tongo Core β€” Quark's Holo-Grid Ledger Simulation Engine", + Long: `Tongo Core is the simulation engine powering Quark's Holo-Grid Ledger. +It generates live match events, simulates combat, calculates real-time +odds, and streams telemetry data into Valkey for the frontend to consume. + +"The riskier the road, the greater the profit." β€” Rule of Acquisition #62`, +} + +// Execute runs the root cobra command. +func Execute() { + if err := rootCmd.Execute(); err != nil { + os.Exit(1) + } +} diff --git a/tongo-core/cmd/tongo/cli/serve.go b/tongo-core/cmd/tongo/cli/serve.go new file mode 100644 index 0000000..0920528 --- /dev/null +++ b/tongo-core/cmd/tongo/cli/serve.go @@ -0,0 +1,28 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var serveCmd = &cobra.Command{ + Use: "serve", + Short: "Start the Tongo Core simulation daemon", + Long: `Starts the main simulation loop. Reads taxonomy data, connects to Valkey, +and begins generating live match events on a 2-second tick cycle. + +The daemon runs until interrupted (SIGINT/SIGTERM).`, + RunE: runServe, +} + +func init() { + rootCmd.AddCommand(serveCmd) +} + +func runServe(cmd *cobra.Command, args []string) error { + fmt.Println("> Subspace Comms Link initializing...") + fmt.Println("> Tongo Core β€” Simulation Engine v0.1.0") + fmt.Println("> Awaiting implementation. All onion modules scaffolded.") + return nil +} diff --git a/tongo-core/cmd/tongo/cli/validate.go b/tongo-core/cmd/tongo/cli/validate.go new file mode 100644 index 0000000..4fd5c12 --- /dev/null +++ b/tongo-core/cmd/tongo/cli/validate.go @@ -0,0 +1,25 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var validateCmd = &cobra.Command{ + Use: "validate", + Short: "Validate the taxonomy YAML file", + Long: `Parses the taxonomy YAML file and reports any structural errors +without starting the simulation engine.`, + RunE: runValidate, +} + +func init() { + rootCmd.AddCommand(validateCmd) +} + +func runValidate(cmd *cobra.Command, args []string) error { + fmt.Println("> Validating taxonomy configuration...") + fmt.Println("> Validation not yet implemented.") + return nil +} diff --git a/tongo-core/cmd/tongo/cli/version.go b/tongo-core/cmd/tongo/cli/version.go new file mode 100644 index 0000000..b0c9d5d --- /dev/null +++ b/tongo-core/cmd/tongo/cli/version.go @@ -0,0 +1,22 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// Version of the tongo application. +const Version = "0.1.0" + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the Tongo Core version", + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Tongo Core v%s\n", Version) + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) +} diff --git a/tongo-core/cmd/tongo/main.go b/tongo-core/cmd/tongo/main.go new file mode 100644 index 0000000..8f70261 --- /dev/null +++ b/tongo-core/cmd/tongo/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/costap/quarkshologridledger/tongo-core/cmd/tongo/cli" + +func main() { + cli.Execute() +} diff --git a/tongo-core/config/tongo.yaml b/tongo-core/config/tongo.yaml new file mode 100644 index 0000000..baa56bf --- /dev/null +++ b/tongo-core/config/tongo.yaml @@ -0,0 +1,41 @@ +# Tongo Core Configuration +# Quark's Holo-Grid Ledger β€” Simulation Engine +# +# Override any value with TONGO_ prefixed environment variables. +# Example: TONGO_VALKEY_HOST=redis.example.com + +daemon: + tick_interval_ms: 2000 + log_level: "info" + +valkey: + host: "localhost" + port: 6379 + password: "" + db: 0 + +engine: + target_active_matches: 8 + max_active_matches: 12 + min_active_matches: 4 + pre_match_duration_ticks: 30 + min_match_duration_ticks: 60 + max_match_duration_ticks: 150 + resolving_duration_ticks: 3 + taxonomy_path: "../data-source/taxonomy.yaml" + +combat: + damage_scaling_factor: 0.1 + damage_variance_low: 0.6 + damage_variance_high: 1.4 + critical_hit_chance: 0.05 + critical_hit_multiplier: 3.0 + +markets: + primary_margin: 1.06 + secondary_margin: 1.075 + exotic_margin: 1.12 + min_price: 1.01 + max_price: 51.00 + min_probability: 0.02 + max_probability: 0.98 diff --git a/tongo-core/go.mod b/tongo-core/go.mod new file mode 100644 index 0000000..6503cb8 --- /dev/null +++ b/tongo-core/go.mod @@ -0,0 +1,29 @@ +module github.com/costap/quarkshologridledger/tongo-core + +go 1.23 + +require ( + github.com/redis/go-redis/v9 v9.7.3 + github.com/spf13/cobra v1.9.1 + github.com/spf13/viper v1.20.1 +) + +require ( + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/tongo-core/go.sum b/tongo-core/go.sum new file mode 100644 index 0000000..9f75c92 --- /dev/null +++ b/tongo-core/go.sum @@ -0,0 +1,68 @@ +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= +github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tongo-core/internal/application/engine.go b/tongo-core/internal/application/engine.go new file mode 100644 index 0000000..6fbd6aa --- /dev/null +++ b/tongo-core/internal/application/engine.go @@ -0,0 +1,65 @@ +package application + +import ( + "context" + "log/slog" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/port" +) + +// Engine is the top-level orchestrator for the Tongo Core simulation. +// It coordinates the scheduler, simulator, event generator, probability engine, and cache. +type Engine struct { + scheduler port.SchedulerService + matchmaker port.MatchmakerService + simulator port.SimulatorService + events port.EventGeneratorService + probability port.ProbabilityService + markets port.MarketService + cache port.CachePort + taxonomy port.TaxonomyPort + logger *slog.Logger +} + +// EngineDeps holds all dependencies for engine construction. +type EngineDeps struct { + Scheduler port.SchedulerService + Matchmaker port.MatchmakerService + Simulator port.SimulatorService + Events port.EventGeneratorService + Probability port.ProbabilityService + Markets port.MarketService + Cache port.CachePort + Taxonomy port.TaxonomyPort + Logger *slog.Logger +} + +// NewEngine creates a new Engine with all service dependencies. +func NewEngine(deps EngineDeps) *Engine { + return &Engine{ + scheduler: deps.Scheduler, + matchmaker: deps.Matchmaker, + simulator: deps.Simulator, + events: deps.Events, + probability: deps.Probability, + markets: deps.Markets, + cache: deps.Cache, + taxonomy: deps.Taxonomy, + logger: deps.Logger, + } +} + +// Run starts the main simulation loop. It blocks until ctx is cancelled. +func (e *Engine) Run(ctx context.Context) error { + e.logger.Info("Starting Tongo Core simulation loop") + // TODO: implement actual tick logic + <-ctx.Done() + return nil +} + +// Shutdown gracefully stops the engine. +func (e *Engine) Shutdown() error { + e.logger.Info("Stopping Tongo Core simulation engine") + return nil +} + diff --git a/tongo-core/internal/application/events/generator.go b/tongo-core/internal/application/events/generator.go new file mode 100644 index 0000000..6af3fa8 --- /dev/null +++ b/tongo-core/internal/application/events/generator.go @@ -0,0 +1,25 @@ +package events + +import ( + "log/slog" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" +) + +// Generator produces random in-match events. +type Generator struct { + logger *slog.Logger +} + +// New creates a new Generator instance. +func New(logger *slog.Logger) *Generator { + return &Generator{ + logger: logger, + } +} + +// Roll checks for and generates any random events this tick. +func (g *Generator) Roll(match *entity.Match, tickResult entity.TickResult) []entity.MatchEvent { + g.logger.Debug("Rolling for random events", "id", match.ID) + return nil +} diff --git a/tongo-core/internal/application/markets/markets.go b/tongo-core/internal/application/markets/markets.go new file mode 100644 index 0000000..5c2174e --- /dev/null +++ b/tongo-core/internal/application/markets/markets.go @@ -0,0 +1,34 @@ +package markets + +import ( + "log/slog" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" +) + +// Service manages market hydration, pricing, and suspension. +type Service struct { + logger *slog.Logger +} + +// New creates a new Service instance. +func New(logger *slog.Logger) *Service { + return &Service{ + logger: logger, + } +} + +// HydrateMarkets generates markets for a new match from templates. +func (s *Service) HydrateMarkets(match *entity.Match, templates []entity.MarketTemplate) { + s.logger.Debug("Hydrating markets from templates for match", "id", match.ID) +} + +// UpdatePrices converts probabilities to prices with margin. +func (s *Service) UpdatePrices(match *entity.Match) { + s.logger.Debug("Updating market prices for match", "id", match.ID) +} + +// SuspendAll suspends all markets in a match. +func (s *Service) SuspendAll(match *entity.Match, durationTicks int) { + s.logger.Info("Suspending all markets for match", "id", match.ID, "duration", durationTicks) +} diff --git a/tongo-core/internal/application/matchmaker/matchmaker.go b/tongo-core/internal/application/matchmaker/matchmaker.go new file mode 100644 index 0000000..3ea931f --- /dev/null +++ b/tongo-core/internal/application/matchmaker/matchmaker.go @@ -0,0 +1,41 @@ +package matchmaker + +import ( + "context" + "log/slog" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/port" +) + +// Matchmaker pairs factions and selects venues to create new matches. +type Matchmaker struct { + quadrants []entity.Quadrant + venues []entity.Venue + templates []entity.MarketTemplate + markets port.MarketService + logger *slog.Logger +} + +// New creates a new Matchmaker instance. +func New( + quadrants []entity.Quadrant, + venues []entity.Venue, + templates []entity.MarketTemplate, + markets port.MarketService, + logger *slog.Logger, +) *Matchmaker { + return &Matchmaker{ + quadrants: quadrants, + venues: venues, + templates: templates, + markets: markets, + logger: logger, + } +} + +// CreateMatch generates a new match by selecting factions and a venue. +func (m *Matchmaker) CreateMatch(ctx context.Context) (*entity.Match, error) { + m.logger.Debug("Creating new match") + return &entity.Match{}, nil +} diff --git a/tongo-core/internal/application/probability/probability.go b/tongo-core/internal/application/probability/probability.go new file mode 100644 index 0000000..05ca540 --- /dev/null +++ b/tongo-core/internal/application/probability/probability.go @@ -0,0 +1,59 @@ +package probability + +import ( + "log/slog" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" +) + +// Calculator recalculates market probabilities from match state. +type Calculator struct { + logger *slog.Logger +} + +// New creates a new Calculator instance. +func New(logger *slog.Logger) *Calculator { + return &Calculator{ + logger: logger, + } +} + +// RecalculateAll recomputes probabilities for all markets in a match. +func (c *Calculator) RecalculateAll(match *entity.Match) { + c.logger.Debug("Recalculating all market probabilities for match", "id", match.ID) +} + +// matchWinner calculates Model A (Match Winner). +func (c *Calculator) matchWinner(match *entity.Match) (homeProb, awayProb float64) { + return 0.5, 0.5 +} + +// kineticYield calculates Model B (Total Kinetic Yield). +func (c *Calculator) kineticYield(match *entity.Match, line float64) (overProb, underProb float64) { + return 0.5, 0.5 +} + +// firstBreach calculates Model C (First Shield Breach). +func (c *Calculator) firstBreach(match *entity.Match) (homeFirstProb, awayFirstProb float64) { + return 0.5, 0.5 +} + +// duration calculates Model D (Engagement Duration). +func (c *Calculator) duration(match *entity.Match, line float64) (overProb, underProb float64) { + return 0.5, 0.5 +} + +// comeback calculates Model E (Comeback Victory). +func (c *Calculator) comeback(match *entity.Match) (homeProb, awayProb float64) { + return 0.05, 0.05 +} + +// mutualDestruction calculates Model F (Mutual Destruction). +func (c *Calculator) mutualDestruction(match *entity.Match) float64 { + return 0.01 +} + +// subspaceAnomaly calculates Model G (Subspace Anomaly). +func (c *Calculator) subspaceAnomaly(match *entity.Match) (anomalyProb, cleanProb float64) { + return 0.1, 0.9 +} diff --git a/tongo-core/internal/application/scheduler/scheduler.go b/tongo-core/internal/application/scheduler/scheduler.go new file mode 100644 index 0000000..7fc476b --- /dev/null +++ b/tongo-core/internal/application/scheduler/scheduler.go @@ -0,0 +1,42 @@ +package scheduler + +import ( + "context" + "log/slog" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/port" +) + +// Scheduler manages the lifecycle of all active matches. +type Scheduler struct { + matchmaker port.MatchmakerService + matches []*entity.Match + logger *slog.Logger +} + +// New creates a new Scheduler instance. +func New(matchmaker port.MatchmakerService, logger *slog.Logger) *Scheduler { + return &Scheduler{ + matchmaker: matchmaker, + matches: make([]*entity.Match, 0), + logger: logger, + } +} + +// Tick advances the scheduler by one cycle, creating or retiring matches as needed. +func (s *Scheduler) Tick(ctx context.Context) error { + s.logger.Debug("Scheduler tick") + return nil +} + +// ActiveMatches returns all currently active matches. +func (s *Scheduler) ActiveMatches() []*entity.Match { + return s.matches +} + +// SeedMatches creates initial matches up to the target count. +func (s *Scheduler) SeedMatches(ctx context.Context, count int) error { + s.logger.Info("Seeding initial matches", "count", count) + return nil +} diff --git a/tongo-core/internal/application/simulator/simulator.go b/tongo-core/internal/application/simulator/simulator.go new file mode 100644 index 0000000..d1d0a46 --- /dev/null +++ b/tongo-core/internal/application/simulator/simulator.go @@ -0,0 +1,27 @@ +package simulator + +import ( + "log/slog" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" +) + +// Simulator resolves combat ticks between factions. +type Simulator struct { + typeAdvantage TypeAdvantageMatrix + logger *slog.Logger +} + +// New creates a new Simulator instance. +func New(logger *slog.Logger) *Simulator { + return &Simulator{ + typeAdvantage: NewTypeAdvantageMatrix(), + logger: logger, + } +} + +// ResolveTick processes one combat tick for a match. +func (s *Simulator) ResolveTick(match *entity.Match) entity.TickResult { + s.logger.Debug("Simulating combat tick for match", "id", match.ID) + return entity.TickResult{} +} diff --git a/tongo-core/internal/application/simulator/typeadvantage.go b/tongo-core/internal/application/simulator/typeadvantage.go new file mode 100644 index 0000000..f1c7770 --- /dev/null +++ b/tongo-core/internal/application/simulator/typeadvantage.go @@ -0,0 +1,22 @@ +package simulator + +import "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" + +// TypeAdvantageMatrix maps attacker type Γ— defender type to a damage multiplier. +type TypeAdvantageMatrix map[entity.FactionType]map[entity.FactionType]float64 + +// NewTypeAdvantageMatrix returns the default type advantage matrix. +func NewTypeAdvantageMatrix() TypeAdvantageMatrix { + // The real implementation will hydrate this with the rock-paper-scissors values + return make(TypeAdvantageMatrix) +} + +// Get returns the advantage multiplier for the given attacker/defender pair. +func (m TypeAdvantageMatrix) Get(attacker, defender entity.FactionType) float64 { + if attackerMap, ok := m[attacker]; ok { + if val, ok := attackerMap[defender]; ok { + return val + } + } + return 1.0 +} diff --git a/tongo-core/internal/domain/entity/event.go b/tongo-core/internal/domain/entity/event.go new file mode 100644 index 0000000..71d05ae --- /dev/null +++ b/tongo-core/internal/domain/entity/event.go @@ -0,0 +1,41 @@ +package entity + +// EventCategory classifies the type of random event. +type EventCategory string + +const ( + EventCategoryCombat EventCategory = "combat" + EventCategoryEnvironmental EventCategory = "environmental" + EventCategoryFaction EventCategory = "faction" + EventCategoryMarket EventCategory = "market" +) + +// EventSeverity indicates the impact level. +type EventSeverity string + +const ( + EventSeverityMinor EventSeverity = "minor" + EventSeverityMajor EventSeverity = "major" + EventSeverityCritical EventSeverity = "critical" +) + +// MatchEvent represents something that happened during a match. +type MatchEvent struct { + ID string `json:"id"` + TemplateID string `json:"templateId"` + Name string `json:"name"` + Description string `json:"description"` + Tick int `json:"tick"` + Category EventCategory `json:"category"` + Severity EventSeverity `json:"severity"` + Effects []EventEffect `json:"effects"` + Duration int `json:"duration"` +} + +// EventEffect describes a single modification caused by an event. +type EventEffect struct { + Target string `json:"target"` + Stat string `json:"stat"` + Operation string `json:"operation"` + Value float64 `json:"value"` +} diff --git a/tongo-core/internal/domain/entity/faction.go b/tongo-core/internal/domain/entity/faction.go new file mode 100644 index 0000000..8992572 --- /dev/null +++ b/tongo-core/internal/domain/entity/faction.go @@ -0,0 +1,50 @@ +package entity + +// Faction represents a team/contender in the sportsbook. +type Faction struct { + ID string `json:"id"` + Name string `json:"name"` + Abbreviation string `json:"abbreviation"` + Type FactionType `json:"type"` + Homeworld string `json:"homeworld"` + ColorCode string `json:"colorCode"` + EmblemGlyph string `json:"emblemGlyph"` + BaseShieldStrength int `json:"baseShieldStrength"` + BaseAttackPower int `json:"baseAttackPower"` + BaseEvasion int `json:"baseEvasion"` + RivalryModifiers map[string]float64 `json:"rivalryModifiers"` +} + +// FactionType defines the combat archetype. +type FactionType string + +const ( + FactionTypeAggressive FactionType = "aggressive" + FactionTypeDefensive FactionType = "defensive" + FactionTypeTactical FactionType = "tactical" + FactionTypeInfiltrator FactionType = "infiltrator" + FactionTypeSwarm FactionType = "swarm" +) + +// FactionState represents a faction's live combat state within a match. +type FactionState struct { + ID string `json:"id"` + Name string `json:"name"` + Abbreviation string `json:"abbreviation"` + Type FactionType `json:"type"` + Glyph string `json:"glyph"` + ColorCode string `json:"colorCode"` + ShieldCapacity float64 `json:"shieldCapacity"` + EffectiveAttack float64 `json:"effectiveAttack"` + EffectiveEvasion float64 `json:"effectiveEvasion"` + ActiveEffects []ActiveEffect `json:"activeEffects"` +} + +// ActiveEffect represents a temporary buff/debuff on a faction. +type ActiveEffect struct { + Name string `json:"name"` + RemainingTicks int `json:"remainingTicks"` + Stat string `json:"stat"` + Operation string `json:"operation"` + Value float64 `json:"value"` +} diff --git a/tongo-core/internal/domain/entity/market.go b/tongo-core/internal/domain/entity/market.go new file mode 100644 index 0000000..f43bdf9 --- /dev/null +++ b/tongo-core/internal/domain/entity/market.go @@ -0,0 +1,49 @@ +package entity + +// MarketCategory classifies a market by risk tier. +type MarketCategory string + +const ( + MarketCategoryPrimary MarketCategory = "primary" + MarketCategorySecondary MarketCategory = "secondary" + MarketCategoryExotic MarketCategory = "exotic" +) + +// MarketStatus tracks whether a market is tradeable. +type MarketStatus string + +const ( + MarketStatusOpen MarketStatus = "OPEN" + MarketStatusSuspended MarketStatus = "SUSPENDED" + MarketStatusClosed MarketStatus = "CLOSED" +) + +// Market represents a single betting market within a match. +type Market struct { + ID string `json:"id"` + TemplateID string `json:"templateId"` + Name string `json:"name"` + Category MarketCategory `json:"category"` + Price float64 `json:"price"` + PreviousPrice float64 `json:"previousPrice"` + Trend string `json:"trend"` + Status MarketStatus `json:"status"` + ImpliedProbability float64 `json:"impliedProbability"` +} + +// MarketTemplate defines the blueprint for generating markets. +type MarketTemplate struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Category MarketCategory `json:"category"` + Selections []SelectionTemplate `json:"selections"` +} + +// SelectionTemplate is a single outcome option within a market template. +type SelectionTemplate struct { + Type string `json:"type"` + Name string `json:"name,omitempty"` + Suffix string `json:"suffix,omitempty"` + BasePrice float64 `json:"basePrice"` +} diff --git a/tongo-core/internal/domain/entity/match.go b/tongo-core/internal/domain/entity/match.go new file mode 100644 index 0000000..796c5e2 --- /dev/null +++ b/tongo-core/internal/domain/entity/match.go @@ -0,0 +1,43 @@ +package entity + +// MatchStatus represents the lifecycle phase of a match. +type MatchStatus string + +const ( + MatchStatusScheduled MatchStatus = "SCHEDULED" + MatchStatusPreMatch MatchStatus = "PRE_MATCH" + MatchStatusLive MatchStatus = "LIVE" + MatchStatusResolving MatchStatus = "RESOLVING" + MatchStatusSettled MatchStatus = "SETTLED" +) + +// Match represents a live engagement between two factions at a venue. +type Match struct { + ID string `json:"id"` + Name string `json:"name"` + Quadrant string `json:"quadrant"` + Status MatchStatus `json:"status"` + Tick int `json:"tick"` + MaxTicks int `json:"maxTicks"` + KineticYield float64 `json:"kinetic_yield"` + Venue Venue `json:"venue"` + Factions MatchFactions `json:"factions"` + Markets []Market `json:"markets"` + RecentEvents []MatchEvent `json:"recentEvents"` +} + +// MatchFactions holds the two competing factions. +type MatchFactions struct { + Home FactionState `json:"home"` + Away FactionState `json:"away"` +} + +// TickResult captures the outcome of a single combat tick. +type TickResult struct { + HomeDamageDealt float64 + AwayDamageDealt float64 + HomeShieldsAfter float64 + AwayShieldsAfter float64 + KineticYieldDelta float64 + EventsFired []MatchEvent +} diff --git a/tongo-core/internal/domain/entity/quadrant.go b/tongo-core/internal/domain/entity/quadrant.go new file mode 100644 index 0000000..a314905 --- /dev/null +++ b/tongo-core/internal/domain/entity/quadrant.go @@ -0,0 +1,11 @@ +package entity + +// Quadrant represents a galactic league division. +type Quadrant struct { + ID string `json:"id"` + Name string `json:"name"` + Designation string `json:"designation"` + ColorCode string `json:"colorCode"` + BaseVolatility float64 `json:"baseVolatility"` + Factions []Faction `json:"factions"` +} diff --git a/tongo-core/internal/domain/entity/venue.go b/tongo-core/internal/domain/entity/venue.go new file mode 100644 index 0000000..6937e9d --- /dev/null +++ b/tongo-core/internal/domain/entity/venue.go @@ -0,0 +1,15 @@ +package entity + +// Venue represents a match location from the sector pool. +type Venue struct { + ID string `json:"id"` + Name string `json:"name"` + Quadrant string `json:"quadrant"` + Coordinates string `json:"coordinates"` + ShieldModifier float64 `json:"shieldModifier"` + DamageModifier float64 `json:"damageModifier"` + EvasionModifier float64 `json:"evasionModifier"` + SpecialEventChance float64 `json:"specialEventChance"` + Status string `json:"status"` + Tags []string `json:"tags"` +} diff --git a/tongo-core/internal/domain/port/cache.go b/tongo-core/internal/domain/port/cache.go new file mode 100644 index 0000000..72af542 --- /dev/null +++ b/tongo-core/internal/domain/port/cache.go @@ -0,0 +1,28 @@ +package port + +import ( + "context" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" +) + +// CachePort defines the interface for the cache layer (Valkey/Redis). +type CachePort interface { + // PushMatchState writes the full match telemetry to the cache. + PushMatchState(ctx context.Context, match *entity.Match) error + + // PushEvent appends an event to the match's event log. + PushEvent(ctx context.Context, matchID string, event entity.MatchEvent) error + + // UpdateActiveIndex updates the set of currently active match IDs. + UpdateActiveIndex(ctx context.Context, matchIDs []string) error + + // UpdateQuadrantIndex updates the set of active matches for a specific quadrant. + UpdateQuadrantIndex(ctx context.Context, quadrantID string, matchIDs []string) error + + // Ping checks that the cache connection is alive. + Ping(ctx context.Context) error + + // Close gracefully shuts down the cache connection. + Close() error +} diff --git a/tongo-core/internal/domain/port/engine.go b/tongo-core/internal/domain/port/engine.go new file mode 100644 index 0000000..35ce88e --- /dev/null +++ b/tongo-core/internal/domain/port/engine.go @@ -0,0 +1,55 @@ +package port + +import ( + "context" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" +) + +// SchedulerService defines the match lifecycle management interface. +type SchedulerService interface { + // Tick advances the scheduler by one cycle, creating or retiring matches as needed. + Tick(ctx context.Context) error + + // ActiveMatches returns all currently active matches. + ActiveMatches() []*entity.Match + + // SeedMatches creates initial matches up to the target count. + SeedMatches(ctx context.Context, count int) error +} + +// MatchmakerService defines the faction pairing and venue selection interface. +type MatchmakerService interface { + // CreateMatch generates a new match by selecting factions and a venue. + CreateMatch(ctx context.Context) (*entity.Match, error) +} + +// SimulatorService defines the combat tick resolution interface. +type SimulatorService interface { + // ResolveTick processes one combat tick for a match. + ResolveTick(match *entity.Match) entity.TickResult +} + +// EventGeneratorService defines the random event system interface. +type EventGeneratorService interface { + // Roll checks for and generates any random events this tick. + Roll(match *entity.Match, tickResult entity.TickResult) []entity.MatchEvent +} + +// ProbabilityService defines the odds calculation interface. +type ProbabilityService interface { + // RecalculateAll recomputes probabilities for all markets in a match. + RecalculateAll(match *entity.Match) +} + +// MarketService defines the market management interface. +type MarketService interface { + // HydrateMarkets generates markets for a new match from templates. + HydrateMarkets(match *entity.Match, templates []entity.MarketTemplate) + + // UpdatePrices converts probabilities to prices with margin. + UpdatePrices(match *entity.Match) + + // SuspendAll suspends all markets in a match. + SuspendAll(match *entity.Match, durationTicks int) +} diff --git a/tongo-core/internal/domain/port/taxonomy.go b/tongo-core/internal/domain/port/taxonomy.go new file mode 100644 index 0000000..31568fe --- /dev/null +++ b/tongo-core/internal/domain/port/taxonomy.go @@ -0,0 +1,15 @@ +package port + +import "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" + +// TaxonomyPort defines the interface for loading taxonomy configuration data. +type TaxonomyPort interface { + // LoadQuadrants returns all quadrant definitions including their factions. + LoadQuadrants() ([]entity.Quadrant, error) + + // LoadVenues returns all sector pool venue definitions. + LoadVenues() ([]entity.Venue, error) + + // LoadMarketTemplates returns all market template definitions. + LoadMarketTemplates() ([]entity.MarketTemplate, error) +} diff --git a/tongo-core/internal/infrastructure/cache/valkey.go b/tongo-core/internal/infrastructure/cache/valkey.go new file mode 100644 index 0000000..b66f52b --- /dev/null +++ b/tongo-core/internal/infrastructure/cache/valkey.go @@ -0,0 +1,66 @@ +package cache + +import ( + "context" + "fmt" + "log/slog" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" + "github.com/costap/quarkshologridledger/tongo-core/internal/infrastructure/config" + "github.com/redis/go-redis/v9" +) + +// ValkeyAdapter implements port.CachePort using a Valkey (Redis-compatible) client. +type ValkeyAdapter struct { + client *redis.Client + logger *slog.Logger +} + +// New creates a new ValkeyAdapter and tests the connection. +func New(cfg config.ValkeyConfig, logger *slog.Logger) (*ValkeyAdapter, error) { + client := redis.NewClient(&redis.Options{ + Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), + Password: cfg.Password, + DB: cfg.DB, + }) + + return &ValkeyAdapter{ + client: client, + logger: logger, + }, nil +} + +// PushMatchState writes the full match telemetry to the cache. +func (v *ValkeyAdapter) PushMatchState(ctx context.Context, match *entity.Match) error { + v.logger.Debug("Pushing match state to Valkey", "id", match.ID) + return nil +} + +// PushEvent appends an event to the match's event log. +func (v *ValkeyAdapter) PushEvent(ctx context.Context, matchID string, event entity.MatchEvent) error { + v.logger.Debug("Pushing event to Valkey", "matchId", matchID, "eventId", event.ID) + return nil +} + +// UpdateActiveIndex updates the set of currently active match IDs. +func (v *ValkeyAdapter) UpdateActiveIndex(ctx context.Context, matchIDs []string) error { + v.logger.Debug("Updating active match index in Valkey", "count", len(matchIDs)) + return nil +} + +// UpdateQuadrantIndex updates the set of active matches for a specific quadrant. +func (v *ValkeyAdapter) UpdateQuadrantIndex(ctx context.Context, quadrantID string, matchIDs []string) error { + v.logger.Debug("Updating quadrant index in Valkey", "quadrant", quadrantID, "count", len(matchIDs)) + return nil +} + +// Ping checks that the cache connection is alive. +func (v *ValkeyAdapter) Ping(ctx context.Context) error { + return v.client.Ping(ctx).Err() +} + +// Close gracefully shuts down the cache connection. +func (v *ValkeyAdapter) Close() error { + v.logger.Info("Closing Valkey connection") + return v.client.Close() +} diff --git a/tongo-core/internal/infrastructure/config/config.go b/tongo-core/internal/infrastructure/config/config.go new file mode 100644 index 0000000..5a84b4e --- /dev/null +++ b/tongo-core/internal/infrastructure/config/config.go @@ -0,0 +1,117 @@ +package config + +import ( + "fmt" + + "github.com/spf13/viper" +) + +// Config holds all Tongo Core configuration values. +type Config struct { + Daemon DaemonConfig `mapstructure:"daemon"` + Valkey ValkeyConfig `mapstructure:"valkey"` + Engine EngineConfig `mapstructure:"engine"` + Combat CombatConfig `mapstructure:"combat"` + Markets MarketsConfig `mapstructure:"markets"` +} + +// DaemonConfig holds parameters for the daemon runtime. +type DaemonConfig struct { + TickIntervalMs int `mapstructure:"tick_interval_ms"` + LogLevel string `mapstructure:"log_level"` +} + +// ValkeyConfig holds connections settings for Valkey/Redis. +type ValkeyConfig struct { + Host string `mapstructure:"host"` + Port int `mapstructure:"port"` + Password string `mapstructure:"password"` + DB int `mapstructure:"db"` +} + +// EngineConfig holds high-level simulation settings. +type EngineConfig struct { + TargetActiveMatches int `mapstructure:"target_active_matches"` + MaxActiveMatches int `mapstructure:"max_active_matches"` + MinActiveMatches int `mapstructure:"min_active_matches"` + PreMatchDurationTicks int `mapstructure:"pre_match_duration_ticks"` + MinMatchDurationTicks int `mapstructure:"min_match_duration_ticks"` + MaxMatchDurationTicks int `mapstructure:"max_match_duration_ticks"` + ResolvingDurationTicks int `mapstructure:"resolving_duration_ticks"` + TaxonomyPath string `mapstructure:"taxonomy_path"` +} + +// CombatConfig holds modifiers for combat simulation. +type CombatConfig struct { + DamageScalingFactor float64 `mapstructure:"damage_scaling_factor"` + DamageVarianceLow float64 `mapstructure:"damage_variance_low"` + DamageVarianceHigh float64 `mapstructure:"damage_variance_high"` + CriticalHitChance float64 `mapstructure:"critical_hit_chance"` + CriticalHitMultiplier float64 `mapstructure:"critical_hit_multiplier"` +} + +// MarketsConfig holds parameters for overround margin and price limits. +type MarketsConfig struct { + PrimaryMargin float64 `mapstructure:"primary_margin"` + SecondaryMargin float64 `mapstructure:"secondary_margin"` + ExoticMargin float64 `mapstructure:"exotic_margin"` + MinPrice float64 `mapstructure:"min_price"` + MaxPrice float64 `mapstructure:"max_price"` + MinProbability float64 `mapstructure:"min_probability"` + MaxProbability float64 `mapstructure:"max_probability"` +} + +// Load reads configuration from the config file and environment variables. +func Load() (*Config, error) { + viper.SetConfigName("tongo") + viper.SetConfigType("yaml") + viper.AddConfigPath("./config") + viper.AddConfigPath(".") + viper.SetEnvPrefix("TONGO") + viper.AutomaticEnv() + + // Defaults + viper.SetDefault("daemon.tick_interval_ms", 2000) + viper.SetDefault("daemon.log_level", "info") + + viper.SetDefault("valkey.host", "localhost") + viper.SetDefault("valkey.port", 6379) + viper.SetDefault("valkey.password", "") + viper.SetDefault("valkey.db", 0) + + viper.SetDefault("engine.target_active_matches", 8) + viper.SetDefault("engine.max_active_matches", 12) + viper.SetDefault("engine.min_active_matches", 4) + viper.SetDefault("engine.pre_match_duration_ticks", 30) + viper.SetDefault("engine.min_match_duration_ticks", 60) + viper.SetDefault("engine.max_match_duration_ticks", 150) + viper.SetDefault("engine.resolving_duration_ticks", 3) + viper.SetDefault("engine.taxonomy_path", "../data-source/taxonomy.yaml") + + viper.SetDefault("combat.damage_scaling_factor", 0.1) + viper.SetDefault("combat.damage_variance_low", 0.6) + viper.SetDefault("combat.damage_variance_high", 1.4) + viper.SetDefault("combat.critical_hit_chance", 0.05) + viper.SetDefault("combat.critical_hit_multiplier", 3.0) + + viper.SetDefault("markets.primary_margin", 1.06) + viper.SetDefault("markets.secondary_margin", 1.075) + viper.SetDefault("markets.exotic_margin", 1.12) + viper.SetDefault("markets.min_price", 1.01) + viper.SetDefault("markets.max_price", 51.00) + viper.SetDefault("markets.min_probability", 0.02) + viper.SetDefault("markets.max_probability", 0.98) + + if err := viper.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); !ok { + return nil, fmt.Errorf("reading config: %w", err) + } + } + + var cfg Config + if err := viper.Unmarshal(&cfg); err != nil { + return nil, fmt.Errorf("unmarshaling config: %w", err) + } + + return &cfg, nil +} diff --git a/tongo-core/internal/infrastructure/taxonomy/loader.go b/tongo-core/internal/infrastructure/taxonomy/loader.go new file mode 100644 index 0000000..70d44b9 --- /dev/null +++ b/tongo-core/internal/infrastructure/taxonomy/loader.go @@ -0,0 +1,101 @@ +package taxonomy + +import ( + "log/slog" + + "github.com/costap/quarkshologridledger/tongo-core/internal/domain/entity" +) + +// YAMLLoader implements port.TaxonomyPort by reading from a YAML file. +type YAMLLoader struct { + path string + logger *slog.Logger +} + +// New creates a new YAMLLoader instance. +func New(path string, logger *slog.Logger) *YAMLLoader { + return &YAMLLoader{ + path: path, + logger: logger, + } +} + +// Intermediary YAML file schema types +type taxonomyFile struct { + Quadrants []yamlQuadrant `yaml:"quadrants"` + MarketTemplates []yamlMarketTemplate `yaml:"market_templates"` + Venues []yamlVenue `yaml:"sector_pool"` +} + +type yamlQuadrant struct { + ID string `yaml:"id"` + Name string `yaml:"name"` + Designation string `yaml:"designation"` + ColorCode string `yaml:"color_code"` + BaseVolatility float64 `yaml:"base_volatility"` + Factions []yamlFaction `yaml:"factions"` +} + +type yamlFaction struct { + ID string `yaml:"id"` + Name string `yaml:"name"` + Abbreviation string `yaml:"abbreviation"` + Type string `yaml:"type"` + Homeworld string `yaml:"homeworld"` + ColorCode string `yaml:"color_code"` + EmblemGlyph string `yaml:"emblem_glyph"` + BaseShieldStrength int `yaml:"base_shield_strength"` + BaseAttackPower int `yaml:"base_attack_power"` + BaseEvasion int `yaml:"base_evasion"` + RivalryModifiers map[string]float64 `yaml:"rivalry_modifiers"` +} + +type yamlVenue struct { + ID string `yaml:"id"` + Name string `yaml:"name"` + Quadrant string `yaml:"quadrant"` + Coordinates string `yaml:"coordinates"` + ShieldModifier float64 `yaml:"shield_modifier"` + DamageModifier float64 `yaml:"damage_modifier"` + EvasionModifier float64 `yaml:"evasion_modifier"` + SpecialEventChance float64 `yaml:"special_event_chance"` + Status string `yaml:"status"` + Tags []string `yaml:"tags"` +} + +type yamlMarketTemplate struct { + ID string `yaml:"id"` + Name string `yaml:"name"` + Description string `yaml:"description"` + Category string `yaml:"category"` + Selections []yamlSelectionTemplate `yaml:"selections"` +} + +type yamlSelectionTemplate struct { + Type string `yaml:"type"` + Name string `yaml:"name,omitempty"` + Suffix string `yaml:"suffix,omitempty"` + BasePrice float64 `yaml:"base_price"` +} + +// LoadQuadrants returns all quadrant definitions including their factions. +func (l *YAMLLoader) LoadQuadrants() ([]entity.Quadrant, error) { + l.logger.Debug("Loading quadrants from taxonomy") + return nil, nil +} + +// LoadVenues returns all sector pool venue definitions. +func (l *YAMLLoader) LoadVenues() ([]entity.Venue, error) { + l.logger.Debug("Loading venues from taxonomy") + return nil, nil +} + +// LoadMarketTemplates returns all market template definitions. +func (l *YAMLLoader) LoadMarketTemplates() ([]entity.MarketTemplate, error) { + l.logger.Debug("Loading market templates from taxonomy") + return nil, nil +} + +func (l *YAMLLoader) loadFile() (*taxonomyFile, error) { + return nil, nil +} diff --git a/web-terminal/.prettierignore b/web-terminal/.prettierignore new file mode 100644 index 0000000..5322d7f --- /dev/null +++ b/web-terminal/.prettierignore @@ -0,0 +1,3 @@ +package-lock.json +pnpm-lock.yaml +yarn.lock \ No newline at end of file diff --git a/web-terminal/eslint.config.js b/web-terminal/eslint.config.js new file mode 100644 index 0000000..ae58115 --- /dev/null +++ b/web-terminal/eslint.config.js @@ -0,0 +1,20 @@ +// @ts-check + +import { tanstackConfig } from '@tanstack/eslint-config' + +export default [ + ...tanstackConfig, + { + rules: { + 'import/no-cycle': 'off', + 'import/order': 'off', + 'sort-imports': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/require-await': 'off', + 'pnpm/json-enforce-catalog': 'off', + }, + }, + { + ignores: ['eslint.config.js', 'prettier.config.js', '.output/**'], + }, +] diff --git a/web-terminal/package-lock.json b/web-terminal/package-lock.json new file mode 100644 index 0000000..9a90d63 --- /dev/null +++ b/web-terminal/package-lock.json @@ -0,0 +1,7352 @@ +{ + "name": "quarkshologridledger", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "quarkshologridledger", + "dependencies": { + "@tailwindcss/vite": "^4.1.18", + "@tanstack/react-devtools": "latest", + "@tanstack/react-router": "latest", + "@tanstack/react-router-devtools": "latest", + "@tanstack/react-router-ssr-query": "latest", + "@tanstack/react-start": "latest", + "@tanstack/router-plugin": "^1.132.0", + "lucide-react": "^0.545.0", + "nitro": "npm:nitro-nightly@latest", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tailwindcss": "^4.1.18" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.16", + "@tanstack/devtools-vite": "latest", + "@tanstack/eslint-config": "latest", + "@tanstack/router-cli": "^1.132.0", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.0", + "@types/node": "^22.10.2", + "@types/react": "^19.2.0", + "@types/react-dom": "^19.2.0", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^9.20.0", + "jsdom": "^28.1.0", + "prettier": "^3.8.1", + "typescript": "^6.0.2", + "vite": "^8.0.0", + "vitest": "^4.1.5" + } + }, + "node_modules/@acemir/cssom": { + "version": "0.9.31", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", + "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.1.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.6" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.9.tgz", + "integrity": "sha512-paQcIaOO53Rk5+YrBaBjm/SgrV4INImjo2BT1DtQRYr+XeTRbeAYlS+jxXp9drqvKmtFnWRJKIalDLhZZDu42A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.2.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.6.tgz", + "integrity": "sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oozcitak/dom": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz", + "integrity": "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==", + "license": "MIT", + "dependencies": { + "@oozcitak/infra": "^2.0.2", + "@oozcitak/url": "^3.0.0", + "@oozcitak/util": "^10.0.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@oozcitak/infra": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-2.0.2.tgz", + "integrity": "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==", + "license": "MIT", + "dependencies": { + "@oozcitak/util": "^10.0.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@oozcitak/url": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-3.0.0.tgz", + "integrity": "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==", + "license": "MIT", + "dependencies": { + "@oozcitak/infra": "^2.0.2", + "@oozcitak/util": "^10.0.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@oozcitak/util": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-10.0.0.tgz", + "integrity": "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==", + "license": "MIT", + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.120.0.tgz", + "integrity": "sha512-WU3qtINx802wOl8RxAF1v0VvmC2O4D9M8Sv486nLeQ7iPHVmncYZrtBhB4SYyX+XZxj2PNnCcN+PW21jHgiOxg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.120.0.tgz", + "integrity": "sha512-SEf80EHdhlbjZEgzeWm0ZA/br4GKMenDW3QB/gtyeTV1gStvvZeFi40ioHDZvds2m4Z9J1bUAUL8yn1/+A6iGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.120.0.tgz", + "integrity": "sha512-xVrrbCai8R8CUIBu3CjryutQnEYhZqs1maIqDvtUCFZb8vY33H7uh9mHpL3a0JBIKoBUKjPH8+rzyAeXnS2d6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.120.0.tgz", + "integrity": "sha512-xyHBbnJ6mydnQUH7MAcafOkkrNzQC6T+LXgDH/3InEq2BWl/g424IMRiJVSpVqGjB+p2bd0h0WRR8iIwzjU7rw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.120.0.tgz", + "integrity": "sha512-UMnVRllquXUYTeNfFKmxTTEdZ/ix1nLl0ducDzMSREoWYGVIHnOOxoKMWlCOvRr9Wk/HZqo2rh1jeumbPGPV9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.120.0.tgz", + "integrity": "sha512-tkvn2CQ7QdcsMnpfiX3fd3wA3EFsWKYlcQzq9cFw/xc89Al7W6Y4O0FgLVkVQpo0Tnq/qtE1XfkJOnRRA9S/NA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.120.0.tgz", + "integrity": "sha512-WN5y135Ic42gQDk9grbwY9++fDhqf8knN6fnP+0WALlAUh4odY/BDK1nfTJRSfpJD9P3r1BwU0m3pW2DU89whQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.120.0.tgz", + "integrity": "sha512-1GgQBCcXvFMw99EPdMy+4NZ3aYyXsxjf9kbUUg8HuAy3ZBXzOry5KfFEzT9nqmgZI1cuetvApkiJBZLAPo8uaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.120.0.tgz", + "integrity": "sha512-gmMQ70gsPdDBgpcErvJEoWNBr7bJooSLlvOBVBSGfOzlP5NvJ3bFvnUeZZ9d+dPrqSngtonf7nyzWUTUj/U+lw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.120.0.tgz", + "integrity": "sha512-T/kZuU0ajop0xhzVMwH5r3srC9Nqup5HaIo+3uFjIN5uPxa0LvSxC1ZqP4aQGJVW5G0z8/nCkjIfSMS91P/wzw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.120.0.tgz", + "integrity": "sha512-vn21KXLAXzaI3N5CZWlBr1iWeXLl9QFIMor7S1hUjUGTeUuWCoE6JZB040/ZNDwf+JXPX8Ao9KbmJq9FMC2iGw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.120.0.tgz", + "integrity": "sha512-SUbUxlar007LTGmSLGIC5x/WJvwhdX+PwNzFJ9f/nOzZOrCFbOT4ikt7pJIRg1tXVsEfzk5mWpGO1NFiSs4PIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.120.0.tgz", + "integrity": "sha512-hYiPJTxyfJY2+lMBFk3p2bo0R9GN+TtpPFlRqVchL1qvLG+pznstramHNvJlw9AjaoRUHwp9IKR7UZQnRPGjgQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.120.0.tgz", + "integrity": "sha512-q+5jSVZkprJCIy3dzJpApat0InJaoxQLsJuD6DkX8hrUS61z2lHQ1Fe9L2+TYbKHXCLWbL0zXe7ovkIdopBGMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.120.0.tgz", + "integrity": "sha512-D9QDDZNnH24e7X4ftSa6ar/2hCavETfW3uk0zgcMIrZNy459O5deTbWrjGzZiVrSWigGtlQwzs2McBP0QsfV1w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.120.0.tgz", + "integrity": "sha512-TBU8ZwOUWAOUWVfmI16CYWbvh4uQb9zHnGBHsw5Cp2JUVG044OIY1CSHODLifqzQIMTXvDvLzcL89GGdUIqNrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.120.0.tgz", + "integrity": "sha512-WG/FOZgDJCpJnuF3ToG/K28rcOmSY7FmFmfBKYb2fmLyhDzPpUldFGV7/Fz4ru0Iz/v4KPmf8xVgO8N3lO4KHA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.120.0.tgz", + "integrity": "sha512-1T0HKGcsz/BKo77t7+89L8Qvu4f9DoleKWHp3C5sJEcbCjDOLx3m9m722bWZTY+hANlUEs+yjlK+lBFsA+vrVQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.120.0.tgz", + "integrity": "sha512-L7vfLzbOXsjBXV0rv/6Y3Jd9BRjPeCivINZAqrSyAOZN3moCopDN+Psq9ZrGNZtJzP8946MtlRFZ0Als0wBCOw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.120.0.tgz", + "integrity": "sha512-ys+upfqNtSu58huAhJMBKl3XCkGzyVFBlMlGPzHeFKgpFF/OdgNs1MMf8oaJIbgMH8ZxgGF7qfue39eJohmKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.120.0.tgz", + "integrity": "sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.4.tgz", + "integrity": "sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.4.tgz", + "integrity": "sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.4.tgz", + "integrity": "sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.4.tgz", + "integrity": "sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.4.tgz", + "integrity": "sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.4.tgz", + "integrity": "sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.4.tgz", + "integrity": "sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.4.tgz", + "integrity": "sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.4.tgz", + "integrity": "sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.4.tgz", + "integrity": "sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.4.tgz", + "integrity": "sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.4.tgz", + "integrity": "sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.4.tgz", + "integrity": "sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.4.tgz", + "integrity": "sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.4.tgz", + "integrity": "sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "license": "MIT" + }, + "node_modules/@solid-primitives/event-listener": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@solid-primitives/event-listener/-/event-listener-2.4.6.tgz", + "integrity": "sha512-5I0YJcTVYIWoMmgBSROBZGcz+ymhew/pGTg2dHW74BUjFKsV8Li4bOZYl0YAGP4mHw5o4UBd9/BEesqBci3wxw==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/keyboard": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@solid-primitives/keyboard/-/keyboard-1.3.7.tgz", + "integrity": "sha512-558RPNYnXx4nGh537DSqAn4xMrC8iFipl/5+xzgzWoTNFst4RnUN3BOLmtDjJ0UGGoQXVMALYR3bNOHM0xnt1Q==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.4.6", + "@solid-primitives/rootless": "^1.5.4", + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/resize-observer": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@solid-primitives/resize-observer/-/resize-observer-2.1.6.tgz", + "integrity": "sha512-GFj6b81KIahl5SBf35VlyClHshDhVEREeZz2WYkHHKBvam66mE5H5f1g3EralabAAjmcU1bBd18YYYETPv0Knw==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.4.6", + "@solid-primitives/rootless": "^1.5.4", + "@solid-primitives/static-store": "^0.1.4", + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/rootless": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@solid-primitives/rootless/-/rootless-1.5.4.tgz", + "integrity": "sha512-TOIZa1VUfVJ+9nkCcRajw3U4t9vBOP1HxX1WHNTbXq32mXwlqTvUnC4CRIilohcryBkT9u2ZkhUDSHRTaGp55g==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/static-store": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@solid-primitives/static-store/-/static-store-0.1.4.tgz", + "integrity": "sha512-LgtVaVBtB7EbmS4+M0b8xY5Iq6pUWXBsIC4VgtrFKDGDdyCaDt88sHk0fUlx1Enxm/XZnZyLXJABRoa39RjJqA==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/utils": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@solid-primitives/utils/-/utils-6.4.1.tgz", + "integrity": "sha512-ISSB5QX1qP2ynrheIpYwc4oKR5Ny4siNuUyf1qZniy+Il+p/PtDB0QK1Dnle8noiHpwRD3gpPdubOC3qI/Zamg==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/types": "^8.56.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.2.tgz", + "integrity": "sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.2" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.2.tgz", + "integrity": "sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.2", + "@tailwindcss/oxide-darwin-arm64": "4.3.2", + "@tailwindcss/oxide-darwin-x64": "4.3.2", + "@tailwindcss/oxide-freebsd-x64": "4.3.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.2", + "@tailwindcss/oxide-linux-x64-musl": "4.3.2", + "@tailwindcss/oxide-wasm32-wasi": "4.3.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.2" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.2.tgz", + "integrity": "sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.2.tgz", + "integrity": "sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.2.tgz", + "integrity": "sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.2.tgz", + "integrity": "sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.2.tgz", + "integrity": "sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.2.tgz", + "integrity": "sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.2.tgz", + "integrity": "sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.2.tgz", + "integrity": "sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.2.tgz", + "integrity": "sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.2.tgz", + "integrity": "sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.2.tgz", + "integrity": "sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.2.tgz", + "integrity": "sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.20.tgz", + "integrity": "sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >=4.0.0 || insiders" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.2.tgz", + "integrity": "sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.2", + "@tailwindcss/oxide": "4.3.2", + "tailwindcss": "4.3.2" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@tanstack/devtools": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@tanstack/devtools/-/devtools-0.12.5.tgz", + "integrity": "sha512-JdxTSeVdjJheycgz4c7qbldNKDCEDWlWr1l9dZBhd9sOmRBT5Z70ka9Eb8mb+FUnalcOIB62IDSR/iSxAIUD8Q==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.4.3", + "@solid-primitives/keyboard": "^1.3.3", + "@solid-primitives/resize-observer": "^2.1.3", + "@tanstack/devtools-client": "0.0.8", + "@tanstack/devtools-event-bus": "0.4.2", + "@tanstack/devtools-ui": "0.6.0", + "clsx": "^2.1.1", + "goober": "^2.1.16", + "solid-js": "^1.9.9" + }, + "bin": { + "intent": "bin/intent.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "solid-js": ">=1.9.7" + } + }, + "node_modules/@tanstack/devtools-client": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@tanstack/devtools-client/-/devtools-client-0.0.8.tgz", + "integrity": "sha512-cG3iZkGWCwN330bLBKa8+9r4Of2AXNoz2zUqcsy/4XsD3105ghVBx78cGyvJj9fSclNomPxoqAnDGXXhg1WLvA==", + "license": "MIT", + "dependencies": { + "@tanstack/devtools-event-client": "^0.5.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/devtools-event-bus": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@tanstack/devtools-event-bus/-/devtools-event-bus-0.4.2.tgz", + "integrity": "sha512-2LHzhwBFlKHCcklsQrGe8TeyjHd4XAF8nuCO6wHmva5fePUkJUULbu6CsCNAlGlCi0KkEsMXZSvRdR4HgMq4yA==", + "license": "MIT", + "dependencies": { + "ws": "^8.18.3" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/devtools-event-client": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@tanstack/devtools-event-client/-/devtools-event-client-0.5.0.tgz", + "integrity": "sha512-H+OH3zC6Vhu/K0NaVfQKknEKawc/+2PT+D3SB3Ox0V8SiMlTo0abbmH2rH0721R2aNYbjdMXA1oENOd8E2UVoA==", + "license": "MIT", + "bin": { + "intent": "bin/intent.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/devtools-ui": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@tanstack/devtools-ui/-/devtools-ui-0.6.0.tgz", + "integrity": "sha512-CVaM6rT6Nl5ijo83vJYFa2SjofvpuOl/uOvbYGhBrRgUhhelNHhx8zZX+hnZCHmIr0/lzM65hsocnZ72592Rvg==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "dayjs": "^1.11.19", + "goober": "^2.1.16", + "solid-js": "^1.9.9" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "solid-js": ">=1.9.7" + } + }, + "node_modules/@tanstack/devtools-vite": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@tanstack/devtools-vite/-/devtools-vite-0.8.1.tgz", + "integrity": "sha512-oQxOo0fI0bwhHtw/psFlIR0OS/bsKrirBxwnw2vuhCM4bjt3k4EZZsW/lvZ1+Vpouhts7LSyvngnxvGXbQ1sUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/devtools-client": "0.0.8", + "@tanstack/devtools-event-bus": "0.4.2", + "chalk": "^5.6.2", + "launch-editor": "^2.11.1", + "magic-string": "^0.30.0", + "oxc-parser": "^0.120.0", + "picomatch": "^4.0.3" + }, + "bin": { + "intent": "bin/intent.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@tanstack/eslint-config": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@tanstack/eslint-config/-/eslint-config-0.4.0.tgz", + "integrity": "sha512-V+Cd81W/f65dqKJKpytbwTGx9R+IwxKAHsG/uJ3nSLYEh36hlAr54lRpstUhggQB8nf/cP733cIw8DuD2dzQUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/js": "^10.0.1", + "@stylistic/eslint-plugin": "^5.8.0", + "eslint-plugin-import-x": "^4.16.1", + "eslint-plugin-n": "^17.24.0", + "globals": "^17.3.0", + "typescript-eslint": "^8.55.0", + "vue-eslint-parser": "^10.4.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0" + } + }, + "node_modules/@tanstack/eslint-config/node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@tanstack/history": { + "version": "1.162.0", + "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.162.0.tgz", + "integrity": "sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==", + "license": "MIT", + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.101.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.2.tgz", + "integrity": "sha512-hH5MLoJhF7KaIGd7q3xTXGXvslI+GYlM1Z/35aSHHWaCJWB7XvTSHYuV3eM7tw+aE0mT/xMro4M4Q9rCGHT0lw==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-devtools": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-devtools/-/react-devtools-0.10.8.tgz", + "integrity": "sha512-YJV6YttQf9lhhPbPBLULgy1eScEvJUMsCS26mjg9hfBKgAJQA5sF9zvzorDzW9Ob6o/asoXikO81JnRUVuFX0Q==", + "license": "MIT", + "dependencies": { + "@tanstack/devtools": "0.12.5" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "@types/react-dom": ">=16.8", + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.101.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.2.tgz", + "integrity": "sha512-seDkr6kzGzX1okaaTtZPtgA688CDPlXUz1C6xSg0ESqn04Vuc8tlrYms1s3de+znBqhPVxFRfpAfUf+6XvfPWg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@tanstack/query-core": "5.101.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-router": { + "version": "1.170.17", + "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.170.17.tgz", + "integrity": "sha512-ppLkjCfSMaeug9rmFRYzOd4TIqWV+yTE7tzIny7alJsSnM7w4lzEZm6eqCehG0SPetpZ0R3K+UnanSmBgOAVcQ==", + "license": "MIT", + "dependencies": { + "@tanstack/history": "1.162.0", + "@tanstack/react-store": "^0.9.3", + "@tanstack/router-core": "1.171.14", + "isbot": "^5.1.22" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-router-devtools": { + "version": "1.167.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-router-devtools/-/react-router-devtools-1.167.0.tgz", + "integrity": "sha512-nGw095EG7IHx0h5NtlEmzf6vcCTaFNPWdTSuDKazajhN0ct/v/TkekJ9J6KYUCeV1a8/2ZmToc58M+0rrOyn7w==", + "license": "MIT", + "dependencies": { + "@tanstack/router-devtools-core": "1.168.0" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-router": "^1.170.0", + "@tanstack/router-core": "^1.170.0", + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + }, + "peerDependenciesMeta": { + "@tanstack/router-core": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-router-ssr-query": { + "version": "1.167.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-router-ssr-query/-/react-router-ssr-query-1.167.1.tgz", + "integrity": "sha512-W9j5JPnBikyafvuUfykFfHIWod58OAbAAa5leNkXBcoDoocghMmu6w9uZOmUZvAWT7CSvgj5tBUtF7CM2OoHXQ==", + "license": "MIT", + "dependencies": { + "@tanstack/router-ssr-query-core": "1.169.1" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/query-core": ">=5.90.0", + "@tanstack/react-query": ">=5.90.0", + "@tanstack/react-router": ">=1.127.0", + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-start": { + "version": "1.168.27", + "resolved": "https://registry.npmjs.org/@tanstack/react-start/-/react-start-1.168.27.tgz", + "integrity": "sha512-rdGFDqfCW71gyofyAxaYxhelNKmeVjpmbpm0uFYbNHORCa///4aBxi7B7ecShibKv9O4GfJ66MPX5F0ozbm+ig==", + "license": "MIT", + "dependencies": { + "@tanstack/react-router": "1.170.17", + "@tanstack/react-start-client": "1.168.15", + "@tanstack/react-start-rsc": "0.1.26", + "@tanstack/react-start-server": "1.167.21", + "@tanstack/router-utils": "1.162.2", + "@tanstack/start-client-core": "1.170.13", + "@tanstack/start-plugin-core": "1.171.19", + "@tanstack/start-server-core": "1.169.16", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@rsbuild/core": "^2.0.0", + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0", + "vite": ">=7.0.0" + }, + "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + }, + "@vitejs/plugin-rsc": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-start-client": { + "version": "1.168.15", + "resolved": "https://registry.npmjs.org/@tanstack/react-start-client/-/react-start-client-1.168.15.tgz", + "integrity": "sha512-pW50PHvadgi50iNCw6deUOvqc9rzs30SstyFZY2tcS9z1XlqTlELSvGowjxdu2m0ymtqm1emj1jau1iP7+3+PQ==", + "license": "MIT", + "dependencies": { + "@tanstack/react-router": "1.170.17", + "@tanstack/router-core": "1.171.14", + "@tanstack/start-client-core": "1.170.13" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-start-rsc": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/@tanstack/react-start-rsc/-/react-start-rsc-0.1.26.tgz", + "integrity": "sha512-+FMm3qtT1gWsl0i5sG/Q70mh1k7tzZUsPBaqbg4v34zVJZ+XGn1mJb34x2w7z1M0/e7co6GkZfV8BRpczrs8UA==", + "license": "MIT", + "dependencies": { + "@tanstack/react-router": "1.170.17", + "@tanstack/router-core": "1.171.14", + "@tanstack/router-utils": "1.162.2", + "@tanstack/start-client-core": "1.170.13", + "@tanstack/start-fn-stubs": "1.162.0", + "@tanstack/start-plugin-core": "1.171.19", + "@tanstack/start-server-core": "1.169.16", + "@tanstack/start-storage-context": "1.167.16", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@rspack/core": ">=2.0.0-0", + "@vitejs/plugin-rsc": ">=0.5.20", + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0", + "react-server-dom-rspack": ">=0.0.2" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "@vitejs/plugin-rsc": { + "optional": true + }, + "react-server-dom-rspack": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-start-server": { + "version": "1.167.21", + "resolved": "https://registry.npmjs.org/@tanstack/react-start-server/-/react-start-server-1.167.21.tgz", + "integrity": "sha512-puJ7eFxaLuDzeM/tiLDJaXCA4uK+PZnEOoIC73zipsFqx865MGzrRS/GSZxeVxjavC5iHU+ZwC+rgI0qYSol1A==", + "license": "MIT", + "dependencies": { + "@tanstack/react-router": "1.170.17", + "@tanstack/router-core": "1.171.14", + "@tanstack/start-server-core": "1.169.16" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-store": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.9.3.tgz", + "integrity": "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==", + "license": "MIT", + "dependencies": { + "@tanstack/store": "0.9.3", + "use-sync-external-store": "^1.6.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/router-cli": { + "version": "1.167.18", + "resolved": "https://registry.npmjs.org/@tanstack/router-cli/-/router-cli-1.167.18.tgz", + "integrity": "sha512-R3DwK6uZY1x97EC/CsjGY/xCVUXmeZZhlaaFf+EYgJ4gb5ozxZ5mmDh304g+Q9Lw/oWt5azDJXL8TPZiTAwHzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/router-generator": "1.167.18", + "chokidar": "^5.0.0", + "yargs": "^17.7.2" + }, + "bin": { + "tsr": "bin/tsr.cjs" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-core": { + "version": "1.171.14", + "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.171.14.tgz", + "integrity": "sha512-Mo3hwx0qB0cJsVYGDjG0+Ouf7VV74h/vsoDMGztdlyzDanp4gBA2s7IVvm6hFrmQM6GpD9F0Z7SqD7OldfLE7g==", + "license": "MIT", + "dependencies": { + "@tanstack/history": "1.162.0", + "cookie-es": "^3.0.0", + "seroval": "^1.5.4", + "seroval-plugins": "^1.5.4" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-devtools-core": { + "version": "1.168.0", + "resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.168.0.tgz", + "integrity": "sha512-wQoQhlBK7nlZgqzaqdYXKWNTpdHdsaREdaPhFZVH0/Ador+F+eM3/NF2i3f2LPeS0GgKraZUQXe1Q/1+KHyEYg==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/router-core": "^1.170.0", + "csstype": "^3.0.10" + }, + "peerDependenciesMeta": { + "csstype": { + "optional": true + } + } + }, + "node_modules/@tanstack/router-generator": { + "version": "1.167.18", + "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.167.18.tgz", + "integrity": "sha512-kFvM4caRds9Q3EXg64bZubJ6rbDxyV0YDSBSGvOGzmKspQPdz5Xrh0uj5T1Ov8avUUg+c761u04VQAaEzSBXRw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5", + "@tanstack/router-core": "1.171.14", + "@tanstack/router-utils": "1.162.2", + "@tanstack/virtual-file-routes": "1.162.0", + "jiti": "^2.7.0", + "magic-string": "^0.30.21", + "prettier": "^3.5.0", + "zod": "^4.4.3" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-plugin": { + "version": "1.168.19", + "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.168.19.tgz", + "integrity": "sha512-aFglwLc+bbPTgZlkXn3PvOwpjJAfgUyPGSuql4MP3XrqTTh6WkBiy2RYb6oaG5h0s7EKwivEuq85K3Y4V0Mt1g==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "@tanstack/router-core": "1.171.14", + "@tanstack/router-generator": "1.167.18", + "@tanstack/router-utils": "1.162.2", + "chokidar": "^5.0.0", + "unplugin": "^3.0.0", + "zod": "^4.4.3" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@rsbuild/core": ">=1.0.2 || ^2.0.0", + "@tanstack/react-router": "^1.170.17", + "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", + "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", + "webpack": ">=5.92.0" + }, + "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + }, + "@tanstack/react-router": { + "optional": true + }, + "vite": { + "optional": true + }, + "vite-plugin-solid": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@tanstack/router-ssr-query-core": { + "version": "1.169.1", + "resolved": "https://registry.npmjs.org/@tanstack/router-ssr-query-core/-/router-ssr-query-core-1.169.1.tgz", + "integrity": "sha512-rngux8s/3mPQzcjLYDLkNU31coYVyCgrVTfpdwqUdY5jIEHqGTXrO73DTkPR1PppwYUeVhmNCgl8TctRcnupjg==", + "license": "MIT", + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/query-core": ">=5.90.0", + "@tanstack/router-core": ">=1.127.0" + } + }, + "node_modules/@tanstack/router-utils": { + "version": "1.162.2", + "resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.162.2.tgz", + "integrity": "sha512-hTWqJtqIFFdvuCl8WXNyrodp2L9zo2G37xKRrcVmVRWpAB2h+U1LuRAfS4tsFTiWOIoE/B+WDVFB8JpoEdw6jQ==", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.28.5", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "ansis": "^4.1.0", + "babel-dead-code-elimination": "^1.0.12", + "diff": "^8.0.2", + "pathe": "^2.0.3", + "tinyglobby": "^0.2.15" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/start-client-core": { + "version": "1.170.13", + "resolved": "https://registry.npmjs.org/@tanstack/start-client-core/-/start-client-core-1.170.13.tgz", + "integrity": "sha512-o37M3msIK5ec87kPrIYJWXb1XPnjIe5/jrkGLXiXpFuVL99z7mhoBCzftKtVPtzqI8EElnRE/VGFYT9BHNnWcw==", + "license": "MIT", + "dependencies": { + "@tanstack/router-core": "1.171.14", + "@tanstack/start-fn-stubs": "1.162.0", + "@tanstack/start-storage-context": "1.167.16", + "seroval": "^1.5.4" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/start-fn-stubs": { + "version": "1.162.0", + "resolved": "https://registry.npmjs.org/@tanstack/start-fn-stubs/-/start-fn-stubs-1.162.0.tgz", + "integrity": "sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/start-plugin-core": { + "version": "1.171.19", + "resolved": "https://registry.npmjs.org/@tanstack/start-plugin-core/-/start-plugin-core-1.171.19.tgz", + "integrity": "sha512-+fpW3Z/2vPT8HDV1c5p2WC6/g2k/AV/ujdJVDcn/VFd+gXRtzSX1D/LfozlaDbhDoEsqOnAk/mGwjg60JkUA2Q==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "7.27.1", + "@babel/core": "^7.28.5", + "@babel/types": "^7.28.5", + "@tanstack/router-core": "1.171.14", + "@tanstack/router-generator": "1.167.18", + "@tanstack/router-plugin": "1.168.19", + "@tanstack/router-utils": "1.162.2", + "@tanstack/start-server-core": "1.169.16", + "exsolve": "^1.0.7", + "lightningcss": "^1.32.0", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "seroval": "^1.5.4", + "source-map": "^0.7.6", + "srvx": "^0.11.9", + "tinyglobby": "^0.2.15", + "ufo": "^1.5.4", + "vitefu": "^1.1.1", + "xmlbuilder2": "^4.0.3", + "zod": "^4.4.3" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@rsbuild/core": "^2.0.0", + "vite": ">=7.0.0" + }, + "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@tanstack/start-plugin-core/node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@tanstack/start-server-core": { + "version": "1.169.16", + "resolved": "https://registry.npmjs.org/@tanstack/start-server-core/-/start-server-core-1.169.16.tgz", + "integrity": "sha512-lvAjQpH3nHJtd4xy0iHIaWbsTbyN9EBxuYCxbtXH0EpeBQPg+TCPhu9GQC9WbbA1rE//s82CpE55oYDQMqkU5A==", + "license": "MIT", + "dependencies": { + "@tanstack/history": "1.162.0", + "@tanstack/router-core": "1.171.14", + "@tanstack/start-client-core": "1.170.13", + "@tanstack/start-storage-context": "1.167.16", + "fetchdts": "^0.1.6", + "h3-v2": "npm:h3@2.0.1-rc.20", + "seroval": "^1.5.4" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/start-storage-context": { + "version": "1.167.16", + "resolved": "https://registry.npmjs.org/@tanstack/start-storage-context/-/start-storage-context-1.167.16.tgz", + "integrity": "sha512-zTegxlij4BC1DbCrC6rsVlMOQVMzOuG5IllacZEkrUdhiFwMIMYpk0VWGH+d0ucx5RBkmv8e8GNX3AOVBWclfg==", + "license": "MIT", + "dependencies": { + "@tanstack/router-core": "1.171.14" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/store": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.9.3.tgz", + "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-file-routes": { + "version": "1.162.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.162.0.tgz", + "integrity": "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==", + "license": "MIT", + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.0.tgz", + "integrity": "sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz", + "integrity": "sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.62.1", + "@typescript-eslint/type-utils": "8.62.1", + "@typescript-eslint/utils": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.62.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.1.tgz", + "integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.62.1", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.1.tgz", + "integrity": "sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.62.1", + "@typescript-eslint/types": "^8.62.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.1.tgz", + "integrity": "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz", + "integrity": "sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.1.tgz", + "integrity": "sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1", + "@typescript-eslint/utils": "8.62.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.1.tgz", + "integrity": "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.1.tgz", + "integrity": "sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.62.1", + "@typescript-eslint/tsconfig-utils": "8.62.1", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.1.tgz", + "integrity": "sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.62.1", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.1.tgz", + "integrity": "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz", + "integrity": "sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.9", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.9", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz", + "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==", + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-dead-code-elimination": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.12.tgz", + "integrity": "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.42", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.42.tgz", + "integrity": "sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", + "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.38", + "caniuse-lite": "^1.0.30001799", + "electron-to-chromium": "^1.5.376", + "node-releases": "^2.0.48", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001800", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz", + "integrity": "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/comment-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", + "integrity": "sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz", + "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossws": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.4.9.tgz", + "integrity": "sha512-iWx+1OMSG2aOHpjyf9AESOzkwsVdS49cXM9dVrI2PDhxU5l2RIWE/KG56gk4BbAnsMoycvniJ9OnOxO9LRzHVA==", + "license": "MIT", + "peerDependencies": { + "srvx": ">=0.11.5" + }, + "peerDependenciesMeta": { + "srvx": { + "optional": true + } + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.2.0.tgz", + "integrity": "sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.0.1", + "@csstools/css-syntax-patches-for-csstree": "^1.0.28", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cssstyle/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/dayjs": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "license": "MIT" + }, + "node_modules/db0": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/db0/-/db0-0.3.4.tgz", + "integrity": "sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==", + "license": "MIT", + "peerDependencies": { + "@electric-sql/pglite": "*", + "@libsql/client": "*", + "better-sqlite3": "*", + "drizzle-orm": "*", + "mysql2": "*", + "sqlite3": "*" + }, + "peerDependenciesMeta": { + "@electric-sql/pglite": { + "optional": true + }, + "@libsql/client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "drizzle-orm": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "sqlite3": { + "optional": true + } + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.387", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.387.tgz", + "integrity": "sha512-TaxwufTFDufvPEoXdhwVrA3UdFWBeWGkYoJ1K8ldF1xe6gKfth6iRNS5lTQ5JPNOHdGQm8PT1QYKUqFLCiUefQ==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-runner": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/env-runner/-/env-runner-0.1.16.tgz", + "integrity": "sha512-2LRJM4P2KLX6J83QZZrMqvgCDt/D5ea7wPcI3yYiy5cG/9rX5QwdwZFx0D7ktWnjdRyZxYjttGGorb5nFqb1CA==", + "license": "MIT", + "dependencies": { + "crossws": "^0.4.8", + "exsolve": "^1.1.0", + "httpxy": "^0.5.4", + "srvx": "^0.11.19" + }, + "bin": { + "env-runner": "dist/cli.mjs" + }, + "peerDependencies": { + "@netlify/runtime": "^4.1.23", + "@vercel/queue": ">=0.2.0", + "miniflare": "^4.20260515.0", + "wrangler": "^4.0.0" + }, + "peerDependenciesMeta": { + "@netlify/runtime": { + "optional": true + }, + "@vercel/queue": { + "optional": true + }, + "miniflare": { + "optional": true + }, + "wrangler": { + "optional": true + } + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.0.tgz", + "integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-compat-utils/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-import-context": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", + "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash-x": "^0.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, + "node_modules/eslint-plugin-import-x": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.17.1.tgz", + "integrity": "sha512-4cdstYkKCyjumM2Q9NSI03K8D2a9F4Ssz33K2lv2hQa4KmR9jPLwk3uWGtNvclfqBrPGfGuMBwsGMbe6dMRbfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "^8.56.0", + "comment-parser": "^1.4.1", + "debug": "^4.4.1", + "eslint-import-context": "^0.1.9", + "is-glob": "^4.0.3", + "minimatch": "^9.0.3 || ^10.1.2", + "semver": "^7.7.2", + "stable-hash-x": "^0.2.0", + "unrs-resolver": "^1.9.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-import-x" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^8.56.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "eslint-import-resolver-node": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/utils": { + "optional": true + }, + "eslint-import-resolver-node": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-import-x/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint-plugin-import-x/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint-plugin-import-x/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-plugin-import-x/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-n": { + "version": "17.24.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.24.0.tgz", + "integrity": "sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.5.0", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "globrex": "^0.1.2", + "ignore": "^5.3.2", + "semver": "^7.6.3", + "ts-declaration-location": "^1.0.6" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": ">=8.23.0" + } + }, + "node_modules/eslint-plugin-n/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/exsolve": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.0.tgz", + "integrity": "sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fetchdts": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.7.tgz", + "integrity": "sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", + "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/goober": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.19.tgz", + "integrity": "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/h3": { + "version": "2.0.1-rc.22", + "resolved": "https://registry.npmjs.org/h3/-/h3-2.0.1-rc.22.tgz", + "integrity": "sha512-Esv0DMIuPkCTSWCA0vO73vcTqwzH1wjSrAO1TXNu/K3up1sZHa9EKMapbmxCDYBeymC3fVTk4qxp7ogQWQ+KgA==", + "license": "MIT", + "dependencies": { + "rou3": "^0.8.1", + "srvx": "^0.11.15" + }, + "bin": { + "h3": "bin/h3.mjs" + }, + "engines": { + "node": ">=20.11.1" + }, + "peerDependencies": { + "crossws": "^0.4.1" + }, + "peerDependenciesMeta": { + "crossws": { + "optional": true + } + } + }, + "node_modules/h3-v2": { + "name": "h3", + "version": "2.0.1-rc.20", + "resolved": "https://registry.npmjs.org/h3/-/h3-2.0.1-rc.20.tgz", + "integrity": "sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==", + "license": "MIT", + "dependencies": { + "rou3": "^0.8.1", + "srvx": "^0.11.13" + }, + "bin": { + "h3": "bin/h3.mjs" + }, + "engines": { + "node": ">=20.11.1" + }, + "peerDependencies": { + "crossws": "^0.4.1" + }, + "peerDependenciesMeta": { + "crossws": { + "optional": true + } + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hookable": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.1.1.tgz", + "integrity": "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==", + "license": "MIT" + }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/httpxy": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/httpxy/-/httpxy-0.5.4.tgz", + "integrity": "sha512-URfeibL0kTH6VuIxxaJDXWQWEk8fKr+9L8MGv6CuAiNy0fGnoVhWbXBvJR1mkdsvCDUxvhX9cW60k2AhtH5s6w==", + "license": "MIT" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isbot": { + "version": "5.1.44", + "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.44.tgz", + "integrity": "sha512-PGEHtwMnKbZpeSEXW2Utx+/JWed7dp6DiH0WWg33vGSDA7RUvpUeJSVlLrVkQ1RCpvDOUc/eH9ql7VsdbBZ8pA==", + "license": "Unlicense", + "engines": { + "node": ">=18" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", + "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@acemir/cssom": "^0.9.31", + "@asamuzakjp/dom-selector": "^6.8.1", + "@bramus/specificity": "^2.4.2", + "@exodus/bytes": "^1.11.0", + "cssstyle": "^6.0.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.0", + "undici": "^7.21.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/launch-editor": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz", + "integrity": "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.4" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.545.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.545.0.tgz", + "integrity": "sha512-7r1/yUuflQDSt4f1bpn5ZAocyIxcTyVyBBChSVtBKn5M+392cPmI5YJMWOJKk/HUWGm5wg83chlAZtCcGbEZtw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nf3": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/nf3/-/nf3-0.3.19.tgz", + "integrity": "sha512-tfOXX/ivQBL+4km/fzxQ0HWMmp1Ewx/YpFLbya080gXVfm26bZy0n4a5K5PPnqTLyuAHu0FobVpXXUadIiIwIQ==", + "license": "MIT" + }, + "node_modules/nitro": { + "name": "nitro-nightly", + "version": "3.0.1-20260702-173353-03122331", + "resolved": "https://registry.npmjs.org/nitro-nightly/-/nitro-nightly-3.0.1-20260702-173353-03122331.tgz", + "integrity": "sha512-XIpdxZKnC6sFhyfq7Rl/TPgrzEupeIBQKZoQD3tPMTMJfXcF3pMJHy7850vPBq1klIS4ec6pTrE06qh7kGm6/Q==", + "license": "MIT", + "dependencies": { + "consola": "^3.4.2", + "crossws": "^0.4.8", + "db0": "^0.3.4", + "env-runner": "^0.1.15", + "h3": "^2.0.1-rc.22", + "hookable": "^6.1.1", + "nf3": "^0.3.19", + "ocache": "^0.1.5", + "ofetch": "^2.0.0-alpha.3", + "ohash": "^2.0.11", + "rolldown": "^1.1.4", + "srvx": "^0.11.20", + "unenv": "^2.0.0-rc.24", + "unstorage": "^2.0.0-alpha.7" + }, + "bin": { + "nitro": "dist/cli/index.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@vercel/queue": "^0.3.1", + "dotenv": "*", + "giget": "*", + "jiti": "^2.7.0", + "rollup": "^4.62.0", + "vite": "^7 || ^8", + "xml2js": "^0.6.2", + "zephyr-agent": "^0.2.0" + }, + "peerDependenciesMeta": { + "@vercel/queue": { + "optional": true + }, + "dotenv": { + "optional": true + }, + "giget": { + "optional": true + }, + "jiti": { + "optional": true + }, + "rollup": { + "optional": true + }, + "vite": { + "optional": true + }, + "xml2js": { + "optional": true + }, + "zephyr-agent": { + "optional": true + } + } + }, + "node_modules/nitro/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "extraneous": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/nitro/node_modules/unstorage": { + "version": "2.0.0-alpha.7", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-2.0.0-alpha.7.tgz", + "integrity": "sha512-ELPztchk2zgFJnakyodVY3vJWGW9jy//keJ32IOJVGUMyaPydwcA1FtVvWqT0TNRch9H+cMNEGllfVFfScImog==", + "license": "MIT", + "peerDependencies": { + "@azure/app-configuration": "^1.11.0", + "@azure/cosmos": "^4.9.1", + "@azure/data-tables": "^13.3.2", + "@azure/identity": "^4.13.0", + "@azure/keyvault-secrets": "^4.10.0", + "@azure/storage-blob": "^12.31.0", + "@capacitor/preferences": "^6 || ^7 || ^8", + "@deno/kv": ">=0.13.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.36.2", + "@vercel/blob": ">=0.27.3", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "chokidar": "^4 || ^5", + "db0": ">=0.3.4", + "idb-keyval": "^6.2.2", + "ioredis": "^5.9.3", + "lru-cache": "^11.2.6", + "mongodb": "^6 || ^7", + "ofetch": "*", + "uploadthing": "^7.7.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "chokidar": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "lru-cache": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "ofetch": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/obug": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", + "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/ocache": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/ocache/-/ocache-0.1.5.tgz", + "integrity": "sha512-kNNnkkVQup/QDvmTz8Q84wc2ntiyoVHDxa6eHWKt5qdGAmFRBIxy83rxgCYEjW0x06UJ9E3P6VgM2yY4rOBH4w==", + "license": "MIT", + "dependencies": { + "ohash": "^2.0.11" + } + }, + "node_modules/ofetch": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-2.0.0-alpha.3.tgz", + "integrity": "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==", + "license": "MIT" + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/oxc-parser": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.120.0.tgz", + "integrity": "sha512-WyPWZlcIm+Fkte63FGfgFB8mAAk33aH9h5N9lphXVOHSXEBFFsmYdOBedVKly363aWABjZdaj/m9lBfEY4wt+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.120.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.120.0", + "@oxc-parser/binding-android-arm64": "0.120.0", + "@oxc-parser/binding-darwin-arm64": "0.120.0", + "@oxc-parser/binding-darwin-x64": "0.120.0", + "@oxc-parser/binding-freebsd-x64": "0.120.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.120.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.120.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.120.0", + "@oxc-parser/binding-linux-arm64-musl": "0.120.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.120.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.120.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.120.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.120.0", + "@oxc-parser/binding-linux-x64-gnu": "0.120.0", + "@oxc-parser/binding-linux-x64-musl": "0.120.0", + "@oxc-parser/binding-openharmony-arm64": "0.120.0", + "@oxc-parser/binding-wasm32-wasi": "0.120.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.120.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.120.0", + "@oxc-parser/binding-win32-x64-msvc": "0.120.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", + "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.4.tgz", + "integrity": "sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/rolldown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.4.tgz", + "integrity": "sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.138.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.4", + "@rolldown/binding-darwin-arm64": "1.1.4", + "@rolldown/binding-darwin-x64": "1.1.4", + "@rolldown/binding-freebsd-x64": "1.1.4", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.4", + "@rolldown/binding-linux-arm64-gnu": "1.1.4", + "@rolldown/binding-linux-arm64-musl": "1.1.4", + "@rolldown/binding-linux-ppc64-gnu": "1.1.4", + "@rolldown/binding-linux-s390x-gnu": "1.1.4", + "@rolldown/binding-linux-x64-gnu": "1.1.4", + "@rolldown/binding-linux-x64-musl": "1.1.4", + "@rolldown/binding-openharmony-arm64": "1.1.4", + "@rolldown/binding-wasm32-wasi": "1.1.4", + "@rolldown/binding-win32-arm64-msvc": "1.1.4", + "@rolldown/binding-win32-x64-msvc": "1.1.4" + } + }, + "node_modules/rolldown/node_modules/@oxc-project/types": { + "version": "0.138.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.138.0.tgz", + "integrity": "sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/rou3": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.8.1.tgz", + "integrity": "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==", + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/seroval": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.4.tgz", + "integrity": "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/seroval-plugins": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.5.4.tgz", + "integrity": "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "seroval": "^1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz", + "integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/solid-js": { + "version": "1.9.14", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.14.tgz", + "integrity": "sha512-sAEXC0Kk0S1EDg+8ysEWJDbYhA3RRoEjwuySUGlKIemeo0I5YZfOyumNjNs9Sv3y2nmhD+0rW66ag2HsMuQiGQ==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.0", + "seroval": "~1.5.4", + "seroval-plugins": "~1.5.4" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/srvx": { + "version": "0.11.21", + "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.21.tgz", + "integrity": "sha512-GWTHjKMeekX8CwJf4VU9Oo6mJpSGaflGMddbCvR+Cmmh9sslRMiGbAoqqZacE0r1ncARh6buCEETr2W52F8b1w==", + "license": "MIT", + "bin": { + "srvx": "bin/srvx.mjs" + }, + "engines": { + "node": ">=20.16.0" + } + }, + "node_modules/stable-hash-x": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", + "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwindcss": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", + "integrity": "sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.6.tgz", + "integrity": "sha512-rbP0Gyx8b3Ae9yO//CU2wbSnQNoQ66m1nJdSbSHmnwKwzkkz/u8mERYU8T2rmlmy+bJvRNn84yNCW8gYqox44Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.6" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.6.tgz", + "integrity": "sha512-TkQNGJIhlEphpHCjKodMTSe23egUZr/g+flI2qkLgiJ/maAzSgXypSLRTNH3nCmqgayEmtcJBiLcfODSAr1xoA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-declaration-location": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", + "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", + "dev": true, + "funding": [ + { + "type": "ko-fi", + "url": "https://ko-fi.com/rebeccastevens" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" + } + ], + "license": "BSD-3-Clause", + "dependencies": { + "picomatch": "^4.0.2" + }, + "peerDependencies": { + "typescript": ">=4.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.1.tgz", + "integrity": "sha512-vymnnM5g0AKQDSAyfP12nMIBvgwgA42syg74kkuZ4x1VuTzwQKwc5h9rGxeShCjny5o+zWAb6OEoz7XLgrIkIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.62.1", + "@typescript-eslint/parser": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1", + "@typescript-eslint/utils": "8.62.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "license": "MIT" + }, + "node_modules/undici": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unenv": { + "version": "2.0.0-rc.24", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", + "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3" + } + }, + "node_modules/unplugin": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.3.0.tgz", + "integrity": "sha512-qa66K+crbfyE6JK10GjvbJeRrOsuC/JpbnHctfyp/i4oBTxWOzJfRZyDiOk1PtErMFRu8JhsU/wPvOdBNWe5Rg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.4", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@farmfe/core": "*", + "@rspack/core": "*", + "bun-types-no-globals": "*", + "esbuild": "*", + "rolldown": "*", + "rollup": "*", + "unloader": "*", + "vite": "*", + "webpack": "*" + }, + "peerDependenciesMeta": { + "@farmfe/core": { + "optional": true + }, + "@rspack/core": { + "optional": true + }, + "bun-types-no-globals": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "rolldown": { + "optional": true + }, + "rollup": { + "optional": true + }, + "unloader": { + "optional": true + }, + "vite": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/unrs-resolver": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.3.tgz", + "integrity": "sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==", + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.16", + "rolldown": "~1.1.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.4.1.tgz", + "integrity": "sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "eslint-scope": "^8.2.0 || ^9.0.0", + "eslint-visitor-keys": "^4.2.0 || ^5.0.0", + "espree": "^10.3.0 || ^11.0.0", + "esquery": "^1.6.0", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "license": "MIT" + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlbuilder2": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-4.0.3.tgz", + "integrity": "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==", + "license": "MIT", + "dependencies": { + "@oozcitak/dom": "^2.0.2", + "@oozcitak/infra": "^2.0.2", + "@oozcitak/util": "^10.0.0", + "js-yaml": "^4.1.1" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/web-terminal/package.json b/web-terminal/package.json new file mode 100644 index 0000000..c462cc6 --- /dev/null +++ b/web-terminal/package.json @@ -0,0 +1,56 @@ +{ + "name": "quarkshologridledger", + "private": true, + "type": "module", + "imports": { + "#/*": "./src/*" + }, + "scripts": { + "dev": "vite dev --port 3000", + "generate-routes": "tsr generate", + "build": "vite build", + "preview": "vite preview", + "test": "vitest run", + "lint": "eslint", + "format": "prettier --write . && eslint --fix", + "check": "prettier --check ." + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.18", + "@tanstack/react-devtools": "latest", + "@tanstack/react-router": "latest", + "@tanstack/react-router-devtools": "latest", + "@tanstack/react-router-ssr-query": "latest", + "@tanstack/react-start": "latest", + "@tanstack/router-plugin": "^1.132.0", + "lucide-react": "^0.545.0", + "nitro": "npm:nitro-nightly@latest", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tailwindcss": "^4.1.18" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.16", + "@tanstack/devtools-vite": "latest", + "@tanstack/eslint-config": "latest", + "@tanstack/router-cli": "^1.132.0", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.0", + "@types/node": "^22.10.2", + "@types/react": "^19.2.0", + "@types/react-dom": "^19.2.0", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^9.20.0", + "jsdom": "^28.1.0", + "prettier": "^3.8.1", + "typescript": "^6.0.2", + "vite": "^8.0.0", + "vitest": "^4.1.5" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "esbuild", + "lightningcss" + ] + } +} diff --git a/web-terminal/prettier.config.js b/web-terminal/prettier.config.js new file mode 100644 index 0000000..f7279f7 --- /dev/null +++ b/web-terminal/prettier.config.js @@ -0,0 +1,10 @@ +// @ts-check + +/** @type {import('prettier').Config} */ +const config = { + semi: false, + singleQuote: true, + trailingComma: 'all', +} + +export default config diff --git a/web-terminal/public/favicon.ico b/web-terminal/public/favicon.ico new file mode 100644 index 0000000..a11777c Binary files /dev/null and b/web-terminal/public/favicon.ico differ diff --git a/web-terminal/public/logo192.png b/web-terminal/public/logo192.png new file mode 100644 index 0000000..fc44b0a Binary files /dev/null and b/web-terminal/public/logo192.png differ diff --git a/web-terminal/public/logo512.png b/web-terminal/public/logo512.png new file mode 100644 index 0000000..a4e47a6 Binary files /dev/null and b/web-terminal/public/logo512.png differ diff --git a/web-terminal/public/manifest.json b/web-terminal/public/manifest.json new file mode 100644 index 0000000..078ef50 --- /dev/null +++ b/web-terminal/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "TanStack App", + "name": "Create TanStack App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/web-terminal/public/robots.txt b/web-terminal/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/web-terminal/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/web-terminal/src/components/ascii/AsciiPanel.tsx b/web-terminal/src/components/ascii/AsciiPanel.tsx new file mode 100644 index 0000000..5054e17 --- /dev/null +++ b/web-terminal/src/components/ascii/AsciiPanel.tsx @@ -0,0 +1,38 @@ +import React from 'react' + +interface AsciiPanelProps { + title: string + subtitle?: string + children: React.ReactNode + variant: 'emerald' | 'amber' | 'slate' +} + +export function AsciiPanel({ + title, + subtitle, + children, + variant = 'slate', +}: AsciiPanelProps) { + const colorMap = { + emerald: + 'border-emerald-500/40 text-emerald-400 shadow-[0_0_10px_rgba(16,185,129,0.05)]', + amber: + 'border-amber-500/40 text-amber-400 shadow-[0_0_10px_rgba(245,158,11,0.05)]', + slate: 'border-slate-800 text-slate-400', + } + return ( +
+ {/* Dynamic Header Band */} +
+ [ {title} ] + {subtitle && {subtitle}} +
+ {/* Panel Inner Body */} +
+ {children} +
+
+ ) +} diff --git a/web-terminal/src/components/ascii/BlinkingCursor.tsx b/web-terminal/src/components/ascii/BlinkingCursor.tsx new file mode 100644 index 0000000..3340b02 --- /dev/null +++ b/web-terminal/src/components/ascii/BlinkingCursor.tsx @@ -0,0 +1,5 @@ +export function BlinkingCursor() { + return ( + + ) +} diff --git a/web-terminal/src/components/ascii/GlyphIcon.tsx b/web-terminal/src/components/ascii/GlyphIcon.tsx new file mode 100644 index 0000000..bf80210 --- /dev/null +++ b/web-terminal/src/components/ascii/GlyphIcon.tsx @@ -0,0 +1,26 @@ +interface GlyphIconProps { + glyph: string + colorCode?: string + size?: 'sm' | 'md' | 'lg' +} + +export function GlyphIcon({ + glyph, + colorCode = '#94a3b8', + size = 'sm', +}: GlyphIconProps) { + const sizeClass = { + sm: 'text-xs w-4 h-4', + md: 'text-sm w-5 h-5', + lg: 'text-base w-6 h-6', + }[size] + + return ( + + {glyph} + + ) +} diff --git a/web-terminal/src/components/ascii/PriceTag.tsx b/web-terminal/src/components/ascii/PriceTag.tsx new file mode 100644 index 0000000..adfff70 --- /dev/null +++ b/web-terminal/src/components/ascii/PriceTag.tsx @@ -0,0 +1,25 @@ +interface PriceTagProps { + price: number + previousPrice?: number + trend?: string +} + +export function PriceTag({ price, previousPrice, trend }: PriceTagProps) { + const showTrend = trend && trend !== 'stable' && previousPrice !== undefined + const isUp = trend === 'up' + + return ( + + + [{price.toFixed(2)}] + + {showTrend && ( + + {isUp ? 'β–²' : 'β–Ό'} + + )} + + ) +} diff --git a/web-terminal/src/components/ascii/ShieldBar.tsx b/web-terminal/src/components/ascii/ShieldBar.tsx new file mode 100644 index 0000000..566295d --- /dev/null +++ b/web-terminal/src/components/ascii/ShieldBar.tsx @@ -0,0 +1,24 @@ +interface ShieldBarProps { + homeShield: number + awayShield: number +} + +// ShieldBar is a low-level plaintext visual decorator showing combatant health +export function ShieldBar({ homeShield, awayShield }: ShieldBarProps) { + return ( +
+ {homeShield}% +
+
+
+
+ {awayShield}% +
+ ) +} diff --git a/web-terminal/src/components/ascii/StatusBadge.tsx b/web-terminal/src/components/ascii/StatusBadge.tsx new file mode 100644 index 0000000..99bed34 --- /dev/null +++ b/web-terminal/src/components/ascii/StatusBadge.tsx @@ -0,0 +1,28 @@ +interface StatusBadgeProps { + status: 'LIVE' | 'PRE' | 'RES' | 'SETTLED' +} + +// StatusBadge is a low-level visual indicator for match states +export function StatusBadge({ status }: StatusBadgeProps) { + const colorMap = { + LIVE: 'text-emerald-400 animate-pulse', + PRE: 'text-amber-500', + RES: 'text-rose-500', + SETTLED: 'text-slate-500', + } + + const labelMap = { + LIVE: '● LIVE', + PRE: 'β—‹ PRE', + RES: 'β—‰ RES', + SETTLED: 'β–  SETTLED', + } + + return ( + + {labelMap[status]} + + ) +} diff --git a/web-terminal/src/components/ascii/TerminalLine.tsx b/web-terminal/src/components/ascii/TerminalLine.tsx new file mode 100644 index 0000000..964cfa6 --- /dev/null +++ b/web-terminal/src/components/ascii/TerminalLine.tsx @@ -0,0 +1,31 @@ +interface TerminalLineProps { + variant?: 'solid' | 'dashed' | 'dotted' | 'double' + label?: string +} + +export function TerminalLine({ variant = 'solid', label }: TerminalLineProps) { + const borderStyle = { + solid: 'border-solid', + dashed: 'border-dashed', + dotted: 'border-dotted', + double: 'border-double border-b-2', + }[variant] + + if (label) { + return ( +
+
+ + {label} + +
+
+ ) + } + + return ( +
+ ) +} diff --git a/web-terminal/src/components/ascii/TickProgress.tsx b/web-terminal/src/components/ascii/TickProgress.tsx new file mode 100644 index 0000000..e748230 --- /dev/null +++ b/web-terminal/src/components/ascii/TickProgress.tsx @@ -0,0 +1,28 @@ +interface TickProgressProps { + current: number + max: number +} + +export function TickProgress({ current, max }: TickProgressProps) { + const percent = Math.min(Math.max((current / max) * 100, 0), 100) + const barLength = 20 + const filledLength = Math.round((percent / 100) * barLength) + const emptyLength = barLength - filledLength + + const filledBar = 'β–ˆ'.repeat(filledLength) + const emptyBar = 'β–‘'.repeat(emptyLength) + + return ( +
+ CYCLE: + + {current}/{max} + + + [{filledBar} + {emptyBar}] + + {percent.toFixed(0)}% +
+ ) +} diff --git a/web-terminal/src/components/panels/AccountSummary.tsx b/web-terminal/src/components/panels/AccountSummary.tsx new file mode 100644 index 0000000..fe4de6f --- /dev/null +++ b/web-terminal/src/components/panels/AccountSummary.tsx @@ -0,0 +1,7 @@ +export function AccountSummary() { + return ( +
+
Account Statistics Summary
+
+ ) +} diff --git a/web-terminal/src/components/panels/BetslipSidecar.tsx b/web-terminal/src/components/panels/BetslipSidecar.tsx new file mode 100644 index 0000000..5240c09 --- /dev/null +++ b/web-terminal/src/components/panels/BetslipSidecar.tsx @@ -0,0 +1,103 @@ +import { useBetslip } from '#/components/providers/BetslipProvider' + +export function BetslipSidecar() { + const { selections, removeSelection, clearAll, updateStake } = useBetslip() + + const totalStake = selections.reduce((sum, s) => sum + (s.stake || 0), 0) + const totalReturn = selections.reduce( + (sum, s) => sum + (s.stake || 0) * s.price, + 0, + ) + + return ( +
+
+ SELECTIONS ({selections.length}) + {selections.length > 0 && ( + + )} +
+ + {selections.length === 0 ? ( +
+ Wager slip standby. Choose active odds matrices to link a prediction. +
+ ) : ( +
+ {selections.map((sel) => ( +
+
+ + {sel.matchName} + + +
+
+ + {sel.factionGlyph} + {sel.selectionName} + + + {sel.price.toFixed(2)} + +
+
+ STAKE: +
+ + updateStake(sel.marketId, parseFloat(e.target.value) || 0) + } + className="w-16 bg-slate-950 border border-slate-800 text-right px-1 text-slate-300 font-mono text-[10px] outline-none" + placeholder="0.00" + /> + GPL +
+
+
+ ))} +
+ )} + + {selections.length > 0 && ( +
+
+ TOTAL STAKE: + {totalStake.toFixed(2)} GPL +
+
+ EST. RETURN: + + {totalReturn.toFixed(2)} GPL + +
+ + +
+ "The riskier the road, the greater the profit." +
β€” Rule of Acquisition #62 +
+
+ )} +
+ ) +} diff --git a/web-terminal/src/components/panels/EngagementLog.tsx b/web-terminal/src/components/panels/EngagementLog.tsx new file mode 100644 index 0000000..8f3e863 --- /dev/null +++ b/web-terminal/src/components/panels/EngagementLog.tsx @@ -0,0 +1,78 @@ +export interface CombatLogEntry { + id: string + tick: number + message: string + type: 'combat' | 'event' | 'system' +} + +interface EngagementLogProps { + logs?: CombatLogEntry[] +} + +export function EngagementLog({ logs }: EngagementLogProps) { + // Default mock logs for display + const defaultLogs: CombatLogEntry[] = [ + { + id: '1', + tick: 42, + message: 'β—† Starfleet Command fires β€” HIT β€” 4.2% shield damage', + type: 'combat', + }, + { + id: '2', + tick: 42, + message: 'β–ˆ Borg Collective fires β€” MISS β€” Evasion successful', + type: 'combat', + }, + { + id: '3', + tick: 38, + message: + '⚑ EVENT: Borg Adaptation active β€” Incoming damage multiplier Γ—0.5', + type: 'event', + }, + { + id: '4', + tick: 35, + message: 'β—† Starfleet Command fires β€” CRIT β€” 12.6% shield damage', + type: 'combat', + }, + { + id: '5', + tick: 31, + message: + 'πŸŒ€ EVENT: Debris Impact β€” Borg Collective shields reduced by 12%', + type: 'event', + }, + { + id: '6', + tick: 28, + message: 'β–ˆ Borg Collective fires β€” HIT β€” 6.1% shield damage', + type: 'combat', + }, + ] + + const displayLogs = logs || defaultLogs + + const logColor = { + combat: 'text-slate-400', + event: 'text-amber-400', + system: 'text-sky-400', + } + + return ( +
+ {displayLogs.map((log) => ( +
+ + [T{log.tick}] + + {log.message} +
+ ))} +
+ ) +} diff --git a/web-terminal/src/components/panels/FactionProfile.tsx b/web-terminal/src/components/panels/FactionProfile.tsx new file mode 100644 index 0000000..c96d1c2 --- /dev/null +++ b/web-terminal/src/components/panels/FactionProfile.tsx @@ -0,0 +1,7 @@ +export function FactionProfile() { + return ( +
+
Faction Tactical Profile View
+
+ ) +} diff --git a/web-terminal/src/components/panels/FactionTable.tsx b/web-terminal/src/components/panels/FactionTable.tsx new file mode 100644 index 0000000..78106cc --- /dev/null +++ b/web-terminal/src/components/panels/FactionTable.tsx @@ -0,0 +1,7 @@ +export function FactionTable() { + return ( +
+
Faction Registry Database Table
+
+ ) +} diff --git a/web-terminal/src/components/panels/LiveTicker.tsx b/web-terminal/src/components/panels/LiveTicker.tsx new file mode 100644 index 0000000..8699555 --- /dev/null +++ b/web-terminal/src/components/panels/LiveTicker.tsx @@ -0,0 +1,64 @@ +export interface TickerEvent { + id: string + time: string + message: string + type: 'combat' | 'event' | 'system' +} + +interface LiveTickerProps { + events?: TickerEvent[] +} + +export function LiveTicker({ events }: LiveTickerProps) { + // Default mock ticker events + const defaultEvents: TickerEvent[] = [ + { + id: '1', + time: '14:32', + message: 'Borg Adaptation triggered β€” Damage reduced 50%', + type: 'event', + }, + { + id: '2', + time: '14:30', + message: 'Critical Hit! Starfleet Command deals 3Γ— damage', + type: 'combat', + }, + { + id: '3', + time: '14:28', + message: 'Bajor Sector: Prophet Intervention β€” Markets SUSPENDED', + type: 'event', + }, + { + id: '4', + time: '14:25', + message: 'New match scheduled: Klingons vs Romulans @ Narendra III', + type: 'system', + }, + ] + + const displayEvents = events || defaultEvents + + const typeColor = { + combat: 'text-rose-400', + event: 'text-amber-400', + system: 'text-sky-400', + } + + return ( +
+ {displayEvents.map((evt) => ( +
+ + [{evt.time}] + + + {evt.type.toUpperCase()}: + + {evt.message} +
+ ))} +
+ ) +} diff --git a/web-terminal/src/components/panels/MarketGrid.tsx b/web-terminal/src/components/panels/MarketGrid.tsx new file mode 100644 index 0000000..8bab40a --- /dev/null +++ b/web-terminal/src/components/panels/MarketGrid.tsx @@ -0,0 +1,103 @@ +import { Link } from '@tanstack/react-router' +import { MarketSelection } from '#/components/panels/MarketSelection' + +export interface SelectionData { + id: string + name: string + price: number + factionGlyph: string +} + +export interface MarketItem { + id: string + templateId: string + name: string + category: 'primary' | 'secondary' | 'exotic' + selections: SelectionData[] +} + +interface MarketGridProps { + matchId: string + matchName: string + markets: MarketItem[] + currentCategory: 'primary' | 'secondary' | 'exotic' | 'all' +} + +export function MarketGrid({ + matchId, + matchName, + markets, + currentCategory, +}: MarketGridProps) { + // Filter tabs config + const tabs = [ + { id: 'all', label: 'ALL MARKETS' }, + { id: 'primary', label: 'PRIMARY' }, + { id: 'secondary', label: 'SECONDARY' }, + { id: 'exotic', label: 'EXOTIC' }, + ] as const + + // Filter markets by current category + const filteredMarkets = + currentCategory === 'all' + ? markets + : markets.filter((m) => m.category === currentCategory) + + return ( +
+ {/* Category Tabs */} +
+ {tabs.map((tab) => ( + ({ ...prev, marketCategory: tab.id })} + className={`flex-1 text-center py-1.5 border font-bold uppercase transition-all cursor-pointer ${ + currentCategory === tab.id + ? 'border-emerald-500/50 text-emerald-400 bg-emerald-950/20' + : 'border-slate-950 text-slate-500 hover:text-slate-400 hover:border-slate-800 bg-black/40' + }`} + > + {tab.label} + + ))} +
+ + {/* Markets List */} +
+ {filteredMarkets.length === 0 ? ( +
+ No active markets available in this category sector. +
+ ) : ( + filteredMarkets.map((market) => ( +
+ {/* Market Header: Title + Category Tag */} +
+ {market.name} + + [{market.category}] + +
+ + {/* Selections Selection Grid (moneyline has 2 columns, others can wrap) */} +
+ {market.selections.map((sel) => ( + + ))} +
+
+ )) + )} +
+
+ ) +} diff --git a/web-terminal/src/components/panels/MarketSelection.tsx b/web-terminal/src/components/panels/MarketSelection.tsx new file mode 100644 index 0000000..1ff005d --- /dev/null +++ b/web-terminal/src/components/panels/MarketSelection.tsx @@ -0,0 +1,58 @@ +import { useBetslip } from '#/components/providers/BetslipProvider' +import { PriceTag } from '#/components/ascii/PriceTag' + +interface MarketSelectionProps { + matchId: string + matchName: string + marketId: string + selectionName: string + price: number + factionGlyph: string +} + +export function MarketSelection({ + matchId, + matchName, + marketId, + selectionName, + price, + factionGlyph, +}: MarketSelectionProps) { + const { selections, addSelection, removeSelection } = useBetslip() + + const isSelected = selections.some((s) => s.marketId === marketId) + + const handleToggle = () => { + if (isSelected) { + removeSelection(marketId) + } else { + addSelection({ + matchId, + matchName, + marketId, + selectionName, + price, + factionGlyph, + }) + } + } + + return ( + + ) +} diff --git a/web-terminal/src/components/panels/MatchCard.tsx b/web-terminal/src/components/panels/MatchCard.tsx new file mode 100644 index 0000000..69665d1 --- /dev/null +++ b/web-terminal/src/components/panels/MatchCard.tsx @@ -0,0 +1,176 @@ +import { Link } from '@tanstack/react-router' +import { GlyphIcon } from '#/components/ascii/GlyphIcon' +import { StatusBadge } from '#/components/ascii/StatusBadge' +import { ShieldBar } from '#/components/ascii/ShieldBar' +import { TerminalLine } from '#/components/ascii/TerminalLine' +import { PriceTag } from '#/components/ascii/PriceTag' + +interface FactionDetail { + abbreviation: string + name: string + glyph: string + colorCode: string + shieldCapacity: number + oddsPrice: number +} + +export interface MatchData { + id: string + name: string + quadrant: 'alpha' | 'beta' | 'gamma' | 'delta' + status: 'LIVE' | 'PRE' | 'RES' + tick: number + maxTicks: number + kineticYield: number + homeFaction: FactionDetail + awayFaction: FactionDetail + marketsOpenCount: number + commencingIn?: string +} + +interface MatchCardProps { + match: MatchData +} + +export function MatchCard({ match }: MatchCardProps) { + const isLive = match.status === 'LIVE' + const isPre = match.status === 'PRE' + + // Format quadrant letter glyph + const quadGlyph = { + alpha: 'Ξ±', + beta: 'Ξ²', + gamma: 'Ξ³', + delta: 'Ξ΄', + }[match.quadrant] + + return ( +
+
+ {/* Header: Venue + Status + Quadrant */} +
+ + {match.name} + +
+ + + {quadGlyph} + +
+
+ + {/* Combat Factions Layout */} +
+ {/* Home Faction */} +
+
+ + + {match.homeFaction.name} + +
+ {isLive && ( + + {match.homeFaction.shieldCapacity}% + + )} +
+ + {/* Away Faction */} +
+
+ + + {match.awayFaction.name} + +
+ {isLive && ( + + {match.awayFaction.shieldCapacity}% + + )} +
+ + {/* Dual Shield Bar for Live Match */} + {isLive && ( +
+ +
+ )} +
+
+ +
+ + + {/* Footer info: Telemetry details + Action Button */} +
+
+ {isLive ? ( +
+
+ KY:{' '} + + {match.kineticYield.toFixed(1)} TW + {' '} + | TICK:{' '} + + {match.tick}/{match.maxTicks} + +
+
+ ODDS: + + {match.homeFaction.abbreviation} + + + | + + {match.awayFaction.abbreviation} + + +
+
+ ) : isPre ? ( +
+
+ COMMENCING IN: {match.commencingIn} +
+
PRE-MATCH ODDS AVAILABLE
+
+ ) : ( +
MATCH IN RESOLUTION PHASE
+ )} +
+ + ({ + ...prev, + quadrant: match.quadrant, + currency: prev.currency || 'Latinum', + })} + className="border border-slate-900 hover:border-amber-500/50 bg-slate-950 px-2 py-1 text-slate-400 hover:text-amber-400 font-bold tracking-wider shrink-0 transition-all cursor-pointer" + > + [VIEW] β†’ + +
+ +
+ β–Έ {match.marketsOpenCount} MARKETS OPEN +
+
+
+ ) +} diff --git a/web-terminal/src/components/panels/NavigationMenu.tsx b/web-terminal/src/components/panels/NavigationMenu.tsx new file mode 100644 index 0000000..5a67f9b --- /dev/null +++ b/web-terminal/src/components/panels/NavigationMenu.tsx @@ -0,0 +1,392 @@ +import { useState } from 'react' +import { Link } from '@tanstack/react-router' +import { ShieldBar } from '#/components/ascii/ShieldBar' +import { StatusBadge } from '#/components/ascii/StatusBadge' +import { GlyphIcon } from '#/components/ascii/GlyphIcon' + +// ─── TYPES ────────────────────────────────────────────────────────────── + +interface ActiveMatchSummary { + id: string + name: string + quadrant: 'alpha' | 'beta' | 'gamma' | 'delta' + status: 'LIVE' | 'PRE' | 'RES' + homeFaction: { + abbreviation: string + glyph: string + colorCode: string + shieldCapacity: number + } + awayFaction: { + abbreviation: string + glyph: string + colorCode: string + shieldCapacity: number + } +} + +interface QuadrantConfig { + id: string + name: string + glyph: string +} + +// ─── MAIN COMPONENT ───────────────────────────────────────────────────── + +export function NavigationMenu() { + // Collapsible quadrant groups state + const [openQuadrants, setOpenQuadrants] = useState>({ + alpha: true, + beta: true, + gamma: false, + delta: false, + }) + + const toggleQuadrant = (q: string) => { + setOpenQuadrants((prev) => ({ + ...prev, + [q]: !prev[q], + })) + } + + // Mock Active Matches aligned with taxonomy.yaml and color codes + const matches: ActiveMatchSummary[] = [ + { + id: 'sector-001', + name: 'Sector 001 β€” Sol Array', + quadrant: 'alpha', + status: 'LIVE', + homeFaction: { + abbreviation: 'SFC', + glyph: 'β—†', + colorCode: '#34d399', + shieldCapacity: 62, + }, + awayFaction: { + abbreviation: 'BRG', + glyph: 'β–ˆ', + colorCode: '#38bdf8', + shieldCapacity: 71, + }, + }, + { + id: 'bajor-wormhole', + name: 'Bajor Sector β€” DS9', + quadrant: 'alpha', + status: 'LIVE', + homeFaction: { + abbreviation: 'BAJ', + glyph: '☼', + colorCode: '#fb923c', + shieldCapacity: 48, + }, + awayFaction: { + abbreviation: 'DOM', + glyph: 'β—‰', + colorCode: '#fb7185', + shieldCapacity: 55, + }, + }, + { + id: 'wolf-359', + name: 'Wolf 359 Outpost', + quadrant: 'alpha', + status: 'PRE', + homeFaction: { + abbreviation: 'SFC', + glyph: 'β—†', + colorCode: '#34d399', + shieldCapacity: 100, + }, + awayFaction: { + abbreviation: 'BRG', + glyph: 'β–ˆ', + colorCode: '#38bdf8', + shieldCapacity: 100, + }, + }, + { + id: 'qonos-arena', + name: "Qo'noS Sector β€” Warrior's Ring", + quadrant: 'beta', + status: 'LIVE', + homeFaction: { + abbreviation: 'KLG', + glyph: 'βš”', + colorCode: '#f87171', + shieldCapacity: 88, + }, + awayFaction: { + abbreviation: 'ROM', + glyph: 'β—ˆ', + colorCode: '#a78bfa', + shieldCapacity: 72, + }, + }, + { + id: 'neutral-zone', + name: 'The Neutral Zone', + quadrant: 'beta', + status: 'LIVE', + homeFaction: { + abbreviation: 'ROM', + glyph: 'β—ˆ', + colorCode: '#a78bfa', + shieldCapacity: 90, + }, + awayFaction: { + abbreviation: 'SFC', + glyph: 'β—†', + colorCode: '#34d399', + shieldCapacity: 95, + }, + }, + { + id: 'karemma-trade-corridor', + name: 'Karemma Trade Corridor', + quadrant: 'gamma', + status: 'LIVE', + homeFaction: { + abbreviation: 'KRM', + glyph: 'β—Š', + colorCode: '#fcd34d', + shieldCapacity: 65, + }, + awayFaction: { + abbreviation: 'DOS', + glyph: 'β–¬', + colorCode: '#c084fc', + shieldCapacity: 80, + }, + }, + { + id: 'grid-325', + name: 'Grid 325 β€” Borg Corridor', + quadrant: 'delta', + status: 'LIVE', + homeFaction: { + abbreviation: 'BRG', + glyph: 'β–ˆ', + colorCode: '#38bdf8', + shieldCapacity: 15, + }, + awayFaction: { + abbreviation: 'S84', + glyph: '∞', + colorCode: '#ec4899', + shieldCapacity: 99, + }, + }, + { + id: 'hirogen-relay', + name: 'Hirogen Relay Nexus', + quadrant: 'delta', + status: 'LIVE', + homeFaction: { + abbreviation: 'HRG', + glyph: 'βŠ—', + colorCode: '#fbbf24', + shieldCapacity: 75, + }, + awayFaction: { + abbreviation: 'KZN', + glyph: 'β•³', + colorCode: '#f97316', + shieldCapacity: 40, + }, + }, + ] + + const quadrants: QuadrantConfig[] = [ + { id: 'alpha', name: 'ALPHA QUADRANT', glyph: 'Ξ±' }, + { id: 'beta', name: 'BETA QUADRANT', glyph: 'Ξ²' }, + { id: 'gamma', name: 'GAMMA QUADRANT', glyph: 'Ξ³' }, + { id: 'delta', name: 'DELTA QUADRANT', glyph: 'Ξ΄' }, + ] + + return ( +
+ {/* 00 Grid Overview Dashboard */} +
+ + + > GRID OVERVIEW + + [00] + +
+ +
+
+ > LIVE ENGAGEMENTS +
+ +
+ {quadrants.map((quad) => ( + toggleQuadrant(quad.id)} + matches={matches.filter((m) => m.quadrant === quad.id)} + /> + ))} +
+
+ + {/* Archives Section */} +
+
+ > STATION ARCHIVES +
+
+ + + + +
+
+
+ ) +} + +// ─── SUB-COMPONENTS ───────────────────────────────────────────────────── + +interface QuadrantGroupProps { + quadrant: QuadrantConfig + isOpen: boolean + onToggle: () => void + matches: ActiveMatchSummary[] +} + +function QuadrantGroup({ + quadrant, + isOpen, + onToggle, + matches, +}: QuadrantGroupProps) { + return ( +
+ + + {isOpen && ( +
+ {matches.length === 0 ? ( +
+ No active engagements +
+ ) : ( + matches.map((match) => ( + + )) + )} +
+ )} +
+ ) +} + +interface MatchNavItemProps { + match: ActiveMatchSummary +} + +function MatchNavItem({ match }: MatchNavItemProps) { + return ( + +
+ + + {match.homeFaction.abbreviation} + VS + + {match.awayFaction.abbreviation} + + + +
+ + {match.status === 'LIVE' && ( + + )} + + ) +} + +interface ArchiveLinkProps { + to: string + label: string + num: string + glyph: string +} + +function ArchiveLink({ to, label, num, glyph }: ArchiveLinkProps) { + return ( + + + [{num}] {label} + + {glyph} + + ) +} diff --git a/web-terminal/src/components/panels/QuadrantFilterBar.tsx b/web-terminal/src/components/panels/QuadrantFilterBar.tsx new file mode 100644 index 0000000..ddd6bb7 --- /dev/null +++ b/web-terminal/src/components/panels/QuadrantFilterBar.tsx @@ -0,0 +1,34 @@ +import { Link } from '@tanstack/react-router' + +interface QuadrantFilterBarProps { + currentQuadrant: 'alpha' | 'beta' | 'gamma' | 'delta' | 'all' +} + +export function QuadrantFilterBar({ currentQuadrant }: QuadrantFilterBarProps) { + const tabs = [ + { id: 'all', label: 'ALL FEEDS' }, + { id: 'alpha', label: 'Ξ± ALPHA' }, + { id: 'beta', label: 'Ξ² BETA' }, + { id: 'gamma', label: 'Ξ³ GAMMA' }, + { id: 'delta', label: 'Ξ΄ DELTA' }, + ] as const + + return ( +
+ {tabs.map((tab) => ( + ({ ...prev, quadrant: tab.id })} + className={`flex-1 text-center py-1.5 border font-bold uppercase transition-all cursor-pointer ${ + currentQuadrant === tab.id + ? 'border-emerald-500/50 text-emerald-400 bg-emerald-950/20' + : 'border-slate-950 text-slate-500 hover:text-slate-400 hover:border-slate-800 bg-black/40' + }`} + > + {tab.label} + + ))} +
+ ) +} diff --git a/web-terminal/src/components/panels/ScheduleCard.tsx b/web-terminal/src/components/panels/ScheduleCard.tsx new file mode 100644 index 0000000..ce6a974 --- /dev/null +++ b/web-terminal/src/components/panels/ScheduleCard.tsx @@ -0,0 +1,7 @@ +export function ScheduleCard() { + return ( +
+
Scheduled Transmission Info
+
+ ) +} diff --git a/web-terminal/src/components/panels/VenueTable.tsx b/web-terminal/src/components/panels/VenueTable.tsx new file mode 100644 index 0000000..2d6f31b --- /dev/null +++ b/web-terminal/src/components/panels/VenueTable.tsx @@ -0,0 +1,7 @@ +export function VenueTable() { + return ( +
+
Sector Pool Venue Database Table
+
+ ) +} diff --git a/web-terminal/src/components/panels/VersusArena.tsx b/web-terminal/src/components/panels/VersusArena.tsx new file mode 100644 index 0000000..89fd796 --- /dev/null +++ b/web-terminal/src/components/panels/VersusArena.tsx @@ -0,0 +1,187 @@ +import { ShieldBar } from '#/components/ascii/ShieldBar' +import { GlyphIcon } from '#/components/ascii/GlyphIcon' +import { TerminalLine } from '#/components/ascii/TerminalLine' + +interface FactionState { + name: string + abbreviation: string + glyph: string + colorCode: string + shieldCapacity: number + attack: number + evasion: number + activeEffects: Array<{ + name: string + description: string + remainingTicks: number + }> +} + +interface VenueDetail { + name: string + coordinates: string + shieldModifier: number + damageModifier: number + evasionModifier: number + tags: string[] +} + +interface VersusArenaProps { + home: FactionState + away: FactionState + kineticYield: number + tick: number + maxTicks: number + venue: VenueDetail +} + +export function VersusArena({ + home, + away, + kineticYield, + tick, + maxTicks, + venue, +}: VersusArenaProps) { + // Combine all active effects for display + const allEffects = [ + ...home.activeEffects.map((e) => ({ ...e, faction: home.abbreviation })), + ...away.activeEffects.map((e) => ({ ...e, faction: away.abbreviation })), + ] + + return ( +
+ {/* Factions Headers */} +
+
+ + + {home.name} + + + [{home.abbreviation}] + +
+ +
+ ✦ VS ✦ +
+ +
+ + + {away.name} + + + [{away.abbreviation}] + +
+
+ + + + {/* Symmetrical Stats Grid */} +
+ {/* Home Stats */} +
+
{home.shieldCapacity}%
+
{home.attack}
+
{home.evasion}
+
+ + {/* Labels */} +
+
SHIELDS
+
ATTACK POWER
+
EVASION CAP.
+
+ + {/* Away Stats */} +
+
{away.shieldCapacity}%
+
{away.attack}
+
{away.evasion}
+
+
+ + {/* Symmetrical Shield Bar */} +
+ +
+ + + + {/* Venue & Environment Telemetry */} +
+
+
+ KINETIC YIELD:{' '} + + {kineticYield.toFixed(1)} TW + +
+
+ CYCLE TICK:{' '} + + {tick} / {maxTicks} + +
+
+ VENUE:{' '} + {venue.name} +
+
+
+
+ COORD: {venue.coordinates} +
+
+ TAGS:{' '} + + [{venue.tags.join(', ')}] + +
+
+ SHDΓ—:{' '} + + {venue.shieldModifier.toFixed(2)} + {' '} + | DMGΓ—:{' '} + + {venue.damageModifier.toFixed(2)} + {' '} + | EVAΓ—:{' '} + + {venue.evasionModifier.toFixed(2)} + +
+
+
+ + {/* Active Effects Section */} + {allEffects.length > 0 && ( +
+
+ > ACTIVE EFFECTS IN SECTOR ARRAY +
+ {allEffects.map((eff, idx) => ( +
+ + ⚑ {eff.name} ({eff.faction}) β€” {eff.description} + + + [{eff.remainingTicks} TICKS REMAINING] + +
+ ))} +
+ )} +
+ ) +} diff --git a/web-terminal/src/components/panels/WagerCard.tsx b/web-terminal/src/components/panels/WagerCard.tsx new file mode 100644 index 0000000..4a6a8b1 --- /dev/null +++ b/web-terminal/src/components/panels/WagerCard.tsx @@ -0,0 +1,7 @@ +export function WagerCard() { + return ( +
+
Wager Details
+
+ ) +} diff --git a/web-terminal/src/components/providers/BetslipProvider.tsx b/web-terminal/src/components/providers/BetslipProvider.tsx new file mode 100644 index 0000000..646505f --- /dev/null +++ b/web-terminal/src/components/providers/BetslipProvider.tsx @@ -0,0 +1,87 @@ +import React, { createContext, useContext, useState } from 'react' + +export interface BetslipSelection { + matchId: string + matchName: string + marketId: string + selectionName: string + price: number + currentPrice: number + stake: number + factionGlyph: string +} + +interface BetslipContextType { + selections: BetslipSelection[] + addSelection: (sel: Omit) => void + removeSelection: (marketId: string) => void + updateStake: (marketId: string, stake: number) => void + clearAll: () => void + accumulatorStake: number + setAccumulatorStake: (stake: number) => void +} + +const BetslipContext = createContext(undefined) + +export function BetslipProvider({ children }: { children: React.ReactNode }) { + const [selections, setSelections] = useState([]) + const [accumulatorStake, setAccumulatorStake] = useState(0) + + const addSelection = ( + sel: Omit, + ) => { + setSelections((prev) => { + // Check if selection already exists + if (prev.some((s) => s.marketId === sel.marketId)) { + return prev + } + return [ + ...prev, + { + ...sel, + currentPrice: sel.price, + stake: 0, + }, + ] + }) + } + + const removeSelection = (marketId: string) => { + setSelections((prev) => prev.filter((s) => s.marketId !== marketId)) + } + + const updateStake = (marketId: string, stake: number) => { + setSelections((prev) => + prev.map((s) => (s.marketId === marketId ? { ...s, stake } : s)), + ) + } + + const clearAll = () => { + setSelections([]) + setAccumulatorStake(0) + } + + return ( + + {children} + + ) +} + +export function useBetslip() { + const context = useContext(BetslipContext) + if (!context) { + throw new Error('useBetslip must be used within a BetslipProvider') + } + return context +} diff --git a/web-terminal/src/components/providers/CurrencyProvider.tsx b/web-terminal/src/components/providers/CurrencyProvider.tsx new file mode 100644 index 0000000..f25d49f --- /dev/null +++ b/web-terminal/src/components/providers/CurrencyProvider.tsx @@ -0,0 +1,31 @@ +import React, { createContext, useContext } from 'react' +import { useRouterState } from '@tanstack/react-router' + +type Currency = 'Latinum' | 'Credits' + +interface CurrencyContextType { + currency: Currency +} + +const CurrencyContext = createContext({ + currency: 'Latinum', +}) + +export function CurrencyProvider({ children }: { children: React.ReactNode }) { + const routerState = useRouterState() + + // Safe search param extraction across any active route + const searchParams = routerState.location.search as Record + const currency: Currency = + searchParams.currency === 'Credits' ? 'Credits' : 'Latinum' + + return ( + + {children} + + ) +} + +export function useCurrency() { + return useContext(CurrencyContext) +} diff --git a/web-terminal/src/routeTree.gen.ts b/web-terminal/src/routeTree.gen.ts new file mode 100644 index 0000000..c03deb9 --- /dev/null +++ b/web-terminal/src/routeTree.gen.ts @@ -0,0 +1,198 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as ScheduleRouteImport } from './routes/schedule' +import { Route as IndexRouteImport } from './routes/index' +import { Route as QuadrantsIndexRouteImport } from './routes/quadrants/index' +import { Route as LedgerIndexRouteImport } from './routes/ledger/index' +import { Route as RegistryVenuesRouteImport } from './routes/registry/venues' +import { Route as RegistryFactionsRouteImport } from './routes/registry/factions' +import { Route as QuadrantsSectorIdRouteImport } from './routes/quadrants/$sectorId' + +const ScheduleRoute = ScheduleRouteImport.update({ + id: '/schedule', + path: '/schedule', + getParentRoute: () => rootRouteImport, +} as any) +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const QuadrantsIndexRoute = QuadrantsIndexRouteImport.update({ + id: '/quadrants/', + path: '/quadrants/', + getParentRoute: () => rootRouteImport, +} as any) +const LedgerIndexRoute = LedgerIndexRouteImport.update({ + id: '/ledger/', + path: '/ledger/', + getParentRoute: () => rootRouteImport, +} as any) +const RegistryVenuesRoute = RegistryVenuesRouteImport.update({ + id: '/registry/venues', + path: '/registry/venues', + getParentRoute: () => rootRouteImport, +} as any) +const RegistryFactionsRoute = RegistryFactionsRouteImport.update({ + id: '/registry/factions', + path: '/registry/factions', + getParentRoute: () => rootRouteImport, +} as any) +const QuadrantsSectorIdRoute = QuadrantsSectorIdRouteImport.update({ + id: '/quadrants/$sectorId', + path: '/quadrants/$sectorId', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/schedule': typeof ScheduleRoute + '/quadrants/$sectorId': typeof QuadrantsSectorIdRoute + '/registry/factions': typeof RegistryFactionsRoute + '/registry/venues': typeof RegistryVenuesRoute + '/ledger/': typeof LedgerIndexRoute + '/quadrants/': typeof QuadrantsIndexRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/schedule': typeof ScheduleRoute + '/quadrants/$sectorId': typeof QuadrantsSectorIdRoute + '/registry/factions': typeof RegistryFactionsRoute + '/registry/venues': typeof RegistryVenuesRoute + '/ledger': typeof LedgerIndexRoute + '/quadrants': typeof QuadrantsIndexRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/schedule': typeof ScheduleRoute + '/quadrants/$sectorId': typeof QuadrantsSectorIdRoute + '/registry/factions': typeof RegistryFactionsRoute + '/registry/venues': typeof RegistryVenuesRoute + '/ledger/': typeof LedgerIndexRoute + '/quadrants/': typeof QuadrantsIndexRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '/schedule' + | '/quadrants/$sectorId' + | '/registry/factions' + | '/registry/venues' + | '/ledger/' + | '/quadrants/' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '/schedule' + | '/quadrants/$sectorId' + | '/registry/factions' + | '/registry/venues' + | '/ledger' + | '/quadrants' + id: + | '__root__' + | '/' + | '/schedule' + | '/quadrants/$sectorId' + | '/registry/factions' + | '/registry/venues' + | '/ledger/' + | '/quadrants/' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + ScheduleRoute: typeof ScheduleRoute + QuadrantsSectorIdRoute: typeof QuadrantsSectorIdRoute + RegistryFactionsRoute: typeof RegistryFactionsRoute + RegistryVenuesRoute: typeof RegistryVenuesRoute + LedgerIndexRoute: typeof LedgerIndexRoute + QuadrantsIndexRoute: typeof QuadrantsIndexRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/schedule': { + id: '/schedule' + path: '/schedule' + fullPath: '/schedule' + preLoaderRoute: typeof ScheduleRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/quadrants/': { + id: '/quadrants/' + path: '/quadrants' + fullPath: '/quadrants/' + preLoaderRoute: typeof QuadrantsIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/ledger/': { + id: '/ledger/' + path: '/ledger' + fullPath: '/ledger/' + preLoaderRoute: typeof LedgerIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/registry/venues': { + id: '/registry/venues' + path: '/registry/venues' + fullPath: '/registry/venues' + preLoaderRoute: typeof RegistryVenuesRouteImport + parentRoute: typeof rootRouteImport + } + '/registry/factions': { + id: '/registry/factions' + path: '/registry/factions' + fullPath: '/registry/factions' + preLoaderRoute: typeof RegistryFactionsRouteImport + parentRoute: typeof rootRouteImport + } + '/quadrants/$sectorId': { + id: '/quadrants/$sectorId' + path: '/quadrants/$sectorId' + fullPath: '/quadrants/$sectorId' + preLoaderRoute: typeof QuadrantsSectorIdRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + ScheduleRoute: ScheduleRoute, + QuadrantsSectorIdRoute: QuadrantsSectorIdRoute, + RegistryFactionsRoute: RegistryFactionsRoute, + RegistryVenuesRoute: RegistryVenuesRoute, + LedgerIndexRoute: LedgerIndexRoute, + QuadrantsIndexRoute: QuadrantsIndexRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/react-start' +declare module '@tanstack/react-start' { + interface Register { + ssr: true + router: Awaited> + } +} diff --git a/web-terminal/src/router.tsx b/web-terminal/src/router.tsx new file mode 100644 index 0000000..e7b1c4d --- /dev/null +++ b/web-terminal/src/router.tsx @@ -0,0 +1,19 @@ +import { createRouter as createTanStackRouter } from '@tanstack/react-router' +import { routeTree } from './routeTree.gen' + +export function getRouter() { + const router = createTanStackRouter({ + routeTree, + scrollRestoration: true, + defaultPreload: 'intent', + defaultPreloadStaleTime: 0, + }) + + return router +} + +declare module '@tanstack/react-router' { + interface Register { + router: ReturnType + } +} diff --git a/web-terminal/src/routes/__root.tsx b/web-terminal/src/routes/__root.tsx new file mode 100644 index 0000000..01e694f --- /dev/null +++ b/web-terminal/src/routes/__root.tsx @@ -0,0 +1,130 @@ +import { + HeadContent, + Outlet, + Scripts, + createRootRoute, +} from '@tanstack/react-router' +import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools' +import { TanStackDevtools } from '@tanstack/react-devtools' + +import appCss from '../styles.css?url' +import { AsciiPanel } from '#/components/ascii/AsciiPanel' +import { NavigationMenu } from '#/components/panels/NavigationMenu' +import { BetslipProvider } from '#/components/providers/BetslipProvider' +import { CurrencyProvider } from '#/components/providers/CurrencyProvider' +import { BetslipSidecar } from '#/components/panels/BetslipSidecar' + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { + charSet: 'utf-8', + }, + { + name: 'viewport', + content: 'width=device-width, initial-scale=1', + }, + { + title: "Quark's Holo-Grid Ledger", + }, + ], + links: [ + { + rel: 'stylesheet', + href: appCss, + }, + ], + }), + shellComponent: RootDocument, + component: RootComponent, +}) + +// RootDocument renders the outer HTML envelope +function RootDocument({ children }: { children: React.ReactNode }) { + return ( + + + + + + {children} + , + }, + ]} + /> + + + + ) +} + +// RootComponent renders the actual terminal UI workspace layout +function RootComponent() { + return ( + + +
+ {/* ================= HEADER SECTION ================= */} +
+
+ [=] QUARK'S HOLO-GRID LEDGER // SUB-NET RECEPTOR +
+
+ STARDATE: 54201.3 + + BALANCE: 4,250.00 LATINUM + +
+
+ + {/* ================= WORKSPACE INTERFACE GRID ================= */} +
+ {/* COLUMN 1: Subspace Navigation Sidecar (Left) */} +
+ + + +
+ + {/* COLUMN 2: Target Matrix / Main Display (Center) */} +
+ {/* The Outlet element renders the individual nested route content dynamically */} + +
+ + {/* COLUMN 3: Transaction Ledger Ticket (Right) */} +
+ + + +
+
+ + {/* ================= DIAGNOSTIC BASE FOOTER ================= */} +
+ SYSTEM RUNTIME: OK // CORE MODULES ACTIVE + POWERED BY TANSTACK START + VITE +
+
+
+
+ ) +} diff --git a/web-terminal/src/routes/index.tsx b/web-terminal/src/routes/index.tsx new file mode 100644 index 0000000..717b010 --- /dev/null +++ b/web-terminal/src/routes/index.tsx @@ -0,0 +1,282 @@ +import { createFileRoute } from '@tanstack/react-router' +import { z } from 'zod' +import { AsciiPanel } from '#/components/ascii/AsciiPanel' +import { QuadrantFilterBar } from '#/components/panels/QuadrantFilterBar' +import type { MatchData } from '#/components/panels/MatchCard' +import { MatchCard } from '#/components/panels/MatchCard' +import { LiveTicker } from '#/components/panels/LiveTicker' + +// Define schema for deterministic URL state filtering (AGENTS.md Rule A compliance) +const dashboardSearchSchema = z.object({ + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta', 'all']).default('all'), + currency: z.enum(['Latinum', 'Credits']).default('Latinum'), +}) + +export const Route = createFileRoute('/')({ + validateSearch: dashboardSearchSchema, + component: DashboardView, +}) + +function DashboardView() { + const { quadrant } = Route.useSearch() + + // Full active matches pool matching taxonomy.yaml configuration + const matches: MatchData[] = [ + { + id: 'sector-001', + name: 'Sector 001 β€” Sol Array', + quadrant: 'alpha', + status: 'LIVE', + tick: 42, + maxTicks: 90, + kineticYield: 14.7, + homeFaction: { + abbreviation: 'SFC', + name: 'Starfleet Command', + glyph: 'β—†', + colorCode: '#34d399', + shieldCapacity: 62, + oddsPrice: 2.85, + }, + awayFaction: { + abbreviation: 'BRG', + name: 'Borg Collective', + glyph: 'β–ˆ', + colorCode: '#38bdf8', + shieldCapacity: 71, + oddsPrice: 1.48, + }, + marketsOpenCount: 6, + }, + { + id: 'bajor-wormhole', + name: 'Bajor Sector β€” DS9', + quadrant: 'alpha', + status: 'LIVE', + tick: 31, + maxTicks: 75, + kineticYield: 8.2, + homeFaction: { + abbreviation: 'BAJ', + name: 'Bajoran Militia', + glyph: '☼', + colorCode: '#fb923c', + shieldCapacity: 48, + oddsPrice: 2.1, + }, + awayFaction: { + abbreviation: 'DOM', + name: 'The Dominion', + glyph: 'β—‰', + colorCode: '#fb7185', + shieldCapacity: 55, + oddsPrice: 1.72, + }, + marketsOpenCount: 8, + }, + { + id: 'wolf-359', + name: 'Wolf 359 Outpost', + quadrant: 'alpha', + status: 'PRE', + tick: 0, + maxTicks: 90, + kineticYield: 0.0, + homeFaction: { + abbreviation: 'SFC', + name: 'Starfleet Command', + glyph: 'β—†', + colorCode: '#34d399', + shieldCapacity: 100, + oddsPrice: 2.4, + }, + awayFaction: { + abbreviation: 'BRG', + name: 'Borg Collective', + glyph: 'β–ˆ', + colorCode: '#38bdf8', + shieldCapacity: 100, + oddsPrice: 1.62, + }, + marketsOpenCount: 4, + commencingIn: '00:47', + }, + { + id: 'qonos-arena', + name: "Qo'noS Sector β€” Warrior's Ring", + quadrant: 'beta', + status: 'LIVE', + tick: 58, + maxTicks: 120, + kineticYield: 12.4, + homeFaction: { + abbreviation: 'KLG', + name: 'Klingon Empire', + glyph: 'βš”', + colorCode: '#f87171', + shieldCapacity: 88, + oddsPrice: 1.75, + }, + awayFaction: { + abbreviation: 'ROM', + name: 'Romulan Star Empire', + glyph: 'β—ˆ', + colorCode: '#a78bfa', + shieldCapacity: 72, + oddsPrice: 2.15, + }, + marketsOpenCount: 6, + }, + { + id: 'neutral-zone', + name: 'The Neutral Zone', + quadrant: 'beta', + status: 'LIVE', + tick: 15, + maxTicks: 80, + kineticYield: 4.2, + homeFaction: { + abbreviation: 'ROM', + name: 'Romulan Star Empire', + glyph: 'β—ˆ', + colorCode: '#a78bfa', + shieldCapacity: 90, + oddsPrice: 1.95, + }, + awayFaction: { + abbreviation: 'SFC', + name: 'Starfleet Command', + glyph: 'β—†', + colorCode: '#34d399', + shieldCapacity: 95, + oddsPrice: 1.85, + }, + marketsOpenCount: 8, + }, + { + id: 'karemma-trade-corridor', + name: 'Karemma Trade Corridor', + quadrant: 'gamma', + status: 'LIVE', + tick: 73, + maxTicks: 100, + kineticYield: 18.1, + homeFaction: { + abbreviation: 'KRM', + name: 'Karemma Trade Alliance', + glyph: 'β—Š', + colorCode: '#fcd34d', + shieldCapacity: 65, + oddsPrice: 2.3, + }, + awayFaction: { + abbreviation: 'DOS', + name: 'Dominion Outpost 6', + glyph: 'β–¬', + colorCode: '#c084fc', + shieldCapacity: 80, + oddsPrice: 1.6, + }, + marketsOpenCount: 6, + }, + { + id: 'grid-325', + name: 'Grid 325 β€” Borg Corridor', + quadrant: 'delta', + status: 'LIVE', + tick: 82, + maxTicks: 90, + kineticYield: 24.5, + homeFaction: { + abbreviation: 'BRG', + name: 'Borg Collective', + glyph: 'β–ˆ', + colorCode: '#38bdf8', + shieldCapacity: 15, + oddsPrice: 9.5, + }, + awayFaction: { + abbreviation: 'S84', + name: 'Species 8472', + glyph: '∞', + colorCode: '#ec4899', + shieldCapacity: 99, + oddsPrice: 1.08, + }, + marketsOpenCount: 8, + }, + { + id: 'hirogen-relay', + name: 'Hirogen Relay Nexus', + quadrant: 'delta', + status: 'LIVE', + tick: 49, + maxTicks: 100, + kineticYield: 9.3, + homeFaction: { + abbreviation: 'HRG', + name: 'Hirogen Hunt Pack', + glyph: 'βŠ—', + colorCode: '#fbbf24', + shieldCapacity: 75, + oddsPrice: 1.55, + }, + awayFaction: { + abbreviation: 'KZN', + name: 'Kazon Sects', + glyph: 'β•³', + colorCode: '#f97316', + shieldCapacity: 40, + oddsPrice: 2.45, + }, + marketsOpenCount: 6, + }, + ] + + // Filter matches based on the URL query param state + const filteredMatches = + quadrant === 'all' + ? matches + : matches.filter((m) => m.quadrant === quadrant) + + return ( + +
+ {/* Broadcast Banner */} +
+
+ > SUBSPACE BROADCAST β€” LIVE ENGAGEMENTS ACROSS ALL QUADRANTS +
+ +
+ + {/* Matches Grid Area */} +
+ {filteredMatches.length === 0 ? ( +
+ No active engagements detected in this quadrant division array. +
+ ) : ( +
+ {filteredMatches.map((match) => ( + + ))} +
+ )} +
+ + {/* Live Feed Event Ticker */} +
+
+ > LIVE GLOBAL TELEMETRY FEED TICKER +
+ +
+
+
+ ) +} diff --git a/web-terminal/src/routes/ledger/index.tsx b/web-terminal/src/routes/ledger/index.tsx new file mode 100644 index 0000000..4243d17 --- /dev/null +++ b/web-terminal/src/routes/ledger/index.tsx @@ -0,0 +1,5 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/ledger/')({ + component: () =>
Wager Ledger Archives
, +}) diff --git a/web-terminal/src/routes/quadrants/$sectorId.tsx b/web-terminal/src/routes/quadrants/$sectorId.tsx new file mode 100644 index 0000000..afedba9 --- /dev/null +++ b/web-terminal/src/routes/quadrants/$sectorId.tsx @@ -0,0 +1,403 @@ +import { createFileRoute } from '@tanstack/react-router' +import { z } from 'zod' +import { AsciiPanel } from '#/components/ascii/AsciiPanel' +import { VersusArena } from '#/components/panels/VersusArena' +import type { MarketItem } from '#/components/panels/MarketGrid' +import { MarketGrid } from '#/components/panels/MarketGrid' +import type { CombatLogEntry } from '#/components/panels/EngagementLog' +import { EngagementLog } from '#/components/panels/EngagementLog' + +// Search parameters validator matching AGENTS.md Rule A compliance +const searchSchema = z.object({ + quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']), + currency: z.enum(['Latinum', 'Credits']).default('Latinum'), + marketCategory: z + .enum(['primary', 'secondary', 'exotic', 'all']) + .default('all'), +}) + +export const Route = createFileRoute('/quadrants/$sectorId')({ + validateSearch: searchSchema, + component: MatchDetailView, +}) + +function MatchDetailView() { + const { sectorId } = Route.useParams() + const { marketCategory } = Route.useSearch() + + // Full detailed mock matches database matching taxonomy.yaml + const matchesDetails: + | Record< + string, + { + name: string + status: 'LIVE' | 'PRE' | 'RES' + kineticYield: number + tick: number + maxTicks: number + venue: { + name: string + coordinates: string + shieldModifier: number + damageModifier: number + evasionModifier: number + tags: string[] + } + homeFaction: { + name: string + abbreviation: string + glyph: string + colorCode: string + shieldCapacity: number + attack: number + evasion: number + activeEffects: Array<{ + name: string + description: string + remainingTicks: number + }> + } + awayFaction: { + name: string + abbreviation: string + glyph: string + colorCode: string + shieldCapacity: number + attack: number + evasion: number + activeEffects: Array<{ + name: string + description: string + remainingTicks: number + }> + } + markets: MarketItem[] + logs: CombatLogEntry[] + } + > + | undefined = { + 'sector-001': { + name: 'Sector 001 β€” Sol Array', + status: 'LIVE', + kineticYield: 14.7, + tick: 42, + maxTicks: 90, + venue: { + name: 'Sol System Orbit', + coordinates: '001-ALPHA-0', + shieldModifier: 1.0, + damageModifier: 1.0, + evasionModifier: 1.0, + tags: ['orbital-grid', 'starfleet-array'], + }, + homeFaction: { + name: 'Starfleet Command', + abbreviation: 'SFC', + glyph: 'β—†', + colorCode: '#34d399', + shieldCapacity: 62, + attack: 75, + evasion: 55, + activeEffects: [], + }, + awayFaction: { + name: 'Borg Collective', + abbreviation: 'BRG', + glyph: 'β–ˆ', + colorCode: '#38bdf8', + shieldCapacity: 71, + attack: 90, + evasion: 15, + activeEffects: [ + { + name: 'BORG ADAPTATION', + description: 'Incoming damage multiplier Γ—0.5', + remainingTicks: 3, + }, + ], + }, + markets: [ + { + id: 's1-m1', + templateId: 'moneyline', + name: 'COMBAT RESOLUTION β€” MONEYLINE', + category: 'primary', + selections: [ + { + id: 's1-m1-o1', + name: 'Starfleet Victory', + price: 2.85, + factionGlyph: 'β—†', + }, + { + id: 's1-m1-o2', + name: 'Borg Assimilation', + price: 1.48, + factionGlyph: 'β–ˆ', + }, + ], + }, + { + id: 's1-m2', + templateId: 'first-breach', + name: 'FIRST SHIELD BREACH', + category: 'primary', + selections: [ + { + id: 's1-m2-o1', + name: 'SFC Shields First', + price: 1.65, + factionGlyph: 'β—†', + }, + { + id: 's1-m2-o2', + name: 'BRG Shields First', + price: 2.2, + factionGlyph: 'β–ˆ', + }, + ], + }, + { + id: 's1-m3', + templateId: 'kinetic-yield', + name: 'TOTAL KINETIC YIELD', + category: 'secondary', + selections: [ + { + id: 's1-m3-o1', + name: 'Over 18.5 TW', + price: 1.85, + factionGlyph: 'β—‡', + }, + { + id: 's1-m3-o2', + name: 'Under 18.5 TW', + price: 1.85, + factionGlyph: 'β—‡', + }, + ], + }, + ], + logs: [ + { + id: 'l1', + tick: 42, + message: 'β—† Starfleet Command fires β€” HIT β€” 4.2% shield damage', + type: 'combat', + }, + { + id: 'l2', + tick: 42, + message: 'β–ˆ Borg Collective fires β€” MISS β€” Evasion successful', + type: 'combat', + }, + { + id: 'l3', + tick: 38, + message: + '⚑ EVENT: Borg Adaptation active β€” Incoming damage multiplier Γ—0.5', + type: 'event', + }, + ], + }, + 'bajor-wormhole': { + name: 'Bajor Sector β€” DS9', + status: 'LIVE', + kineticYield: 8.2, + tick: 31, + maxTicks: 75, + venue: { + name: 'Denorios Belt β€” Wormhole', + coordinates: 'BAJ-WORM-1', + shieldModifier: 0.85, + damageModifier: 1.15, + evasionModifier: 0.9, + tags: ['high-gravitational', 'plasma-clouds'], + }, + homeFaction: { + name: 'Bajoran Militia', + abbreviation: 'BAJ', + glyph: '☼', + colorCode: '#fb923c', + shieldCapacity: 48, + attack: 60, + evasion: 75, + activeEffects: [], + }, + awayFaction: { + name: 'The Dominion', + abbreviation: 'DOM', + glyph: 'β—‰', + colorCode: '#fb7185', + shieldCapacity: 55, + attack: 85, + evasion: 40, + activeEffects: [], + }, + markets: [ + { + id: 's2-m1', + templateId: 'moneyline', + name: 'COMBAT RESOLUTION β€” MONEYLINE', + category: 'primary', + selections: [ + { + id: 's2-m1-o1', + name: 'Bajoran Defiance', + price: 2.1, + factionGlyph: '☼', + }, + { + id: 's2-m1-o2', + name: 'Dominion Conquest', + price: 1.72, + factionGlyph: 'β—‰', + }, + ], + }, + ], + logs: [ + { + id: 'l2-1', + tick: 31, + message: '☼ Bajoran Militia fires β€” HIT β€” 3.1% shield damage', + type: 'combat', + }, + { + id: 'l2-2', + tick: 30, + message: 'β—‰ The Dominion fires β€” HIT β€” 5.4% shield damage', + type: 'combat', + }, + ], + }, + 'wolf-359': { + name: 'Wolf 359 Outpost', + status: 'PRE', + kineticYield: 0.0, + tick: 0, + maxTicks: 90, + venue: { + name: 'Wolf 359 Debris Field', + coordinates: '359-DEBRIS-2', + shieldModifier: 0.95, + damageModifier: 1.1, + evasionModifier: 0.8, + tags: ['debris-field', 'high-anomaly'], + }, + homeFaction: { + name: 'Starfleet Command', + abbreviation: 'SFC', + glyph: 'β—†', + colorCode: '#34d399', + shieldCapacity: 100, + attack: 75, + evasion: 55, + activeEffects: [], + }, + awayFaction: { + name: 'Borg Collective', + abbreviation: 'BRG', + glyph: 'β–ˆ', + colorCode: '#38bdf8', + shieldCapacity: 100, + attack: 90, + evasion: 15, + activeEffects: [], + }, + markets: [ + { + id: 's3-m1', + templateId: 'moneyline', + name: 'COMBAT RESOLUTION β€” MONEYLINE', + category: 'primary', + selections: [ + { + id: 's3-m1-o1', + name: 'Starfleet Victory', + price: 2.4, + factionGlyph: 'β—†', + }, + { + id: 's3-m1-o2', + name: 'Borg Assimilation', + price: 1.62, + factionGlyph: 'β–ˆ', + }, + ], + }, + ], + logs: [ + { + id: 'l3-1', + tick: 0, + message: + 'Subspace communications linked. Awaiting combat deployment.', + type: 'system', + }, + ], + }, + } + + // Get current match detail + const match = (matchesDetails as Record)[sectorId] + + if (!match) { + return ( + +
+
> ERROR: SECTOR ARRAY COORDINATES OFFLINE
+
+ Link signals for sector [{sectorId}] cannot be parsed. Select an + active fleet connection link from the left array. +
+
+
+ ) + } + + return ( + +
+ {/* Versus Arena header and stats */} + + + {/* Markets configuration grid */} +
+
+ > AVAILABLE ODDS MATRICES +
+ +
+ + {/* Live log feed specific to match */} +
+
+ > TACTICAL ENGAGEMENT LOG +
+ +
+
+
+ ) +} diff --git a/web-terminal/src/routes/quadrants/index.tsx b/web-terminal/src/routes/quadrants/index.tsx new file mode 100644 index 0000000..03a3ea4 --- /dev/null +++ b/web-terminal/src/routes/quadrants/index.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/quadrants/')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/quadrants/"!
+} diff --git a/web-terminal/src/routes/registry/factions.tsx b/web-terminal/src/routes/registry/factions.tsx new file mode 100644 index 0000000..f62a6a7 --- /dev/null +++ b/web-terminal/src/routes/registry/factions.tsx @@ -0,0 +1,5 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/registry/factions')({ + component: () =>
Faction Registry Database
, +}) diff --git a/web-terminal/src/routes/registry/venues.tsx b/web-terminal/src/routes/registry/venues.tsx new file mode 100644 index 0000000..5ead586 --- /dev/null +++ b/web-terminal/src/routes/registry/venues.tsx @@ -0,0 +1,5 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/registry/venues')({ + component: () =>
Venue Sector Database
, +}) diff --git a/web-terminal/src/routes/schedule.tsx b/web-terminal/src/routes/schedule.tsx new file mode 100644 index 0000000..159b35b --- /dev/null +++ b/web-terminal/src/routes/schedule.tsx @@ -0,0 +1,5 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/schedule')({ + component: () =>
Transmission Schedule
, +}) diff --git a/web-terminal/src/styles.css b/web-terminal/src/styles.css new file mode 100644 index 0000000..4ad72ed --- /dev/null +++ b/web-terminal/src/styles.css @@ -0,0 +1,15 @@ +@import 'tailwindcss'; + +* { + box-sizing: border-box; +} + +html, +body, +#app { + min-height: 100%; +} + +body { + margin: 0; +} diff --git a/web-terminal/tsconfig.json b/web-terminal/tsconfig.json new file mode 100644 index 0000000..f08699f --- /dev/null +++ b/web-terminal/tsconfig.json @@ -0,0 +1,35 @@ +{ + "include": [ + "**/*.ts", + "**/*.tsx", + "eslint.config.js", + "prettier.config.js", + "vite.config.js" + ], + + "compilerOptions": { + "target": "ES2022", + "jsx": "react-jsx", + "module": "ESNext", + "paths": { + "#/*": ["./src/*"], + "@/*": ["./src/*"] + }, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + /* Linting */ + "skipLibCheck": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + } +} diff --git a/web-terminal/tsr.config.json b/web-terminal/tsr.config.json new file mode 100644 index 0000000..8b6b6ed --- /dev/null +++ b/web-terminal/tsr.config.json @@ -0,0 +1,3 @@ +{ + "target": "react" +} diff --git a/web-terminal/vite.config.ts b/web-terminal/vite.config.ts new file mode 100644 index 0000000..5a46a66 --- /dev/null +++ b/web-terminal/vite.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from 'vite' +import { devtools } from '@tanstack/devtools-vite' + +import { tanstackStart } from '@tanstack/react-start/plugin/vite' + +import viteReact from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' +import { nitro } from 'nitro/vite' + +const config = defineConfig({ + resolve: { tsconfigPaths: true }, + plugins: [ + devtools(), + nitro({ rollupConfig: { external: [/^@sentry\//] } }), + tailwindcss(), + tanstackStart(), + viteReact(), + ], +}) + +export default config