Use numerical acks

This commit is contained in:
Jack Kingsman committed 2026-01-10 00:51:54 -08:00
1 parent e262bd677a
commit 2798b551f8
17 files changed
+79 -58

No files matched your search

+10 -2
View File
@@ -258,6 +258,11 @@ KeyStore.clear_private_key()
## ACK and Repeat Detection
The `acked` field is an integer count, not a boolean:
- `0` = not acked
- `1` = one ACK/echo received
- `2+` = multiple flood echoes received
### Direct Message ACKs
When sending a direct message, an expected ACK code is tracked:
@@ -267,7 +272,7 @@ from app.event_handlers import track_pending_ack
track_pending_ack(expected_ack="abc123", message_id=42, timeout_ms=30000)
```
When ACK event arrives, the message is marked as acked.
When ACK event arrives, the message's ack count is incremented.
### Channel Message Repeats
@@ -276,7 +281,10 @@ Flood messages echo back through repeaters. Detection uses:
- Text hash
- Timestamp (±5 second window)
When a repeat is detected, the original outgoing message is marked as "acked".
Each repeat increments the ack count. The frontend displays:
- `?` = no acks
- `✓` = 1 echo
- `✓2`, `✓3`, etc. = multiple echoes (real-time updates via WebSocket)
### Auto-Contact Sync to Radio
+2 -2
View File
@@ -180,8 +180,8 @@ async def on_ack(event: "Event") -> None:
message_id, _, _ = _pending_acks.pop(ack_code)
logger.info("ACK received for message %d", message_id)
await MessageRepository.mark_acked(message_id)
broadcast_event("message_acked", {"message_id": message_id})
ack_count = await MessageRepository.increment_ack_count(message_id)
broadcast_event("message_acked", {"message_id": message_id, "ack_count": ack_count})
else:
logger.debug("ACK code %s does not match any pending messages", ack_code)
+1 -1
View File
@@ -76,7 +76,7 @@ class Message(BaseModel):
txt_type: int = 0
signature: str | None = None
outgoing: bool = False
acked: bool = False
acked: int = 0
class RawPacket(BaseModel):
+2 -2
View File
@@ -230,8 +230,8 @@ async def _process_group_text(
# Don't pop - let it expire naturally so subsequent repeats via
# different radio paths are also caught as duplicates
logger.info("Repeat detected for channel message %d", message_id)
await MessageRepository.mark_acked(message_id)
broadcast_event("message_acked", {"message_id": message_id})
ack_count = await MessageRepository.increment_ack_count(message_id)
broadcast_event("message_acked", {"message_id": message_id, "ack_count": ack_count})
is_repeat = True
break
+10 -4
View File
@@ -313,17 +313,23 @@ class MessageRepository:
txt_type=row["txt_type"],
signature=row["signature"],
outgoing=bool(row["outgoing"]),
acked=bool(row["acked"]),
acked=row["acked"],
)
for row in rows
]
@staticmethod
async def mark_acked(message_id: int) -> None:
async def increment_ack_count(message_id: int) -> int:
"""Increment ack count and return the new value."""
await db.conn.execute(
"UPDATE messages SET acked = 1 WHERE id = ?", (message_id,)
"UPDATE messages SET acked = acked + 1 WHERE id = ?", (message_id,)
)
await db.conn.commit()
cursor = await db.conn.execute(
"SELECT acked FROM messages WHERE id = ?", (message_id,)
)
row = await cursor.fetchone()
return row["acked"] if row else 1
@staticmethod
async def find_duplicate(
@@ -398,7 +404,7 @@ class MessageRepository:
txt_type=row["txt_type"],
signature=row["signature"],
outgoing=bool(row["outgoing"]),
acked=bool(row["acked"]),
acked=row["acked"],
)
for row in rows
]
+2 -2
View File
@@ -88,7 +88,7 @@ The `useWebSocket` hook manages real-time connection:
const wsHandlers = useMemo(() => ({
onHealth: (data: HealthStatus) => setHealth(data),
onMessage: (msg: Message) => { /* add to list, track unread */ },
onMessageAcked: (messageId: number) => { /* update acked status */ },
onMessageAcked: (messageId: number, ackCount: number) => { /* update ack count */ },
// ...
}), []);
@@ -199,7 +199,7 @@ interface Message {
conversation_key: string; // PublicKey for PRIV, ChannelKey for CHAN
text: string;
outgoing: boolean;
acked: boolean;
acked: number; // 0=not acked, 1+=ack count (flood echoes)
// ...
}
@@ -34,10 +34,10 @@ var Zv=Object.defineProperty;var Xv=(a,r,o)=>r in a?Zv(a,r,{enumerable:!0,config
`+q+e}var L=!1;function Q(e,i){if(!e||L)return"";L=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(i)if(i=function(){throw Error()},Object.defineProperty(i.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(i,[])}catch(Z){var t=Z}Reflect.construct(e,[],i)}else{try{i.call()}catch(Z){t=Z}e.call(i.prototype)}else{try{throw Error()}catch(Z){t=Z}e()}}catch(Z){if(Z&&t&&typeof Z.stack=="string"){for(var p=Z.stack.split(`
`),b=t.stack.split(`
`),E=p.length-1,P=b.length-1;1<=E&&0<=P&&p[E]!==b[P];)P--;for(;1<=E&&0<=P;E--,P--)if(p[E]!==b[P]){if(E!==1||P!==1)do if(E--,P--,0>P||p[E]!==b[P]){var M=`
`+p[E].replace(" at new "," at ");return e.displayName&&M.includes("<anonymous>")&&(M=M.replace("<anonymous>",e.displayName)),M}while(1<=E&&0<=P);break}}}finally{L=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?I(e):""}function de(e){switch(e.tag){case 5:return I(e.type);case 16:return I("Lazy");case 13:return I("Suspense");case 19:return I("SuspenseList");case 0:case 2:case 15:return e=Q(e.type,!1),e;case 11:return e=Q(e.type.render,!1),e;case 1:return e=Q(e.type,!0),e;default:return""}}function ge(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case R:return"Fragment";case D:return"Portal";case O:return"Profiler";case F:return"StrictMode";case H:return"Suspense";case K:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case T:return(e.displayName||"Context")+".Consumer";case N:return(e._context.displayName||"Context")+".Provider";case W:var i=e.render;return e=e.displayName,e||(e=i.displayName||i.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ae:return i=e.displayName||null,i!==null?i:ge(e.type)||"Memo";case X:i=e._payload,e=e._init;try{return ge(e(i))}catch{}}return null}function be(e){var i=e.type;switch(e.tag){case 24:return"Cache";case 9:return(i.displayName||"Context")+".Consumer";case 10:return(i._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=i.render,e=e.displayName||e.name||"",i.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return i;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return ge(i);case 8:return i===F?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof i=="function")return i.displayName||i.name||null;if(typeof i=="string")return i}return null}function se(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function ce(e){var i=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(i==="checkbox"||i==="radio")}function Ae(e){var i=ce(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,i),t=""+e[i];if(!e.hasOwnProperty(i)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var p=n.get,b=n.set;return Object.defineProperty(e,i,{configurable:!0,get:function(){return p.call(this)},set:function(E){t=""+E,b.call(this,E)}}),Object.defineProperty(e,i,{enumerable:n.enumerable}),{getValue:function(){return t},setValue:function(E){t=""+E},stopTracking:function(){e._valueTracker=null,delete e[i]}}}}function Fe(e){e._valueTracker||(e._valueTracker=Ae(e))}function He(e){if(!e)return!1;var i=e._valueTracker;if(!i)return!0;var n=i.getValue(),t="";return e&&(t=ce(e)?e.checked?"true":"false":e.value),e=t,e!==n?(i.setValue(e),!0):!1}function ai(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Qe(e,i){var n=i.checked;return ee({},i,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Oe(e,i){var n=i.defaultValue==null?"":i.defaultValue,t=i.checked!=null?i.checked:i.defaultChecked;n=se(i.value!=null?i.value:n),e._wrapperState={initialChecked:t,initialValue:n,controlled:i.type==="checkbox"||i.type==="radio"?i.checked!=null:i.value!=null}}function Me(e,i){i=i.checked,i!=null&&w(e,"checked",i,!1)}function Xe(e,i){Me(e,i);var n=se(i.value),t=i.type;if(n!=null)t==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(t==="submit"||t==="reset"){e.removeAttribute("value");return}i.hasOwnProperty("value")?Ge(e,i.type,n):i.hasOwnProperty("defaultValue")&&Ge(e,i.type,se(i.defaultValue)),i.checked==null&&i.defaultChecked!=null&&(e.defaultChecked=!!i.defaultChecked)}function Ve(e,i,n){if(i.hasOwnProperty("value")||i.hasOwnProperty("defaultValue")){var t=i.type;if(!(t!=="submit"&&t!=="reset"||i.value!==void 0&&i.value!==null))return;i=""+e._wrapperState.initialValue,n||i===e.value||(e.value=i),e.defaultValue=i}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Ge(e,i,n){(i!=="number"||ai(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var yi=Array.isArray;function si(e,i,n,t){if(e=e.options,i){i={};for(var p=0;p<n.length;p++)i["$"+n[p]]=!0;for(n=0;n<e.length;n++)p=i.hasOwnProperty("$"+e[n].value),e[n].selected!==p&&(e[n].selected=p),p&&t&&(e[n].defaultSelected=!0)}else{for(n=""+se(n),i=null,p=0;p<e.length;p++){if(e[p].value===n){e[p].selected=!0,t&&(e[p].defaultSelected=!0);return}i!==null||e[p].disabled||(i=e[p])}i!==null&&(i.selected=!0)}}function Le(e,i){if(i.dangerouslySetInnerHTML! Line truncated
`).replace(uv,"")}function ls(e,i,n){if(i=op(i),op(e)!==i&&n)throw Error(o(425))}function cs(){}var Hl=null,Vl=null;function Ul(e,i){return e==="textarea"||e==="noscript"||typeof i.children=="string"||typeof i.children=="number"||typeof i.dangerouslySetInnerHTML=="object"&&i.dangerouslySetInnerHTML!==null&&i.dangerouslySetInnerHTML.__html!=null}var Wl=typeof setTimeout=="function"?setTimeout:void 0,dv=typeof clearTimeout=="function"?clearTimeout:void 0,rp=typeof Promise=="function"?Promise:void 0,pv=typeof queueMicrotask=="function"?queueMicrotask:typeof rp<"u"?function(e){return rp.resolve(null).then(e).catch(mv)}:Wl;function mv(e){setTimeout(function(){throw e})}function $l(e,i){var n=i,t=0;do{var p=n.nextSibling;if(e.removeChild(n),p&&p.nodeType===8)if(n=p.data,n==="/$"){if(t===0){e.removeChild(p),Uo(i);return}t--}else n!=="$"&&n!=="$?"&&n!=="$!"||t++;n=p}while(n);Uo(i)}function un(e){for(;e!=null;e=e.nextSibling){var i=e.nodeType;if(i===1||i===3)break;if(i===8){if(i=e.data,i==="$"||i==="$!"||i==="$?")break;if(i==="/$")return null}}return e}function sp(e){e=e.previousSibling;for(var i=0;e;){if(e.nodeType===8){var n=e.data;if(n==="$"||n==="$!"||n==="$?"){if(i===0)return e;i--}else n==="/$"&&i++}e=e.previousSibling}return null}var so=Math.random().toString(36).slice(2),Fa="__reactFiber$"+so,ir="__reactProps$"+so,Va="__reactContainer$"+so,Ql="__reactEvents$"+so,hv="__reactListeners$"+so,gv="__reactHandles$"+so;function Sn(e){var i=e[Fa];if(i)return i;for(var n=e.parentNode;n;){if(i=n[Va]||n[Fa]){if(n=i.alternate,i.child!==null||n!==null&&n.child!==null)for(e=sp(e);e!==null;){if(n=e[Fa])return n;e=sp(e)}return i}e=n,n=e.parentNode}return null}function ar(e){return e=e[Fa]||e[Va],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function to(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(o(33))}function us(e){return e[ir]||null}var Gl=[],lo=-1;function dn(e){return{current:e}}function li(e){0>lo||(e.current=Gl[lo],Gl[lo]=null,lo--)}function ri(e,i){lo++,Gl[lo]=e.current,e.current=i}var pn={},Li=dn(pn),Zi=dn(!1),Bn=pn;function co(e,i){var n=e.type.contextTypes;if(!n)return pn;var t=e.stateNode;if(t&&t.__reactInternalMemoizedUnmaskedChildContext===i)return t.__reactInternalMemoizedMaskedChildContext;var p={},b;for(b in n)p[b]=i[b];return t&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=i,e.__reactInternalMemoizedMaskedChildContext=p),p}function Xi(e){return e=e.childContextTypes,e!=null}function ds(){li(Zi),li(Li)}function tp(e,i,n){if(Li.current!==pn)throw Error(o(168));ri(Li,i),ri(Zi,n)}function lp(e,i,n){var t=e.stateNode;if(i=i.childContextTypes,typeof t.getChildContext!="function")return n;t=t.getChildContext();for(var p in t)if(!(p in i))throw Error(o(108,be(e)||"Unknown",p));return ee({},n,t)}function ps(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||pn,Bn=Li.current,ri(Li,e),ri(Zi,Zi.current),!0}function cp(e,i,n){var t=e.stateNode;if(!t)throw Error(o(169));n?(e=lp(e,i,Bn),t.__reactInternalMemoizedMergedChildContext=e,li(Zi),li(Li),ri(Li,e)):li(Zi),ri(Zi,n)}var Ua=null,ms=!1,Kl=!1;function up(e){Ua===null?Ua=[e]:Ua.push(e)}function yv(e){ms=!0,up(e)}function mn(){if(!Kl&&Ua!==null){Kl=!0;var e=0,i=ii;try{var n=Ua;for(ii=1;e<n.length;e++){var t=n[e];do t=t(!0);while(t!==null)}Ua=null,ms=!1}catch(p){throw Ua!==null&&(Ua=Ua.slice(e+1)),pd(bl,mn),p}finally{ii=i,Kl=!1}}return null}var uo=[],po=0,hs=null,gs=0,pa=[],ma=0,_n=null,Wa=1,$a="";function Dn(e,i){uo[po++]=gs,uo[po++]=hs,hs=e,gs=i}function dp(e,i,n){pa[ma++]=Wa,pa[ma++]=$a,pa[ma++]=_n,_n=e;var t=Wa;e=$a;var p=32-wa(t)-1;t&=~(1<<p),n+=1;var b=32-wa(i)+p;if(30<b){var E=p-p%5;b=(t&(1<<E)-1).toString(32),t>>=E,p-=E,Wa=1<<32-wa(i)+p|n<<p|t,$a=b+e}else Wa=1<<b|n<<p|t,$a=e}function Yl(e){e.return!==null&&(Dn(e,1),dp(e,1,0))}function Zl(e){for(;e===hs;)hs=uo[--po],uo[po]=null,gs=uo[--po],uo[po]=null;for(;e===_n;)_n=pa[--ma],pa[ma]=null,$a=pa[--ma],pa[ma]=null,Wa=pa[--ma],pa[ma]=null}var sa=null,ta=null,ci=!1,za=null;function pp(e,i){var n=ba(5,null,null,0);n.elementType="DELETED",n.stateNode=i,n.return=e,i=e.deletions,i===null?(e.deletions=[n],e.flags|=16):i.push(n)}function mp(e,i){switch(e.tag){case 5:var n=e.type;return i=i.nodeType!==1||n.toLowerCase()!==i.nodeName.toLowerCase()?null:i,i!==null?(e.stateNode=i,sa=e,ta=un(i.firstChild),!0):!1;case 6:return i=e.pendingProps===""||i.nodeType!==3?null:i,i!==null?(e.stateNode=i,sa=e,ta=null,!0):!1;case 13:return i=i.nodeType!==8?null:i,i!==null?(n=_n!==null?{id:Wa,overflow:$a}:null,e.memoizedState={dehydrated:i,treeContext:n,retryLane:1073741824},n=ba(18,null,null,0),n.stateNode=i,n.return=e,e.child=n,sa=e,ta=null,!0):!1;default:return!1}}function Xl(e){return(e.mode&1)!==0&&(e.flags&128)===0}function Jl(e){if(ci){var i=ta;if(i){var n=i;if(!mp(e,i)){if(Xl(e))throw Error(o(418));i=un(n.nextSibling);var t=sa;i&&mp(e,i)?pp(t,n):(e.flags=e.flags&-4097|2,ci=!1,sa=e)}}else{if(Xl(e))throw Error(o(418));e.flags=e.flags&-4097|2,ci=!1,sa=e}}}function hp(e){for(e=e Line truncated
`+p[E].replace(" at new "," at ");return e.displayName&&M.includes("<anonymous>")&&(M=M.replace("<anonymous>",e.displayName)),M}while(1<=E&&0<=P);break}}}finally{L=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?I(e):""}function de(e){switch(e.tag){case 5:return I(e.type);case 16:return I("Lazy");case 13:return I("Suspense");case 19:return I("SuspenseList");case 0:case 2:case 15:return e=Q(e.type,!1),e;case 11:return e=Q(e.type.render,!1),e;case 1:return e=Q(e.type,!0),e;default:return""}}function ge(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case R:return"Fragment";case D:return"Portal";case O:return"Profiler";case F:return"StrictMode";case H:return"Suspense";case K:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case T:return(e.displayName||"Context")+".Consumer";case N:return(e._context.displayName||"Context")+".Provider";case W:var i=e.render;return e=e.displayName,e||(e=i.displayName||i.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ae:return i=e.displayName||null,i!==null?i:ge(e.type)||"Memo";case X:i=e._payload,e=e._init;try{return ge(e(i))}catch{}}return null}function be(e){var i=e.type;switch(e.tag){case 24:return"Cache";case 9:return(i.displayName||"Context")+".Consumer";case 10:return(i._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=i.render,e=e.displayName||e.name||"",i.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return i;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return ge(i);case 8:return i===F?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof i=="function")return i.displayName||i.name||null;if(typeof i=="string")return i}return null}function se(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function ce(e){var i=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(i==="checkbox"||i==="radio")}function Ae(e){var i=ce(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,i),t=""+e[i];if(!e.hasOwnProperty(i)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var p=n.get,b=n.set;return Object.defineProperty(e,i,{configurable:!0,get:function(){return p.call(this)},set:function(E){t=""+E,b.call(this,E)}}),Object.defineProperty(e,i,{enumerable:n.enumerable}),{getValue:function(){return t},setValue:function(E){t=""+E},stopTracking:function(){e._valueTracker=null,delete e[i]}}}}function Fe(e){e._valueTracker||(e._valueTracker=Ae(e))}function He(e){if(!e)return!1;var i=e._valueTracker;if(!i)return!0;var n=i.getValue(),t="";return e&&(t=ce(e)?e.checked?"true":"false":e.value),e=t,e!==n?(i.setValue(e),!0):!1}function ai(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Qe(e,i){var n=i.checked;return ee({},i,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Oe(e,i){var n=i.defaultValue==null?"":i.defaultValue,t=i.checked!=null?i.checked:i.defaultChecked;n=se(i.value!=null?i.value:n),e._wrapperState={initialChecked:t,initialValue:n,controlled:i.type==="checkbox"||i.type==="radio"?i.checked!=null:i.value!=null}}function Me(e,i){i=i.checked,i!=null&&w(e,"checked",i,!1)}function Xe(e,i){Me(e,i);var n=se(i.value),t=i.type;if(n!=null)t==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(t==="submit"||t==="reset"){e.removeAttribute("value");return}i.hasOwnProperty("value")?Ge(e,i.type,n):i.hasOwnProperty("defaultValue")&&Ge(e,i.type,se(i.defaultValue)),i.checked==null&&i.defaultChecked!=null&&(e.defaultChecked=!!i.defaultChecked)}function Ve(e,i,n){if(i.hasOwnProperty("value")||i.hasOwnProperty("defaultValue")){var t=i.type;if(!(t!=="submit"&&t!=="reset"||i.value!==void 0&&i.value!==null))return;i=""+e._wrapperState.initialValue,n||i===e.value||(e.value=i),e.defaultValue=i}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Ge(e,i,n){(i!=="number"||ai(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var yi=Array.isArray;function si(e,i,n,t){if(e=e.options,i){i={};for(var p=0;p<n.length;p++)i["$"+n[p]]=!0;for(n=0;n<e.length;n++)p=i.hasOwnProperty("$"+e[n].value),e[n].selected!==p&&(e[n].selected=p),p&&t&&(e[n].defaultSelected=!0)}else{for(n=""+se(n),i=null,p=0;p<e.length;p++){if(e[p].value===n){e[p].selected=!0,t&&(e[p].defaultSelected=!0);return}i!==null||e[p].disabled||(i=e[p])}i!==null&&(i.selected=!0)}}function Le(e,i){if(i.dangerouslySetInnerHTML! Line truncated
`).replace(uv,"")}function ls(e,i,n){if(i=op(i),op(e)!==i&&n)throw Error(o(425))}function cs(){}var Hl=null,Vl=null;function Ul(e,i){return e==="textarea"||e==="noscript"||typeof i.children=="string"||typeof i.children=="number"||typeof i.dangerouslySetInnerHTML=="object"&&i.dangerouslySetInnerHTML!==null&&i.dangerouslySetInnerHTML.__html!=null}var Wl=typeof setTimeout=="function"?setTimeout:void 0,dv=typeof clearTimeout=="function"?clearTimeout:void 0,rp=typeof Promise=="function"?Promise:void 0,pv=typeof queueMicrotask=="function"?queueMicrotask:typeof rp<"u"?function(e){return rp.resolve(null).then(e).catch(mv)}:Wl;function mv(e){setTimeout(function(){throw e})}function $l(e,i){var n=i,t=0;do{var p=n.nextSibling;if(e.removeChild(n),p&&p.nodeType===8)if(n=p.data,n==="/$"){if(t===0){e.removeChild(p),Uo(i);return}t--}else n!=="$"&&n!=="$?"&&n!=="$!"||t++;n=p}while(n);Uo(i)}function un(e){for(;e!=null;e=e.nextSibling){var i=e.nodeType;if(i===1||i===3)break;if(i===8){if(i=e.data,i==="$"||i==="$!"||i==="$?")break;if(i==="/$")return null}}return e}function sp(e){e=e.previousSibling;for(var i=0;e;){if(e.nodeType===8){var n=e.data;if(n==="$"||n==="$!"||n==="$?"){if(i===0)return e;i--}else n==="/$"&&i++}e=e.previousSibling}return null}var so=Math.random().toString(36).slice(2),Fa="__reactFiber$"+so,ir="__reactProps$"+so,Va="__reactContainer$"+so,Ql="__reactEvents$"+so,hv="__reactListeners$"+so,gv="__reactHandles$"+so;function Sn(e){var i=e[Fa];if(i)return i;for(var n=e.parentNode;n;){if(i=n[Va]||n[Fa]){if(n=i.alternate,i.child!==null||n!==null&&n.child!==null)for(e=sp(e);e!==null;){if(n=e[Fa])return n;e=sp(e)}return i}e=n,n=e.parentNode}return null}function ar(e){return e=e[Fa]||e[Va],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function to(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(o(33))}function us(e){return e[ir]||null}var Gl=[],lo=-1;function dn(e){return{current:e}}function li(e){0>lo||(e.current=Gl[lo],Gl[lo]=null,lo--)}function ri(e,i){lo++,Gl[lo]=e.current,e.current=i}var pn={},Li=dn(pn),Zi=dn(!1),Bn=pn;function co(e,i){var n=e.type.contextTypes;if(!n)return pn;var t=e.stateNode;if(t&&t.__reactInternalMemoizedUnmaskedChildContext===i)return t.__reactInternalMemoizedMaskedChildContext;var p={},b;for(b in n)p[b]=i[b];return t&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=i,e.__reactInternalMemoizedMaskedChildContext=p),p}function Xi(e){return e=e.childContextTypes,e!=null}function ds(){li(Zi),li(Li)}function tp(e,i,n){if(Li.current!==pn)throw Error(o(168));ri(Li,i),ri(Zi,n)}function lp(e,i,n){var t=e.stateNode;if(i=i.childContextTypes,typeof t.getChildContext!="function")return n;t=t.getChildContext();for(var p in t)if(!(p in i))throw Error(o(108,be(e)||"Unknown",p));return ee({},n,t)}function ps(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||pn,Bn=Li.current,ri(Li,e),ri(Zi,Zi.current),!0}function cp(e,i,n){var t=e.stateNode;if(!t)throw Error(o(169));n?(e=lp(e,i,Bn),t.__reactInternalMemoizedMergedChildContext=e,li(Zi),li(Li),ri(Li,e)):li(Zi),ri(Zi,n)}var Ua=null,ms=!1,Kl=!1;function up(e){Ua===null?Ua=[e]:Ua.push(e)}function yv(e){ms=!0,up(e)}function mn(){if(!Kl&&Ua!==null){Kl=!0;var e=0,i=ii;try{var n=Ua;for(ii=1;e<n.length;e++){var t=n[e];do t=t(!0);while(t!==null)}Ua=null,ms=!1}catch(p){throw Ua!==null&&(Ua=Ua.slice(e+1)),pd(bl,mn),p}finally{ii=i,Kl=!1}}return null}var uo=[],po=0,hs=null,gs=0,pa=[],ma=0,_n=null,Wa=1,$a="";function Dn(e,i){uo[po++]=gs,uo[po++]=hs,hs=e,gs=i}function dp(e,i,n){pa[ma++]=Wa,pa[ma++]=$a,pa[ma++]=_n,_n=e;var t=Wa;e=$a;var p=32-wa(t)-1;t&=~(1<<p),n+=1;var b=32-wa(i)+p;if(30<b){var E=p-p%5;b=(t&(1<<E)-1).toString(32),t>>=E,p-=E,Wa=1<<32-wa(i)+p|n<<p|t,$a=b+e}else Wa=1<<b|n<<p|t,$a=e}function Yl(e){e.return!==null&&(Dn(e,1),dp(e,1,0))}function Zl(e){for(;e===hs;)hs=uo[--po],uo[po]=null,gs=uo[--po],uo[po]=null;for(;e===_n;)_n=pa[--ma],pa[ma]=null,$a=pa[--ma],pa[ma]=null,Wa=pa[--ma],pa[ma]=null}var sa=null,ta=null,ci=!1,za=null;function pp(e,i){var n=ba(5,null,null,0);n.elementType="DELETED",n.stateNode=i,n.return=e,i=e.deletions,i===null?(e.deletions=[n],e.flags|=16):i.push(n)}function mp(e,i){switch(e.tag){case 5:var n=e.type;return i=i.nodeType!==1||n.toLowerCase()!==i.nodeName.toLowerCase()?null:i,i!==null?(e.stateNode=i,sa=e,ta=un(i.firstChild),!0):!1;case 6:return i=e.pendingProps===""||i.nodeType!==3?null:i,i!==null?(e.stateNode=i,sa=e,ta=null,!0):!1;case 13:return i=i.nodeType!==8?null:i,i!==null?(n=_n!==null?{id:Wa,overflow:$a}:null,e.memoizedState={dehydrated:i,treeContext:n,retryLane:1073741824},n=ba(18,null,null,0),n.stateNode=i,n.return=e,e.child=n,sa=e,ta=null,!0):!1;default:return!1}}function Xl(e){return(e.mode&1)!==0&&(e.flags&128)===0}function Jl(e){if(ci){var i=ta;if(i){var n=i;if(!mp(e,i)){if(Xl(e))throw Error(o(418));i=un(n.nextSibling);var t=sa;i&&mp(e,i)?pp(t,n):(e.flags=e.flags&-4097|2,ci=!1,sa=e)}}else{if(Xl(e))throw Error(o(418));e.flags=e.flags&-4097|2,ci=!1,sa=e}}}function hp(e){for(e=e Line truncated
Error generating stack: `+b.message+`
`+b.stack}return{value:e,source:i,stack:p,digest:null}}function wc(e,i,n){return{value:e,source:null,stack:n??null,digest:i??null}}function xc(e,i){try{console.error(i.value)}catch(n){setTimeout(function(){throw n})}}var jv=typeof WeakMap=="function"?WeakMap:Map;function Gp(e,i,n){n=Ga(-1,n),n.tag=3,n.payload={element:null};var t=i.value;return n.callback=function(){Ts||(Ts=!0,Nc=t),xc(e,i)},n}function Kp(e,i,n){n=Ga(-1,n),n.tag=3;var t=e.type.getDerivedStateFromError;if(typeof t=="function"){var p=i.value;n.payload=function(){return t(p)},n.callback=function(){xc(e,i)}}var b=e.stateNode;return b!==null&&typeof b.componentDidCatch=="function"&&(n.callback=function(){xc(e,i),typeof t!="function"&&(bn===null?bn=new Set([this]):bn.add(this));var E=i.stack;this.componentDidCatch(i.value,{componentStack:E!==null?E:""})}),n}function Yp(e,i,n){var t=e.pingCache;if(t===null){t=e.pingCache=new jv;var p=new Set;t.set(i,p)}else p=t.get(i),p===void 0&&(p=new Set,t.set(i,p));p.has(n)||(p.add(n),e=Mv.bind(null,e,i,n),i.then(e,e))}function Zp(e){do{var i;if((i=e.tag===13)&&(i=e.memoizedState,i=i!==null?i.dehydrated!==null:!0),i)return e;e=e.return}while(e!==null);return null}function Xp(e,i,n,t,p){return(e.mode&1)===0?(e===i?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(i=Ga(-1,1),i.tag=2,gn(n,i,1))),n.lanes|=1),e):(e.flags|=65536,e.lanes=p,e)}var Av=_.ReactCurrentOwner,Ji=!1;function $i(e,i,n,t){i.child=e===null?fp(i,null,n,t):ho(i,e.child,n,t)}function Jp(e,i,n,t,p){n=n.render;var b=i.ref;return yo(i,p),t=mc(e,i,n,t,b,p),n=hc(),e!==null&&!Ji?(i.updateQueue=e.updateQueue,i.flags&=-2053,e.lanes&=~p,Ka(e,i,p)):(ci&&n&&Yl(i),i.flags|=1,$i(e,i,t,p),i.child)}function em(e,i,n,t,p){if(e===null){var b=n.type;return typeof b=="function"&&!Uc(b)&&b.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(i.tag=15,i.type=b,im(e,i,b,t,p)):(e=Ls(n.type,null,t,i,i.mode,p),e.ref=i.ref,e.return=i,i.child=e)}if(b=e.child,(e.lanes&p)===0){var E=b.memoizedProps;if(n=n.compare,n=n!==null?n:Yo,n(E,t)&&e.ref===i.ref)return Ka(e,i,p)}return i.flags|=1,e=wn(b,t),e.ref=i.ref,e.return=i,i.child=e}function im(e,i,n,t,p){if(e!==null){var b=e.memoizedProps;if(Yo(b,t)&&e.ref===i.ref)if(Ji=!1,i.pendingProps=t=b,(e.lanes&p)!==0)(e.flags&131072)!==0&&(Ji=!0);else return i.lanes=e.lanes,Ka(e,i,p)}return zc(e,i,n,t,p)}function am(e,i,n){var t=i.pendingProps,p=t.children,b=e!==null?e.memoizedState:null;if(t.mode==="hidden")if((i.mode&1)===0)i.memoizedState={baseLanes:0,cachePool:null,transitions:null},ri(ko,la),la|=n;else{if((n&1073741824)===0)return e=b!==null?b.baseLanes|n:n,i.lanes=i.childLanes=1073741824,i.memoizedState={baseLanes:e,cachePool:null,transitions:null},i.updateQueue=null,ri(ko,la),la|=e,null;i.memoizedState={baseLanes:0,cachePool:null,transitions:null},t=b!==null?b.baseLanes:n,ri(ko,la),la|=t}else b!==null?(t=b.baseLanes|n,i.memoizedState=null):t=n,ri(ko,la),la|=t;return $i(e,i,p,n),i.child}function nm(e,i){var n=i.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(i.flags|=512,i.flags|=2097152)}function zc(e,i,n,t,p){var b=Xi(n)?Bn:Li.current;return b=co(i,b),yo(i,p),n=mc(e,i,n,t,b,p),t=hc(),e!==null&&!Ji?(i.updateQueue=e.updateQueue,i.flags&=-2053,e.lanes&=~p,Ka(e,i,p)):(ci&&t&&Yl(i),i.flags|=1,$i(e,i,n,p),i.child)}function om(e,i,n,t,p){if(Xi(n)){var b=!0;ps(i)}else b=!1;if(yo(i,p),i.stateNode===null)Bs(e,i),$p(i,n,t),kc(i,n,t,p),t=!0;else if(e===null){var E=i.stateNode,P=i.memoizedProps;E.props=P;var M=E.context,Z=n.contextType;typeof Z=="object"&&Z!==null?Z=ha(Z):(Z=Xi(n)?Bn:Li.current,Z=co(i,Z));var le=n.getDerivedStateFromProps,ue=typeof le=="function"||typeof E.getSnapshotBeforeUpdate=="function";ue||typeof E.UNSAFE_componentWillReceiveProps!="function"&&typeof E.componentWillReceiveProps!="function"||(P!==t||M!==Z)&&Qp(i,E,t,Z),hn=!1;var te=i.memoizedState;E.state=te,ws(i,t,E,p),M=i.memoizedState,P!==t||te!==M||Zi.current||hn?(typeof le=="function"&&(vc(i,n,le,t),M=i.memoizedState),(P=hn||Wp(i,n,P,t,te,M,Z))?(ue||typeof E.UNSAFE_componentWillMount!="function"&&typeof E.componentWillMount!="function"||(typeof E.componentWillMount=="function"&&E.componentWillMount(),typeof E.UNSAFE_componentWillMount=="function"&&E.UNSAFE_componentWillMount()),typeof E.componentDidMount=="function"&&(i.flags|=4194308)):(typeof E.componentDidMount=="function"&&(i.flags|=4194308),i.memoizedProps=t,i.memoizedState=M),E.props=t,E.state=M,E.context=Z,t=P):(typeof E.componentDidMount=="function"&&(i.flags|=4194308),t=!1)}else{E=i.stateNode,kp(e,i),P=i.memoizedProps,Z=i.type===i.elementType?P:qa(i.type,P),E.props=Z,ue=i.pendingProps,te=E.context,M=n.contextType,typeof M=="object"&&M!==null?M=ha(M):(M=Xi(n)?Bn:Li.current,M=co(i,M));var fe=n.getDerivedStateFromProps;(le=typeof fe=="function"||typeof E.getSnapshotBeforeUpdate=="function")||typeof E.UNSAFE_componentWillReceiveProps!="function"&&typeof E.componentWillReceiveProps!="function"||(P!==ue||te!==M)&&Qp(i,E,t,M),hn=!1,te=i.memoizedState,E Line truncated
`+b.stack}return{value:e,source:i,stack:p,digest:null}}function wc(e,i,n){return{value:e,source:null,stack:n??null,digest:i??null}}function xc(e,i){try{console.error(i.value)}catch(n){setTimeout(function(){throw n})}}var jv=typeof WeakMap=="function"?WeakMap:Map;function Gp(e,i,n){n=Ga(-1,n),n.tag=3,n.payload={element:null};var t=i.value;return n.callback=function(){Ts||(Ts=!0,Nc=t),xc(e,i)},n}function Kp(e,i,n){n=Ga(-1,n),n.tag=3;var t=e.type.getDerivedStateFromError;if(typeof t=="function"){var p=i.value;n.payload=function(){return t(p)},n.callback=function(){xc(e,i)}}var b=e.stateNode;return b!==null&&typeof b.componentDidCatch=="function"&&(n.callback=function(){xc(e,i),typeof t!="function"&&(bn===null?bn=new Set([this]):bn.add(this));var E=i.stack;this.componentDidCatch(i.value,{componentStack:E!==null?E:""})}),n}function Yp(e,i,n){var t=e.pingCache;if(t===null){t=e.pingCache=new jv;var p=new Set;t.set(i,p)}else p=t.get(i),p===void 0&&(p=new Set,t.set(i,p));p.has(n)||(p.add(n),e=Mv.bind(null,e,i,n),i.then(e,e))}function Zp(e){do{var i;if((i=e.tag===13)&&(i=e.memoizedState,i=i!==null?i.dehydrated!==null:!0),i)return e;e=e.return}while(e!==null);return null}function Xp(e,i,n,t,p){return(e.mode&1)===0?(e===i?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(i=Ga(-1,1),i.tag=2,gn(n,i,1))),n.lanes|=1),e):(e.flags|=65536,e.lanes=p,e)}var Av=_.ReactCurrentOwner,Ji=!1;function $i(e,i,n,t){i.child=e===null?fp(i,null,n,t):ho(i,e.child,n,t)}function Jp(e,i,n,t,p){n=n.render;var b=i.ref;return yo(i,p),t=mc(e,i,n,t,b,p),n=hc(),e!==null&&!Ji?(i.updateQueue=e.updateQueue,i.flags&=-2053,e.lanes&=~p,Ka(e,i,p)):(ci&&n&&Yl(i),i.flags|=1,$i(e,i,t,p),i.child)}function em(e,i,n,t,p){if(e===null){var b=n.type;return typeof b=="function"&&!Uc(b)&&b.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(i.tag=15,i.type=b,im(e,i,b,t,p)):(e=Ls(n.type,null,t,i,i.mode,p),e.ref=i.ref,e.return=i,i.child=e)}if(b=e.child,(e.lanes&p)===0){var E=b.memoizedProps;if(n=n.compare,n=n!==null?n:Yo,n(E,t)&&e.ref===i.ref)return Ka(e,i,p)}return i.flags|=1,e=wn(b,t),e.ref=i.ref,e.return=i,i.child=e}function im(e,i,n,t,p){if(e!==null){var b=e.memoizedProps;if(Yo(b,t)&&e.ref===i.ref)if(Ji=!1,i.pendingProps=t=b,(e.lanes&p)!==0)(e.flags&131072)!==0&&(Ji=!0);else return i.lanes=e.lanes,Ka(e,i,p)}return zc(e,i,n,t,p)}function am(e,i,n){var t=i.pendingProps,p=t.children,b=e!==null?e.memoizedState:null;if(t.mode==="hidden")if((i.mode&1)===0)i.memoizedState={baseLanes:0,cachePool:null,transitions:null},ri(ko,la),la|=n;else{if((n&1073741824)===0)return e=b!==null?b.baseLanes|n:n,i.lanes=i.childLanes=1073741824,i.memoizedState={baseLanes:e,cachePool:null,transitions:null},i.updateQueue=null,ri(ko,la),la|=e,null;i.memoizedState={baseLanes:0,cachePool:null,transitions:null},t=b!==null?b.baseLanes:n,ri(ko,la),la|=t}else b!==null?(t=b.baseLanes|n,i.memoizedState=null):t=n,ri(ko,la),la|=t;return $i(e,i,p,n),i.child}function nm(e,i){var n=i.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(i.flags|=512,i.flags|=2097152)}function zc(e,i,n,t,p){var b=Xi(n)?Bn:Li.current;return b=co(i,b),yo(i,p),n=mc(e,i,n,t,b,p),t=hc(),e!==null&&!Ji?(i.updateQueue=e.updateQueue,i.flags&=-2053,e.lanes&=~p,Ka(e,i,p)):(ci&&t&&Yl(i),i.flags|=1,$i(e,i,n,p),i.child)}function om(e,i,n,t,p){if(Xi(n)){var b=!0;ps(i)}else b=!1;if(yo(i,p),i.stateNode===null)Bs(e,i),$p(i,n,t),kc(i,n,t,p),t=!0;else if(e===null){var E=i.stateNode,P=i.memoizedProps;E.props=P;var M=E.context,Z=n.contextType;typeof Z=="object"&&Z!==null?Z=ha(Z):(Z=Xi(n)?Bn:Li.current,Z=co(i,Z));var le=n.getDerivedStateFromProps,ue=typeof le=="function"||typeof E.getSnapshotBeforeUpdate=="function";ue||typeof E.UNSAFE_componentWillReceiveProps!="function"&&typeof E.componentWillReceiveProps!="function"||(P!==t||M!==Z)&&Qp(i,E,t,Z),hn=!1;var te=i.memoizedState;E.state=te,ws(i,t,E,p),M=i.memoizedState,P!==t||te!==M||Zi.current||hn?(typeof le=="function"&&(vc(i,n,le,t),M=i.memoizedState),(P=hn||Wp(i,n,P,t,te,M,Z))?(ue||typeof E.UNSAFE_componentWillMount!="function"&&typeof E.componentWillMount!="function"||(typeof E.componentWillMount=="function"&&E.componentWillMount(),typeof E.UNSAFE_componentWillMount=="function"&&E.UNSAFE_componentWillMount()),typeof E.componentDidMount=="function"&&(i.flags|=4194308)):(typeof E.componentDidMount=="function"&&(i.flags|=4194308),i.memoizedProps=t,i.memoizedState=M),E.props=t,E.state=M,E.context=Z,t=P):(typeof E.componentDidMount=="function"&&(i.flags|=4194308),t=!1)}else{E=i.stateNode,kp(e,i),P=i.memoizedProps,Z=i.type===i.elementType?P:qa(i.type,P),E.props=Z,ue=i.pendingProps,te=E.context,M=n.contextType,typeof M=="object"&&M!==null?M=ha(M):(M=Xi(n)?Bn:Li.current,M=co(i,M));var ve=n.getDerivedStateFromProps;(le=typeof ve=="function"||typeof E.getSnapshotBeforeUpdate=="function")||typeof E.UNSAFE_componentWillReceiveProps!="function"&&typeof E.componentWillReceiveProps!="function"||(P!==ue||te!==M)&&Qp(i,E,t,M),hn=!1,te=i.memoizedState,E Line truncated
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
@@ -72,8 +72,8 @@ Error generating stack: `+b.message+`
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const vk=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],$g=Nu("x",vk);var Qg=Ug();const Gg=Fo(Qg);function kk(a){if(typeof document>"u")return;let r=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css",r.appendChild(o),o.styleSheet?o.styleSheet.cssText=a:o.appendChild(document.createTextNode(a))}const wk=a=>{switch(a){case"success":return qk;case"info":return Ak;case"warning":return jk;case"error":return Ck;default:return null}},xk=Array(12).fill(0),zk=({visible:a,className:r})=>he.createElement("div",{className:["sonner-loading-wrapper",r].filter(Boolean).join(" "),"data-visible":a},he.createElement("div",{className:"sonner-spinner"},xk.map((o,s)=>he.createElement("div",{className:"sonner-loading-bar",key:`spinner-bar-${s}`})))),qk=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},he.createElement("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",clipRule:"evenodd"})),jk=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",height:"20",width:"20"},he.createElement("path",{fillRule:"evenodd",d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z",clipRule:"evenodd"})),Ak=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},he.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z",clipRule:"evenodd"})),Ck=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},he.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",clipRule:"evenodd"})),Ek=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"},he.createElement("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),he.createElement("line",{x1:"6",y1:"6",x2:"18",y2:"18"})),Sk=()=>{const[a,r]=he.useState(document.hidden);return he.useEffect(()=>{const o=()=>{r(document.hidden)};return document.addEventListener("visibilitychange",o),()=>window.removeEventListener("visibilitychange",o)},[]),a};let ku=1;class Bk{constructor(){this.subscribe=r=>(this.subscribers.push(r),()=>{const o=this.subscribers.indexOf(r);this.subscribers.splice(o,1)}),this.publish=r=>{this.subscribers.forEach(o=>o(r))},this.addToast=r=>{this.publish(r),this.toasts=[...this.toasts,r]},this.create=r=>{var o;const{message:s,...u}=r,l=typeof(r==null?void 0:r.id)=="number"||((o=r.id)==null?void 0:o.length)>0?r.id:ku++,m=this.toasts.find(h=>h.id===l),c=r.dismissible===void 0?!0:r.dismissible;return this.dismissedToasts.has(l)&&this.dismissedToasts.delete(l),m?this.toasts=this.toasts.map(h=>h.id===l?(this.publish({...h,...r,id:l,title:s}),{...h,...r,id:l,dismissible:c,title:s}):h):this.addToast({title:s,...u,dismissible:c,id:l}),l},this.dismiss=r=>(r?(this.dismissedToasts.add(r),requestAnimationFrame(()=>this.subscribers.forEach(o=>o({id:r,dismiss:!0})))):this.toasts.forEach(o=>{this.subscribers.forEach(s=>s({id:o.id,dismiss:!0}))}),r),this.message=(r,o)=>this.create({...o,message:r}),this.error=(r,o)=>this.create({...o,message:r,type:"error"}),this.success=(r,o)=>this.create({...o,type:"success",message:r}),this.info=(r,o)=>this.create({...o,type:"info",message:r}),this.warning=(r,o)=>this.create({...o,type:"warning",message:r}),this.loading=(r,o)=>this.create({...o,type:"loading",message:r}),this.promise=(r,o)=>{if(!o)return;let s;o.loading!==void 0&&(s=this.create({...o,promise:r,type:"loading",message:o.loading,description:typeof o.description!="function"?o.description:void 0}));const u=Promise.resolve(r instanceof Function?r():r);let l=s!==void 0,m;const c=u.then(async d=>{if(m=["resolve",d],he.isValidElement(d))l=!1,this.create({id:s,type:"default",message:d});else if(Dk(d)&&!d.ok){l=!1;const g=typeof o.error=="function"?await o.error(`HTTP error! status: ${d.status}`):o.error,f=typeof o.description=="function"?await o.description(`HTTP error! status: ${d.status}`):o.description,k=typeof g=="object"&&!he.isValidElement(g)?g:{message:g};this.create({id:s,type:"error",description:f,...k})}else if(d instanceof Error){l=!1;const g=typeof o.error=="function"?await o.error(d):o.error,Line truncated
`).map((q,I,L)=>B.jsxs("span",{children:[nx(q,c),I<L.length-1&&B.jsx("br",{})]},I)),!X&&B.jsx("span",{className:"text-[10px] text-muted-foreground/50 ml-2",children:th(x.sender_timestamp||x.received_at)}),x.outgoing&&(x.acked?" ✓":" ?")]})]})]},x.id)})]}),g&&B.jsx("button",{onClick:j,className:"absolute bottom-4 right-4 w-10 h-10 rounded-full bg-muted hover:bg-accent border border-border flex items-center justify-center shadow-lg transition-opacity",title:"Scroll to bottom",children:B.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"text-muted-foreground",children:B.jsx("polyline",{points:"6 9 12 15 18 9"})})})]})}const rx=S.forwardRef(function({onSend:r,disabled:o,placeholder:s,isRepeaterMode:u},l){const[m,c]=S.useState(""),[h,d]=S.useState(!1),y=S.useRef(null);S.useImperativeHandle(l,()=>({appendText:k=>{var j;c(v=>v+k),(j=y.current)==null||j.focus()}}));const g=S.useCallback(async k=>{var v;k.preventDefault();const j=m.trim();if(u){if(h||o)return;const A=j==="."?"":j;d(!0);try{await r(A),c("")}catch(C){console.error("Failed to request telemetry:",C)}finally{d(!1)}}else{if(!j||h||o)return;d(!0);try{await r(j),c(""),(v=y.current)==null||v.focus()}catch(A){console.error("Failed to send message:",A)}finally{d(!1)}}},[m,h,o,r,u]),f=S.useCallback(k=>{k.key==="Enter"&&!k.shiftKey&&(k.preventDefault(),g(k))},[g]),z=u?m.trim().length>0||m===".":m.trim().length>0;return B.jsxs("form",{className:"px-4 py-3 border-t border-border flex gap-2",onSubmit:g,children:[B.jsx(zi,{ref:y,type:u?"password":"text",value:m,onChange:k=>c(k.target.value),onKeyDown:f,placeholder:s||(u?"Enter password (or . for none)...":"Type a message..."),disabled:o||h,className:"flex-1"}),B.jsx(La,{type:"submit",disabled:o||h||!z,children:h?u?"Fetching...":"Sending...":u?"Fetch":"Send"})]})});function Si(a,r,{checkForDefaultPrevented:o=!0}={}){return function(u){if(a==null||a(u),o===!1||!u.defaultPrevented)return r==null?void 0:r(u)}}function sx(a,r){const o=S.createContext(r),s=l=>{const{children:m,...c}=l,h=S.useMemo(()=>c,Object.values(c));return B.jsx(o.Provider,{value:h,children:m})};s.displayName=a+"Provider";function u(l){const m=S.useContext(o);if(m)return m;if(r!==void 0)return r;throw new Error(`\`${l}\` must be used within \`${a}\``)}return[s,u]}function Lr(a,r=[]){let o=[];function s(l,m){const c=S.createContext(m),h=o.length;o=[...o,m];const d=g=>{var A;const{scope:f,children:z,...k}=g,j=((A=f==null?void 0:f[a])==null?void 0:A[h])||c,v=S.useMemo(()=>k,Object.values(k));return B.jsx(j.Provider,{value:v,children:z})};d.displayName=l+"Provider";function y(g,f){var j;const z=((j=f==null?void 0:f[a])==null?void 0:j[h])||c,k=S.useContext(z);if(k)return k;if(m!==void 0)return m;throw new Error(`\`${g}\` must be used within \`${l}\``)}return[d,y]}const u=()=>{const l=o.map(m=>S.createContext(m));return function(c){const h=(c==null?void 0:c[a])||l;return S.useMemo(()=>({[`__scope${a}`]:{...c,[a]:h}}),[c,h])}};return u.scopeName=a,[s,tx(u,...r)]}function tx(...a){const r=a[0];if(a.length===1)return r;const o=()=>{const s=a.map(u=>({useScope:u(),scopeName:u.scopeName}));return function(l){const m=s.reduce((c,{useScope:h,scopeName:d})=>{const g=h(l)[`__scope${d}`];return{...c,...g}},{});return S.useMemo(()=>({[`__scope${r.scopeName}`]:m}),[m])}};return o.scopeName=r.scopeName,o}var _o=globalThis!=null&&globalThis.document?S.useLayoutEffect:()=>{},lx=Pu[" useId ".trim().toString()]||(()=>{}),cx=0;function Pr(a){const[r,o]=S.useState(lx());return _o(()=>{o(s=>s??String(cx++))},[a]),r?`radix-${r}`:""}var ux=Pu[" useInsertionEffect ".trim().toString()]||_o;function nl({prop:a,defaultProp:r,onChange:o=()=>{},caller:s}){const[u,l,m]=dx({defaultProp:r,onChange:o}),c=a!==void 0,h=c?a:u;{const y=S.useRef(a!==void 0);S.useEffect(()=>{const g=y.current;g!==c&&console.warn(`${s} is changing from ${g?"controlled":"uncontrolled"} to ${c?"controlled":"uncontrolled"}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`),y.current=c},[c,s])}const d=S.useCallback(y=>{var g;if(c){const f=px(y)?y(a):y;f!==a&&((g=m.current)==null||g.call(m,f))}else l(y)},[c,a,l,m]);return[h,d]}function dx({defaultProp:a,onChange:r}){const[o,s]=S.useState(a),u=S.useRef(o),l=S.useRef(r);return ux(()=>{l.current=r},[r]),S.useEffect(()=>{var m;u.current!==o&&((m=l.current)==null||m.call(l,o),u.current=o)},[o,u]),[o,s,l]}function px(a){return typeof a=="function"}function mx(a){const r=hx(a),o=S.forwardRef((s,u)=>{const{children:l,...m}=s,c=S.Children.toArray(l),h=c.find(yx);if(h){const d=h.props.children,y=c.map(g=>g===h?S.Children.count(d)>1?S.Children.only(null):S.isValidElement(d)?d.props.children:null:g);return B.jsx(r,{...m,ref:u,children:S.isValidElement(d)?S.cloneElement(d,void 0,y):null})}return B.jsx(r,{...m,ref:u,Line truncated
*/const vk=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],$g=Nu("x",vk);var Qg=Ug();const Gg=Fo(Qg);function kk(a){if(typeof document>"u")return;let r=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css",r.appendChild(o),o.styleSheet?o.styleSheet.cssText=a:o.appendChild(document.createTextNode(a))}const wk=a=>{switch(a){case"success":return qk;case"info":return Ak;case"warning":return jk;case"error":return Ck;default:return null}},xk=Array(12).fill(0),zk=({visible:a,className:r})=>he.createElement("div",{className:["sonner-loading-wrapper",r].filter(Boolean).join(" "),"data-visible":a},he.createElement("div",{className:"sonner-spinner"},xk.map((o,s)=>he.createElement("div",{className:"sonner-loading-bar",key:`spinner-bar-${s}`})))),qk=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},he.createElement("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",clipRule:"evenodd"})),jk=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",height:"20",width:"20"},he.createElement("path",{fillRule:"evenodd",d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z",clipRule:"evenodd"})),Ak=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},he.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z",clipRule:"evenodd"})),Ck=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},he.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",clipRule:"evenodd"})),Ek=he.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"},he.createElement("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),he.createElement("line",{x1:"6",y1:"6",x2:"18",y2:"18"})),Sk=()=>{const[a,r]=he.useState(document.hidden);return he.useEffect(()=>{const o=()=>{r(document.hidden)};return document.addEventListener("visibilitychange",o),()=>window.removeEventListener("visibilitychange",o)},[]),a};let ku=1;class Bk{constructor(){this.subscribe=r=>(this.subscribers.push(r),()=>{const o=this.subscribers.indexOf(r);this.subscribers.splice(o,1)}),this.publish=r=>{this.subscribers.forEach(o=>o(r))},this.addToast=r=>{this.publish(r),this.toasts=[...this.toasts,r]},this.create=r=>{var o;const{message:s,...u}=r,l=typeof(r==null?void 0:r.id)=="number"||((o=r.id)==null?void 0:o.length)>0?r.id:ku++,m=this.toasts.find(h=>h.id===l),c=r.dismissible===void 0?!0:r.dismissible;return this.dismissedToasts.has(l)&&this.dismissedToasts.delete(l),m?this.toasts=this.toasts.map(h=>h.id===l?(this.publish({...h,...r,id:l,title:s}),{...h,...r,id:l,dismissible:c,title:s}):h):this.addToast({title:s,...u,dismissible:c,id:l}),l},this.dismiss=r=>(r?(this.dismissedToasts.add(r),requestAnimationFrame(()=>this.subscribers.forEach(o=>o({id:r,dismiss:!0})))):this.toasts.forEach(o=>{this.subscribers.forEach(s=>s({id:o.id,dismiss:!0}))}),r),this.message=(r,o)=>this.create({...o,message:r}),this.error=(r,o)=>this.create({...o,message:r,type:"error"}),this.success=(r,o)=>this.create({...o,type:"success",message:r}),this.info=(r,o)=>this.create({...o,type:"info",message:r}),this.warning=(r,o)=>this.create({...o,type:"warning",message:r}),this.loading=(r,o)=>this.create({...o,type:"loading",message:r}),this.promise=(r,o)=>{if(!o)return;let s;o.loading!==void 0&&(s=this.create({...o,promise:r,type:"loading",message:o.loading,description:typeof o.description!="function"?o.description:void 0}));const u=Promise.resolve(r instanceof Function?r():r);let l=s!==void 0,m;const c=u.then(async d=>{if(m=["resolve",d],he.isValidElement(d))l=!1,this.create({id:s,type:"default",message:d});else if(Dk(d)&&!d.ok){l=!1;const g=typeof o.error=="function"?await o.error(`HTTP error! status: ${d.status}`):o.error,f=typeof o.description=="function"?await o.description(`HTTP error! status: ${d.status}`):o.description,k=typeof g=="object"&&!he.isValidElement(g)?g:{message:g};this.create({id:s,type:"error",description:f,...k})}else if(d instanceof Error){l=!1;const g=typeof o.error=="function"?await o.error(d):o.error,Line truncated
`).map((q,I,L)=>B.jsxs("span",{children:[nx(q,c),I<L.length-1&&B.jsx("br",{})]},I)),!X&&B.jsx("span",{className:"text-[10px] text-muted-foreground/50 ml-2",children:th(x.sender_timestamp||x.received_at)}),x.outgoing&&(x.acked>0?` ✓${x.acked>1?x.acked:""}`:" ?")]})]})]},x.id)})]}),g&&B.jsx("button",{onClick:j,className:"absolute bottom-4 right-4 w-10 h-10 rounded-full bg-muted hover:bg-accent border border-border flex items-center justify-center shadow-lg transition-opacity",title:"Scroll to bottom",children:B.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"text-muted-foreground",children:B.jsx("polyline",{points:"6 9 12 15 18 9"})})})]})}const rx=S.forwardRef(function({onSend:r,disabled:o,placeholder:s,isRepeaterMode:u},l){const[m,c]=S.useState(""),[h,d]=S.useState(!1),y=S.useRef(null);S.useImperativeHandle(l,()=>({appendText:k=>{var j;c(v=>v+k),(j=y.current)==null||j.focus()}}));const g=S.useCallback(async k=>{k.preventDefault();const j=m.trim();if(u){if(h||o)return;const v=j==="."?"":j;d(!0);try{await r(v),c("")}catch(A){console.error("Failed to request telemetry:",A);return}finally{d(!1)}setTimeout(()=>{var A;return(A=y.current)==null?void 0:A.focus()},0)}else{if(!j||h||o)return;d(!0);try{await r(j),c("")}catch(v){console.error("Failed to send message:",v);return}finally{d(!1)}setTimeout(()=>{var v;return(v=y.current)==null?void 0:v.focus()},0)}},[m,h,o,r,u]),f=S.useCallback(k=>{k.key==="Enter"&&!k.shiftKey&&(k.preventDefault(),g(k))},[g]),z=u?m.trim().length>0||m===".":m.trim().length>0;return B.jsxs("form",{className:"px-4 py-3 border-t border-border flex gap-2",onSubmit:g,children:[B.jsx(zi,{ref:y,type:u?"password":"text",value:m,onChange:k=>c(k.target.value),onKeyDown:f,placeholder:s||(u?"Enter password (or . for none)...":"Type a message..."),disabled:o||h,className:"flex-1"}),B.jsx(La,{type:"submit",disabled:o||h||!z,children:h?u?"Fetching...":"Sending...":u?"Fetch":"Send"})]})});function Si(a,r,{checkForDefaultPrevented:o=!0}={}){return function(u){if(a==null||a(u),o===!1||!u.defaultPrevented)return r==null?void 0:r(u)}}function sx(a,r){const o=S.createContext(r),s=l=>{const{children:m,...c}=l,h=S.useMemo(()=>c,Object.values(c));return B.jsx(o.Provider,{value:h,children:m})};s.displayName=a+"Provider";function u(l){const m=S.useContext(o);if(m)return m;if(r!==void 0)return r;throw new Error(`\`${l}\` must be used within \`${a}\``)}return[s,u]}function Lr(a,r=[]){let o=[];function s(l,m){const c=S.createContext(m),h=o.length;o=[...o,m];const d=g=>{var A;const{scope:f,children:z,...k}=g,j=((A=f==null?void 0:f[a])==null?void 0:A[h])||c,v=S.useMemo(()=>k,Object.values(k));return B.jsx(j.Provider,{value:v,children:z})};d.displayName=l+"Provider";function y(g,f){var j;const z=((j=f==null?void 0:f[a])==null?void 0:j[h])||c,k=S.useContext(z);if(k)return k;if(m!==void 0)return m;throw new Error(`\`${g}\` must be used within \`${l}\``)}return[d,y]}const u=()=>{const l=o.map(m=>S.createContext(m));return function(c){const h=(c==null?void 0:c[a])||l;return S.useMemo(()=>({[`__scope${a}`]:{...c,[a]:h}}),[c,h])}};return u.scopeName=a,[s,tx(u,...r)]}function tx(...a){const r=a[0];if(a.length===1)return r;const o=()=>{const s=a.map(u=>({useScope:u(),scopeName:u.scopeName}));return function(l){const m=s.reduce((c,{useScope:h,scopeName:d})=>{const g=h(l)[`__scope${d}`];return{...c,...g}},{});return S.useMemo(()=>({[`__scope${r.scopeName}`]:m}),[m])}};return o.scopeName=r.scopeName,o}var _o=globalThis!=null&&globalThis.document?S.useLayoutEffect:()=>{},lx=Pu[" useId ".trim().toString()]||(()=>{}),cx=0;function Pr(a){const[r,o]=S.useState(lx());return _o(()=>{o(s=>s??String(cx++))},[a]),r?`radix-${r}`:""}var ux=Pu[" useInsertionEffect ".trim().toString()]||_o;function nl({prop:a,defaultProp:r,onChange:o=()=>{},caller:s}){const[u,l,m]=dx({defaultProp:r,onChange:o}),c=a!==void 0,h=c?a:u;{const y=S.useRef(a!==void 0);S.useEffect(()=>{const g=y.current;g!==c&&console.warn(`${s} is changing from ${g?"controlled":"uncontrolled"} to ${c?"controlled":"uncontrolled"}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`),y.current=c},[c,s])}const d=S.useCallback(y=>{var g;if(c){const f=px(y)?y(a):y;f!==a&&((g=m.current)==null||g.call(m,f))}else l(y)},[c,a,l,m]);return[h,d]}function dx({defaultProp:a,onChange:r}){const[o,s]=S.useState(a),u=S.useRef(o),l=S.useRef(r);return ux(()=>{l.current=r},[r]),S.useEffect(()=>{var m;u.current!==o&&((m=l.current)==null||m.call(l,o),u.current=o)},[o,u]),[o,s,l]}function px(a){return typeof a=="function"}function mx(a){const r=hx(a),o=S.forwardRef((s,u)=>{const{children:l,...m}=s,c=S.Children.toArray(l),h=c.find(yx);if(h){const d=h.props.children,y=c.map(g=>g===h?S.Children.count(d)>1?S.Children.only(null):S.isValidElement(d)?d.prLine truncated
.`.concat(Hx,` {
overflow: hidden `).concat(s,`;
padding-right: `).concat(c,"px ").concat(s,`;
@@ -117,7 +117,7 @@ Error generating stack: `+b.message+`
If you want to hide the \`${r.titleName}\`, you can wrap it with our VisuallyHidden component.
For more information, see https://radix-ui.com/primitives/docs/components/${r.docsSlug}`;return S.useEffect(()=>{a&&(document.getElementById(a)||console.error(o))},[o,a]),null},Lz="DialogDescriptionWarning",Hz=({contentRef:a,descriptionId:r})=>{const s=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${Vy(Lz).contentName}}.`;return S.useEffect(()=>{var l;const u=(l=a.current)==null?void 0:l.getAttribute("aria-describedby");r&&u&&(document.getElementById(r)||console.warn(s))},[s,a,r]),null},Uy=By,Wy=Fy,sl=Ry,tl=Ty,ll=Ny,cl=My,$y=Ly;const Qy=Uy,Vz=Wy,Gy=S.forwardRef(({className:a,...r},o)=>B.jsx(sl,{ref:o,className:$e("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",a),...r}));Gy.displayName=sl.displayName;const Vu=S.forwardRef(({className:a,children:r,...o},s)=>B.jsxs(Vz,{children:[B.jsx(Gy,{}),B.jsxs(tl,{ref:s,className:$e("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",a),...o,children:[r,B.jsxs($y,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[B.jsx($g,{className:"h-4 w-4"}),B.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));Vu.displayName=tl.displayName;const Uu=({className:a,...r})=>B.jsx("div",{className:$e("flex flex-col space-y-1.5 text-center sm:text-left",a),...r});Uu.displayName="DialogHeader";const Wu=({className:a,...r})=>B.jsx("div",{className:$e("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...r});Wu.displayName="DialogFooter";const $u=S.forwardRef(({className:a,...r},o)=>B.jsx(ll,{ref:o,className:$e("text-lg font-semibold leading-none tracking-tight",a),...r}));$u.displayName=ll.displayName;const Uz=S.forwardRef(({className:a,...r},o)=>B.jsx(cl,{ref:o,className:$e("text-sm text-muted-foreground",a),...r}));Uz.displayName=cl.displayName;function kh(a){const r=Wz(a),o=S.forwardRef((s,u)=>{const{children:l,...m}=s,c=S.Children.toArray(l),h=c.find(Qz);if(h){const d=h.props.children,y=c.map(g=>g===h?S.Children.count(d)>1?S.Children.only(null):S.isValidElement(d)?d.props.children:null:g);return B.jsx(r,{...m,ref:u,children:S.isValidElement(d)?S.cloneElement(d,void 0,y):null})}return B.jsx(r,{...m,ref:u,children:l})});return o.displayName=`${a}.Slot`,o}function Wz(a){const r=S.forwardRef((o,s)=>{const{children:u,...l}=o;if(S.isValidElement(u)){const m=Kz(u),c=Gz(l,u.props);return u.type!==S.Fragment&&(c.ref=s?Or(s,m):m),S.cloneElement(u,c)}return S.Children.count(u)>1?S.Children.only(null):null});return r.displayName=`${a}.SlotClone`,r}var $z=Symbol("radix.slottable");function Qz(a){return S.isValidElement(a)&&typeof a.type=="function"&&"__radixId"in a.type&&a.type.__radixId===$z}function Gz(a,r){const o={...r};for(const s in r){const u=a[s],l=r[s];/^on[A-Z]/.test(s)?u&&l?o[s]=(...c)=>{const h=l(...c);return u(...c),h}:u&&(o[s]=u):s==="style"?o[s]={...u,...l}:s==="className"&&(o[s]=[u,l].filter(Boolean).join(" "))}return{...a,...o}}function Kz(a){var s,u;let r=(s=Object.getOwnPropertyDescriptor(a.props,"ref"))==null?void 0:s.get,o=r&&"isReactWarning"in r&&r.isReactWarning;return o?a.ref:(r=(u=Object.getOwnPropertyDescriptor(a,"ref"))==null?void 0:u.get,o=r&&"isReactWarning"in r&&r.isReactWarning,o?a.props.ref:a.props.ref||a.ref)}function Yz(a){const r=a+"CollectionProvider",[o,s]=Lr(r),[u,l]=o(r,{collectionRef:{current:null},itemMap:new Map}),m=j=>{const{scope:v,children:A}=j,C=he.useRef(null),w=he.useRef(new Map).current;return B.jsx(u,{scope:v,itemMap:w,collectionRef:C,children:A})};m.displayName=r;const c=a+"CollectionSlot",h=kh(c),d=he.forwardRef((j,v)=>{const{scope:A,children:C}=j,w=l(c,A),_=fa(v,w.collectionRef);return B.jsx(h,{ref:_,children:C})});d.displayName=c;const y=a+"CollectionItemSlot",g="data-radix-collection-item",f=kh(y),z=he.forwardRef((j,v)=>{const{scope:A,children:C,...w}=j,_=he.useRef(null),x=fa(v,_),D=l(y,A);return he.useEffect(()=>(D.itemMap.set(_,{ref:_,...w}),()=>void D.itemMap.delete(_))),B.jsx(f,{[g]:"",ref:x,children:C})});z.displayName=y;function k(j){const v=l(a+"CollectionConsumer",j);return he.useCallback(()=>{const C=v.collectionRef.current;if(!C)return[];const w=Array.from(C.querySelectorAll(`[${g}]`));return Array.from(v.itemMap.values()).sort((D,R)=>w.indexOf(D.ref.current)-w.indexOf(R.ref.current))},[v.coll Line truncated
For more information, see https://radix-ui.com/primitives/docs/components/${r.docsSlug}`;return S.useEffect(()=>{a&&(document.getElementById(a)||console.error(o))},[o,a]),null},Lz="DialogDescriptionWarning",Hz=({contentRef:a,descriptionId:r})=>{const s=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${Vy(Lz).contentName}}.`;return S.useEffect(()=>{var l;const u=(l=a.current)==null?void 0:l.getAttribute("aria-describedby");r&&u&&(document.getElementById(r)||console.warn(s))},[s,a,r]),null},Uy=By,Wy=Fy,sl=Ry,tl=Ty,ll=Ny,cl=My,$y=Ly;const Qy=Uy,Vz=Wy,Gy=S.forwardRef(({className:a,...r},o)=>B.jsx(sl,{ref:o,className:$e("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",a),...r}));Gy.displayName=sl.displayName;const Vu=S.forwardRef(({className:a,children:r,...o},s)=>B.jsxs(Vz,{children:[B.jsx(Gy,{}),B.jsxs(tl,{ref:s,className:$e("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",a),...o,children:[r,B.jsxs($y,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[B.jsx($g,{className:"h-4 w-4"}),B.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));Vu.displayName=tl.displayName;const Uu=({className:a,...r})=>B.jsx("div",{className:$e("flex flex-col space-y-1.5 text-center sm:text-left",a),...r});Uu.displayName="DialogHeader";const Wu=({className:a,...r})=>B.jsx("div",{className:$e("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...r});Wu.displayName="DialogFooter";const $u=S.forwardRef(({className:a,...r},o)=>B.jsx(ll,{ref:o,className:$e("text-lg font-semibold leading-none tracking-tight",a),...r}));$u.displayName=ll.displayName;const Uz=S.forwardRef(({className:a,...r},o)=>B.jsx(cl,{ref:o,className:$e("text-sm text-muted-foreground",a),...r}));Uz.displayName=cl.displayName;function kh(a){const r=Wz(a),o=S.forwardRef((s,u)=>{const{children:l,...m}=s,c=S.Children.toArray(l),h=c.find(Qz);if(h){const d=h.props.children,y=c.map(g=>g===h?S.Children.count(d)>1?S.Children.only(null):S.isValidElement(d)?d.props.children:null:g);return B.jsx(r,{...m,ref:u,children:S.isValidElement(d)?S.cloneElement(d,void 0,y):null})}return B.jsx(r,{...m,ref:u,children:l})});return o.displayName=`${a}.Slot`,o}function Wz(a){const r=S.forwardRef((o,s)=>{const{children:u,...l}=o;if(S.isValidElement(u)){const m=Kz(u),c=Gz(l,u.props);return u.type!==S.Fragment&&(c.ref=s?Or(s,m):m),S.cloneElement(u,c)}return S.Children.count(u)>1?S.Children.only(null):null});return r.displayName=`${a}.SlotClone`,r}var $z=Symbol("radix.slottable");function Qz(a){return S.isValidElement(a)&&typeof a.type=="function"&&"__radixId"in a.type&&a.type.__radixId===$z}function Gz(a,r){const o={...r};for(const s in r){const u=a[s],l=r[s];/^on[A-Z]/.test(s)?u&&l?o[s]=(...c)=>{const h=l(...c);return u(...c),h}:u&&(o[s]=u):s==="style"?o[s]={...u,...l}:s==="className"&&(o[s]=[u,l].filter(Boolean).join(" "))}return{...a,...o}}function Kz(a){var s,u;let r=(s=Object.getOwnPropertyDescriptor(a.props,"ref"))==null?void 0:s.get,o=r&&"isReactWarning"in r&&r.isReactWarning;return o?a.ref:(r=(u=Object.getOwnPropertyDescriptor(a,"ref"))==null?void 0:u.get,o=r&&"isReactWarning"in r&&r.isReactWarning,o?a.props.ref:a.props.ref||a.ref)}function Yz(a){const r=a+"CollectionProvider",[o,s]=Lr(r),[u,l]=o(r,{collectionRef:{current:null},itemMap:new Map}),m=j=>{const{scope:v,children:A}=j,C=he.useRef(null),w=he.useRef(new Map).current;return B.jsx(u,{scope:v,itemMap:w,collectionRef:C,children:A})};m.displayName=r;const c=a+"CollectionSlot",h=kh(c),d=he.forwardRef((j,v)=>{const{scope:A,children:C}=j,w=l(c,A),_=fa(v,w.collectionRef);return B.jsx(h,{ref:_,children:C})});d.displayName=c;const y=a+"CollectionItemSlot",g="data-radix-collection-item",f=kh(y),z=he.forwardRef((j,v)=>{const{scope:A,children:C,...w}=j,_=he.useRef(null),x=fa(v,_),D=l(y,A);return he.useEffect(()=>(D.itemMap.set(_,{ref:_,...w}),()=>void D.itemMap.delete(_))),B.jsx(f,{[g]:"",ref:x,children:C})});z.displayName=y;function k(j){const v=l(a+"CollectionConsumer",j);return he.useCallback(()=>{const C=v.collectionRef.current;if(!C)return[];const w=Array.from(C.querySelectorAll(`[${g}]`));return Array.from(v.itemMap.values()).sort((D,R)=>w.indexOf(D.ref.current)-w.indexOf(R.ref.current))},[v.coll Line truncated
(c) 2012 by Cédric Mesnil. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
@@ -130,7 +130,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${r.do
* Counter block mode compatible with Dr Brian Gladman fileenc.c
* derived from CryptoJS.mode.CTR
* Jan Hruby jhruby.web@gmail.com
*/return o.mode.CTRGladman=(function(){var s=o.lib.BlockCipherMode.extend();function u(c){if((c>>24&255)===255){var h=c>>16&255,d=c>>8&255,y=c&255;h===255?(h=0,d===255?(d=0,y===255?y=0:++y):++d):++h,c=0,c+=h<<16,c+=d<<8,c+=y}else c+=1<<24;return c}function l(c){return(c[0]=u(c[0]))===0&&(c[1]=u(c[1])),c}var m=s.Encryptor=s.extend({processBlock:function(c,h){var d=this._cipher,y=d.blockSize,g=this._iv,f=this._counter;g&&(f=this._counter=g.slice(0),this._iv=void 0),l(f);var z=f.slice(0);d.encryptBlock(z,0);for(var k=0;k<y;k++)c[h+k]^=z[k]}});return s.Decryptor=m,s})(),o.mode.CTRGladman})})(Et)),Et.exports}var St={exports:{}},bq=St.exports,Qh;function fq(){return Qh||(Qh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(bq,function(o){return o.mode.OFB=(function(){var s=o.lib.BlockCipherMode.extend(),u=s.Encryptor=s.extend({processBlock:function(l,m){var c=this._cipher,h=c.blockSize,d=this._iv,y=this._keystream;d&&(y=this._keystream=d.slice(0),this._iv=void 0),c.encryptBlock(y,0);for(var g=0;g<h;g++)l[m+g]^=y[g]}});return s.Decryptor=u,s})(),o.mode.OFB})})(St)),St.exports}var Bt={exports:{}},vq=Bt.exports,Gh;function kq(){return Gh||(Gh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(vq,function(o){return o.mode.ECB=(function(){var s=o.lib.BlockCipherMode.extend();return s.Encryptor=s.extend({processBlock:function(u,l){this._cipher.encryptBlock(u,l)}}),s.Decryptor=s.extend({processBlock:function(u,l){this._cipher.decryptBlock(u,l)}}),s})(),o.mode.ECB})})(Bt)),Bt.exports}var _t={exports:{}},wq=_t.exports,Kh;function xq(){return Kh||(Kh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(wq,function(o){return o.pad.AnsiX923={pad:function(s,u){var l=s.sigBytes,m=u*4,c=m-l%m,h=l+c-1;s.clamp(),s.words[h>>>2]|=c<<24-h%4*8,s.sigBytes+=c},unpad:function(s){var u=s.words[s.sigBytes-1>>>2]&255;s.sigBytes-=u}},o.pad.Ansix923})})(_t)),_t.exports}var Dt={exports:{}},zq=Dt.exports,Yh;function qq(){return Yh||(Yh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(zq,function(o){return o.pad.Iso10126={pad:function(s,u){var l=u*4,m=l-s.sigBytes%l;s.concat(o.lib.WordArray.random(m-1)).concat(o.lib.WordArray.create([m<<24],1))},unpad:function(s){var u=s.words[s.sigBytes-1>>>2]&255;s.sigBytes-=u}},o.pad.Iso10126})})(Dt)),Dt.exports}var Ft={exports:{}},jq=Ft.exports,Zh;function Aq(){return Zh||(Zh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(jq,function(o){return o.pad.Iso97971={pad:function(s,u){s.concat(o.lib.WordArray.create([2147483648],1)),o.pad.ZeroPadding.pad(s,u)},unpad:function(s){o.pad.ZeroPadding.unpad(s),s.sigBytes--}},o.pad.Iso97971})})(Ft)),Ft.exports}var Rt={exports:{}},Cq=Rt.exports,Xh;function Eq(){return Xh||(Xh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(Cq,function(o){return o.pad.ZeroPadding={pad:function(s,u){var l=u*4;s.clamp(),s.sigBytes+=l-(s.sigBytes%l||l)},unpad:function(s){for(var u=s.words,l=s.sigBytes-1,l=s.sigBytes-1;l>=0;l--)if(u[l>>>2]>>>24-l%4*8&255){s.sigBytes=l+1;break}}},o.pad.ZeroPadding})})(Rt)),Rt.exports}var Tt={exports:{}},Sq=Tt.exports,Jh;function Bq(){return Jh||(Jh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(Sq,function(o){return o.pad.NoPadding={pad:function(){},unpad:function(){}},o.pad.NoPadding})})(Tt)),Tt.exports}var Pt={exports:{}},_q=Pt.exports,eg;function Dq(){return eg||(eg=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(_q,function(o){return(function(s){var u=o,l=u.lib,m=l.CipherParams,c=u.enc,h=c.Hex,d=u.format;d.Hex={stringify:function(y){return y.ciphertext.toString(h)},parse:function(y){var g=h.parse(y);return m.create({ciphertext:g})}}})(),o.format.Hex})})(Pt)),Pt.exports}var Nt={exports:{}},Fq=Nt.exports,ig;function Rq(){return ig||(ig=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Xn(),Jn(),Cn(),Ri())})(Fq,function(o){return(function(){var s=o,u=s.lib,l=u.BlockCipher,m=s.algo,c=[],h=[],d=[],y=[],g=[],f=[],z=[],k=[],j=[],v=[];(function(){for(var w=[],_=0;_<256;_++)_<128?w[_]=_<<1:w[_]=_<<1^283;for(var x=0,D=0,_=0;_<256;_++){var R=D^D<<1^D<<2^D<<3^D<<4;R=R>>>8^R&255^99,c[x]=R,h[R]=x;var F=w[x],O=w[F],N=w[O],T=w[R]*257^R*16843008;d[x]=T<<24|T>>>8,y[x]=T<<16|T>>>16,g[x]=T<<8|T>>>24,f[x]=T;var T=N*16843009^O*65537^F*257^x*16843008;z[R]=T<<24|T>>>8,k[R]=T<<16|T>>>16,j[R]=T<<8|T>>>24,v[R]=T,x?(x=F^w[w[w[N^F]]],D^=w[w[D]]):x=D=1}})();var A=[0,1,2,4,8,16,32,64,128,27,54],C=m.AES=l.extend({_doReset:function(){var w;if(!(this._nRounds&&this._keyPriorReset===this._key)){for(var _=this._keyPriorReset=this._key,x=_.words,D=_.sigBytes/4,R=this._nRounds=D+6,F=(R+1)*4,O=this._keySchedule=[],N=0;N<F;N++)N<D?O[N]=x[N]:(w=O[N-1],N%D?D>6&&N%D==4&&(w=c[w>>>24]<<24|c[w>>>16&255]<<16|c[w>>>8&255]<<8|c[w&255]):(w=w<<8|w>>>24,w=c[w>>>24]<<24|c[w>>>16&255]<<16|c[w>>>8&255]<<8|c[w&255],w^=A[N/D|0]<<24),O[N]=O[N-D]^w);for(var T=this._invKeySchedule=[],W=0;W<F;W++){var N=F-W;if(W%4)var w=O[N];else var w=O[N-4];W<4||N<=4?T[W]=w:T[W]=z[c[w>>>24]]^k[c[w>>>16&255]]^j[c[w>>>8&255]]^v[c[w&255]]}}},encryptBlock:Line truncated
*/return o.mode.CTRGladman=(function(){var s=o.lib.BlockCipherMode.extend();function u(c){if((c>>24&255)===255){var h=c>>16&255,d=c>>8&255,y=c&255;h===255?(h=0,d===255?(d=0,y===255?y=0:++y):++d):++h,c=0,c+=h<<16,c+=d<<8,c+=y}else c+=1<<24;return c}function l(c){return(c[0]=u(c[0]))===0&&(c[1]=u(c[1])),c}var m=s.Encryptor=s.extend({processBlock:function(c,h){var d=this._cipher,y=d.blockSize,g=this._iv,f=this._counter;g&&(f=this._counter=g.slice(0),this._iv=void 0),l(f);var z=f.slice(0);d.encryptBlock(z,0);for(var k=0;k<y;k++)c[h+k]^=z[k]}});return s.Decryptor=m,s})(),o.mode.CTRGladman})})(Et)),Et.exports}var St={exports:{}},bq=St.exports,Qh;function fq(){return Qh||(Qh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(bq,function(o){return o.mode.OFB=(function(){var s=o.lib.BlockCipherMode.extend(),u=s.Encryptor=s.extend({processBlock:function(l,m){var c=this._cipher,h=c.blockSize,d=this._iv,y=this._keystream;d&&(y=this._keystream=d.slice(0),this._iv=void 0),c.encryptBlock(y,0);for(var g=0;g<h;g++)l[m+g]^=y[g]}});return s.Decryptor=u,s})(),o.mode.OFB})})(St)),St.exports}var Bt={exports:{}},vq=Bt.exports,Gh;function kq(){return Gh||(Gh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(vq,function(o){return o.mode.ECB=(function(){var s=o.lib.BlockCipherMode.extend();return s.Encryptor=s.extend({processBlock:function(u,l){this._cipher.encryptBlock(u,l)}}),s.Decryptor=s.extend({processBlock:function(u,l){this._cipher.decryptBlock(u,l)}}),s})(),o.mode.ECB})})(Bt)),Bt.exports}var _t={exports:{}},wq=_t.exports,Kh;function xq(){return Kh||(Kh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(wq,function(o){return o.pad.AnsiX923={pad:function(s,u){var l=s.sigBytes,m=u*4,c=m-l%m,h=l+c-1;s.clamp(),s.words[h>>>2]|=c<<24-h%4*8,s.sigBytes+=c},unpad:function(s){var u=s.words[s.sigBytes-1>>>2]&255;s.sigBytes-=u}},o.pad.Ansix923})})(_t)),_t.exports}var Dt={exports:{}},zq=Dt.exports,Yh;function qq(){return Yh||(Yh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(zq,function(o){return o.pad.Iso10126={pad:function(s,u){var l=u*4,m=l-s.sigBytes%l;s.concat(o.lib.WordArray.random(m-1)).concat(o.lib.WordArray.create([m<<24],1))},unpad:function(s){var u=s.words[s.sigBytes-1>>>2]&255;s.sigBytes-=u}},o.pad.Iso10126})})(Dt)),Dt.exports}var Ft={exports:{}},jq=Ft.exports,Zh;function Aq(){return Zh||(Zh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(jq,function(o){return o.pad.Iso97971={pad:function(s,u){s.concat(o.lib.WordArray.create([2147483648],1)),o.pad.ZeroPadding.pad(s,u)},unpad:function(s){o.pad.ZeroPadding.unpad(s),s.sigBytes--}},o.pad.Iso97971})})(Ft)),Ft.exports}var Rt={exports:{}},Cq=Rt.exports,Xh;function Eq(){return Xh||(Xh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(Cq,function(o){return o.pad.ZeroPadding={pad:function(s,u){var l=u*4;s.clamp(),s.sigBytes+=l-(s.sigBytes%l||l)},unpad:function(s){for(var u=s.words,l=s.sigBytes-1,l=s.sigBytes-1;l>=0;l--)if(u[l>>>2]>>>24-l%4*8&255){s.sigBytes=l+1;break}}},o.pad.ZeroPadding})})(Rt)),Rt.exports}var Tt={exports:{}},Sq=Tt.exports,Jh;function Bq(){return Jh||(Jh=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(Sq,function(o){return o.pad.NoPadding={pad:function(){},unpad:function(){}},o.pad.NoPadding})})(Tt)),Tt.exports}var Pt={exports:{}},_q=Pt.exports,eg;function Dq(){return eg||(eg=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Ri())})(_q,function(o){return(function(s){var u=o,l=u.lib,m=l.CipherParams,c=u.enc,h=c.Hex,d=u.format;d.Hex={stringify:function(y){return y.ciphertext.toString(h)},parse:function(y){var g=h.parse(y);return m.create({ciphertext:g})}}})(),o.format.Hex})})(Pt)),Pt.exports}var Nt={exports:{}},Fq=Nt.exports,ig;function Rq(){return ig||(ig=1,(function(a,r){(function(o,s,u){a.exports=s(Ie(),Xn(),Jn(),Cn(),Ri())})(Fq,function(o){return(function(){var s=o,u=s.lib,l=u.BlockCipher,m=s.algo,c=[],h=[],d=[],y=[],g=[],f=[],z=[],k=[],j=[],v=[];(function(){for(var w=[],_=0;_<256;_++)_<128?w[_]=_<<1:w[_]=_<<1^283;for(var x=0,D=0,_=0;_<256;_++){var R=D^D<<1^D<<2^D<<3^D<<4;R=R>>>8^R&255^99,c[x]=R,h[R]=x;var F=w[x],O=w[F],N=w[O],T=w[R]*257^R*16843008;d[x]=T<<24|T>>>8,y[x]=T<<16|T>>>16,g[x]=T<<8|T>>>24,f[x]=T;var T=N*16843009^O*65537^F*257^x*16843008;z[R]=T<<24|T>>>8,k[R]=T<<16|T>>>16,j[R]=T<<8|T>>>24,v[R]=T,x?(x=F^w[w[w[N^F]]],D^=w[w[D]]):x=D=1}})();var A=[0,1,2,4,8,16,32,64,128,27,54],C=m.AES=l.extend({_doReset:function(){var w;if(!(this._nRounds&&this._keyPriorReset===this._key)){for(var _=this._keyPriorReset=this._key,x=_.words,D=_.sigBytes/4,R=this._nRounds=D+6,F=(R+1)*4,O=this._keySchedule=[],N=0;N<F;N++)N<D?O[N]=x[N]:(w=O[N-1],N%D?D>6&&N%D==4&&(w=c[w>>>24]<<24|c[w>>>16&255]<<16|c[w>>>8&255]<<8|c[w&255]):(w=w<<8|w>>>24,w=c[w>>>24]<<24|c[w>>>16&255]<<16|c[w>>>8&255]<<8|c[w&255],w^=A[N/D|0]<<24),O[N]=O[N-D]^w);for(var T=this._invKeySchedule=[],W=0;W<F;W++){var N=F-W;if(W%4)var w=O[N];else var w=O[N-4];W<4||N<=4?T[W]=w:T[W]=z[c[w>>>24]]^k[c[w>>>16&255]]^j[c[w>>>8&255]]^v[c[w&255]]}}},encryptBlock:Line truncated
• Timestamp (4 bytes) - send time as unix timestamp
• Request Type (1 byte) - type of request (GetStats, GetTelemetryData, etc.)
• Request Data (remaining bytes) - additional request-specific data`,startByte:c+h,endByte:c+u.length-1,value:f});const z={type:a.PayloadType.Request,version:a.PayloadVersion.Version1,isValid:!0,timestamp:0,requestType:a.RequestType.GetStats,requestData:"",destinationHash:d,sourceHash:y,cipherMac:g,ciphertext:f};return l!=null&&l.includeSegments&&(z.segments=m),z}catch(m){return{type:a.PayloadType.Request,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode request payload"],timestamp:0,requestType:a.RequestType.GetStats,requestData:"",destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:""}}}}return jr.RequestPayloadDecoder=o,jr}var Ar={},qg;function yj(){if(qg)return Ar;qg=1,Object.defineProperty(Ar,"__esModule",{value:!0}),Ar.ResponsePayloadDecoder=void 0;const a=ua(),r=Ii();class o{static decode(u,l){try{if(u.length<4){const k={type:a.PayloadType.Response,version:a.PayloadVersion.Version1,isValid:!1,errors:["Response payload too short (minimum 4 bytes: dest + source + MAC)"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return l!=null&&l.includeSegments&&(k.segments=[{name:"Invalid Response Data",description:"Response payload too short (minimum 4 bytes required)",startByte:l.segmentOffset||0,endByte:(l.segmentOffset||0)+u.length-1,value:(0,r.bytesToHex)(u)}]),k}const m=[],c=(l==null?void 0:l.segmentOffset)||0;let h=0;const d=(0,r.byteToHex)(u[h]);l!=null&&l.includeSegments&&m.push({name:"Destination Hash",description:"First byte of destination node public key",startByte:c+h,endByte:c+h,value:d}),h+=1;const y=(0,r.byteToHex)(u[h]);l!=null&&l.includeSegments&&m.push({name:"Source Hash",description:"First byte of source node public key",startByte:c+h,endByte:c+h,value:y}),h+=1;const g=(0,r.bytesToHex)(u.subarray(h,h+2));l!=null&&l.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data in next field",startByte:c+h,endByte:c+h+1,value:g}),h+=2;const f=(0,r.bytesToHex)(u.subarray(h));l!=null&&l.includeSegments&&u.length>h&&m.push({name:"Ciphertext",description:"Encrypted response data (tag + content)",startByte:c+h,endByte:c+u.length-1,value:f});const z={type:a.PayloadType.Response,version:a.PayloadVersion.Version1,isValid:!0,destinationHash:d,sourceHash:y,cipherMac:g,ciphertext:f,ciphertextLength:u.length-4};return l!=null&&l.includeSegments&&(z.segments=m),z}catch(m){return{type:a.PayloadType.Response,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode response payload"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0}}}}return Ar.ResponsePayloadDecoder=o,Ar}var Cr={},jg;function bj(){if(jg)return Cr;jg=1,Object.defineProperty(Cr,"__esModule",{value:!0}),Cr.AnonRequestPayloadDecoder=void 0;const a=ua(),r=Ii();class o{static decode(u,l){try{if(u.length<35){const k={type:a.PayloadType.AnonRequest,version:a.PayloadVersion.Version1,isValid:!1,errors:["AnonRequest payload too short (minimum 35 bytes: dest + public key + MAC)"],destinationHash:"",senderPublicKey:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return l!=null&&l.includeSegments&&(k.segments=[{name:"Invalid AnonRequest Data",description:"AnonRequest payload too short (minimum 35 bytes required: 1 for dest hash + 32 for public key + 2 for MAC)",startByte:l.segmentOffset||0,endByte:(l.segmentOffset||0)+u.length-1,value:(0,r.bytesToHex)(u)}]),k}const m=[],c=(l==null?void 0:l.segmentOffset)||0;let h=0;const d=(0,r.byteToHex)(u[0]);l!=null&&l.includeSegments&&m.push({name:"Destination Hash",description:`First byte of destination node public key: 0x${d}`,startByte:c+h,endByte:c+h,value:d}),h+=1;const y=(0,r.bytesToHex)(u.subarray(1,33));l!=null&&l.includeSegments&&m.push({name:"Sender Public Key",description:"Ed25519 public key of the sender (32 bytes)",startByte:c+h,endByte:c+h+31,value:y}),h+=32;const g=(0,r.bytesToHex)(u.subarray(33,35));l!=null&&l.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data verification (2 bytes)",startByte:c+h,endByte:c+h+1,value:g}),h+=2;const f=(0,r.bytesToHex)(u.subarray(35));l!=null&&l.includeSegments&&u.length>35&&m.push({name:"Ciphertext",description:`Encrypted message data (${u.length-35} bytes). Contains encrypted plaintext with this structure:
@@ -534,4 +534,4 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
No neighbors reported`;const r=[...a].sort((s,u)=>u.snr-s.snr),o=[`Neighbors (${r.length})`];for(const s of r){const u=s.name||s.pubkey_prefix,l=s.snr>=0?`+${s.snr.toFixed(1)}`:s.snr.toFixed(1);o.push(`${u}, ${l} dB [${Qt(s.last_heard_seconds)} ago]`)}return o.join(`
`)}function Zj(a){if(a.length===0)return`ACL
No ACL entries`;const r=[`ACL (${a.length})`];for(const o of a){const s=o.name||o.pubkey_prefix;r.push(`${s}: ${o.permission_name}`)}return r.join(`
`)}function Xj(a){return`${a.type}-${a.conversation_key}-${a.text}-${a.sender_timestamp}`}function Jj(){const a=window.location.hash.slice(1);if(!a)return null;if(a==="raw")return{type:"raw",name:"raw"};const r=a.indexOf("/");if(r===-1)return null;const o=a.slice(0,r),s=decodeURIComponent(a.slice(r+1));return(o==="channel"||o==="contact")&&s?{type:o,name:s}:null}function eA(a){if(!a)return"";if(a.type==="raw")return"#raw";const r=a.type==="channel"&&a.name.startsWith("#")?a.name.slice(1):a.name;return`#${a.type}/${encodeURIComponent(r)}`}function iA(){const a=S.useRef(null),r=S.useRef(null),o=S.useRef(new Set),[s,u]=S.useState(null),[l,m]=S.useState(null),[c,h]=S.useState(null),[d,y]=S.useState([]),[g,f]=S.useState([]),[z,k]=S.useState([]),[j,v]=S.useState(!1),[A,C]=S.useState(!1),[w,_]=S.useState([]),[x,D]=S.useState(null),[R,F]=S.useState(!1),[O,N]=S.useState(!1),[T,W]=S.useState(!1),[H,K]=S.useState(!1),[ae,X]=S.useState(0),[ne,$]=S.useState(!1),[oe,ee]=S.useState(!1),[q,I]=S.useState(!1),[L,Q]=S.useState(Zm),[de,ge]=S.useState({}),be=S.useRef(null),se=S.useMemo(()=>({onHealth:V=>{const J=be.current;be.current=V,u(V),J!==null&&J.radio_connected!==V.radio_connected&&(V.radio_connected?Tr.success("Radio connected",{description:V.serial_port?`Connected to ${V.serial_port}`:void 0}):Tr.error("Radio disconnected",{description:"Check radio connection and power"}))},onError:V=>{Tr.error(V.message,{description:V.details})},onContacts:V=>y(V),onChannels:V=>f(V),onMessage:V=>{const J=r.current,re=Xj(V);if(o.current.has(re)){console.debug("Duplicate message content ignored:",re.slice(0,50));return}if(o.current.add(re),o.current.size>1e3){const _e=Array.from(o.current);o.current=new Set(_e.slice(-500))}let ye=null;V.type==="CHAN"&&V.conversation_key?ye=an("channel",V.conversation_key):V.type==="PRIV"&&V.conversation_key&&(ye=an("contact",V.conversation_key));const ve=J?V.type==="CHAN"&&J.type==="channel"?V.conversation_key===J.id:V.type==="PRIV"&&J.type==="contact"?V.conversation_key&&Kg(J.id,V.conversation_key):!1:!1;if(ve&&k(_e=>_e.some(ni=>ni.id===V.id)?_e:[..._e,V]),ye){const _e=V.received_at||Math.floor(Date.now()/1e3),ni=nu(ye,_e);Q(ni),!V.outgoing&&!ve&&ge(Ce=>({...Ce,[ye]:(Ce[ye]||0)+1}))}},onContact:V=>{y(J=>{const re=J.findIndex(ye=>ye.public_key===V.public_key);if(re>=0){const ye=[...J],ve=J[re];return ye[re]={...ve,...V,name:V.name??ve.name,last_path:V.last_path??ve.last_path,lat:V.lat??ve.lat,lon:V.lon??ve.lon},ye}return[...J,V]})},onRawPacket:V=>{_(J=>{if(J.some(ye=>ye.id===V.id))return J;const re=[...J,V];return re.length>Hg?re.slice(-Hg):re})},onMessageAcked:V=>{k(J=>{const re=J.findIndex(ye=>ye.id===V);if(re>=0){const ye=[...J];return ye[re]={...J[re],acked:!0},ye}return J})}}),[]);ck(se);const ce=S.useCallback(async()=>{try{const V=await ei.getRadioConfig();m(V)}catch(V){console.error("Failed to fetch config:",V)}},[]),Ae=S.useCallback(async()=>{try{const V=await ei.getSettings();h(V)}catch(V){console.error("Failed to fetch app settings:",V)}},[]),Fe=S.useCallback(async()=>{try{const V=await ei.getUndecryptedPacketCount();X(V.count)}catch(V){console.error("Failed to fetch undecrypted count:",V)}},[]),He=200,ai=S.useCallback(async(V=!1)=>{if(!x){k([]),v(!1);return}V&&F(!0);try{const J=await ei.getMessages({type:x.type==="channel"?"CHAN":"PRIV",conversation_key:x.id,limit:He});k(J),v(J.length>=He)}catch(J){console.error("Failed to fetch messages:",J)}finally{V&&F(!1)}},[x]),Qe=S.useCallback(async()=>{if(!(!x||A||!j)){C(!0);try{const V=await ei.getMessages({type:x.type==="channel"?"CHAN":"PRIV",conversation_key:x.id,limit:He,offset:z.length});V.length>0&&k(J=>[...J,...V]),v(V.length>=He)}catch(V){console.error("Failed to fetch older messages:",V)}finally{C(!1)}}},[x,A,j,z.length]);S.useEffect(()=>{ce(),Ae(),Fe()},[ce,Ae,Fe]);const Oe=S.useCallback(()=>{const V=Jj();if(!V)return null;if(V.type==="raw")return{type:"raw",id:"raw",name:"Raw Packet Feed"};if(V.type==="channel"){const J=g.find(re=>re.name===V.name||re.name===`#${V.name}`);if(J)return{type:"channel",id:J.key,name:J.name}}if(V.type==="contact"){const J=d.find(re=>Kn(re.name,re.public_key)===V.name);if(J)return{type:"contact",id:J.public_key,name:Kn(J.name,J.public_key)}}return null},[g,d]),Me=S.useRef(!1);S.useEffect(()=>{if(Me.current||x||g.length===0&&d.length===0)return;const V=Oe();if(V){D(V),Me.current=!0;return}const J=g.find(re=>re.name==="Public");J&&(D({type:"channel",id:J.key,name:J.name}),Me.current=!0)},[g,d,x,Oe]);const Xe=S.useRef(new Set),Ve=S.useRef(new Set);S.useEffect(()=>{const V=g.filter(ye=>!Xe.current.has(ye.key)),J=d.filter(ye=>ye.public_key&&!Ve.current.has(ye.public_key));if(V.length===0&&J.length===0)return;V.forEach(ye=>Xe.current.add(ye.key)),J.forEach(ye=>Ve.current.add(ye.public_key)),(async()=>{const ye=[...V.map(ve=>({type:"CHAN",conversation_key:ve.key})),...J.map(ve=>({type:"PRIV",conversation_key:ve.public_key}))];if(ye.length!==0)try{const ve=await ei.getMessagesBulk(ye,100),_e=Yk(),ni={},Ce={};for(const T Line truncated
`)}function Xj(a){return`${a.type}-${a.conversation_key}-${a.text}-${a.sender_timestamp}`}function Jj(){const a=window.location.hash.slice(1);if(!a)return null;if(a==="raw")return{type:"raw",name:"raw"};const r=a.indexOf("/");if(r===-1)return null;const o=a.slice(0,r),s=decodeURIComponent(a.slice(r+1));return(o==="channel"||o==="contact")&&s?{type:o,name:s}:null}function eA(a){if(!a)return"";if(a.type==="raw")return"#raw";const r=a.type==="channel"&&a.name.startsWith("#")?a.name.slice(1):a.name;return`#${a.type}/${encodeURIComponent(r)}`}function iA(){const a=S.useRef(null),r=S.useRef(null),o=S.useRef(new Set),[s,u]=S.useState(null),[l,m]=S.useState(null),[c,h]=S.useState(null),[d,y]=S.useState([]),[g,f]=S.useState([]),[z,k]=S.useState([]),[j,v]=S.useState(!1),[A,C]=S.useState(!1),[w,_]=S.useState([]),[x,D]=S.useState(null),[R,F]=S.useState(!1),[O,N]=S.useState(!1),[T,W]=S.useState(!1),[H,K]=S.useState(!1),[ae,X]=S.useState(0),[ne,$]=S.useState(!1),[oe,ee]=S.useState(!1),[q,I]=S.useState(!1),[L,Q]=S.useState(Zm),[de,ge]=S.useState({}),be=S.useRef(null),se=S.useMemo(()=>({onHealth:V=>{const J=be.current;be.current=V,u(V),J!==null&&J.radio_connected!==V.radio_connected&&(V.radio_connected?Tr.success("Radio connected",{description:V.serial_port?`Connected to ${V.serial_port}`:void 0}):Tr.error("Radio disconnected",{description:"Check radio connection and power"}))},onError:V=>{Tr.error(V.message,{description:V.details})},onContacts:V=>y(V),onChannels:V=>f(V),onMessage:V=>{const J=r.current,re=Xj(V);if(o.current.has(re)){console.debug("Duplicate message content ignored:",re.slice(0,50));return}if(o.current.add(re),o.current.size>1e3){const _e=Array.from(o.current);o.current=new Set(_e.slice(-500))}let ye=null;V.type==="CHAN"&&V.conversation_key?ye=an("channel",V.conversation_key):V.type==="PRIV"&&V.conversation_key&&(ye=an("contact",V.conversation_key));const fe=J?V.type==="CHAN"&&J.type==="channel"?V.conversation_key===J.id:V.type==="PRIV"&&J.type==="contact"?V.conversation_key&&Kg(J.id,V.conversation_key):!1:!1;if(fe&&k(_e=>_e.some(ni=>ni.id===V.id)?_e:[..._e,V]),ye){const _e=V.received_at||Math.floor(Date.now()/1e3),ni=nu(ye,_e);Q(ni),!V.outgoing&&!fe&&ge(Ce=>({...Ce,[ye]:(Ce[ye]||0)+1}))}},onContact:V=>{y(J=>{const re=J.findIndex(ye=>ye.public_key===V.public_key);if(re>=0){const ye=[...J],fe=J[re];return ye[re]={...fe,...V,name:V.name??fe.name,last_path:V.last_path??fe.last_path,lat:V.lat??fe.lat,lon:V.lon??fe.lon},ye}return[...J,V]})},onRawPacket:V=>{_(J=>{if(J.some(ye=>ye.id===V.id))return J;const re=[...J,V];return re.length>Hg?re.slice(-Hg):re})},onMessageAcked:(V,J)=>{k(re=>{const ye=re.findIndex(fe=>fe.id===V);if(ye>=0){const fe=[...re];return fe[ye]={...re[ye],acked:J},fe}return re})}}),[]);ck(se);const ce=S.useCallback(async()=>{try{const V=await ei.getRadioConfig();m(V)}catch(V){console.error("Failed to fetch config:",V)}},[]),Ae=S.useCallback(async()=>{try{const V=await ei.getSettings();h(V)}catch(V){console.error("Failed to fetch app settings:",V)}},[]),Fe=S.useCallback(async()=>{try{const V=await ei.getUndecryptedPacketCount();X(V.count)}catch(V){console.error("Failed to fetch undecrypted count:",V)}},[]),He=200,ai=S.useCallback(async(V=!1)=>{if(!x){k([]),v(!1);return}V&&F(!0);try{const J=await ei.getMessages({type:x.type==="channel"?"CHAN":"PRIV",conversation_key:x.id,limit:He});k(J),v(J.length>=He)}catch(J){console.error("Failed to fetch messages:",J)}finally{V&&F(!1)}},[x]),Qe=S.useCallback(async()=>{if(!(!x||A||!j)){C(!0);try{const V=await ei.getMessages({type:x.type==="channel"?"CHAN":"PRIV",conversation_key:x.id,limit:He,offset:z.length});V.length>0&&k(J=>[...J,...V]),v(V.length>=He)}catch(V){console.error("Failed to fetch older messages:",V)}finally{C(!1)}}},[x,A,j,z.length]);S.useEffect(()=>{ce(),Ae(),Fe()},[ce,Ae,Fe]);const Oe=S.useCallback(()=>{const V=Jj();if(!V)return null;if(V.type==="raw")return{type:"raw",id:"raw",name:"Raw Packet Feed"};if(V.type==="channel"){const J=g.find(re=>re.name===V.name||re.name===`#${V.name}`);if(J)return{type:"channel",id:J.key,name:J.name}}if(V.type==="contact"){const J=d.find(re=>Kn(re.name,re.public_key)===V.name);if(J)return{type:"contact",id:J.public_key,name:Kn(J.name,J.public_key)}}return null},[g,d]),Me=S.useRef(!1);S.useEffect(()=>{if(Me.current||x||g.length===0&&d.length===0)return;const V=Oe();if(V){D(V),Me.current=!0;return}const J=g.find(re=>re.name==="Public");J&&(D({type:"channel",id:J.key,name:J.name}),Me.current=!0)},[g,d,x,Oe]);const Xe=S.useRef(new Set),Ve=S.useRef(new Set);S.useEffect(()=>{const V=g.filter(ye=>!Xe.current.has(ye.key)),J=d.filter(ye=>ye.public_key&&!Ve.current.has(ye.public_key));if(V.length===0&&J.length===0)return;V.forEach(ye=>Xe.current.add(ye.key)),J.forEach(ye=>Ve.current.add(ye.public_key)),(async()=>{const ye=[...V.map(fe=>({type:"CHAN",conversation_key:fe.key})),...J.map(fe=>({type:"PRIV",conversation_key:fe.public_key}))];if(ye.length!==0)try{const fe=await ei.getMessagesBulk(ye,100),_e=Yk(),ni={},Ce={};for Line truncated
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>RemoteTerm for MeshCore</title>
<script type="module" crossorigin src="/assets/index-Dj98vxU3.js"></script>
<script type="module" crossorigin src="/assets/index-BtEbese6.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CtV9BARe.css">
</head>
<body>
+10 -10
View File
@@ -305,13 +305,13 @@ export function App() {
return updated;
});
},
onMessageAcked: (messageId: number) => {
// Update message acked status
onMessageAcked: (messageId: number, ackCount: number) => {
// Update message acked count
setMessages((prev) => {
const idx = prev.findIndex((m) => m.id === messageId);
if (idx >= 0) {
const updated = [...prev];
updated[idx] = { ...prev[idx], acked: true };
updated[idx] = { ...prev[idx], acked: ackCount };
return updated;
}
return prev;
@@ -639,7 +639,7 @@ export function App() {
txt_type: 0,
signature: null,
outgoing: false, // Show as incoming (from the repeater)
acked: true, // Mark as acked since it's a response
acked: 1, // Mark as acked since it's a response
};
// Create a second message for neighbors
@@ -654,7 +654,7 @@ export function App() {
txt_type: 0,
signature: null,
outgoing: false,
acked: true,
acked: 1,
};
// Create a third message for ACL
@@ -669,7 +669,7 @@ export function App() {
txt_type: 0,
signature: null,
outgoing: false,
acked: true,
acked: 1,
};
// Add all messages to the list
@@ -690,7 +690,7 @@ export function App() {
txt_type: 0,
signature: null,
outgoing: false,
acked: true,
acked: 1,
};
setMessages((prev) => [...prev, errorMessage]);
}
@@ -718,7 +718,7 @@ export function App() {
txt_type: 0,
signature: null,
outgoing: true,
acked: true,
acked: 1,
};
setMessages((prev) => [...prev, commandMessage]);
@@ -740,7 +740,7 @@ export function App() {
txt_type: 0,
signature: null,
outgoing: false,
acked: true,
acked: 1,
};
setMessages((prev) => [...prev, responseMessage]);
@@ -756,7 +756,7 @@ export function App() {
txt_type: 0,
signature: null,
outgoing: false,
acked: true,
acked: 1,
};
setMessages((prev) => [...prev, errorMessage]);
}
+1 -1
View File
@@ -295,7 +295,7 @@ export function MessageList({
{formatTime(msg.sender_timestamp || msg.received_at)}
</span>
)}
{msg.outgoing && (msg.acked ? ' ✓' : ' ?')}
{msg.outgoing && (msg.acked > 0 ? ` ✓${msg.acked > 1 ? msg.acked : ''}` : ' ?')}
</div>
</div>
</div>
@@ -37,7 +37,7 @@ function createMessage(overrides: Partial<Message>): Message {
txt_type: 0,
signature: null,
outgoing: false,
acked: false,
acked: 0,
...overrides,
};
}
+3 -3
View File
@@ -52,7 +52,7 @@ describe('Repeater message sender parsing', () => {
it('non-repeater messages still get sender parsed', () => {
const channelMessage = 'Alice: Hello everyone!';
const contactType = CONTACT_TYPE_CLIENT;
const contactType: number = CONTACT_TYPE_CLIENT;
const isRepeater = contactType === CONTACT_TYPE_REPEATER;
const { sender, content } = isRepeater
@@ -107,7 +107,7 @@ describe('Repeater password handling', () => {
});
it('normal password is passed through unchanged', () => {
const trimmed = 'mySecretPassword';
const trimmed: string = 'mySecretPassword';
const password = trimmed === '.' ? '' : trimmed;
expect(password).toBe('mySecretPassword');
@@ -123,7 +123,7 @@ describe('Repeater password handling', () => {
});
it('".." is NOT converted (only single dot)', () => {
const trimmed = '..';
const trimmed: string = '..';
const password = trimmed === '.' ? '' : trimmed;
// Double dot is passed through as-is (it's a valid password)
+1 -1
View File
@@ -73,7 +73,7 @@ describe('shouldIncrementUnread', () => {
txt_type: 0,
signature: null,
outgoing: false,
acked: false,
acked: 0,
...overrides,
});
+9 -7
View File
@@ -21,7 +21,7 @@ function parseWebSocketMessage(
onMessage?: (message: Message) => void;
onContact?: (contact: Contact) => void;
onRawPacket?: (packet: RawPacket) => void;
onMessageAcked?: (messageId: number) => void;
onMessageAcked?: (messageId: number, ackCount: number) => void;
}
): { type: string; handled: boolean } {
try {
@@ -46,9 +46,11 @@ function parseWebSocketMessage(
case 'raw_packet':
handlers.onRawPacket?.(msg.data as RawPacket);
return { type: msg.type, handled: !!handlers.onRawPacket };
case 'message_acked':
handlers.onMessageAcked?.((msg.data as { message_id: number }).message_id);
case 'message_acked': {
const ackData = msg.data as { message_id: number; ack_count: number };
handlers.onMessageAcked?.(ackData.message_id, ackData.ack_count);
return { type: msg.type, handled: !!handlers.onMessageAcked };
}
case 'pong':
return { type: msg.type, handled: true };
default:
@@ -77,18 +79,18 @@ describe('parseWebSocketMessage', () => {
});
});
it('routes message_acked to onMessageAcked with message ID', () => {
it('routes message_acked to onMessageAcked with message ID and ack count', () => {
const onMessageAcked = vi.fn();
const data = JSON.stringify({
type: 'message_acked',
data: { message_id: 42 },
data: { message_id: 42, ack_count: 3 },
});
const result = parseWebSocketMessage(data, { onMessageAcked });
expect(result.type).toBe('message_acked');
expect(result.handled).toBe(true);
expect(onMessageAcked).toHaveBeenCalledWith(42);
expect(onMessageAcked).toHaveBeenCalledWith(42, 3);
});
it('routes new message to onMessage handler', () => {
@@ -100,7 +102,7 @@ describe('parseWebSocketMessage', () => {
text: 'Hello',
received_at: 1700000000,
outgoing: false,
acked: false,
acked: 0,
};
const data = JSON.stringify({ type: 'message', data: messageData });
+4 -2
View File
@@ -76,7 +76,8 @@ export interface Message {
txt_type: number;
signature: string | null;
outgoing: boolean;
acked: boolean;
/** ACK count: 0 = not acked, 1+ = number of acks/flood echoes received */
acked: number;
}
export type ConversationType = 'contact' | 'channel' | 'raw';
@@ -110,7 +111,8 @@ export interface AppSettingsUpdate {
max_radio_contacts?: number;
}
/** Contact type constant for repeaters */
/** Contact type constants */
export const CONTACT_TYPE_CLIENT = 1;
export const CONTACT_TYPE_REPEATER = 2;
export interface NeighborInfo {
+5 -3
View File
@@ -18,7 +18,7 @@ interface UseWebSocketOptions {
onMessage?: (message: Message) => void;
onContact?: (contact: Contact) => void;
onRawPacket?: (packet: RawPacket) => void;
onMessageAcked?: (messageId: number) => void;
onMessageAcked?: (messageId: number, ackCount: number) => void;
onError?: (error: ErrorEvent) => void;
}
@@ -82,9 +82,11 @@ export function useWebSocket(options: UseWebSocketOptions) {
case 'raw_packet':
options.onRawPacket?.(msg.data as RawPacket);
break;
case 'message_acked':
options.onMessageAcked?.((msg.data as { message_id: number }).message_id);
case 'message_acked': {
const ackData = msg.data as { message_id: number; ack_count: number };
options.onMessageAcked?.(ackData.message_id, ackData.ack_count);
break;
}
case 'error':
options.onError?.(msg.data as ErrorEvent);
break;
+9 -8
View File
@@ -143,7 +143,7 @@ class TestAckEventHandler:
# Mock dependencies
with patch("app.event_handlers.MessageRepository") as mock_repo, \
patch("app.event_handlers.broadcast_event") as mock_broadcast:
mock_repo.mark_acked = AsyncMock()
mock_repo.increment_ack_count = AsyncMock(return_value=1)
# Create mock event
class MockEvent:
@@ -151,11 +151,11 @@ class TestAckEventHandler:
await on_ack(MockEvent())
# Verify message marked as acked
mock_repo.mark_acked.assert_called_once_with(123)
# Verify ack count incremented
mock_repo.increment_ack_count.assert_called_once_with(123)
# Verify broadcast sent
mock_broadcast.assert_called_once_with("message_acked", {"message_id": 123})
# Verify broadcast sent with ack_count
mock_broadcast.assert_called_once_with("message_acked", {"message_id": 123, "ack_count": 1})
# Verify pending ACK removed
assert "deadbeef" not in _pending_acks
@@ -169,13 +169,14 @@ class TestAckEventHandler:
with patch("app.event_handlers.MessageRepository") as mock_repo, \
patch("app.event_handlers.broadcast_event") as mock_broadcast:
mock_repo.increment_ack_count = AsyncMock()
class MockEvent:
payload = {"code": "different"}
await on_ack(MockEvent())
mock_repo.mark_acked.assert_not_called()
mock_repo.increment_ack_count.assert_not_called()
mock_broadcast.assert_not_called()
assert "expected" in _pending_acks
@@ -185,14 +186,14 @@ class TestAckEventHandler:
from app.event_handlers import on_ack
with patch("app.event_handlers.MessageRepository") as mock_repo:
mock_repo.mark_acked = AsyncMock()
mock_repo.increment_ack_count = AsyncMock()
class MockEvent:
payload = {"code": ""}
await on_ack(MockEvent())
mock_repo.mark_acked.assert_not_called()
mock_repo.increment_ack_count.assert_not_called()
class TestContactMessageCLIFiltering: