diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 8b5c996..4fef7eb 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -160,6 +160,12 @@ const Room: Component = () => { send({ type: "shuffle_queue" }); }; + // Remove a queued track by id. The state machine no-ops if the track + // is active or already gone. + const handleRemoveQueueItem = (itemId: string) => { + send({ type: "remove_queue_item", item_id: itemId }); + }; + return (
@@ -253,6 +259,7 @@ const Room: Component = () => { onTogglePlaylist={handleTogglePlaylist} onMoveQueueItem={handleMoveQueueItem} onShuffleQueue={handleShuffleQueue} + onRemoveQueueItem={handleRemoveQueueItem} /> send({ type: "chat", content })} /> )}
diff --git a/frontend/src/types.ts b/frontend/src/types.ts index e874e52..fe1af1b 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -68,4 +68,5 @@ export type ClientMessage = | { type: "set_playlist_enabled"; enabled: boolean } | { type: "ping" } | { type: "move_queue_item"; from: number; to: number } - | { type: "shuffle_queue" }; + | { type: "shuffle_queue" } + | { type: "remove_queue_item"; item_id: string }; diff --git a/src/room.rs b/src/room.rs index ea97cea..d3c50d8 100644 --- a/src/room.rs +++ b/src/room.rs @@ -67,6 +67,9 @@ pub(crate) enum RoomCommand { to: usize, }, ShuffleQueue, + RemoveQueueItem { + track_id: TrackId, + }, } /// Per-room event-loop actor. Owns all mutable state. @@ -406,6 +409,9 @@ impl RoomActor { RoomCommand::Shutdown => self.handle_shutdown().await, RoomCommand::MoveQueueItem { from, to } => self.handle_move_queue_item(from, to).await, RoomCommand::ShuffleQueue => self.handle_shuffle_queue().await, + RoomCommand::RemoveQueueItem { track_id } => { + self.handle_remove_queue_item(track_id).await + } } } @@ -708,6 +714,21 @@ impl RoomActor { false } + /// Remove a queued track. The state machine no-ops if the track is the + /// active one (you can't delete a playing track) or if it isn't in + /// the queue at all. + async fn handle_remove_queue_item(&mut self, track_id: TrackId) -> bool { + let effects = self + .state + .transition(&Event::RemoveQueueItem { track_id }, 0); + if effects.is_empty() { + return false; + } + self.persist_effects(&effects).await; + self.execute_effects(effects).await; + false + } + async fn handle_chat( &mut self, user_name: String, diff --git a/src/state.rs b/src/state.rs index 899e898..3c8a05b 100644 --- a/src/state.rs +++ b/src/state.rs @@ -97,6 +97,9 @@ pub(crate) enum Event { /// Shuffle the up-next queue deterministically. Same seed → same result. /// Empty/single-item queues are no-ops. Active track is not affected. ShuffleQueue { seed: u64 }, + /// Remove a track from the up-next queue. No-op if the track isn't + /// queued (active and history are unaffected). + RemoveQueueItem { track_id: TrackId }, } /// Side effects to execute after a transition. @@ -147,6 +150,10 @@ pub(crate) enum Effect { /// column for every queued track so a fresh `SELECT ... ORDER BY /// position` returns the new order. ReorderQueue { new_order: Vec }, + /// Delete a queued track from the store. Emitted alongside a + /// `PublishSnapshot` after the state machine removes the track from + /// its in-memory `queue` Vec. + RemoveQueuedTrack { track_id: TrackId }, } /// Pure playback state: no IO handles, no DB connections. @@ -203,6 +210,7 @@ impl PlaybackState { Event::SetPlaylistEnabled(enabled) => self.handle_set_playlist_enabled(*enabled), Event::MoveQueueItem { from, to } => self.handle_move_queue_item(*from, *to), Event::ShuffleQueue { seed } => self.handle_shuffle_queue(*seed), + Event::RemoveQueueItem { track_id } => self.handle_remove_queue_item(*track_id), } } @@ -533,6 +541,24 @@ impl PlaybackState { vec![Effect::ReorderQueue { new_order }, Effect::PublishSnapshot] } + /// Remove a track from the up-next queue. The active track and history + /// are unaffected. No-op (returns empty) if the track isn't in the + /// queue. After removal, the remaining queue positions are renumbered + /// via `Effect::ReorderQueue` so the store stays in sync. + fn handle_remove_queue_item(&mut self, track_id: TrackId) -> Vec { + let pos = self.queue.iter().position(|t| t.id == track_id); + let Some(_) = pos else { + return Vec::new(); + }; + self.queue.retain(|t| t.id != track_id); + let new_order: Vec = self.queue.iter().map(|t| t.id).collect(); + vec![ + Effect::RemoveQueuedTrack { track_id }, + Effect::ReorderQueue { new_order }, + Effect::PublishSnapshot, + ] + } + /// Pop the first track from the queue and start playing it. /// /// Returns effects for starting the pipeline and publishing state. @@ -1667,6 +1693,78 @@ mod tests { assert_eq!(s.active.as_ref().unwrap().id, original_active); assert_eq!(s.queue.len(), 5); } + + // --- queue item removal --- + + #[test] + fn test_remove_queue_item_basic() { + // Queue: [B, C, D], active A. Remove C → [B, D]. + let (mut s, ids) = queue_with(3); + let effects = s.transition(&Event::RemoveQueueItem { track_id: ids[2] }, 0); + assert_eq!(s.queue.len(), 2); + assert_eq!(s.queue[0].id, ids[1]); + assert_eq!(s.queue[1].id, ids[3]); + // Active track is untouched. + assert_eq!(s.active.as_ref().unwrap().id, ids[0]); + // Effects: delete, reorder, snapshot. + assert!(effects.iter().any(|e| matches!( + e, + Effect::RemoveQueuedTrack { track_id } if *track_id == ids[2] + ))); + assert!(effects.iter().any(|e| matches!( + e, + Effect::ReorderQueue { new_order } if new_order == &vec![ids[1], ids[3]] + ))); + assert!(effects.iter().any(|e| matches!(e, Effect::PublishSnapshot))); + } + + #[test] + fn test_remove_queue_item_unknown_id_is_noop() { + let (mut s, ids) = queue_with(3); + let ghost = track_id(0xdeadbeef); + let effects = s.transition(&Event::RemoveQueueItem { track_id: ghost }, 0); + assert_eq!(s.queue.len(), 3); + assert!(effects.is_empty()); + let _ = ids; + } + + #[test] + fn test_remove_queue_item_active_is_noop() { + // Active track is NOT in the queue Vec, so removing it should be a + // no-op. The state machine never lets you delete a playing track. + let (mut s, ids) = queue_with(2); + let active_id = s.active.as_ref().unwrap().id; + let effects = s.transition( + &Event::RemoveQueueItem { + track_id: active_id, + }, + 0, + ); + assert_eq!(s.queue.len(), 2); + assert!(effects.is_empty()); + let _ = ids; + } + + #[test] + fn test_remove_queue_item_empty_queue_is_noop() { + let mut s = PlaybackState::default(); + let effects = s.transition( + &Event::RemoveQueueItem { + track_id: track_id(1), + }, + 0, + ); + assert!(effects.is_empty()); + } + + #[test] + fn test_remove_queue_item_last_track() { + // Queue has 1 track, remove it → empty. + let (mut s, ids) = queue_with(1); + let effects = s.transition(&Event::RemoveQueueItem { track_id: ids[1] }, 0); + assert!(s.queue.is_empty()); + assert!(effects.iter().any(|e| matches!(e, Effect::PublishSnapshot))); + } } /// Deterministic simulation testing: random event sequences with invariant @@ -1701,13 +1799,24 @@ mod dst { MetadataUpdated(u64), DownloadResolved(u64), DownloadFailed(u64), - MoveQueueItem { from: u8, to: u8 }, - ShuffleQueue { seed: u64 }, + MoveQueueItem { + from: u8, + to: u8, + }, + ShuffleQueue { + seed: u64, + }, + /// Remove a queued track. `n` indexes into the same 0..12 track pool + /// as the other ops; if the track isn't in the queue the state + /// machine no-ops, mirroring the real-world "clicked X on a track + /// already removed" case. + RemoveQueueItem(u64), } fn op_strategy() -> impl Strategy> { - // Move and shuffle are weighted higher than the other ops so the new - // handlers get meaningful coverage in the 1024-case run. + // Move, shuffle, and remove are weighted higher than the other ops + // so the new queue-management handlers get meaningful coverage in + // the 1024-case run. let op = prop_oneof![ 2 => (0u64..12).prop_map(Op::Queue), 1 => Just(Op::Skip), @@ -1718,6 +1827,7 @@ mod dst { 1 => (0u64..12).prop_map(Op::DownloadFailed), 3 => (0u8..16, 0u8..16).prop_map(|(from, to)| Op::MoveQueueItem { from, to }), 2 => (0u64..1000).prop_map(|seed| Op::ShuffleQueue { seed }), + 3 => (0u64..12).prop_map(Op::RemoveQueueItem), ]; proptest::collection::vec(op, 0..50) } @@ -1831,6 +1941,7 @@ mod dst { let from_in = (*from as usize) < queue_len; let to_in = (*to as usize) < queue_len; let changed = from_in && to_in && from != to; + let moved_track_id = changed.then(|| state.queue[*from as usize].id); let expected_ids: Vec<_> = if changed { let mut q = state.queue.clone(); let t = q.remove(*from as usize); @@ -1851,6 +1962,13 @@ mod dst { actual_ids, expected_ids, "MoveQueueItem {from},{to} produced wrong order", ); + // The moved track must end at the destination index. + if let Some(id) = moved_track_id { + assert_eq!( + state.queue[*to as usize].id, id, + "moved track not at destination index" + ); + } if changed { assert!(effects.iter().any(|e| matches!(e, Effect::PublishSnapshot))); } else { @@ -1875,6 +1993,35 @@ mod dst { } effects } + Op::RemoveQueueItem(n) => { + // Pick the track id from the same 0..12 pool used by + // other ops. The state machine no-ops when the track + // isn't in the queue (or it's the active track), so + // this arm covers both the actual-remove and no-op + // cases. + let target = tid(*n); + let was_in_queue = state.queue.iter().any(|t| t.id == target); + let prev_len = state.queue.len(); + let effects = state.transition(&Event::RemoveQueueItem { track_id: target }, 0); + if was_in_queue { + assert_eq!( + state.queue.len(), + prev_len - 1, + "remove should shrink queue by exactly one", + ); + assert!( + !state.queue.iter().any(|t| t.id == target), + "removed track must not remain in queue", + ); + assert!(effects.iter().any(|e| matches!(e, Effect::PublishSnapshot))); + assert!(effects + .iter() + .any(|e| matches!(e, Effect::RemoveQueuedTrack { .. }))); + } else { + assert!(effects.is_empty(), "no-op remove must return no effects"); + } + effects + } }; check_invariants(&state, &effects, &queued_ids, &mut history_snapshot); @@ -1893,11 +2040,19 @@ mod dst { }, 0, ); - // Determinism: same event on identical state should produce same effects. - let mut clone = state.clone(); - let e1 = state.transition(&Event::Skip, 0); - let e2 = clone.transition(&Event::Skip, 0); - assert_eq!(e1, e2, "non-deterministic Skip on final state"); + // Determinism: same event on identical state should produce same + // effects. Tested across the main event families, not just Skip. + for event in &[ + Event::Skip, + Event::MoveQueueItem { from: 0, to: 0 }, + Event::ShuffleQueue { seed: 0 }, + Event::RemoveQueueItem { track_id: tid(0) }, + ] { + let mut clone = state.clone(); + let e1 = state.transition(event, 0); + let e2 = clone.transition(event, 0); + assert_eq!(e1, e2, "non-deterministic {event:?} on final state"); + } } fn check_invariants( @@ -2033,6 +2188,77 @@ mod dst { "AbortDownload without PersistFinished" ); } + + // === Queue-management invariants === + + // 10. ReorderQueue and RemoveQueuedTrack are state-changing: they + // must be followed by PublishSnapshot in the same transition. + let has_reorder = effects + .iter() + .any(|e| matches!(e, Effect::ReorderQueue { .. })); + let has_remove = effects + .iter() + .any(|e| matches!(e, Effect::RemoveQueuedTrack { .. })); + if has_reorder || has_remove { + assert!( + effects.iter().any(|e| matches!(e, Effect::PublishSnapshot)), + "queue-management effects without PublishSnapshot: {effects:?}" + ); + } + + // 11. Effect/state consistency: a ReorderQueue effect carries the + // post-transition queue order, so the state must match it. This + // catches handlers that mutate self.queue and emit a new_order + // that don't agree. + if let Some(new_order) = effects.iter().find_map(|e| { + if let Effect::ReorderQueue { new_order } = e { + Some(new_order.clone()) + } else { + None + } + }) { + let state_ids: Vec = state.queue.iter().map(|t| t.id).collect(); + assert_eq!( + state_ids, new_order, + "ReorderQueue's new_order doesn't match post-transition state.queue" + ); + } + + // 12. When RemoveQueuedTrack is emitted, the removed track must not + // be in the post-transition queue. + for e in effects { + if let Effect::RemoveQueuedTrack { track_id } = e { + assert!( + !state.queue.iter().any(|t| t.id == *track_id), + "RemoveQueuedTrack({track_id}) but track is still in state.queue" + ); + } + } + + // 13. When both RemoveQueuedTrack and ReorderQueue are emitted in + // the same transition, the removed track must not appear in + // new_order (the two effects must agree). + if let (Some(removed), Some(new_order)) = ( + effects.iter().find_map(|e| { + if let Effect::RemoveQueuedTrack { track_id } = e { + Some(*track_id) + } else { + None + } + }), + effects.iter().find_map(|e| { + if let Effect::ReorderQueue { new_order } = e { + Some(new_order) + } else { + None + } + }), + ) { + assert!( + !new_order.contains(&removed), + "ReorderQueue.new_order still contains just-removed track {removed}" + ); + } } fn is_persist_effect(e: &Effect) -> bool { @@ -2044,6 +2270,8 @@ mod dst { | Effect::PersistMetadata { .. } | Effect::AddPlaylistEntry { .. } | Effect::RemovePlaylistEntry(_) + | Effect::ReorderQueue { .. } + | Effect::RemoveQueuedTrack { .. } ) } diff --git a/src/store.rs b/src/store.rs index 02c409a..ca6fa96 100644 --- a/src/store.rs +++ b/src/store.rs @@ -298,6 +298,9 @@ impl RoomStore for InMemoryStore { // matched. The SQLite path handles position renumbering. let _ = new_order; } + Effect::RemoveQueuedTrack { track_id } => { + room.queue.retain(|t| t.id != *track_id); + } _ => {} } } @@ -619,6 +622,23 @@ impl SqliteStore { .await?; } } + Effect::RemoveQueuedTrack { track_id } => { + // Delete the track from the queue. The reorder effect + // that follows renumbers the remaining tracks, but + // keeping this as a separate statement means a partial + // failure leaves the queue in a recoverable state. + sqlx::query( + "DELETE FROM tracks + WHERE id = ?1 + AND room_id = ?2 + AND played = 0 + AND started_at_ms IS NULL", + ) + .bind(track_id.as_str_buf()) + .bind(room_id) + .execute(&mut *tx) + .await?; + } _ => {} } } diff --git a/src/transport.rs b/src/transport.rs index 2b389f2..d9514e2 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -44,6 +44,11 @@ enum WsClientMessage { }, /// Shuffle the entire queue (server picks the seed). ShuffleQueue, + /// Remove a queued track by id. No-op if the track is active or + /// already gone. + RemoveQueueItem { + item_id: TrackId, + }, } /// Run a WebSocket session for a single client. @@ -149,6 +154,11 @@ pub(crate) async fn handle_ws_session( WsClientMessage::ShuffleQueue => { let _ = cmd_tx.send(RoomCommand::ShuffleQueue).await; } + WsClientMessage::RemoveQueueItem { item_id } => { + let _ = cmd_tx + .send(RoomCommand::RemoveQueueItem { track_id: item_id }) + .await; + } } } } diff --git a/static/dist/assets/index-B3kVSRJi.js b/static/dist/assets/index-B3kVSRJi.js new file mode 100644 index 0000000..adb9176 --- /dev/null +++ b/static/dist/assets/index-B3kVSRJi.js @@ -0,0 +1 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))r(i);new MutationObserver(i=>{for(const o of i)if(o.type==="childList")for(const s of o.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function n(i){const o={};return i.integrity&&(o.integrity=i.integrity),i.referrerPolicy&&(o.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?o.credentials="include":i.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function r(i){if(i.ep)return;i.ep=!0;const o=n(i);fetch(i.href,o)}})();class U extends Error{source;constructor(t){super(),this.source=t}}class Bt extends Error{source;constructor(t,n){super(n instanceof Error?n.message:String(n),{cause:n}),this.source=t}}class En extends Error{constructor(){super("")}}class hr extends Error{constructor(){super("")}}const Cn=0,Ve=1,Ie=2,pt=4,ue=8,Je=16,H=32,he=64,we=128,Jt=256,at=512,He=1024,wt=1,gr=2,bt=4,mr=8,On=16,Ne=32,Ht=64,O=1,W=2,F=4,Re=1,J=2,_e=3,S={},yr=typeof Proxy=="function",Yt={},pr=Symbol("refresh");function Tn(e,t){const n=(e.i?.t?e.i.u?.o:e.i?.o)??-1;n>=e.o&&(e.o=n+1);const r=e.o,i=t.l[r];if(i===void 0)t.l[r]=e;else{const o=i.S;o.T=e,e.S=o,i.S=e}r>t._&&(t._=r)}function Qe(e,t){let n=e.O;n&(ue|pt|He)||(n&Ve?e.O=n&-4|Ie|ue:e.O=n|ue,n&Je||Tn(e,t))}function An(e,t){let n=e.O;n&(ue|pt|Je|He)||(e.O=n|Je,Tn(e,t))}function qe(e,t){const n=e.O;if(!(n&(ue|Je)))return;e.O=n&-25;const r=e.o;if(e.S===e)t.l[r]=void 0;else{const i=e.T,o=t.l[r],s=i??o;e===o?t.l[r]=i:e.S.T=i,s.S=e.S}e.S=e,e.T=void 0}function wr(e){if(!e.R){e.R=!0;for(let t=0;t<=e._;t++)for(let n=e.l[t];n!==void 0;n=n.T)n.O&ue&&ft(n)}}function ft(e,t=Ie){const n=e.O;if(!((n&(Ve|Ie))>=t)){e.O=n&-4|t;for(let r=e.I;r!==null;r=r.p)ft(r.h,Ve);if(e.N!==null)for(let r=e.N;r!==null;r=r.A)for(let i=r.I;i!==null;i=i.p)ft(i.h,Ve)}}function Fe(e,t){for(e.R=!1,e.C=0;e.C<=e._;e.C++){let n=e.l[e.C];for(;n!==void 0;)n.O&ue?t(n):br(n,e),n=e.l[e.C]}e._=0}function br(e,t){qe(e,t);let n=e.o;for(let r=e.P;r;r=r.D){const i=r.m,o=i.V||i;o.L&&o.o>=n&&(n=o.o+1)}if(e.o!==n){e.o=n;for(let r=e.I;r!==null;r=r.p)An(r.h,t)}}const dt=new WeakMap,ne=new Set;function vr(e){let t=dt.get(e);if(t)return V(t);const n=e.U,r=n?.G?V(n.G):null;return t={k:e,F:new Set,W:[[],[]],H:null,M:b,j:r},dt.set(e,t),ne.add(t),e.$=!1,t}function V(e){for(;e.H;)e=e.H;return e}function Rn(e,t){if(e=V(e),t=V(t),e===t)return e;t.H=e;for(const n of t.F)e.F.add(n);return e.W[0].push(...t.W[0]),e.W[1].push(...t.W[1]),e}function Pe(e){const t=e.G;if(!t)return;const n=V(t);if(ne.has(n))return n;e.G=void 0}function Be(e){return Pe(e)?.M??e.M}function vt(e){return e.K!==void 0&&e.K!==S}function Zt(e,t){const n=V(t),r=e.G;if(r){if(r.H){e.G=t;return}const i=V(r);if(ne.has(i)){i!==n&&!vt(e)&&(n.j&&V(n.j)===i?e.G=t:i.j&&V(i.j)===n||Rn(n,i));return}}e.G=t}const je=new Set,x={l:new Array(2e3).fill(void 0),R:!1,C:0,_:0},Y={l:new Array(2e3).fill(void 0),R:!1,C:0,_:0};let M=0,b=null,Ye=!1,jt=0,lt=null;const Ke=new Set;function $r(e){return je.size===0&&ne.size===0&&e.Y.length===0&&e.Z.length===0&&e.q.size===0&&Ke.size===0}function _r(){if(Ke.size!==0)for(const e of Ke){if(e.I!==null){Ke.delete(e);continue}e.B===S&&(e.K!==void 0&&e.K!==S||(Ke.delete(e),e.X?.()))}}function Sr(e){return!!lt?.has(e)}function nt(e){for(const t of ne){if(t.H||t.F.size>0)continue;const n=t.W[e-1];n.length&&(t.W[e-1]=[],gt(n,e))}}function Er(e){for(let t=e.I;t!==null;t=t.p){const n=t.h;if(!n.J)continue;if(n.J===_e){n.ee||(n.ee=!0,n.te.enqueue(J,n.ne));continue}const r=n.O&H?Y:x;r.C>n.o&&(r.C=n.o),Qe(n,r)}}function Cr(e,t){t.ie=e,e.re.push(...t.re);for(const n of ne)n.M===t&&(n.M=e);e.Z.push(...t.Z);for(const n of t.q)e.q.add(n);for(const[n,r]of t.oe){let i=e.oe.get(n);i||e.oe.set(n,i=new Set);for(const o of r)i.add(o)}for(const n of t.se)e.se.add(n)}function Or(e){for(let t=0;t=0&&(this.Y.splice(n,1),t.i=null)}notify(t,n,r,i){return this.i?this.i.notify(t,n,r,i):!1}run(t){if(this.le[t-1].length){const n=this.le[t-1];this.le[t-1]=[],gt(n,t)}for(let n=0;n=x.C,an(r.fe),b=null,!r.re.length&&!r.oe.size&&r.Z.length){lt=new Set;for(let i=0;i=x.C&&(Fe(x,X.Ee),ht())):(je.size&&Fe(Y,X.Ee),kt());M++,Ye=x._>=x.C,ne.size&&nt(Re),this.run(Re),ne.size&&nt(J),this.run(J)}finally{this.ce=!1}}}notify(t,n,r,i){if(n&O){if(r&O){const o=i!==void 0?i:t.Re;if(b&&o){const s=o.source;let c=b.oe.get(s);c||b.oe.set(s,c=new Set);const l=c.size;c.add(t),c.size!==l&&ve()}}return!0}return!1}initTransition(t){if(t&&(t=In(t)),!(t&&t===b)&&!(!t&&b&&b.Ie===M)){if(!b)b=t??{Ie:M,fe:[],oe:new Map,Z:[],q:new Set,re:[],_e:{le:[[],[]],Y:[]},ie:!1,se:new Set};else if(t){const n=b;Cr(t,n),je.delete(n),b=t}if(je.add(b),b.Ie=M,this.ae!==null&&(this.ae.M=b,b.fe.push(this.ae),this.ae=null),this.fe!==b.fe){for(let n=0;ni.h.o&&(s.C=i.h.o),Qe(i.h,s)}}function cn(e){const t=e;if(!t.L){e.B!==S&&(e.ue=e.B,e.B=S);return}e.B!==S&&(e.ue=e.B,e.B=S,e.J&&e.J!==_e&&(e.ee=!0)),t.O&=~He,t.he&O||(t.he&=~F),(t.Ne!==null||t.Ae!==null)&&X.Se(t,!1,!0)}function ht(){E.ae!==null&&(cn(E.ae),E.ae=null);const e=E.fe;for(let t=0;t=x.C;if(r&&Fe(x,X.Ee),n){if(r&&ht(),Or(e?e.Z:E.Z),e&&e.se.size){for(const i of e.se){if(i.O&he)continue;if(i.J===_e){i.ee||(i.ee=!0,i.te.enqueue(J,i.ne));continue}const o=i.O&H?Y:x;o.C>i.o&&(o.C=i.o),Qe(i,o)}e.se.clear()}e?e.q:E.q,_r(),Tr(e)}}function Pn(e){for(const t of e.Y)t.checkSources?.(),Pn(t)}function an(e){for(let t=0;te(()=>n.dispose()))}function en(e){const t=e.m,n=e.D,r=e.p,i=e.Le;if(r!==null?r.Le=i:t.Ue=i,i!==null)i.p=r;else if(t.I=r,r===null){t.X?.();const o=t;o.L&&o.Oe&Ne&&!(o.O&H)&&Ln(o)}return n}function xn(e){const t=e.ye;let n=t!==null?t.D:e.P;if(n!==null){do n=en(n);while(n!==null);t!==null?t.D=null:e.P=null}}function Ln(e){qe(e,e.O&H?Y:x);let t=e.P;for(;t!==null;)t=en(t);e.P=null,e.ye=null,Xe(e,!0)}function De(e,t){const n=t.ye;if(n!==null&&n.m===e)return;let r=null;const i=t.O&pt;if(i&&(r=n!==null?n.D:t.P,r!==null&&r.m===e)){t.ye=r;return}const o=e.Ue;if(o!==null&&o.h===t&&(!i||qr(o,t)))return;const s=t.ye=e.Ue={m:e,h:t,D:r,Le:o,p:null};n!==null?n.D=s:t.P=s,o!==null?o.p=s:e.I=s}function qr(e,t){const n=t.ye;if(n!==null){let r=t.P;do{if(r===e)return!0;if(r===n)break;r=r.D}while(r!==null)}return!1}function Mr(e,t){return e.Ce===t||e.Pe?.has(t)?!1:e.Ce?(e.Pe?e.Pe.add(t):e.Pe=new Set([e.Ce,t]),e.Ce=void 0,!0):(e.Ce=t,!0)}function Dr(e,t){return e.Ce?e.Ce!==t?!1:(e.Ce=void 0,!0):e.Pe?.delete(t)?(e.Pe.size===1?(e.Ce=e.Pe.values().next().value,e.Pe=void 0):e.Pe.size===0&&(e.Pe=void 0),!0):!1}function Nn(e){e.Ce=void 0,e.Pe?.clear(),e.Pe=void 0}function mt(e,t,n){if(!t){e.Re=null;return}if(n instanceof U&&n.source===t){e.Re=n;return}const r=e.Re;(!(r instanceof U)||r.source!==t)&&(e.Re=new U(t))}function Kt(e,t){for(let n=e.I;n!==null;n=n.p)t(n.h);for(let n=e.N;n!==null;n=n.A)for(let r=n.I;r!==null;r=r.p)t(r.h)}function Fr(e){let t=!1;const n=new Set,r=i=>{if(n.has(i)||!Dr(i,e))return;n.add(i),i.Ie=M;const o=i.Ce??i.Pe?.values().next().value;if(o)mt(i,o),$e(i);else{if(i.he&=~O,mt(i),$e(i),i.Ge){if(i.J===_e){const s=i;s.ee||(s.ee=!0,s.te.enqueue(J,s.ne))}else{const s=i.O&H?Y:x;s.C>i.o&&(s.C=i.o),Qe(i,s)}t=!0}i.Ge=!1}Kt(i,r)};Kt(e,r),t&&ve()}function Br(e,t,n){let r=!1,i=!1;if(typeof t=="object"&&t!==null&&ee(()=>{r=t[Symbol.asyncIterator],i=!r&&typeof t.then=="function"}),!i&&!r)return e.ve=null,t;e.ve=t;let o;const s=l=>{e.ve===t&&(E.initTransition(Be(e)),tn(e,l instanceof U?O:W,l),e.Ie=M)},c=(l,d)=>{if(e.ve!==t||e.O&(Ie|we))return;E.initTransition(Be(e));const h=!!(e.he&F);xn(e),qn(e);const f=Pe(e);if(f&&f.F.delete(e),e.K!==void 0)e.K!==void 0&&e.K!==S?e.B=l:(e.ue=l,ke(e)),e.Ie=M;else if(f){const g=e.J,p=e.ue,y=e.ke;(!g&&h||!y||!y(l,p))&&(e.ue=l,e.Ie=M,e.Fe&&ae(e.Fe,l),ke(e,!0))}else ae(e,()=>l);Fr(e),ve(),xe(),d?.()};if(i){let l=!1,d=!0;if(t.then(h=>{d?(o=h,l=!0):c(h)},h=>{d||s(h)}),d=!1,!l)throw E.initTransition(Be(e)),new U($)}if(r){const l=t[Symbol.asyncIterator]();let d=!1,h=!1;_t(()=>{if(!h){h=!0;try{const p=l.return?.();p&&typeof p.then=="function"&&p.then(void 0,()=>{})}catch{}}});const f=()=>{let p,y=!1,u=!0;return l.next().then(a=>{if(u)p=a,y=!0,a.done&&(h=!0);else{if(e.ve!==t)return;a.done?(h=!0,ve(),xe()):c(a.value,f)}},a=>{!u&&e.ve===t&&(h=!0,s(a))}),u=!1,y&&!p.done?(o=p.value,d=!0,f()):y&&p.done},g=f();if(!d&&!g)throw E.initTransition(Be(e)),new U($)}return o}function qn(e,t=!1){(e.Ce||e.Pe)&&Nn(e),e.Ge&&(e.Ge=!1),e.he=t?0:e.he&F,e.Re&&mt(e),e.We&&$e(e),e.xe&&e.xe()}function tn(e,t,n,r,i){t===W&&!(n instanceof Bt)&&!(n instanceof U)&&(n=new Bt(e,n));const o=t===O&&n instanceof U?n.source:void 0,s=o===e,c=t===O&&e.K!==void 0&&!s,l=c&&vt(e);r||(t===O&&o?(Mr(e,o),e.he=O|e.he&F,mt(e,o,n)):(Nn(e),e.he=t|(t!==W?e.he&F:0),e.Re=n),$e(e)),i&&!r&&Zt(e,i);const d=r||l,h=r||c?void 0:i;if(e.xe){if(r&&t===O)return;d?e.xe(t,n):e.xe();return}Kt(e,f=>{f.Ie=M,(t===O&&o&&f.Ce!==o&&!f.Pe?.has(o)||t!==O&&(f.Re!==n||f.Ce||f.Pe))&&(!d&&!f.M&&$t(f),tn(f,t,n,d,h))})}let jr=null;X.Ee=ce;X.Se=Xe;let K=!1,re=!1,$=null,G=null;function ce(e,t=!1){const n=e.J;t||(e.M&&(!n||b)&&b!==e.M&&E.initTransition(e.M),qe(e,e.O&H?Y:x),e.ve=null,e.M||n===_e?Xe(e):(e.ge!==null||e.be!==null)&&(kn(e),e.Ae=e.be,e.Ne=e.ge,e.be=null,e.ge=null,e.me=0));let r=!!(e.O&we);const i=e.K!==void 0&&e.K!==S,o=!!(e.he&O),s=!!(e.he&F),c=$;$=e,e.ye=null,e.O=pt,e.Ie=M;let l=e.B===S?e.ue:e.B,d=e.o,h=K,f=G;if(K=!0,r){const u=Pe(e);u&&(G=u)}else if(b&&!t&&b.Z.length)for(let u=e.P;u;u=u.D){const a=u.m;if(a.O&we){const m=Pe(a);if(m){r=!0,G=m,e.O|=we,Zt(e,m);break}}}const g=n&&n!==J,p=re;g&&(re=!0);try{if(e.Oe&Ht)l=e.L(l),e.ve=null;else{const u=e.ve,a=e.L(l),m=typeof a=="object"&&a!==null,w=e.ve!==u;l=w||!m?a:Br(e,a),!w&&!m&&(e.ve=null)}if(qn(e,t),e.G){const u=Pe(e);u&&(u.F.delete(e),$e(u.k))}}catch(u){if(u instanceof U&&G){const a=V(G);a.k!==e&&(a.F.add(e),e.G=a,$e(a.k))}u instanceof U&&(e.Ge=!0),tn(e,u instanceof U?O:W,u,void 0,u instanceof U?e.G:void 0)}finally{K=h,g&&(re=p),e.O=Cn|(t?e.O&Jt:0),$=c}if(!e.Re){xn(e);const u=i?e.K:e.B===S?e.ue:e.B,a=!n&&s||!e.ke||!e.ke(u,l);if(n&&a&&(e.ee=!e.Re,t||e.te.enqueue(n,X.Te.bind(null,e))),a){const m=i?e.K:void 0;t||n&&b!==e.M||r?(e.ue=l,i&&r&&(e.K=l,e.B=l)):e.B=l,i&&!r&&o&&!e.$&&(e.K=l),(!i||r||e.K!==m)&&ke(e,r||i)}else if(i)e.B=l;else if(e.o!=d)for(let m=e.I;m!==null;m=m.p)An(m.h,m.h.O&H?Y:x)}G=f,(e.B!==S||e.Ne!==null||e.Ae!==null||!!(e.he&(O|F)))&&(!t||e.he&O)&&!e.M&&!(b&&i)&&$t(e),e.M&&n&&b!==e.M&&Ir(e.M,()=>ce(e))}function Mn(e){if(e.O&Ve)for(let t=e.P;t;t=t.D){const n=t.m,r=n.V||n;if(r.L&&Mn(r),e.O&Ie)break}(e.O&(Ie|we)||e.Re&&e.Ie=(o?Y.C:x.C)&&(ft(t),wr(o?Y:x),Mn(r));const s=r.o;s>=t.o&&e.i!==t&&(t.o=s+1)}if(r.he&O)if(t&&!(re&&r.M&&b!==r.M))if(G){const o=r.G,s=V(G);if(o&&V(o)===s&&!vt(r))throw!K&&e!==t&&De(e,t),r.Re}else throw!K&&e!==t&&De(e,t),r.Re;else{if(t&&r!==e&&r.he&F)throw!K&&e!==t&&De(e,t),r.Re;if(!t&&r.he&F)throw r.Re}if(e.L&&e.he&W){if(e.Ie0)}return!0}return e.K!==void 0&&e.K===S&&!e.U?!1:e.B!==S&&!(t.he&F)?!0:!!(t.he&O&&!(t.he&F))}function $e(e){if(e.We){const t=zr(e),n=e.We;if(ae(n,t),!t&&n.G){const r=Pe(e);if(r&&r.F.size>0){const i=V(n.G);i!==r&&Rn(r,i)}dt.delete(n),n.G=void 0}}}function Gr(e,t=!0){const n=re;re=t;try{return e()}finally{re=n}}function Jr(e,t=et()){if(!t)throw new En;const n=Yr(e,t)?t.Ve[e.id]:e.defaultValue;if(nn(n))throw new hr;return n}function Hr(e,t,n=et()){if(!n)throw new En;n.Ve={...n.Ve,[e.id]:nn(t)?e.defaultValue:t}}function Yr(e,t){return!nn(t?.Ve[e.id])}function nn(e){return typeof e>"u"}function jn(e,t,n,r){const i=!!r?.user,o=Kr(e,t,n,i?J:Re,Zr,r);ce(o,!0),!r?.defer&&(o.J===J||r?.schedule?o.te.enqueue(o.J,Ut.bind(null,o)):Ut(o))}function Zr(e,t){const n=e!==void 0?e:this.he,r=t!==void 0?t:this.Re;if(n&W){let i=r;if(this.te.notify(this,O,0),this.J===J)try{return this.je?this.je(i,()=>{this.$e?.(),this.$e=void 0}):console.error(i)}catch(o){i=o}if(!this.te.notify(this,W,W))throw i}else this.J===Re&&this.te.notify(this,O|W,n,r)}function Ut(e){if(!(!e.ee||e.O&he)){e.$e?.(),e.$e=void 0;try{const t=e.Qe(e.ue,e.Me);e.$e=t,e.$e&&!e.Ke&&(e.Ke=!0,le(e.i,()=>_t(()=>e.$e?.())))}catch(t){if(e.Re=new Bt(e,t),e.he|=W,!e.te.notify(e,W,W))throw t}finally{e.Me=e.ue,e.ee=!1}}}X.Te=Ut;function Qr(e,t){const n=()=>{if(!(!r.ee||r.O&he))try{r.ee=!1,ce(r)}finally{}},r=St(()=>{r.$e?.(),r.$e=void 0;const i=Gr(e);r.$e=i},{...t,lazy:!0});r.$e=void 0,r.Oe=r.Oe&~Ne|On,r.ee=!0,r.J=_e,r.xe=(i,o)=>{if((i!==void 0?i:r.he)&W){r.te.notify(r,O,0);const c=o!==void 0?o:r.Re;if(!r.te.notify(r,W,W))throw c}},r.ne=n,r.te.enqueue(J,n),_t(()=>r.$e?.())}function Kn(e){return _t(e)}function de(e){const t=Bn.bind(null,e);return t[pr]=e,t}function Xr(e,t){if(typeof e=="function"){const r=St(e,t);return r.Oe&=~Ne,[de(r),Vr.bind(null,r)]}const n=Ue(e,t);return[de(n),ae.bind(null,n)]}function be(e,t){return de(St(e,t))}function ei(e,t,n){jn(e,t.effect||t,t.error,{user:!0,...n})}function ti(e,t,n){jn(e,t,void 0,n)}function ni(e,t){Qr(e,t)}function ri(e){const t=et();t&&!(t.Oe&On)?ni(()=>ee(e),void 0):E.enqueue(J,()=>{e()?.()})}const ii=Symbol(0),Wt=Symbol(0);function fn(e){return e==null||typeof e!="object"||Object.isFrozen(e)?!1:typeof Node>"u"||!(e instanceof Node)}const Un=Symbol(0);function dn(e){return e==="__proto__"||e==="constructor"||e==="prototype"}function We(e,t,n=0){let r,i=e;if(n{We(n,t)}},{DELETE:Un});function rt(){return!0}const oi={get(e,t,n){return t===Wt?n:e.get(t)},has(e,t){return t===Wt?!0:e.has(t)},set:rt,deleteProperty:rt,getOwnPropertyDescriptor(e,t){return{configurable:!0,enumerable:!0,get(){return e.get(t)},set:rt,deleteProperty:rt}},ownKeys(e){return e.keys()}};function xt(e){return(e=typeof e=="function"?e():e)?e:{}}const Lt=Symbol(0);function si(...e){if(e.length===1&&typeof e[0]!="function")return e[0];let t=!1;const n=[];for(let l=0;l=0;d--){const h=xt(n[d]);if(l in h)return h[l]}},has(l){for(let d=n.length-1;d>=0;d--)if(l in xt(n[d]))return!0;return!1},keys(){const l=new Set;for(let d=0;d=0;l--){const d=n[l];if(!d){l===o&&o--;continue}const h=Object.getOwnPropertyNames(d);for(let f=h.length-1;f>=0;f--){const g=h[f];if(!(g==="__proto__"||g==="constructor")&&!r[g]){i=i||l!==o;const p=Object.getOwnPropertyDescriptor(d,g);r[g]=p.get?{enumerable:!0,configurable:!0,get:p.get.bind(d)}:p}}}if(!i)return n[o];const s={},c=Object.keys(r);for(let l=c.length-1;l>=0;l--){const d=c[l],h=r[d];h.get?Object.defineProperty(s,d,h):s[d]=h.value}return s[Lt]=n,s}function li(e,t,n){const r=typeof n?.keyed=="function"?n.keyed:void 0,i=t.length>1,o=t,s={Ze:ze(),qe:0,Be:e,ze:[],Xe:o,Je:[],et:[],tt:r,nt:r||n?.keyed===!1?[]:void 0,it:i&&n?.keyed!==!1?[]:void 0,rt:n?.keyed===!1,ot:n?.fallback},c=St(ui.bind(s));return s.Ze.u=c,c.Oe&=~Ne,de(c)}const it={ownedWrite:!0};function ui(){const e=this.Be()||[],t=e.length;return e[ii],le(this.Ze,()=>{let n,r,i=this.nt?this.rt?()=>(this.nt[r]=Ue(e[r],it),this.Xe(de(this.nt[r]),r)):()=>(this.nt[r]=Ue(e[r],it),this.it&&(this.it[r]=Ue(r,it)),this.Xe(de(this.nt[r]),this.it?de(this.it[r]):void 0)):this.it?()=>{const o=e[r];return this.it[r]=Ue(r,it),this.Xe(o,de(this.it[r]))}:()=>{const o=e[r];return this.Xe(o)};if(t===0)this.qe!==0&&(this.Ze.dispose(!1),this.et=[],this.ze=[],this.Je=[],this.qe=0,this.nt&&(this.nt=[]),this.it&&(this.it=[])),this.ot&&!this.Je[0]&&(this.Je[0]=le(this.et[0]=ze(),this.ot));else if(this.qe===0){for(this.et[0]&&this.et[0].dispose(),this.Je=new Array(t),r=0;r=o&&c>=o&&(this.ze[s]===e[c]||this.nt&&hn(this.tt,this.ze[s],e[c]));s--,c--)g[c]=this.Je[s],p[c]=this.et[s],y&&(y[c]=this.nt[s]),u&&(u[c]=this.it[s]);for(h=new Map,f=new Array(c+1),r=c;r>=o;r--)l=e[r],d=this.tt?this.tt(l):l,n=h.get(d),f[r]=n===void 0?-1:n,h.set(d,r);for(n=o;n<=s;n++)l=this.ze[n],d=this.tt?this.tt(l):l,r=h.get(d),r!==void 0&&r!==-1?(g[r]=this.Je[n],p[r]=this.et[n],y&&(y[r]=this.nt[n]),u&&(u[r]=this.it[n]),r=f[r],h.set(d,r)):this.et[n].dispose();for(r=o;r{let r=[];return Vt(n,r,{...t,doNotUnwrap:!1}),r}:n}return e}}function Vt(e,t=[],n){let r=null,i=!1;for(let o=0;o(Hr(r,i.value),on(()=>i.children)))}return r.id=n,r.defaultValue=e,r}function Vn(e){return Jr(e)}function on(e){const t=be(e,{lazy:!0}),n=be(()=>rn(t()),{lazy:!0,sync:!0});return n.toArray=()=>{const r=n();return Array.isArray(r)?r:r!=null?[r]:[]},n}class Ae{static{for(const t of["all","allSettled","any","race","reject","resolve"])Ae[t]=()=>new Ae}catch(){return new Ae}then(){return new Ae}finally(){return new Ae}}const Q=(...e)=>be(...e),q=(...e)=>Xr(...e),ci=(...e)=>ti(...e),Et=(...e)=>ei(...e);function L(e,t){return ee(()=>e(t||{}))}const ai=e=>`Stale read from <${e}>.`;function ut(e){const t="fallback"in e?{keyed:e.keyed,fallback:()=>e.fallback}:{keyed:e.keyed};return li(()=>e.each,e.children,t)}function zn(e){const t=e.keyed,n=be(()=>e.when,void 0),r=t?n:be(n,{equals:(i,o)=>!i==!o,sync:!0});return be(()=>{const i=r();if(i){const o=e.children;return typeof o=="function"&&o.length>0?ee(t?()=>o(i):()=>o(()=>{if(!ee(r))throw ai("Show");return n()})):o}return e.fallback},{sync:!0})}const j=Symbol("slot"),fi={transparent:!0,sync:!0},di={sync:!0},Z=(e,t,n)=>ci(e,t,n?{transparent:!0,sync:!0,...n}:fi),D=e=>Q(()=>e(),di);function hi(e,t,n,r){let i=n.length,o=t.length,s=i,c=0,l=0,d=t[o-1],h=d[j],f=d.parentNode===e&&(!h||h===r)?d.nextSibling:r||null,g=null,p,y;for(;c=o-1||l>=s)break}while(t[c]===n[s-1]&&n[l]===t[o-1]);else do if(e.insertBefore(t[--o],p),l++,c>=o-1||l>=s)break;while(t[c]===n[s-1]&&n[l]===t[o-1]);else{if(!g){g=new Map;let a=l;for(;au-l){const C=t[c],A=C[j],P=C.parentNode===e&&(!A||A===r)?C:f;for(;l{if(i=o,t===document){const s=e();Z(()=>rn(s),()=>{})}else{const s=e();v(t,()=>s,t.firstChild?null:void 0,n,r.insertOptions)}},{id:r.renderId})}catch(o){throw i&&i(),yn(t),o}return()=>{i(),yn(t),t.textContent=""}}function mi(e,t,n){const r=document.createElement("template");return r.innerHTML=e,n===2?r.content.firstChild.firstChild:r.content.firstChild}function T(e,t){let n;return i=>(n||(n=mi(e,i,t))).cloneNode(!0)}function tt(e){for(let t=0,n=e.length;tGn(r,o,i)))}}function yi(e){const t=pi(e,e);t&&(t.roots=(t.roots||0)+1)}function yn(e){const t=Le.get(e);t&&(t.roots>1?t.roots--:delete t.roots),wi(e,e)}function pi(e,t=e){if(!e||!t)return;let n=Le.get(e);return n||Le.set(e,n={owners:new Map,handlers:new Map}),n.owners.set(t,(n.owners.get(t)||0)+1),zt.forEach(r=>Gn(r,e,n)),n}function wi(e,t=e){const n=Le.get(e);if(!n)return;const r=n.owners.get(t);r>1?n.owners.set(t,r-1):n.owners.delete(t),!n.owners.size&&(n.handlers.forEach((i,o)=>e.removeEventListener(o,i)),Le.delete(e))}function Gn(e,t,n){if(n.handlers.has(e))return;const r=i=>$i(i,t,n);n.handlers.set(e,r),t.addEventListener(e,r)}function bi(e,t){let n=e,r=0;for(;n;){if(t.owners.has(n))return{owner:n,distance:r};r++,n=n._$host||n.parentNode||n.host}}function ie(e,t,n){n==null||n===!1?e.removeAttribute(t):e.setAttribute(t,n===!0?"":n)}function Ze(e,t,n){if(t==null||t===!1){n&&e.removeAttribute("class");return}if(typeof t=="string"){t!==n&&e.setAttribute("class",t);return}typeof n=="string"?(n={},e.removeAttribute("class")):n=wn(n||{}),t=wn(t);const r=Object.keys(t||{}),i=Object.keys(n);let o,s;for(o=0,s=i.length;oi.call(e,n[1],o))}else e.addEventListener(t,n,typeof n!="function"&&n)}function vi(e,t){Array.isArray(e)?e.flat(1/0).forEach(n=>n&&n(t)):e(t)}function yt(e,t){const n=ee(e);le(null,()=>vi(n,t))}function v(e,t,n,r,i){const o=n!==void 0;if(o&&!r&&(r=[]),typeof t!="function"&&(t=qt(t,r,o,!0),typeof t!="function"))return Nt(e,t,r,n);if(o&&r.length===0){const c=document.createTextNode("");e.insertBefore(c,n),r=[c]}let s=r;Z(c=>{const l=qt(t(),s,o,!0);return typeof l!="function"?l:(Z(()=>qt(l,s,o),d=>{Nt(e,d,s,n),s=d},c!==void 0&&!(i&&i.schedule)?{...i,schedule:!0}:i),mn)},c=>{c!==mn&&(Nt(e,c,s,n),s=c)},i)}function wn(e){if(Array.isArray(e)){const t={};Jn(e,t),e=t}if(e&&typeof e=="object"){const t={},n=Object.keys(e);for(let r=0,i=n.length;rObject.defineProperty(e,"target",{configurable:!0,value:f}),d=()=>{const f=i[o];if(f&&!i.disabled){const g=i[`${o}Data`];if(g!==void 0?f.call(i,g,e):f.call(i,e),e.cancelBubble)return}return i.host&&typeof i.host!="string"&&!i.host._$host&&i.contains(e.target)&&l(i.host),!0},h=()=>{for(;d()&&!(i===c||i.parentNode===c);)i=i._$host||i.parentNode||i.host};if(Object.defineProperty(e,"currentTarget",{configurable:!0,get(){return i||c||document}}),e.composedPath){const f=e.composedPath();if(f.length){l(f[0]);for(let g=0;g=0;o--){const s=t[o];if(r!==s){const c=s[j],l=s.parentNode===e&&(!c||c===n);r&&!i&&!o?l?e.replaceChild(r,s):e.insertBefore(r,n):l&&s.remove()}else i=!0}}else r&&e.insertBefore(r,n);r&&n&&(r[j]=n)}const _i=!1;function Si(e,t,n,r={}){try{const i=gi(e,t,n,{...r,insertOptions:{schedule:!0}});return xe(),i}finally{}}function Hn(){let e=new Set;function t(i){return e.add(i),()=>e.delete(i)}let n=!1;function r(i,o){if(n)return!(n=!1);const s={to:i,options:o,defaultPrevented:!1,preventDefault:()=>s.defaultPrevented=!0};for(const c of e)c.listener({...s,from:c.location,retry:l=>{l&&(n=!0),c.navigate(i,{...o,resolve:!1})}});return!s.defaultPrevented}return{subscribe:t,confirm:r}}let Gt;function sn(){(!window.history.state||window.history.state._depth==null)&&window.history.replaceState({...window.history.state,_depth:window.history.length-1},""),Gt=window.history.state._depth}sn();function Ei(e){return{...e,_depth:window.history.state&&window.history.state._depth}}function Ci(e,t){let n=!1;return()=>{const r=Gt;sn();const i=r==null?null:Gt-r;if(n){n=!1;return}i&&t(i)?(n=!0,window.history.go(-i)):e()}}const Oi=/^(?:[a-z0-9]+:)?\/\//i,Ti=/^\/+|(\/)\/+$/g,Yn="http://sr";function Ge(e,t=!1){const n=e.replace(Ti,"$1");return n?t||/^[?#]/.test(n)?n:"/"+n:""}function ct(e,t,n){if(Oi.test(t))return;const r=Ge(e),i=n&&Ge(n);let o="";return!i||t.startsWith("/")?o=r:i.toLowerCase().indexOf(r.toLowerCase())!==0?o=r+i:o=i,(o||"/")+Ge(t,!o)}function Ai(e,t){if(e==null)throw new Error(t);return e}function Ri(e,t){return Ge(e).replace(/\/*(\*.*)?$/g,"")+Ge(t)}function Zn(e){const t={};return e.searchParams.forEach((n,r)=>{r in t?Array.isArray(t[r])?t[r].push(n):t[r]=[t[r],n]:t[r]=n}),t}function Pi(e,t,n){const[r,i]=e.split("/*",2),o=r.split("/").filter(Boolean),s=o.length;return c=>{const l=c.split("/").filter(Boolean),d=l.length-s;if(d<0||d>0&&i===void 0&&!t)return null;const h={path:s?"":"/",params:{}},f=g=>n===void 0?void 0:n[g];for(let g=0;gr===e;return t===void 0?!0:typeof t=="string"?n(t):typeof t=="function"?t(e):Array.isArray(t)?t.some(n):t instanceof RegExp?t.test(e):!1}function Ii(e){const[t,n]=e.pattern.split("/*",2),r=t.split("/").filter(Boolean);return r.reduce((i,o)=>i+(o.startsWith(":")?2:3),r.length-(n===void 0?0:1))}function Qn(e){const t=new Map,n=et();return new Proxy({},{get(r,i){return t.has(i)||le(n,()=>t.set(i,Q(()=>e()[i]))),t.get(i)()},getOwnPropertyDescriptor(){return{enumerable:!0,configurable:!0}},ownKeys(){return Reflect.ownKeys(e())},has(r,i){return i in e()}})}function Xn(e){let t=/(\/?\:[^\/]+)\?/.exec(e);if(!t)return[e];let n=e.slice(0,t.index),r=e.slice(t.index+t[0].length);const i=[n,n+=t[1]];for(;t=/^(\/\:[^\/]+)\?/.exec(r);)i.push(n+=t[1]),r=r.slice(t[0].length);return Xn(r).reduce((o,s)=>[...o,...i.map(c=>c+s)],[])}const ki=100,er=Wn(),tr=Wn();function xi(e){try{return Vn(e)}catch{return}}const nr=()=>Ai(Vn(er)," and 'use' router primitives can be only used inside a Route."),rr=()=>nr().navigatorFactory(),Li=()=>nr().params;function Ni(e,t=""){const{component:n,preload:r,children:i,info:o}=e,s=!i||Array.isArray(i)&&!i.length,c={key:e,component:n,preload:r,info:o};return ir(e.path).reduce((l,d)=>{for(const h of Xn(d)){const f=Ri(t,h);let g=s?f:f.split("/*",1)[0];g=g.split("/").map(p=>p.startsWith(":")||p.startsWith("*")?p:encodeURIComponent(p)).join("/"),l.push({...c,originalPath:d,pattern:g,matcher:Pi(g,!s,e.matchFilters)})}return l},[])}function qi(e,t=0){return{routes:e,score:Ii(e[e.length-1])*1e4-t,matcher(n){const r=[];for(let i=e.length-1;i>=0;i--){const o=e[i],s=o.matcher(n);if(!s)return null;r.unshift({...s,route:o})}return r}}}function ir(e){return Array.isArray(e)?e:[e]}function or(e,t="",n=[],r=[]){const i=ir(e);for(let o=0,s=i.length;os.score-o.score)}function Dt(e,t){for(let n=0,r=e.length;n{const f=e();try{return new URL(f,r)}catch{return console.error(`Invalid path ${f}`),h}},{equals:(h,f)=>h.href===f.href}),o=Q(()=>i().pathname),s=Q(()=>i().search),c=Q(()=>i().hash),l=()=>"",d=Q(()=>Zn(i()));return{get pathname(){return o()},get search(){return s()},get hash(){return c()},get state(){return t()},get key(){return l()},query:n?n(d):Qn(d)}}let pe;function Di(){return pe}function Fi(e,t,n,r={}){const{signal:[i,o],utils:s={}}=e,c=s.parsePath||(I=>I),l=s.renderPath||(I=>I),d=s.beforeLeave||Hn(),h=ct("",r.base||""),f=ee(i);if(h===void 0)throw new Error(`${h} is not a valid base path`);h&&!f.value&&o({value:h,replace:!0,scroll:!1});const[g,p]=q(!1,{ownedWrite:!0}),[y,u]=q(void 0,{ownedWrite:!0});let a;const m=Q(()=>y()??i()),w=Mi(()=>m().value,()=>m().state,s.queryWrapper),C=[],A=q([],{ownedWrite:!0}),P=Q(()=>typeof r.transformUrl=="function"?Dt(t(),r.transformUrl(w.pathname)):Dt(t(),w.pathname)),B=()=>{const I=P(),k={};for(let z=0;zh,outlet:()=>null,resolvePath(I){return ct(h,I)}};return{base:ge,location:w,params:Se,isRouting:g,renderPath:l,parsePath:c,navigatorFactory:Ct,matches:P,beforeLeave:d,preloadRoute:Tt,singleFlight:r.singleFlight===void 0?!0:r.singleFlight,submissions:A};function Ee(I,k,z){ee(()=>{if(typeof k=="number"){k&&(s.go?s.go(k):console.warn("Router integration does not support relative routing"));return}const Ce=!k||k[0]==="?",{replace:Oe,resolve:te,scroll:Te,state:oe}={replace:!1,resolve:!Ce,scroll:!0,...z},me=te?I.resolvePath(k):ct(Ce&&w.pathname||"",k);if(me===void 0)throw new Error(`Path '${k}' is not a routable path`);if(C.length>=ki)throw new Error("Too many redirects");const fe=m();if((me!==fe.value||oe!==fe.state)&&!_i){if(d.confirm(me,z)){C.push({value:fe.value,replace:Oe,scroll:Te,state:fe.state});const ye={value:me,state:oe};a===void 0&&(p(!0),xe()),pe="navigate",a=ye,a===ye&&(u({...a}),queueMicrotask(()=>{a===ye&&(pe=void 0,Ot(a),u(void 0),p(!1),a=void 0)}))}}})}function Ct(I){return I=I||xi(tr)||ge,(k,z)=>Ee(I,k,z)}function Ot(I){const k=C[0];k&&(o({...I,replace:k.replace,scroll:k.scroll}),C.length=0)}function Tt(I,k){const z=Dt(t(),I.pathname),Ce=pe;pe="preload";for(let Oe in z){const{route:te,params:Te}=z[Oe];te.component&&te.component.preload&&te.component.preload();const{preload:oe}=te;k&&oe&&le(n(),()=>oe({params:Te,location:{pathname:I.pathname,search:I.search,hash:I.hash,query:Zn(I),state:null,key:""},intent:"preload"}))}pe=Ce}}function Bi(e,t,n,r){const{base:i,location:o,params:s}=e,{pattern:c,component:l,preload:d}=r().route,h=Q(()=>r().path);l&&l.preload&&l.preload();const f=d?d({params:s,location:o,intent:pe||"initial"}):void 0;return{parent:t,pattern:c,path:h,outlet:()=>l?L(l,{params:s,location:o,data:f,get children(){return n()}}):n(),resolvePath(p){return ct(i.path(),p,h())}}}const ji=e=>function(n){const{base:r,singleFlight:i,transformUrl:o,root:s,rootPreload:c,routeChildren:l}=ee(()=>({base:n.base,singleFlight:n.singleFlight,transformUrl:n.transformUrl,root:n.root,rootPreload:n.rootPreload,routeChildren:n.children})),d=on(()=>l),h=Q(()=>or(d(),r||""));let f;const g=Fi(e,h,()=>f,{base:r,singleFlight:i,transformUrl:o});return e.create&&e.create(g),L(er,{value:g,get children(){return L(Ki,{routerState:g,root:s,preload:c,get children(){return[D(()=>(f=et())&&null),L(Ui,{routerState:g,get branches(){return h()}})]}})}})};function Ki(e){const t=e.routerState.location,n=e.routerState.params,r=Q(()=>e.preload&&ee(()=>{e.preload({params:n,location:t,intent:Di()||"initial"})})),i=e.root;return i?L(i,{params:n,location:t,get data(){return r()},get children(){return e.children}}):e.children}function Ui(e){const t=[];let n,r;const i=Q(s=>{const c=e.routerState.matches(),l=r;let d=l&&c.length===l.length;const h=[];for(let f=0,g=c.length;f{t[f]=u,h[f]=Bi(e.routerState,h[f-1]||e.routerState.base,vn(()=>i()?.[f+1]),()=>{const a=e.routerState.matches();return a[f]??a[0]})}))}return t.splice(c.length).forEach(f=>f()),s&&d?(r=c,s):(n=h[0],r=c,h)}),o=vn(()=>i()&&n);return D(o)}const vn=e=>()=>{const t=e();if(t)return L(tr,{value:t,get children(){return t.outlet()}})},$n=e=>{const t=on(()=>e.children);return si(e,{get children(){return t()}})};function Wi(e){let t=!1;const n=s=>typeof s=="string"?{value:s}:s,[r,i]=q(n(e.get()),{equals:(s,c)=>s.value===c.value&&s.state===c.state,ownedWrite:!0}),o=[r,s=>{!t&&e.set(s),i(s)}];return e.init&&Kn(e.init((s=e.get())=>{t=!0,o[1](n(s)),t=!1})),ji({signal:o,create:e.create,utils:e.utils})}function Vi(e,t,n){return e.addEventListener(t,n),()=>e.removeEventListener(t,n)}function zi(e,t){const n=e&&document.getElementById(e);n?n.scrollIntoView():t&&window.scrollTo(0,0)}const Gi=new Map;function Ji({preload:e=!0,explicitLinks:t=!1,actionBase:n="/_server",transformUrl:r}={}){return i=>{const o=i.base.path(),s=i.navigatorFactory(i.base);let c,l;function d(u){return u.namespaceURI==="http://www.w3.org/2000/svg"}function h(u){if(u.defaultPrevented||u.button!==0||u.metaKey||u.altKey||u.ctrlKey||u.shiftKey)return;const a=u.composedPath().find(B=>B instanceof Node&&B.nodeName.toUpperCase()==="A");if(!a||t&&!a.hasAttribute("link"))return;const m=d(a),w=m?a.href.baseVal:a.href;if((m?a.target.baseVal:a.target)||!w&&!a.hasAttribute("state"))return;const A=(a.getAttribute("rel")||"").split(/\s+/);if(a.hasAttribute("download")||A&&A.includes("external"))return;const P=m?new URL(w,document.baseURI):new URL(w);if(!(P.origin!==window.location.origin||o&&P.pathname&&!P.pathname.toLowerCase().startsWith(o.toLowerCase())))return[a,P]}function f(u){const a=h(u);if(!a)return;const[m,w]=a,C=i.parsePath(w.pathname+w.search+w.hash),A=m.getAttribute("state");u.preventDefault(),s(C,{resolve:!1,replace:m.hasAttribute("replace"),scroll:!m.hasAttribute("noscroll"),state:A?JSON.parse(A):void 0})}function g(u){const a=h(u);if(!a)return;const[m,w]=a;r&&(w.pathname=r(w.pathname)),i.preloadRoute(w,m.getAttribute("preload")!=="false")}function p(u){clearTimeout(c);const a=h(u);if(!a)return l=null;const[m,w]=a;l!==m&&(r&&(w.pathname=r(w.pathname)),c=setTimeout(()=>{i.preloadRoute(w,m.getAttribute("preload")!=="false"),l=m},20))}function y(u){if(u.defaultPrevented)return;let a=u.submitter&&u.submitter.hasAttribute("formaction")?u.submitter.getAttribute("formaction"):u.target.getAttribute("action");if(!a)return;if(!a.startsWith("https://action/")){const w=new URL(a,Yn);if(a=i.parsePath(w.pathname+w.search),!a.startsWith(n))return}if(u.target.method.toUpperCase()!=="POST")throw new Error("Only POST forms are supported for Actions");const m=Gi.get(a);if(m){u.preventDefault();const w=new FormData(u.target,u.submitter);m.call({r:i,f:u.target},u.target.enctype==="multipart/form-data"?w:new URLSearchParams(w))}}tt(["click","submit"]),document.addEventListener("click",f),e&&(document.addEventListener("mousemove",p,{passive:!0}),document.addEventListener("focusin",g,{passive:!0}),document.addEventListener("touchstart",g,{passive:!0})),document.addEventListener("submit",y),Kn(()=>{document.removeEventListener("click",f),e&&(document.removeEventListener("mousemove",p),document.removeEventListener("focusin",g),document.removeEventListener("touchstart",g)),document.removeEventListener("submit",y)})}}function Hi(e){const t=()=>{const r=window.location.pathname.replace(/^\/+/,"/")+window.location.search,i=window.history.state&&window.history.state._depth&&Object.keys(window.history.state).length===1?void 0:window.history.state;return{value:r+window.location.hash,state:i}},n=Hn();return Wi({get:t,set({value:r,replace:i,scroll:o,state:s}){i?window.history.replaceState(Ei(s),"",r):window.history.pushState(s,"",r),zi(decodeURIComponent(window.location.hash.slice(1)),o),sn()},init:r=>Vi(window,"popstate",Ci(r,i=>{if(i)return!n.confirm(i);{const o=t();return!n.confirm(o.value,{state:o.state})}})),create:Ji({preload:e.preload,explicitLinks:e.explicitLinks,actionBase:e.actionBase,transformUrl:e.transformUrl}),utils:{go:r=>window.history.go(r),beforeLeave:n}})(e)}var Yi=T('