ncc-client-poc 0.2.0 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/pure-ei6B17Q0.js","assets/vendor-nostr-tools-gLyVtdq-.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{r as n,a as hs,R as bs}from"./vendor-react-KfUPlHYY.js";import{S as qe,n as X,f as Se,g as xe,a as re,b as gs}from"./vendor-nostr-tools-gLyVtdq-.js";import{N as fs,a as ys,b as vs,p as Be,c as Ns,i as js,d as ws,e as ks}from"./vendor-ncc-CFk2iOfs.js";import{W as Ss,C as We,K as Cs,E as Es,Q as _s,R as he,N as Ps,A as He,S as ve,c as Q,B as Rs,L as ze,a as Ve,b as Is,d as Ts,e as Os,f as Ls,U as As,P as Ie,g as Ds,h as $s,i as Qe,X as Ks,j as Ms,k as Ge,l as Ws,T as Xe,m as Fs,n as Us,o as Js,G as qs,p as Bs}from"./vendor-utils-D1mPQilD.js";(function(){const s=document.createElement("link").relList;if(s&&s.supports&&s.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))h(u);new MutationObserver(u=>{for(const o of u)if(o.type==="childList")for(const f of o.addedNodes)f.tagName==="LINK"&&f.rel==="modulepreload"&&h(f)}).observe(document,{childList:!0,subtree:!0});function P(u){const o={};return u.integrity&&(o.integrity=u.integrity),u.referrerPolicy&&(o.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?o.credentials="include":u.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function h(u){if(u.ep)return;u.ep=!0;const o=P(u);fetch(u.href,o)}})();var Ye={exports:{}},Ce={};/**
|
|
3
|
+
* @license React
|
|
4
|
+
* react-jsx-runtime.production.min.js
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
7
|
+
*
|
|
8
|
+
* This source code is licensed under the MIT license found in the
|
|
9
|
+
* LICENSE file in the root directory of this source tree.
|
|
10
|
+
*/var Hs=n,zs=Symbol.for("react.element"),Vs=Symbol.for("react.fragment"),Qs=Object.prototype.hasOwnProperty,Gs=Hs.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,Xs={key:!0,ref:!0,__self:!0,__source:!0};function Ze(a,s,P){var h,u={},o=null,f=null;P!==void 0&&(o=""+P),s.key!==void 0&&(o=""+s.key),s.ref!==void 0&&(f=s.ref);for(h in s)Qs.call(s,h)&&!Xs.hasOwnProperty(h)&&(u[h]=s[h]);if(a&&a.defaultProps)for(h in s=a.defaultProps,s)u[h]===void 0&&(u[h]=s[h]);return{$$typeof:zs,type:a,key:o,ref:f,props:u,_owner:Gs.current}}Ce.Fragment=Vs;Ce.jsx=Ze;Ce.jsxs=Ze;Ye.exports=Ce;var e=Ye.exports,Te={},Fe=hs;Te.createRoot=Fe.createRoot,Te.hydrateRoot=Fe.hydrateRoot;const le=new qe,es=n.createContext(void 0);function Ys({children:a}){const[s,P]=n.useState({pubkey:localStorage.getItem("ncc_pubkey"),privkey:sessionStorage.getItem("ncc_privkey"),method:localStorage.getItem("ncc_method")||null,isLoading:!1,bunkerPubkey:localStorage.getItem("ncc_bunker_pubkey"),bunkerRelay:localStorage.getItem("ncc_bunker_relay"),clientSecretKey:sessionStorage.getItem("ncc_client_secret")}),h=c=>{var i;return Uint8Array.from(((i=c.match(/.{1,2}/g))==null?void 0:i.map(m=>parseInt(m,16)))||[])},u=async()=>{P(c=>({...c,isLoading:!0}));try{let c=0;for(;typeof window.nostr>"u"&&c<10;)await new Promise(m=>setTimeout(m,100)),c++;if(typeof window.nostr>"u"){alert("Nostr extension not found!"),P(m=>({...m,isLoading:!1}));return}const i=await window.nostr.getPublicKey();P({pubkey:i,privkey:null,method:"nip07",isLoading:!1}),x("nip07",i,null)}catch(c){console.error("NIP-07 Login Error:",c),alert("Login failed: "+(c.message||"Unknown error")),P(i=>({...i,isLoading:!1}))}},o=c=>{try{let i=c,m;if(c.startsWith("nsec")){const{data:O}=re.decode(c);m=O,i=Array.from(m).map(l=>l.toString(16).padStart(2,"0")).join("")}else i=c,m=h(i);const p=xe(m);P({pubkey:p,privkey:i,method:"nsec",isLoading:!1}),x("nsec",p,i)}catch{alert("Invalid Private Key")}},f=c=>{try{let i=c;if(c.startsWith("npub")){const{data:m}=re.decode(c);i=m}P({pubkey:i,privkey:null,method:"readonly",isLoading:!1}),x("readonly",i,null)}catch{alert("Invalid Public Key")}},g=(c,i,m)=>{P(p=>({...p,pubkey:c,method:"nip46",bunkerPubkey:c,bunkerRelay:i,clientSecretKey:m,isLoading:!1})),x("nip46",c,null,{bunkerPubkey:c,bunkerRelay:i,clientSecret:m})},C=async c=>{if(s.method==="nsec"&&s.privkey)return Se(c,h(s.privkey));if(s.method==="nip07"&&window.nostr)return window.nostr.signEvent(c);if(s.method==="nip46"&&s.bunkerPubkey&&s.bunkerRelay&&s.clientSecretKey){const i=h(s.clientSecretKey),m=Math.random().toString(36).substring(7),p={id:m,method:"sign_event",params:[JSON.stringify(c)]},O=X.getConversationKey(i,s.bunkerPubkey),l=X.encrypt(JSON.stringify(p),O),I=Se({kind:24133,created_at:Math.floor(Date.now()/1e3),tags:[["p",s.bunkerPubkey]],content:l},i);return await le.publish([s.bunkerRelay],I),new Promise((j,R)=>{const r=le.subscribeMany([s.bunkerRelay],[{kinds:[24133],"#p":[xe(i)],authors:[s.bunkerPubkey]}],{onevent(_){try{const L=X.decrypt(_.content,O),A=JSON.parse(L);A.id===m&&(r.close(),A.result?j(JSON.parse(A.result)):R(new Error(A.error||"Remote signing failed")))}catch{}}});setTimeout(()=>{r.close(),R(new Error("Remote signing timed out"))},3e4)})}throw new Error("No signing method available")},w=async(c,i)=>{var m;if(s.method==="nsec"&&s.privkey){const p=X.getConversationKey(h(s.privkey),c);return X.encrypt(i,p)}if(s.method==="nip07"&&((m=window.nostr)!=null&&m.nip44))return window.nostr.nip44.encrypt(c,i);if(s.method==="nip46"&&s.bunkerPubkey&&s.bunkerRelay&&s.clientSecretKey){const p=h(s.clientSecretKey),O=Math.random().toString(36).substring(7),l={id:O,method:"nip44_encrypt",params:[c,i]},I=X.getConversationKey(p,s.bunkerPubkey),j=X.encrypt(JSON.stringify(l),I),R=Se({kind:24133,created_at:Math.floor(Date.now()/1e3),tags:[["p",s.bunkerPubkey]],content:j},p);return await le.publish([s.bunkerRelay],R),new Promise((r,_)=>{const L=le.subscribeMany([s.bunkerRelay],[{kinds:[24133],"#p":[xe(p)],authors:[s.bunkerPubkey]}],{onevent(A){try{const S=X.decrypt(A.content,I),b=JSON.parse(S);b.id===O&&(L.close(),b.result?r(b.result):_(new Error(b.error||"Remote encryption failed")))}catch{}}});setTimeout(()=>{L.close(),_(new Error("Remote encryption timed out"))},3e4)})}throw new Error("No encryption method available")},k=async(c,i)=>{var m;if(s.method==="nsec"&&s.privkey){const p=X.getConversationKey(h(s.privkey),c);return X.decrypt(i,p)}if(s.method==="nip07"&&((m=window.nostr)!=null&&m.nip44))return window.nostr.nip44.decrypt(c,i);if(s.method==="nip46"&&s.bunkerPubkey&&s.bunkerRelay&&s.clientSecretKey){const p=h(s.clientSecretKey),O=Math.random().toString(36).substring(7),l={id:O,method:"nip44_decrypt",params:[c,i]},I=X.getConversationKey(p,s.bunkerPubkey),j=X.encrypt(JSON.stringify(l),I),R=Se({kind:24133,created_at:Math.floor(Date.now()/1e3),tags:[["p",s.bunkerPubkey]],content:j},p);return await le.publish([s.bunkerRelay],R),new Promise((r,_)=>{const L=le.subscribeMany([s.bunkerRelay],[{kinds:[24133],"#p":[xe(p)],authors:[s.bunkerPubkey]}],{onevent(A){try{const S=X.decrypt(A.content,I),b=JSON.parse(S);b.id===O&&(L.close(),b.result?r(b.result):_(new Error(b.error||"Remote decryption failed")))}catch{}}});setTimeout(()=>{L.close(),_(new Error("Remote decryption timed out"))},3e4)})}throw new Error("No decryption method available")},v=()=>{P({pubkey:null,privkey:null,method:null,isLoading:!1,bunkerPubkey:null,bunkerRelay:null,clientSecretKey:null}),localStorage.removeItem("ncc_pubkey"),localStorage.removeItem("ncc_method"),localStorage.removeItem("ncc_privkey"),localStorage.removeItem("ncc_bunker_pubkey"),localStorage.removeItem("ncc_bunker_relay"),sessionStorage.removeItem("ncc_privkey"),sessionStorage.removeItem("ncc_client_secret")},x=(c,i,m,p)=>{localStorage.setItem("ncc_method",c),localStorage.setItem("ncc_pubkey",i),m?sessionStorage.setItem("ncc_privkey",m):sessionStorage.removeItem("ncc_privkey"),c==="nip46"&&p&&(localStorage.setItem("ncc_bunker_pubkey",p.bunkerPubkey),localStorage.setItem("ncc_bunker_relay",p.bunkerRelay),sessionStorage.setItem("ncc_client_secret",p.clientSecret))};return e.jsx(es.Provider,{value:{...s,loginWithNip07:u,loginWithNsec:o,loginReadOnly:f,loginWithNip46:g,signEvent:C,encryptNip44:w,decryptNip44:k,logout:v},children:a})}function me(){const a=n.useContext(es);if(!a)throw new Error("useAuth must be used within AuthProvider");return a}const ye=["wss://relay.damus.io","wss://nos.lol","wss://relay.primal.net"],B={load(){const a=localStorage.getItem("ncc_bootstrap_relays");if(a===null)return ye;try{const s=JSON.parse(a);return Array.isArray(s)?s:ye}catch{return ye}},save(a){localStorage.setItem("ncc_bootstrap_relays",JSON.stringify(a))},add(a){const s=this.load();s.includes(a)||this.save([...s,a])},remove(a){const P=this.load().filter(h=>h!==a);this.save(P.length>0?P:ye)},restoreDefaults(){this.save(ye)}},ss=n.createContext(void 0);function Zs({children:a}){const s=n.useMemo(()=>{const P=B.load(),h=g=>{if(g.url.includes(".onion")&&!g.url.includes("/bridge?target=")){const C=g.url;g.url=`ws://${window.location.host}/bridge?target=${encodeURIComponent(C)}`,console.log(`[NCC-SDK] 🧅 Auto-Bridged Onion: ${C}`)}return g},u=new fs({pool:le,bootstrapRelays:P,urlTransformer:h}),o=new ys({pool:le,timeout:5e3}),f=new vs(P,{pool:le});return{ncc05Resolver:u,ncc05Publisher:o,ncc02Resolver:f,pool:le}},[]);return e.jsx(ss.Provider,{value:s,children:a})}function pe(){const a=n.useContext(ss);if(!a)throw new Error("useNCC must be used within NCCProvider");return a}function et(){const{loginWithNip07:a,loginWithNsec:s,loginReadOnly:P,loginWithNip46:h,isLoading:u}=me(),{pool:o}=pe(),[f,g]=n.useState(""),[C,w]=n.useState("options"),[k,v]=n.useState(""),[x,c]=n.useState("generate"),i=n.useRef(null),m=l=>Array.from(l).map(I=>I.toString(16).padStart(2,"0")).join(""),p=()=>{const l=gs(),I=xe(l),j=B.load()[0]||"wss://relay.damus.io",R=encodeURIComponent(JSON.stringify({name:"NCC Client PoC"})),r=`nostrconnect://${I}?relay=${encodeURIComponent(j)}&metadata=${R}`;v(r),c("wait"),O(I,j,l)},O=(l,I,j)=>{i.current&&i.current.close(),console.log("[NIP-46] Listening for responses on",I),i.current=o.subscribeMany([I],[{kinds:[24133],"#p":[l]}],{onevent(R){try{const r=X.getConversationKey(j,R.pubkey),_=X.decrypt(R.content,r),L=JSON.parse(_);(L.result==="ack"||L.method==="connect")&&(console.log("[NIP-46] Connection Established with",R.pubkey),h(R.pubkey,I,m(j)))}catch(r){console.error("[NIP-46] Decryption failed (might be NIP-04, not supported yet in this PoC)",r)}}})};return n.useEffect(()=>()=>{i.current&&i.current.close()},[]),u?e.jsx("div",{className:"loading loading-spinner loading-lg"}):e.jsx("div",{className:"card w-96 bg-base-100 shadow-xl border border-base-300",children:e.jsxs("div",{className:"card-body p-6",children:[e.jsx("h2",{className:"card-title justify-center mb-6 font-bold text-xl",children:"NCC Login"}),C==="options"&&e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("button",{className:"btn btn-primary w-full shadow-md",onClick:()=>a(),children:[e.jsx(Ss,{className:"w-4 h-4 mr-2"}),"Extension (NIP-07)"]}),e.jsxs("button",{className:"btn btn-secondary w-full shadow-md",onClick:()=>w("nip46"),children:[e.jsx(We,{className:"w-4 h-4 mr-2"}),"Nostr Connect (NIP-46)"]}),e.jsx("div",{className:"divider text-[10px] opacity-30 uppercase tracking-widest",children:"Legacy / Read Only"}),e.jsxs("button",{className:"btn btn-neutral btn-sm w-full",onClick:()=>w("nsec"),children:[e.jsx(Cs,{className:"w-4 h-4 mr-2"}),"Private Key (nsec)"]}),e.jsxs("button",{className:"btn btn-ghost btn-sm w-full opacity-60",onClick:()=>w("readonly"),children:[e.jsx(Es,{className:"w-4 h-4 mr-2"}),"Read Only (Watch)"]})]}),C==="nip46"&&e.jsxs("div",{className:"flex flex-col items-center gap-4 fade-in text-center",children:[x==="generate"?e.jsxs(e.Fragment,{children:[e.jsx(We,{className:"w-12 h-12 text-secondary mb-2"}),e.jsx("h3",{className:"font-bold",children:"Connect Remotely"}),e.jsx("p",{className:"text-xs opacity-60 px-4",children:"Sign events using a mobile app (Amber, etc.) or a dedicated Bunker."}),e.jsx("button",{className:"btn btn-secondary w-full mt-4",onClick:p,children:"Generate Connection QR"})]}):e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"bg-white p-4 rounded-xl shadow-inner border-4 border-base-200 inline-block",children:e.jsx(_s,{value:k,size:200})}),e.jsxs("div",{className:"flex flex-col gap-1 items-center",children:[e.jsxs("div",{className:"flex items-center gap-2 text-primary font-bold animate-pulse",children:[e.jsx(he,{className:"w-3 h-3 animate-spin"}),e.jsx("span",{className:"text-xs",children:"Waiting for signer..."})]}),e.jsx("p",{className:"text-[10px] opacity-50 px-6",children:"Scan this QR with your Nostr signing app. Once scanned, the connection will be established automatically."})]}),e.jsx("button",{className:"btn btn-ghost btn-xs opacity-50",onClick:()=>{var l;c("generate"),(l=i.current)==null||l.close()},children:"Reset Connection"})]}),e.jsx("button",{className:"btn btn-ghost btn-sm w-full mt-2",onClick:()=>w("options"),children:"Back to Login Options"})]}),(C==="nsec"||C==="readonly")&&e.jsxs("div",{className:"flex flex-col gap-3 fade-in",children:[e.jsxs("div",{className:"form-control",children:[e.jsx("label",{className:"label text-xs uppercase opacity-50 font-bold",children:e.jsx("span",{className:"label-text",children:C==="nsec"?"Enter nsec / hex private key":"Enter npub / hex public key"})}),e.jsx("input",{type:"password",placeholder:C==="nsec"?"nsec1...":"npub1...",className:"input input-bordered w-full font-mono text-xs",value:f,onChange:l=>g(l.target.value)})]}),e.jsxs("div",{className:"flex gap-2 mt-4",children:[e.jsx("button",{className:"btn btn-ghost flex-1 btn-sm",onClick:()=>w("options"),children:"Back"}),e.jsx("button",{className:"btn btn-success flex-1 btn-sm",onClick:()=>C==="nsec"?s(f):P(f),children:"Login"})]})]})]})})}const ts=n.createContext(void 0);function st({children:a}){const{pool:s}=pe(),{privkey:P}=me(),[h,u]=n.useState(()=>{const k=localStorage.getItem("ncc_tracked_services");return k?JSON.parse(k):[]});n.useEffect(()=>{localStorage.setItem("ncc_tracked_services",JSON.stringify(h))},[h]),n.useEffect(()=>{if(h.length===0)return;const k=[...new Set(h.map(x=>x.pubkey))],v=s.subscribeMany(B.load(),[{kinds:[30053,30058,30059],authors:k}],{onevent(x){o(x)}});return()=>{v.close()}},[h.length]);const o=async k=>{var c;const v=(c=k.tags.find(i=>i[0]==="d"))==null?void 0:c[1];if(!v)return;const x=v.replace(/-locator$/,"").replace(/-loc$/,"");u(i=>{const m=i.findIndex(j=>j.pubkey===k.pubkey&&j.serviceId===x);if(m===-1)return i;const p=i[m];let O=!1;const l={...p};if(k.kind===30059)(!p.serviceDef||k.created_at>p.serviceDef.created_at)&&(l.serviceDef=k,O=!0);else if(k.kind===30058&&(!p.latestEvent||k.created_at>p.latestEvent.created_at)&&(l.latestEvent=k,l.lastChecked=Math.floor(Date.now()/1e3),l.decryptedPayload=null,O=!0,P&&!k.content.trim().startsWith("{")))try{const j=_=>{var L;return Uint8Array.from(((L=_.match(/.{1,2}/g))==null?void 0:L.map(A=>parseInt(A,16)))||[])},R=X.getConversationKey(j(P),k.pubkey),r=X.decrypt(k.content,R);l.decryptedPayload=JSON.parse(r)}catch(j){console.error("Auto-decrypt failed",j)}if(!O)return i;const I=[...i];return I[m]=l,I})},f=(k,v)=>{u(x=>x.some(c=>c.pubkey===k&&c.serviceId===v)?x:[...x,{pubkey:k,serviceId:v,latestEvent:null,serviceDef:null,decryptedPayload:null,lastChecked:Math.floor(Date.now()/1e3)}])},g=(k,v)=>{u(x=>x.filter(c=>!(c.pubkey===k&&c.serviceId===v)))},C=(k,v)=>h.some(x=>x.pubkey===k&&x.serviceId===v),w=(k,v)=>h.find(x=>x.pubkey===k&&x.serviceId===v);return e.jsx(ts.Provider,{value:{tracked:h,trackService:f,untrackService:g,isTracked:C,findTracked:w},children:a})}function ns(){const a=n.useContext(ts);if(!a)throw new Error("useTracking must be used within TrackingProvider");return a}const as=n.createContext(void 0);function tt({children:a}){const[s,P]=n.useState(""),[h,u]=n.useState(""),[o,f]=n.useState("idle"),[g,C]=n.useState([]),[w,k]=n.useState(null),[v,x]=n.useState(null),[c,i]=n.useState([]),[m,p]=n.useState({}),[O,l]=n.useState({}),[I,j]=n.useState(!1),[R,r]=n.useState([]),A={pubkeyInput:s,setPubkeyInput:P,serviceId:h,setServiceId:u,step:o,setStep:f,logs:g,addLog:S=>C(b=>[...b,S]),clearLogs:()=>C([]),error:w,setError:k,resolvedEndpoint:v,setResolvedEndpoint:x,rawEvents:c,setRawEvents:i,profiles:m,setProfiles:p,decryptedPayloads:O,setDecryptedPayloads:l,showExpired:I,setShowExpired:j,attestedIds:R,setAttestedIds:r};return e.jsx(as.Provider,{value:A,children:a})}function nt(){const a=n.useContext(as);if(!a)throw new Error("useDiscovery must be used within DiscoveryProvider");return a}const rs=n.createContext(void 0);function at({children:a}){const{pubkey:s}=me(),{pool:P}=pe(),[h,u]=n.useState(()=>{const w=localStorage.getItem("ncc_wot_follows");return w?JSON.parse(w):[]}),[o,f]=n.useState(!1),g=async()=>{if(s){f(!0);try{const w=await P.get(B.load(),{kinds:[3],authors:[s]});if(w){const k=[s,...w.tags.filter(v=>v[0]==="p").map(v=>v[1])];u(k),localStorage.setItem("ncc_wot_follows",JSON.stringify(k))}else u([s]),localStorage.setItem("ncc_wot_follows",JSON.stringify([s]))}catch(w){console.error("Failed to fetch WoT",w)}finally{f(!1)}}};n.useEffect(()=>{s?(u(w=>w.includes(s)?w:[s,...w]),g()):(u([]),localStorage.removeItem("ncc_wot_follows"))},[s]);const C=w=>h.includes(w);return e.jsx(rs.Provider,{value:{follows:h,isFollowing:C,refreshFollows:g,loading:o},children:a})}function cs(){const a=n.useContext(rs);if(!a)throw new Error("useWoT must be used within WoTProvider");return a}const de=a=>a.replace(/[&<"']/g,s=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[s]);function rt({onConnect:a}){const{ncc02Resolver:s,ncc05Resolver:P,pool:h}=pe(),{pubkey:u,privkey:o,signEvent:f,decryptNip44:g}=me(),{trackService:C,isTracked:w,untrackService:k}=ns(),{isFollowing:v}=cs(),{pubkeyInput:x,setPubkeyInput:c,serviceId:i,setServiceId:m,step:p,setStep:O,logs:l,addLog:I,clearLogs:j,error:R,setError:r,resolvedEndpoint:_,setResolvedEndpoint:L,rawEvents:A,setRawEvents:S,profiles:b,setProfiles:H,decryptedPayloads:z,setDecryptedPayloads:te,showExpired:Y,setShowExpired:t,attestedIds:E,setAttestedIds:$}=nt(),[K,D]=n.useState({}),[U,ne]=n.useState(!1),[Z,ce]=n.useState(!1),[ue,os]=n.useState({});n.useEffect(()=>{const y=async()=>{const N={};for(const d of A)(d.kind===30058||d.kind===30059)&&(N[d.id]=await ls(d));os(N)};A.length>0&&u&&y()},[A,u,z]),n.useEffect(()=>{if(A.length>0&&u){const y=A.filter(N=>N.kind===30060&&N.pubkey===u).map(N=>{var d;return(d=N.tags.find(T=>T[0]==="e"))==null?void 0:d[1]}).filter(N=>N);y.length>0&&$(N=>{const d=[...new Set([...N,...y])];return d.length===N.length?N:d})}},[A,u]);const Oe=async y=>{D(T=>({...T,[y]:"loading"}));const N=Date.now();let d=y;y.includes(".onion")&&(d=`ws://${window.location.host}/bridge?target=${encodeURIComponent(y)}`);try{const T=new WebSocket(d),W=setTimeout(()=>T.close(),1e4);await new Promise((V,q)=>{T.onopen=()=>{clearTimeout(W),T.close(),V(!0)},T.onerror=ie=>{clearTimeout(W),q(ie)}});const ee=Date.now()-N;D(V=>({...V,[y]:ee}))}catch{D(W=>({...W,[y]:"error"}))}},Ne=y=>{const N=Math.floor(Date.now()/1e3);if(y.kind===30059){const d=y.tags.find(T=>T[0]==="exp");if(d&&parseInt(d[1])<N)return!0}if(y.kind===30058)try{if(y.content.trim().startsWith("{")){const d=JSON.parse(y.content);if(d.updated_at&&d.ttl&&d.updated_at+d.ttl<N)return!0}else{const d=z[y.id];if(d&&d.updated_at&&d.ttl&&d.updated_at+d.ttl<N)return!0}}catch{}return!1},Le=async y=>{const N=[...new Set(y.map(d=>d.pubkey))];if(N.length!==0)try{const d=await h.querySync(B.load(),{kinds:[0],authors:N}),T={};d.forEach(W=>{try{const ee=JSON.parse(W.content);T[W.pubkey]={...ee,_tags:W.tags}}catch{}}),H(W=>({...W,...T}))}catch(d){console.error("Failed to fetch profiles",d)}},is=y=>{const N=b[y];if(N&&(N.display_name||N.name))return N.display_name||N.name;try{const d=re.npubEncode(y);return`${d.slice(0,10)}...${d.slice(-4)}`}catch{return y.slice(0,8)}},ls=async y=>{var N,d;if(!u)return!1;if(y.kind===30058){const T=z[y.id];if(T&&((N=T.privaterecipients)!=null&&N.includes(u)))return!0;if(y.content.startsWith("{"))try{if((d=JSON.parse(y.content).privaterecipients)!=null&&d.includes(u))return!0}catch{}}if(y.kind===30059){const T=Ns(y.tags);if(T.length>0){const W={nip44Decrypt:(ee,V)=>g(ee,V),getPublicKey:()=>Promise.resolve(u)};try{return await js(T,y.pubkey,W)}catch{return!1}}}return y.tags.some(T=>T[0]==="p"&&T[1]===u)},ds=async y=>{try{const N=await g(y.pubkey,y.content);te(d=>({...d,[y.id]:JSON.parse(N)}))}catch(N){alert("Decryption failed: "+N.message)}},us=async()=>{var N;O("verifying"),j(),r(null),L(null),S([]),H({}),te({});const y=(d,T,W)=>Promise.race([d,new Promise((ee,V)=>setTimeout(()=>V(new Error(W)),T))]);try{let d=x;if(x.startsWith("npub")&&(d=re.decode(x).data),!d){I("🌐 Global Search: Querying bootstrap relays...");const q={kinds:[30053,30058,30059,30060,30061],limit:50};i&&(q["#d"]=[i]);const ie=await y(h.querySync(B.load(),q),1e4,"Global search timed out after 10s");S(ie),Le(ie),I(`✅ Found ${ie.length} records globally.`),O("complete");return}I("🔍 NCC Discovery: Querying service events...");const T={getPublicKey:async()=>u||"",signEvent:async q=>f(q),getConversationKey:async q=>{if(o){const ie=J=>{var F;return Uint8Array.from(((F=J.match(/.{1,2}/g))==null?void 0:F.map(se=>parseInt(se,16)))||[])};return X.getConversationKey(ie(o),q)}throw new Error("Local decryption key not available. Ensure you are logged in with NSEC.")}};I("📍 NCC-05: Resolving latest locator...");const W=await y(P.resolveLatest(d,T),1e4,"Locator resolution timed out");I("🛡️ NCC-02: Verifying service trust...");const V=[(await y(s.resolve(d,i||"relay",{requireAttestation:!1,minLevel:"self"}),5e3,"Trust verification timed out")).serviceEvent,...W?[]:[]].filter(q=>q);S(V),Le(V),W&&((N=W.endpoints)==null?void 0:N.length)>0&&(L(W.endpoints[0]),I(`📍 Found ${W.endpoints.length} endpoints.`)),O("complete")}catch(d){r(d.message||"Discovery failed"),I(`❌ Error: ${d.message}`),O("idle")}},Ee=(y,N)=>{let d=N;if(!d&&_&&x)try{let W=x;x.startsWith("npub")&&(W=re.decode(x).data),d={pubkey:W,id:i||"addr"}}catch{}d&&(w(d.pubkey,d.id)||C(d.pubkey,d.id));let T=y||(_?_.url||_.uri:null);if(T){if(T.includes("://")||(T=T.includes(".onion")?`ws://${T}`:`wss://${T}`),T.startsWith("http")&&(T=T.replace("http","ws")),T.includes(".onion"))if(window.confirm(`🧅 Tor Onion Address Detected
|
|
11
|
+
|
|
12
|
+
1. OK: Use Bridge (requires npm run bridge)
|
|
13
|
+
2. Cancel: Direct (Tor Browser/Orbot)`)){const ee=`ws://${window.location.host}/bridge?target=${encodeURIComponent(T)}`;a(ee,d);return}else{if(window.confirm("Attempt direct connection?")){a(T,d);return}navigator.clipboard.writeText(T);return}a(T,d)}},ms=async y=>{var ee;if(!u)return alert("Please login first.");const N=(ee=y.tags.find(V=>V[0]==="d"))==null?void 0:ee[1];if(!N)return;const d=Math.floor(Date.now()/1e3),T=d+30*24*60*60,W={kind:30060,created_at:d,tags:[["subj",y.pubkey],["srv",N],["e",y.id],["std","nostr-service-trust-v0.1"],["lvl","verified"],["nbf",d.toString()],["exp",T.toString()]],content:"NCC-02 Attestation",pubkey:u};try{const V=await f(W);V&&(I(`✍️ Publishing Attestation for ${N}...`),await h.publish(B.load(),V),$(q=>[...q,y.id]),alert("Attestation Published Successfully!"))}catch(V){console.error(V),alert("Attestation failed: "+V.message)}};return e.jsx("div",{className:"card bg-base-100 shadow-lg border border-base-200",children:e.jsxs("div",{className:"card-body p-4 sm:p-8",children:[e.jsxs("h3",{className:"card-title text-xl mb-4 flex items-center",children:[e.jsx(Ps,{className:"w-6 h-6 mr-2 text-primary"}),"Discovery"]}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"form-control",children:[e.jsx("label",{className:"label text-sm",children:"Target Pubkey"}),e.jsx("input",{className:"input input-bordered w-full",placeholder:"npub1...",value:x,onChange:y=>c(y.target.value)})]}),e.jsxs("div",{className:"form-control",children:[e.jsx("label",{className:"label text-xs",children:"Service ID (Optional)"}),e.jsx("input",{className:"input input-bordered w-full",placeholder:"e.g. relay",value:i,onChange:y=>m(y.target.value)})]}),e.jsx("div",{className:"form-control",children:e.jsxs("label",{className:"cursor-pointer label justify-start gap-4",children:[e.jsx("span",{className:"label-text text-sm",children:"Show Expired"}),e.jsx("input",{type:"checkbox",className:"toggle toggle-sm toggle-warning",checked:Y,onChange:y=>t(y.target.checked)})]})}),e.jsx("div",{className:"form-control",children:e.jsxs("label",{className:"cursor-pointer label justify-start gap-4",children:[e.jsx("span",{className:"label-text text-sm font-bold text-secondary",children:"Network Only (WoT)"}),e.jsx("input",{type:"checkbox",className:"toggle toggle-sm toggle-secondary",checked:U,onChange:y=>ne(y.target.checked)})]})}),e.jsx("div",{className:"form-control",children:e.jsxs("label",{className:"cursor-pointer label justify-start gap-4",children:[e.jsx("span",{className:"label-text text-sm font-bold text-success",children:"Targeted to Me"}),e.jsx("input",{type:"checkbox",className:"toggle toggle-sm toggle-success",checked:Z,onChange:y=>ce(y.target.checked)})]})}),e.jsxs("button",{className:"btn btn-primary w-full",onClick:()=>us(),disabled:p==="verifying"||p==="resolving",children:[p!=="idle"&&p!=="complete"&&e.jsx("span",{className:"loading loading-spinner"}),"Run Discovery"]})]}),R&&e.jsxs("div",{className:"alert alert-error mt-4 text-xs",children:[e.jsx(He,{className:"w-4 h-4 flex-shrink-0"}),e.jsx("span",{children:R})]}),e.jsxs("div",{className:"mt-4 bg-base-300 p-3 rounded-box font-mono text-[10px] max-h-32 overflow-y-auto",children:[l.length===0&&e.jsx("span",{className:"opacity-50",children:"Idle..."}),l.map((y,N)=>e.jsx("div",{className:"mb-1",dangerouslySetInnerHTML:{__html:de(y)}},N))]}),A.length>0&&e.jsx("div",{className:"mt-6 space-y-6",children:(()=>{const y={};return A.forEach(N=>{(y[N.pubkey]=y[N.pubkey]||[]).push(N)}),Object.entries(y).map(([N,d])=>{const T=is(N),W=re.npubEncode(N),ee=Math.max(...d.map(J=>J.created_at)),V=new Date(ee*1e3).toLocaleString(),q={};d.forEach(J=>{var oe;const se=(((oe=J.tags.find(be=>be[0]==="d"))==null?void 0:oe[1])||"unknown").replace(/-locator$/,"").replace(/-loc$/,"");q[se]||(q[se]={locators:[],attestations:[],revocations:[]}),J.kind===30059?(!q[se].service||J.created_at>q[se].service.created_at)&&(q[se].service=J):J.kind===30058?(q[se].locators.length===0||J.created_at>q[se].locators[0].created_at)&&(q[se].locators=[J]):J.kind===30060?q[se].attestations.push(J):J.kind===30061&&q[se].revocations.push(J)});const ie=Object.keys(q).sort().filter(J=>{const F=q[J];if(!(Y||F.service&&!Ne(F.service)||F.locators.some(oe=>!Ne(oe))))return!1;if(Z){const oe=F.service&&ue[F.service.id],be=F.locators.some(je=>ue[je.id]);if(!oe&&!be)return!1}return U?!!(v(N)||F.attestations.some(oe=>v(oe.pubkey))):!0});return ie.length===0?null:e.jsx("div",{className:"card bg-base-100 border border-base-300 w-full overflow-hidden shadow-sm",children:e.jsxs("div",{className:"card-body p-3",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-2 mb-3 pb-2 border-b border-base-200",children:[e.jsxs("div",{className:"flex items-center gap-3 min-w-0",children:[e.jsx("div",{className:"avatar placeholder",children:e.jsx("div",{className:"bg-neutral text-neutral-content rounded-full w-8",children:e.jsx("span",{dangerouslySetInnerHTML:{__html:de(T.slice(0,2).toUpperCase())}})})}),e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"font-bold text-sm truncate",dangerouslySetInnerHTML:{__html:de(T)}}),(v(N)||d.some(J=>J.kind===30060&&v(J.pubkey)))&&e.jsxs("div",{className:"badge badge-secondary badge-xs gap-1",children:[e.jsx(ve,{className:"w-2 h-2"})," Network Trusted"]})]}),e.jsx("div",{className:"text-[9px] opacity-50 truncate",dangerouslySetInnerHTML:{__html:de(W)}})]})]}),e.jsxs("div",{className:"text-[9px] opacity-40 font-mono text-right sm:text-left",children:["Last Update: ",V]})]}),e.jsx("div",{className:"space-y-4",children:ie.map(J=>{var De,$e;const F=q[J],se=F.service&&(Be(F.service.tags)??!F.service.tags.find(M=>M[0]==="u")),oe=F.service&&ue[F.service.id],be=F.service&&Ne(F.service),je=F.revocations.length>0,ps=w(N,J),Ae=F.attestations.filter(M=>v(M.pubkey)),fe=E.includes((De=F.service)==null?void 0:De.id)||F.attestations.some(M=>M.pubkey===u);return e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between px-1",children:[e.jsxs("div",{className:"flex flex-col min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsxs("span",{className:Q("font-black text-[10px] uppercase truncate",je?"text-error line-through":"opacity-70"),children:["Service: ",e.jsx("span",{dangerouslySetInnerHTML:{__html:de(J)}})]}),je&&e.jsx("div",{className:"badge badge-error badge-xs scale-75 font-bold",children:"REVOKED"}),be&&e.jsx("div",{className:"badge badge-error badge-xs scale-75",children:"EXPIRED"}),F.service&&(()=>{try{const M=JSON.parse(F.service.content);if(M.v>1)return e.jsxs("div",{className:"badge badge-warning badge-xs scale-75",title:"Newer protocol version detected",children:["v",M.v," !"]})}catch{}return null})()]}),Ae.length>0&&e.jsxs("span",{className:"text-[8px] text-secondary font-bold",children:["✓ Trusted by ",Ae.length," in your network"]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[F.service&&e.jsxs("button",{className:Q("btn btn-xs gap-1 p-0 h-auto min-h-0",fe?"text-success":"btn-ghost text-secondary"),title:fe?"You have attested to this":"Attest to this service",onClick:()=>!fe&&ms(F.service),disabled:fe,children:[e.jsx(Rs,{className:"w-3 h-3"}),e.jsx("span",{className:"text-[9px]",children:fe?"Attested":"Attest"})]}),e.jsxs("label",{className:"flex items-center gap-1 cursor-pointer",children:[e.jsx("span",{className:"text-[9px] opacity-50",children:"Track"}),e.jsx("input",{type:"checkbox",className:"checkbox checkbox-xs",checked:ps,onChange:M=>M.target.checked?C(N,J):k(N,J)})]})]})]}),e.jsxs("div",{className:`border ${be?"border-error bg-error/5":"border-base-200"} rounded-box overflow-hidden`,children:[e.jsx("div",{className:"p-2 bg-base-200/30",children:F.service?e.jsxs("div",{className:"collapse collapse-arrow bg-base-100 border border-base-200 rounded-box shadow-xs",children:[e.jsx("input",{type:"checkbox"}),e.jsxs("div",{className:"collapse-title text-[10px] font-bold py-1 min-h-0 flex items-center gap-2",children:["NCC-02 Record",se&&e.jsx(ze,{className:Q("w-3 h-3",oe?"text-success":"text-warning")}),se&&oe&&e.jsx("span",{className:"text-[8px] text-success uppercase",children:"Authorized"})]}),e.jsx("div",{className:"collapse-content",children:e.jsx("pre",{className:"text-[9px] bg-black text-green-500 p-2 rounded mt-1 overflow-x-auto",children:JSON.stringify(F.service,null,2)})})]}):e.jsx("div",{className:"text-[9px] opacity-50 px-2 italic",children:"No NCC-02"})}),e.jsxs("div",{className:"p-2 space-y-2",children:[($e=F.service)==null?void 0:$e.tags.filter(M=>M[0]==="u").map((M,we)=>e.jsxs("div",{className:"flex items-center justify-between gap-2 p-2 bg-base-200/50 rounded-lg",children:[e.jsxs("div",{className:"flex flex-col min-w-0 flex-1",children:[e.jsx("span",{className:"text-[9px] font-mono truncate",dangerouslySetInnerHTML:{__html:de(M[1])}}),K[M[1]]&&e.jsx("span",{className:Q("text-[8px] font-bold",K[M[1]]==="error"?"text-error":K[M[1]]==="loading"?"animate-pulse":"text-success"),children:K[M[1]]==="loading"?"Probing...":K[M[1]]==="error"?"Offline":`${K[M[1]]}ms`})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("button",{className:"btn btn-xs btn-ghost",onClick:()=>Oe(M[1]),children:"Probe"}),e.jsx("button",{className:"btn btn-xs btn-secondary flex-shrink-0",onClick:()=>Ee(M[1],{pubkey:N,id:J}),children:"Connect"})]})]},we)),F.locators.map(M=>{const we=ue[M.id],_e=!M.content.trim().startsWith("{"),ke=z[M.id],Pe=Ne(M);if(!Y&&Pe)return null;let Ke=[];try{const ae=ke||(_e?null:JSON.parse(M.content));ae!=null&&ae.endpoints&&(Ke=ae.endpoints)}catch{}return e.jsx("div",{className:`border-l-2 ${we?"border-success":Pe?"border-error":"border-primary"} pl-2 ml-1`,children:e.jsxs("div",{className:"collapse collapse-arrow bg-base-100 border border-base-200 rounded-box",children:[e.jsx("input",{type:"checkbox"}),e.jsxs("div",{className:"collapse-title text-[10px] py-1 min-h-0 flex flex-wrap items-center gap-1",children:[e.jsx("span",{children:"📍 NCC-05"}),we&&e.jsx("div",{className:"badge badge-success badge-xs scale-75",children:"FOR YOU"}),Pe&&e.jsx("div",{className:"badge badge-error badge-xs scale-75",children:"EXPIRED"}),_e&&!ke&&e.jsx("div",{className:"badge badge-warning badge-xs scale-75",children:"LOCKED"})]}),e.jsx("div",{className:"collapse-content",children:_e&&!ke?e.jsx("button",{className:"btn btn-xs btn-neutral w-full mt-1",onClick:ae=>{ae.stopPropagation(),ds(M)},children:"Decrypt"}):e.jsxs("div",{className:"space-y-2 mt-1",children:[Ke.map((ae,xs)=>{let G=ae.url||ae.uri;G&&!G.includes("://")&&(G=G.includes(".onion")?`ws://${G}`:`wss://${G}`);const Me=G&&(G.startsWith("ws")||G.startsWith("wss"));return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsxs("button",{className:"btn btn-xs btn-primary w-full flex flex-col items-start h-auto py-2 gap-1",onClick:()=>Me?Ee(G,{pubkey:N,id:J}):window.open(G,"_blank"),children:[e.jsxs("div",{className:"flex items-center gap-1 font-bold",children:[" ",ae.family==="onion"&&"🧅"," Connect ",e.jsx("span",{dangerouslySetInnerHTML:{__html:de(ae.type||(Me?"Relay":"Web"))}})]}),e.jsx("div",{className:"text-[8px] opacity-70 truncate w-full",dangerouslySetInnerHTML:{__html:de(G)}})]}),e.jsxs("div",{className:"flex items-center justify-between px-1",children:[e.jsx("button",{className:"text-[8px] link opacity-50",onClick:()=>Oe(G),children:"Probe Health"}),K[G]&&e.jsx("span",{className:Q("text-[8px] font-bold",K[G]==="error"?"text-error":K[G]==="loading"?"animate-pulse":"text-success"),children:K[G]==="loading"?"Probing...":K[G]==="error"?"Offline":`${K[G]}ms`})]})]},xs)}),e.jsx("pre",{className:"text-[8px] bg-black text-green-500 p-2 rounded overflow-x-auto",children:JSON.stringify(ke||M,null,2)})]})})]})},M.id)})]})]})]},J)})})]})},N)})})()}),_&&p==="complete"&&e.jsxs("div",{className:"mt-6 p-4 bg-base-200 rounded-box border border-success flex flex-col gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ve,{className:"text-success w-6 h-6 flex-shrink-0"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h4",{className:"font-bold text-xs",children:"Target Resolved"}),e.jsx("p",{className:"text-[10px] opacity-70 truncate font-mono",dangerouslySetInnerHTML:{__html:de(_.url||_.uri)}})]})]}),e.jsx("button",{className:"btn btn-success btn-sm w-full",onClick:()=>Ee(),children:"Connect to Relay"})]})]})})}const ge=a=>a.replace(/[&<>"']/g,s=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[s]);function ct({relayUrl:a}){const[s,P]=n.useState([]),[h,u]=n.useState({}),[o,f]=n.useState("disconnected"),[g,C]=n.useState(null),[w,k]=n.useState("desc"),[v,x]=n.useState(!1),{isFollowing:c}=cs(),i=n.useRef(new qe),m=n.useRef([]),p=n.useRef(null),[O,l]=n.useState(0),I=r=>{m.current.push(r),!p.current&&(p.current=setTimeout(()=>{const _=[...m.current];m.current=[],p.current=null,P(L=>{let A=[...L],S=!1;return _.forEach(b=>{var H;if(b.kind>=3e4&&b.kind<4e4){const z=((H=b.tags.find(Y=>Y[0]==="d"))==null?void 0:H[1])||"",te=A.findIndex(Y=>{var t;return Y.pubkey===b.pubkey&&Y.kind===b.kind&&(((t=Y.tags.find(E=>E[0]==="d"))==null?void 0:t[1])||"")===z});te!==-1?b.created_at>A[te].created_at&&(A[te]=b,S=!0):(A.push(b),S=!0)}else A.find(z=>z.id===b.id)||(A.push(b),S=!0)}),S?j([...A],w):L})},100))},j=(r,_)=>[...r].sort((L,A)=>_==="asc"?L.created_at-A.created_at:A.created_at-L.created_at),R=()=>{const r=w==="asc"?"desc":"asc";k(r),P(_=>j(_,r))};return n.useEffect(()=>{P([]),u({}),f("disconnected"),C(null),m.current=[],p.current&&(clearTimeout(p.current),p.current=null)},[a]),n.useEffect(()=>{if(!a)return;let r,_,L=!1;return(async()=>{f("connecting"),C(null),a.includes(".onion")&&console.warn("[Feed] Tor connection requested. Handshake may take up to 45 seconds."),console.log(`[Feed] Subscribing to ${a}...`),r=i.current.subscribeMany([a],[{kinds:[1,30051,30053,30058,30059,30060,30061],limit:50}],{onevent(S){L=!0,I(S),f("connected")},oneose(){L=!0,console.log(`[Feed] EOSE received from ${a}.`),f("connected")},onclose(S){console.error("[Feed] Subscription closed:",S),L||(f("error"),C("Connection closed by relay or bridge."))}}),_=setTimeout(()=>{L||(console.error("[Feed] Connection watchdog triggered after 30s"),f("error"),C("Relay did not respond. Tor might be slow or the relay is empty."),r&&r.close())},3e4)})(),()=>{_&&clearTimeout(_),r&&r.close()}},[a,O]),n.useEffect(()=>{if(!a||s.length===0)return;const r=[...new Set(s.map(L=>L.pubkey))].filter(L=>!h[L]);if(r.length===0)return;const _=i.current.subscribeMany([a],[{kinds:[0],authors:r}],{onevent(L){try{const A=JSON.parse(L.content);u(S=>({...S,[L.pubkey]:A}))}catch{}},oneose(){}});return()=>{_.close()}},[s.length,a]),a?e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex flex-col bg-base-100 p-4 rounded-box shadow-sm border border-base-200 gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:`badge ${o==="connected"?"badge-success":o==="connecting"?"badge-warning":"badge-error"} badge-xs animate-pulse`}),e.jsxs("div",{className:"flex flex-col min-w-0",children:[e.jsx("span",{className:"font-mono text-sm font-bold truncate max-w-[200px] sm:max-w-md",children:a}),e.jsxs("span",{className:"text-xs opacity-50 capitalize",children:[o," ",o==="connected"&&`(${s.length} events)`]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"form-control mr-2 hidden sm:flex",children:e.jsxs("label",{className:"cursor-pointer label justify-start gap-2",children:[e.jsx("span",{className:"label-text text-[10px] font-bold opacity-50 uppercase",children:"Network Only"}),e.jsx("input",{type:"checkbox",className:"toggle toggle-xs toggle-secondary",checked:v,onChange:r=>x(r.target.checked)})]})}),e.jsxs("button",{className:"btn btn-sm btn-ghost gap-2",onClick:R,title:w==="desc"?"Showing Newest First":"Showing Oldest First",children:[e.jsx(Is,{className:Q("w-4 h-4",w==="asc"&&"rotate-180 transition-transform")}),w==="desc"?e.jsx(Ts,{className:"w-3 h-3"}):e.jsx(Os,{className:"w-3 h-3"})]}),o==="error"?e.jsxs("button",{className:"btn btn-sm btn-error",onClick:()=>l(r=>r+1),children:[e.jsx(he,{className:"w-4 h-4 mr-2"}),"Retry"]}):e.jsxs("button",{className:`btn btn-sm btn-ghost ${o==="connecting"?"loading":""}`,onClick:()=>l(r=>r+1),disabled:o==="connecting",children:[e.jsx(he,{className:"w-4 h-4"}),e.jsx("span",{className:"hidden sm:inline ml-2",children:"Refresh"})]})]})]}),o==="connected"&&s.length>0&&e.jsxs("div",{className:"flex flex-wrap gap-2 pt-2 border-t border-base-200",children:[e.jsx("div",{className:"text-[10px] uppercase font-bold opacity-30 w-full mb-1",children:"Content Summary"}),[1,30051,30053,30058,30059,30060,30061].map(r=>{const _=s.filter(L=>L.kind===r).length;return _===0?null:e.jsxs("div",{className:"badge badge-ghost badge-sm text-[10px] gap-1",children:["Kind ",r,": ",e.jsx("span",{className:"font-bold",children:_})]},r)})]})]}),o==="error"&&e.jsxs("div",{className:"alert alert-error text-sm",children:[e.jsx(Ls,{className:"w-4 h-4 flex-shrink-0"}),e.jsxs("span",{children:["Failed to connect: ",g]})]}),e.jsx("div",{className:"space-y-4",children:s.filter(r=>!v||c(r.pubkey)).map(r=>{var K;const _=h[r.pubkey],L=(_==null?void 0:_.display_name)||(_==null?void 0:_.name)||r.pubkey.slice(0,8),A=c(r.pubkey),S=r.tags.some(D=>D[0]==="ttl"),b=r.tags.some(D=>D[0]==="private"&&D[1]==="true"),H=r.tags.some(D=>D[0]==="exp"),z=r.kind===30058&&(S||b),te=r.kind===30059&&H,Y=r.kind===30060,t=r.kind===30061,E=r.kind===30053,$=r.kind===30051;return e.jsx("div",{className:"card bg-base-100 shadow-sm border border-base-200 overflow-hidden",children:e.jsx("div",{className:"card-body p-3 sm:p-4",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"avatar flex-shrink-0",children:e.jsx("div",{className:"w-10 h-10 rounded-full bg-base-300",children:_!=null&&_.picture?e.jsx("img",{src:_.picture,alt:L,onError:D=>D.currentTarget.src=`https://api.dicebear.com/7.x/identicon/svg?seed=${r.pubkey}`}):e.jsx("div",{className:"flex items-center justify-center w-full h-full text-base-content/30 bg-base-200",children:e.jsx(As,{className:"w-5 h-5"})})})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between mb-1 gap-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"font-bold text-sm truncate text-primary",dangerouslySetInnerHTML:{__html:ge(L)}}),A&&e.jsx("div",{className:"badge badge-secondary badge-xs gap-1",title:"You follow this author",children:e.jsx(ve,{className:"w-2 h-2"})})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-1",children:[z&&e.jsx("div",{className:"badge badge-primary badge-xs scale-90 sm:scale-100",children:"NCC-05 LOCATOR"}),te&&e.jsx("div",{className:"badge badge-secondary badge-xs scale-90 sm:scale-100",children:"NCC-02 SERVICE"}),Y&&e.jsx("div",{className:"badge badge-accent badge-xs scale-90 sm:scale-100",children:"NCC-02 ATTEST"}),t&&e.jsx("div",{className:"badge badge-error badge-xs scale-90 sm:scale-100",children:"NCC-02 REVOKE"}),E&&e.jsx("div",{className:"badge badge-info badge-xs scale-90 sm:scale-100",children:"NCC-01 DETAIL"}),$&&e.jsx("div",{className:"badge badge-neutral badge-xs scale-90 sm:scale-100",children:"NCC-00 REPT"}),r.kind===1&&e.jsx("div",{className:"badge badge-ghost badge-xs opacity-50 text-[8px]",children:"NOTE"}),!z&&!te&&!Y&&!t&&!E&&!$&&r.kind>1&&e.jsxs("div",{className:"badge badge-ghost badge-xs opacity-50 text-[8px]",children:["KIND ",r.kind]}),e.jsx("div",{className:"text-[9px] opacity-40 whitespace-nowrap font-mono ml-auto sm:ml-0",children:new Date(r.created_at*1e3).toLocaleTimeString()})]})]}),e.jsx("div",{className:"text-sm leading-relaxed mt-1",children:r.kind===1?e.jsx("p",{className:"whitespace-pre-wrap break-words",dangerouslySetInnerHTML:{__html:ge(r.content)}}):e.jsxs("div",{className:"bg-base-200/50 p-2 rounded border border-base-300 text-xs font-mono overflow-x-auto",children:[e.jsx("div",{className:"font-bold mb-1 opacity-50 italic text-[10px]",children:z?"Service Locator (NCC-05)":te?"Service Record (NCC-02)":Y?"Service Attestation (NCC-02)":t?"Service Revocation (NCC-02)":E?"Service Detail (NCC-01)":$?"Succession Report (NCC-00)":`Event Kind ${r.kind}`}),e.jsxs("div",{className:"flex gap-2 mb-1",children:[e.jsx("span",{className:"opacity-50",children:"d-tag:"}),e.jsx("span",{className:"font-bold",dangerouslySetInnerHTML:{__html:ge(((K=r.tags.find(D=>D[0]==="d"))==null?void 0:K[1])||"none")}})]}),z&&r.content.startsWith("{")&&e.jsx("div",{className:"mt-1 space-y-1",children:(()=>{var D;try{return(D=JSON.parse(r.content).endpoints)==null?void 0:D.map((ne,Z)=>e.jsxs("div",{className:"text-[10px] bg-base-300/50 p-1 rounded border border-base-400/30 flex items-center justify-between",children:[e.jsx("span",{className:"truncate flex-1",dangerouslySetInnerHTML:{__html:ge(ne.url||ne.uri)}}),e.jsx("span",{className:"badge badge-outline badge-xs opacity-50 ml-1",dangerouslySetInnerHTML:{__html:ge(ne.type)}})]},Z))}catch{return null}})()}),e.jsxs("div",{className:"opacity-70 mt-1 truncate max-w-full",children:[e.jsx("span",{className:"opacity-50 mr-1",children:"Content:"}),e.jsx("span",{dangerouslySetInnerHTML:{__html:ge(r.content.slice(0,80))}}),r.content.length>80&&"..."]})]})})]})]})})},r.id)})})]}):e.jsxs("div",{className:"flex flex-col items-center justify-center h-64 text-base-content/50 border-2 border-dashed border-base-300 rounded-box",children:[e.jsx(Ve,{className:"w-12 h-12 mb-4"}),e.jsx("h3",{className:"font-bold text-lg",children:"No Relay Connected"}),e.jsx("p",{children:"Use the Service Discovery tab to find and connect to a relay."})]})}function ot(){const{signEvent:a,method:s}=me(),{ncc05Publisher:P}=pe(),[h,u]=n.useState(!1),[o,f]=n.useState(""),[g,C]=n.useState(!1),[w,k]=n.useState(""),[v,x]=n.useState({loading:!1,services:[]}),[c,i]=n.useState({type:"ws",url:"",priority:1,family:"onion"}),m=async()=>{x(l=>({...l,loading:!0}));try{const I=await(await fetch("http://localhost:3005/inventory")).json();I&&I.services&&x({loading:!1,services:I.services})}catch{console.warn("Sidecar not detected at localhost:3005"),x({loading:!1,services:[]}),alert("NCC Sidecar not detected on localhost:3005. Ensure it is running.")}},p=l=>{i({type:l.type||"ws",url:l.onion_address||"",priority:1,family:"onion"})};if(s==="readonly")return e.jsx("div",{className:"alert alert-warning",children:"Read-only users cannot publish. Please login with an extension or nsec."});const O=async()=>{C(!0),k("");try{const l=o.split(",").map(j=>j.trim()).filter(j=>j).map(j=>j.startsWith("npub")?re.decode(j).data:j),I={v:1,ttl:3600,updated_at:Math.floor(Date.now()/1e3),endpoints:[c],...h&&{privaterecipients:l}};await P.publish(B.load(),a,I,{public:!h,identifier:"addr",recipientPubkey:l[0]}),k(`Service Published ${h?"Privately":"Publicly"}!`)}catch(l){console.error(l),alert("Publish failed: "+l.message)}finally{C(!1)}};return e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{className:"card bg-base-300 border border-base-content/10 shadow-sm",children:e.jsxs("div",{className:"card-body p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ie,{className:"text-secondary w-5 h-5"}),e.jsx("h3",{className:"font-bold text-sm",children:"NCC Sidecar Integration"})]}),e.jsx("button",{className:Q("btn btn-xs btn-outline btn-secondary",v.loading&&"loading"),onClick:m,children:v.loading?"Detecting...":"Detect Local Services"})]}),v.services.length>0&&e.jsxs("div",{className:"mt-3 space-y-2 fade-in",children:[e.jsx("p",{className:"text-[10px] opacity-60 uppercase font-bold tracking-widest px-1",children:"Local Services Found"}),v.services.map((l,I)=>e.jsxs("div",{className:"flex items-center justify-between p-2 bg-base-100 rounded border border-base-200",children:[e.jsxs("div",{className:"flex flex-col min-w-0",children:[e.jsx("span",{className:"text-xs font-bold truncate",children:l.name||l.id}),e.jsx("span",{className:"text-[9px] font-mono opacity-50 truncate",children:l.onion_address})]}),e.jsx("button",{className:"btn btn-xs btn-ghost text-secondary",onClick:()=>p(l),children:"Import"})]},I))]})]})}),e.jsx("div",{className:"card bg-base-100 shadow-lg border border-base-200",children:e.jsxs("div",{className:"card-body",children:[e.jsxs("h3",{className:"card-title text-xl mb-4 flex items-center",children:[e.jsx(Ds,{className:"w-6 h-6 mr-2 text-secondary"}),"Publish Service (NCC-05)"]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"form-control",children:[e.jsx("label",{className:"label",children:"Type"}),e.jsxs("select",{className:"select select-bordered",value:c.type,onChange:l=>i({...c,type:l.target.value}),children:[e.jsx("option",{value:"https",children:"HTTPS"}),e.jsx("option",{value:"http",children:"HTTP"}),e.jsx("option",{value:"tcp",children:"TCP"}),e.jsx("option",{value:"ipfs",children:"IPFS"}),e.jsx("option",{value:"ws",children:"WebSocket (Relay)"})]})]}),e.jsxs("div",{className:"form-control",children:[e.jsx("label",{className:"label",children:"Family"}),e.jsxs("select",{className:"select select-bordered",value:c.family,onChange:l=>i({...c,family:l.target.value}),children:[e.jsx("option",{value:"ipv4",children:"IPv4"}),e.jsx("option",{value:"ipv6",children:"IPv6"}),e.jsx("option",{value:"onion",children:"Onion (Tor)"})]})]}),e.jsxs("div",{className:"form-control md:col-span-2",children:[e.jsx("label",{className:"label",children:"URI / URL"}),e.jsx("input",{className:"input input-bordered",placeholder:c.family==="onion"?"xyz...onion":"192.168.1.1",value:c.url,onChange:l=>i({...c,url:l.target.value})})]}),e.jsxs("div",{className:"form-control md:col-span-2 border-t pt-4 mt-2",children:[e.jsxs("label",{className:"label cursor-pointer justify-start gap-4",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-secondary",checked:h,onChange:l=>u(l.target.checked)}),e.jsx("span",{className:"label-text font-bold",children:"Private Discovery (Encrypted)"})]}),e.jsx("p",{className:"text-[10px] opacity-60 mb-2",children:"Private records are only visible to specific pubkeys using NIP-44 encryption."}),h&&e.jsxs("div",{className:"fade-in",children:[e.jsx("label",{className:"label text-xs",children:"Recipients (Comma separated npubs)"}),e.jsx("textarea",{className:"textarea textarea-bordered w-full h-20 text-xs font-mono",placeholder:"npub1..., npub1...",value:o,onChange:l=>f(l.target.value)})]})]})]}),e.jsx("div",{className:"card-actions justify-end mt-4",children:e.jsxs("button",{className:"btn btn-secondary",onClick:O,disabled:g||!c.url||h&&!o,children:[g?e.jsx("span",{className:"loading loading-spinner"}):e.jsx($s,{className:"w-4 h-4 mr-2"}),h?"Publish Private":"Publish to Network"]})}),w&&e.jsx("div",{className:"alert alert-success mt-2",children:w})]})})]})}function it(){const{ncc02Resolver:a}=pe(),[s,P]=n.useState(""),[h,u]=n.useState("media"),[o,f]=n.useState(null),[g,C]=n.useState(!1),[w,k]=n.useState(null),v=async()=>{C(!0),k(null),f(null);try{let x=s;if(s.startsWith("npub")){const{data:i}=re.decode(s);x=i}const c=await a.resolve(x,h,{requireAttestation:!1,minLevel:"self"});f(c)}catch(x){console.error(x),k(x.message||"Verification failed")}finally{C(!1)}};return e.jsx("div",{className:"card bg-base-100 shadow-lg border border-base-200",children:e.jsxs("div",{className:"card-body",children:[e.jsxs("h3",{className:"card-title text-xl mb-4 flex items-center",children:[e.jsx(Qe,{className:"w-6 h-6 mr-2 text-accent"}),"Trust Explorer (NCC-02)"]}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"form-control",children:[e.jsx("label",{className:"label",children:"Target Pubkey"}),e.jsx("input",{className:"input input-bordered",placeholder:"npub1...",value:s,onChange:x=>P(x.target.value)})]}),e.jsxs("div",{className:"form-control",children:[e.jsx("label",{className:"label",children:"Service ID"}),e.jsx("input",{className:"input input-bordered",placeholder:"media",value:h,onChange:x=>u(x.target.value)})]}),e.jsx("button",{className:"btn btn-accent",onClick:v,disabled:g,children:g?e.jsx("span",{className:"loading loading-spinner"}):"Verify Service"})]}),w&&e.jsxs("div",{className:"alert alert-error mt-4",children:[e.jsx(Ks,{className:"w-6 h-6"}),e.jsx("span",{children:w})]}),o&&e.jsxs("div",{className:"mt-6 p-4 bg-base-200 rounded-box",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(Ms,{className:"text-success w-5 h-5"}),e.jsx("span",{className:"font-bold",children:"Service Verified"})]}),e.jsx("pre",{className:"text-xs overflow-auto bg-base-300 p-2 rounded",children:JSON.stringify(o,null,2)})]})]})})}const lt="modulepreload",dt=function(a){return"/"+a},Ue={},Je=function(s,P,h){let u=Promise.resolve();if(P&&P.length>0){document.getElementsByTagName("link");const f=document.querySelector("meta[property=csp-nonce]"),g=(f==null?void 0:f.nonce)||(f==null?void 0:f.getAttribute("nonce"));u=Promise.allSettled(P.map(C=>{if(C=dt(C),C in Ue)return;Ue[C]=!0;const w=C.endsWith(".css"),k=w?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${C}"]${k}`))return;const v=document.createElement("link");if(v.rel=w?"stylesheet":lt,w||(v.as="script"),v.crossOrigin="",v.href=C,g&&v.setAttribute("nonce",g),document.head.appendChild(v),w)return new Promise((x,c)=>{v.addEventListener("load",x),v.addEventListener("error",()=>c(new Error(`Unable to preload CSS for ${C}`)))})}))}function o(f){const g=new Event("vite:preloadError",{cancelable:!0});if(g.payload=f,window.dispatchEvent(g),!g.defaultPrevented)throw f}return u.then(f=>{for(const g of f||[])g.status==="rejected"&&o(g.reason);return s().catch(o)})},Re=a=>a.replace(/[&<>"']/g,s=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[s]);function ut(){const{pubkey:a,method:s,signEvent:P,encryptNip44:h}=me(),{pool:u}=pe(),[o,f]=n.useState(()=>{const t=localStorage.getItem("ncc_managed_identities");return t?JSON.parse(t):[]}),[g,C]=n.useState({label:"",key:""}),[w,k]=n.useState(!1),[v,x]=n.useState(!1),[c,i]=n.useState([]),[m,p]=n.useState(null),[O,l]=n.useState(""),[I,j]=n.useState(!1),[R,r]=n.useState({ownerPubkey:"",serviceId:"relay",endpoint:"",isPrivate:!1,recipients:""}),_=t=>{var E;return Uint8Array.from(((E=t.match(/.{1,2}/g))==null?void 0:E.map($=>parseInt($,16)))||[])},L=t=>Array.from(t).map(E=>E.toString(16).padStart(2,"0")).join(""),A=[...a?[a]:[],...o.map(t=>t.pubkey)],S=async()=>{if(A.length!==0){x(!0);try{const t=await u.querySync(B.load(),{kinds:[30053,30058,30059,30060,30061],authors:A}),E=new Map;t.forEach($=>{var U;const K=((U=$.tags.find(ne=>ne[0]==="d"))==null?void 0:U[1])||"",D=`${$.kind}:${$.pubkey}:${K}`;(!E.has(D)||$.created_at>E.get(D).created_at)&&E.set(D,$)}),i(Array.from(E.values()))}catch(t){console.error("Scan failed",t)}finally{x(!1)}}};n.useEffect(()=>{localStorage.setItem("ncc_managed_identities",JSON.stringify(o))},[o]),n.useEffect(()=>{S()},[o.length,a]);const b=()=>{try{let t=g.key,E;if(g.key.startsWith("nsec")){const $=re.decode(g.key);t=L($.data),E=t,t=xe($.data)}else if(g.key.startsWith("npub"))t=re.decode(g.key).data;else if(g.key.length===64)try{const $=_(g.key),K=xe($);E=t,t=K}catch{}if(A.includes(t)){alert("Identity already managed");return}f([...o,{pubkey:t,privkey:E,label:g.label||`Service ${t.slice(0,4)}`}]),C({label:"",key:""}),k(!1)}catch{alert("Invalid Key Format")}},H=t=>{f(o.filter(E=>E.pubkey!==t))},z=async()=>{const t=o.find(E=>E.pubkey===R.ownerPubkey)||(R.ownerPubkey===a?{pubkey:a,privkey:void 0}:null);if(!t)return alert("Select a managed identity first.");x(!0);try{const E=new ws(t.privkey||{getPublicKey:()=>Promise.resolve(t.pubkey),signEvent:D=>P(D)});let $;if(R.isPrivate&&R.recipients){const D=R.recipients.split(",").map(U=>U.trim()).filter(U=>U).map(U=>U.startsWith("npub")?re.decode(U).data:U);if(D.length>0){const U=t.privkey||{nip44Encrypt:(ne,Z)=>h(ne,Z),getPublicKey:()=>Promise.resolve(t.pubkey)};$=await ks(U,D)}}const K=await E.createServiceRecord({serviceId:R.serviceId,endpoint:R.endpoint||void 0,expiryDays:30,isPrivate:R.isPrivate,privateRecipients:$});await u.publish(B.load(),K),alert("NCC-02 Service Record Published!"),j(!1),S()}catch(E){alert("Publish failed: "+E.message)}finally{x(!1)}},te=async t=>{const E=o.find(K=>K.pubkey===t.pubkey),$=E==null?void 0:E.privkey;x(!0);try{const K=Math.floor(Date.now()/1e3),D={kind:t.kind,created_at:K,tags:[...t.tags],content:t.content,pubkey:t.pubkey},U=D.tags.findIndex(ce=>ce[0]==="exp");if(U!==-1){const ce=K+2592e3;D.tags[U]=["exp",ce.toString()]}if(D.tags.findIndex(ce=>ce[0]==="private")===-1){const ce=D.tags.some(ue=>ue[0]==="u");D.tags.push(["private",ce?"false":"true"])}let Z;if($){const{finalizeEvent:ce}=await Je(async()=>{const{finalizeEvent:ue}=await import("./pure-ei6B17Q0.js");return{finalizeEvent:ue}},__vite__mapDeps([0,1]));Z=ce(D,_($))}else Z=await P(D);await u.publish(B.load(),Z),alert("Record Renewed!"),S()}catch(K){alert("Renew failed: "+K.message)}finally{x(!1)}},Y=async()=>{if(!m)return;const t=o.find($=>$.pubkey===m.pubkey),E=t==null?void 0:t.privkey;x(!0);try{const $={kind:m.kind,content:O,created_at:Math.floor(Date.now()/1e3),tags:[...m.tags],pubkey:m.pubkey};let K;if(E){const{finalizeEvent:D}=await Je(async()=>{const{finalizeEvent:U}=await import("./pure-ei6B17Q0.js");return{finalizeEvent:U}},__vite__mapDeps([0,1]));K=D($,_(E))}else K=await P($);await u.publish(B.load(),K),alert("Record Updated!"),p(null),S()}catch($){alert("Update failed: "+$.message)}finally{x(!1)}};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ie,{className:"text-primary w-6 h-6"}),e.jsx("h2",{className:"text-xl font-bold",children:"Infrastructure Inventory"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("button",{className:Q("btn btn-sm",v&&"loading"),onClick:S,children:[e.jsx(he,{className:"w-4 h-4"})," Scan Network"]}),e.jsxs("button",{className:"btn btn-sm btn-secondary",onClick:()=>j(!I),children:[e.jsx(ve,{className:"w-4 h-4"})," Publish NCC-02"]}),e.jsxs("button",{className:"btn btn-sm btn-primary",onClick:()=>k(!w),children:[e.jsx(Ge,{className:"w-4 h-4"})," Add Identity"]})]})]}),I&&e.jsx("div",{className:"card bg-base-100 shadow-lg border border-secondary/20",children:e.jsxs("div",{className:"card-body p-4",children:[e.jsx("h3",{className:"font-bold text-sm mb-3",children:"Publish NCC-02 Service Record"}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"form-control",children:[e.jsx("label",{className:"label text-[10px] font-bold uppercase opacity-50",children:"Identity"}),e.jsxs("select",{className:"select select-bordered select-sm",value:R.ownerPubkey,onChange:t=>r({...R,ownerPubkey:t.target.value}),children:[e.jsx("option",{value:"",children:"Select Managed Identity..."}),A.map(t=>{var E;return e.jsx("option",{value:t,children:((E=o.find($=>$.pubkey===t))==null?void 0:E.label)||(t===a?"Primary Account":t.slice(0,12))},t)})]})]}),e.jsxs("div",{className:"form-control",children:[e.jsx("label",{className:"label text-[10px] font-bold uppercase opacity-50",children:"Service ID"}),e.jsx("input",{className:"input input-bordered input-sm",placeholder:"e.g. relay, media, api",value:R.serviceId,onChange:t=>r({...R,serviceId:t.target.value})})]}),e.jsxs("div",{className:"form-control sm:col-span-2",children:[e.jsx("label",{className:"label text-[10px] font-bold uppercase opacity-50",children:"Endpoint URL (Optional)"}),e.jsx("input",{className:"input input-bordered input-sm font-mono",placeholder:"wss://... or https://...",value:R.endpoint,onChange:t=>r({...R,endpoint:t.target.value})})]}),e.jsx("div",{className:"form-control sm:col-span-2",children:e.jsxs("label",{className:"label cursor-pointer justify-start gap-4",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-secondary toggle-sm",checked:R.isPrivate,onChange:t=>r({...R,isPrivate:t.target.checked})}),e.jsx("span",{className:"label-text font-bold text-xs",children:"Private Service (Requires 'private' tag)"})]})}),R.isPrivate&&e.jsxs("div",{className:"form-control sm:col-span-2 fade-in",children:[e.jsx("label",{className:"label text-[10px] font-bold uppercase opacity-50",children:"Authorized Recipients (npubs, comma separated)"}),e.jsx("textarea",{className:"textarea textarea-bordered h-20 text-xs font-mono",placeholder:"npub1..., npub1...",value:R.recipients,onChange:t=>r({...R,recipients:t.target.value})})]})]}),e.jsxs("div",{className:"card-actions justify-end mt-4",children:[e.jsx("button",{className:"btn btn-sm btn-ghost",onClick:()=>j(!1),children:"Cancel"}),e.jsx("button",{className:Q("btn btn-sm btn-secondary",v&&"loading"),onClick:z,disabled:!R.ownerPubkey,children:"Publish Record"})]})]})}),w&&e.jsx("div",{className:"card bg-base-100 shadow-lg border border-primary/20",children:e.jsxs("div",{className:"card-body p-4",children:[e.jsx("h3",{className:"font-bold text-sm mb-3",children:"Add Identity to Manage"}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsx("input",{className:"input input-bordered input-sm",placeholder:"Label (e.g. My Media Node)",value:g.label,onChange:t=>C({...g,label:t.target.value})}),e.jsx("input",{className:"input input-bordered input-sm font-mono",placeholder:"nsec / npub / hex",value:g.key,onChange:t=>C({...g,key:t.target.value})})]}),e.jsxs("div",{className:"card-actions justify-end mt-2",children:[e.jsx("button",{className:"btn btn-sm btn-ghost",onClick:()=>k(!1),children:"Cancel"}),e.jsx("button",{className:"btn btn-sm btn-primary",onClick:b,disabled:!g.key,children:"Add"})]})]})}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[e.jsx("div",{className:"card bg-base-300 border border-base-content/10",children:e.jsxs("div",{className:"card-body p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ve,{className:"text-success w-4 h-4"}),e.jsx("span",{className:"font-bold text-sm",children:"Primary Account (Active Session)"})]}),e.jsx("div",{className:"badge badge-outline badge-xs",children:s})]}),e.jsx("div",{className:"text-[10px] font-mono opacity-50 truncate",children:a})]})}),o.map(t=>e.jsx("div",{className:"card bg-base-100 border border-base-200",children:e.jsxs("div",{className:"card-body p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(Ws,{className:Q("w-4 h-4",t.privkey?"text-warning":"opacity-30")}),e.jsx("span",{className:"font-bold text-sm truncate",dangerouslySetInnerHTML:{__html:Re(t.label)}})]}),e.jsx("button",{className:"btn btn-ghost btn-xs text-error",onClick:()=>H(t.pubkey),children:e.jsx(Xe,{className:"w-3 h-3"})})]}),e.jsx("div",{className:"text-[10px] font-mono opacity-50 truncate",children:t.pubkey})]})},t.pubkey))]}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("h3",{className:"text-sm font-bold opacity-50 uppercase tracking-widest px-1",children:"Found Services"}),c.length===0&&!v&&e.jsxs("div",{className:"text-center p-12 bg-base-200 rounded-box border-2 border-dashed border-base-300",children:[e.jsx(Ie,{className:"w-12 h-12 mx-auto mb-2 opacity-20"}),e.jsx("p",{className:"opacity-50",children:"No NCC records found for these identities."})]}),e.jsx("div",{className:"grid grid-cols-1 gap-3",children:c.map(t=>{var ne;const E=o.find(Z=>Z.pubkey===t.pubkey),$=E?E.label:"Primary",K=((ne=t.tags.find(Z=>Z[0]==="d"))==null?void 0:ne[1])||"none",D=t.kind===30059&&t.tags.find(Z=>Z[0]==="exp"&&parseInt(Z[1])<Date.now()/1e3),U=t.kind===30059&&Be(t.tags);return e.jsx("div",{className:Q("card bg-base-100 border shadow-sm",D?"border-error/30":"border-base-200"),children:e.jsxs("div",{className:"card-body p-4",children:[e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{className:"flex flex-col gap-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"badge badge-neutral badge-xs font-bold",dangerouslySetInnerHTML:{__html:Re($)}}),e.jsxs("span",{className:"text-sm font-black uppercase",children:["Service: ",e.jsx("span",{dangerouslySetInnerHTML:{__html:Re(K)}})]}),U&&e.jsx(ze,{className:"w-3 h-3 text-warning"}),D&&e.jsx("div",{className:"badge badge-error badge-xs",children:"EXPIRED"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("span",{className:"text-[10px] opacity-50",children:["Kind ",t.kind]}),e.jsx("span",{className:"text-[10px] opacity-30 font-mono",children:new Date(t.created_at*1e3).toLocaleString()})]})]}),e.jsx("div",{className:"flex gap-2",children:((E==null?void 0:E.privkey)||t.pubkey===a&&s!=="readonly")&&e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"btn btn-xs btn-outline btn-primary",onClick:()=>te(t),disabled:v,children:"Renew"}),e.jsx("button",{className:"btn btn-xs btn-outline",onClick:()=>{p(t),l(t.content)},disabled:v,children:"Edit"})]})})]}),e.jsx("pre",{className:"text-[9px] bg-black text-green-500 p-2 rounded mt-2 overflow-x-auto max-h-24",children:JSON.stringify(t,null,2)})]})},t.id)})})]}),m&&e.jsx("div",{className:"modal modal-open",children:e.jsxs("div",{className:"modal-box max-w-2xl",children:[e.jsx("h3",{className:"font-bold text-lg mb-2",children:"Edit Record Content"}),e.jsxs("p",{className:"text-xs opacity-50 mb-4",children:["Editing Kind ",m.kind," for ",m.pubkey.slice(0,12),"..."]}),e.jsx("textarea",{className:"textarea textarea-bordered w-full h-64 font-mono text-xs",value:O,onChange:t=>l(t.target.value)}),e.jsxs("div",{className:"modal-action",children:[e.jsx("button",{className:"btn btn-ghost",onClick:()=>p(null),children:"Cancel"}),e.jsx("button",{className:Q("btn btn-primary",v&&"loading"),onClick:Y,children:"Save Changes"})]})]})})]})}function mt(){const{pool:a,ncc05Resolver:s}=pe(),{pubkey:P,privkey:h,signEvent:u}=me(),[o,f]=n.useState(()=>B.load()),[g,C]=n.useState({}),[w,k]=n.useState(""),[v,x]=n.useState(!1),[c,i]=n.useState(!1),[m,p]=n.useState(null),[O,l]=n.useState(null),I=S=>{var b;return Uint8Array.from(((b=S.match(/.{1,2}/g))==null?void 0:b.map(H=>parseInt(H,16)))||[])},j=async()=>{x(!0);const S={};for(const b of o)try{const H=await a.querySync([b],{kinds:[30058,30059],limit:1});S[b]={url:b,lastSeen:Date.now(),status:"online",supportsNCC:H.length>0}}catch{S[b]={url:b,lastSeen:Date.now(),status:"offline",supportsNCC:!1}}C(S),x(!1)};n.useEffect(()=>{j()},[]);const R=async()=>{var H;if(console.log("[Settings] handleAdd called with:",w),!w)return;let S=w.trim();if(S.startsWith("npub")){console.log("[Settings] Detected npub input, starting identity-centric resolution..."),i(!0),p("Fetching authored records...");try{const{data:z}=re.decode(S),te=z,Y={getPublicKey:async()=>P||"",signEvent:async E=>u(E),getConversationKey:async E=>{if(!h)throw new Error("Decryption requires NSEC or active remote signer");return X.getConversationKey(I(h),E)}};p("Resolving latest locator...");const t=await s.resolveLatest(te,h||Y);if(t&&((H=t.endpoints)==null?void 0:H.length)>0){p(null);const E=t.endpoints.map($=>$.url);l(E)}else{p("Checking public service records...");const E=B.load(),K=(await a.querySync(E,{kinds:[30059],authors:[te],limit:10})).sort((U,ne)=>ne.created_at-U.created_at)[0],D=K==null?void 0:K.tags.filter(U=>U[0]==="u").map(U=>U[1]);if(D&&D.length>0)l(D);else throw new Error("No valid infrastructure endpoints found for this identity.")}}catch(z){console.error("[Settings] Resolution Error:",z),alert("Resolution failed: "+z.message)}finally{i(!1),p(null),j()}return}let b=S;b.startsWith("ws")||(b=`wss://${b}`),B.add(b),f(B.load()),k(""),j()},r=S=>{B.remove(S),f(B.load())},_=()=>{B.restoreDefaults(),f(B.load()),j()},L=S=>{let b=S;if(b.includes("://")||(b=b.includes(".onion")?`ws://${b}`:`wss://${b}`),b.includes(".onion")&&!b.includes("/bridge?target=")){const H=b;b=`ws://${window.location.host}/bridge?target=${encodeURIComponent(H)}`,console.log(`[Settings] 🧅 Bridging: ${H} -> ${b}`)}B.add(b),f(B.load()),l(null),k(""),j()},A=()=>{l(null),k("")};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Fs,{className:"text-primary w-6 h-6"}),e.jsx("h2",{className:"text-xl font-bold",children:"Network Settings"})]}),e.jsxs("button",{className:Q("btn btn-sm btn-ghost",v&&"loading"),onClick:j,disabled:v,children:[e.jsx(he,{className:"w-4 h-4 mr-2"})," Refresh Health"]})]}),e.jsx("div",{className:"card bg-base-100 shadow-sm border border-base-200",children:e.jsxs("div",{className:"card-body",children:[e.jsxs("h3",{className:"card-title text-sm opacity-70 uppercase mb-4 flex items-center gap-2",children:[e.jsx(Us,{className:"w-4 h-4"})," Bootstrap Relays"]}),e.jsx("div",{className:"space-y-3",children:o.map(S=>{const b=g[S];return e.jsxs("div",{className:"flex items-center justify-between p-3 bg-base-200/50 rounded-lg border border-base-300",children:[e.jsxs("div",{className:"flex flex-col min-w-0",children:[e.jsx("span",{className:"font-mono text-xs font-bold truncate",children:S}),e.jsxs("div",{className:"flex items-center gap-2 mt-1",children:[(b==null?void 0:b.status)==="online"?e.jsxs("span",{className:"badge badge-success badge-xs gap-1",children:[e.jsx(Js,{className:"w-2 h-2"})," Online"]}):(b==null?void 0:b.status)==="offline"?e.jsxs("span",{className:"badge badge-error badge-xs gap-1",children:[e.jsx(He,{className:"w-2 h-2"})," Offline"]}):e.jsx("span",{className:"badge badge-ghost badge-xs",children:"Checking..."}),(b==null?void 0:b.supportsNCC)&&e.jsx("span",{className:"badge badge-primary badge-xs",children:"NCC-Ready"})]})]}),e.jsx("button",{className:"btn btn-ghost btn-xs text-error",onClick:()=>r(S),title:"Remove Relay",children:e.jsx(Xe,{className:"w-4 h-4"})})]},S)})}),O?e.jsxs("div",{className:"mt-4 p-4 bg-base-200 rounded-box border border-primary/20 fade-in",children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsx("h4",{className:"text-xs font-bold uppercase opacity-70",children:"Discovered Endpoints"}),e.jsx("button",{className:"btn btn-xs btn-ghost",onClick:A,children:"Cancel"})]}),e.jsx("div",{className:"space-y-2",children:O.map((S,b)=>e.jsxs("div",{className:"flex items-center justify-between p-2 bg-base-100 rounded border border-base-300",children:[e.jsx("span",{className:"text-[10px] font-mono truncate flex-1 pr-2",children:S}),e.jsx("button",{className:"btn btn-xs btn-primary",onClick:()=>L(S),children:"Add This"})]},b))}),e.jsx("p",{className:"text-[9px] opacity-50 mt-3 italic",children:"Select an endpoint above to add it to your bootstrap list. Onion addresses will be automatically bridged."})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex gap-2 mt-4",children:[e.jsx("input",{className:"input input-bordered input-sm flex-1 font-mono text-xs",placeholder:"wss://... or npub1...",value:w,onChange:S=>k(S.target.value),onKeyDown:S=>S.key==="Enter"&&R(),disabled:c}),e.jsx("button",{className:Q("btn btn-sm btn-primary",c&&"loading"),onClick:R,disabled:c||!w,children:c?"Resolving...":e.jsxs(e.Fragment,{children:[e.jsx(Ge,{className:"w-4 h-4 mr-1"})," Add"]})})]}),m&&e.jsxs("div",{className:"flex items-center gap-2 mt-2 px-1 text-[10px] text-primary animate-pulse font-bold",children:[e.jsx(he,{className:"w-3 h-3 animate-spin"}),m]})]}),e.jsx("div",{className:"card-actions justify-start mt-2",children:e.jsx("button",{className:"btn btn-link btn-xs opacity-50",onClick:_,children:"Restore Default Relays"})})]})}),e.jsx("div",{className:"card bg-base-100 shadow-sm border border-base-200",children:e.jsxs("div",{className:"card-body",children:[e.jsxs("h3",{className:"card-title text-sm opacity-70 uppercase mb-4 flex items-center gap-2",children:[e.jsx(Qe,{className:"w-4 h-4"})," Security & Protocol"]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-bold",children:"NCC Protocol Version"}),e.jsx("p",{className:"text-xs opacity-50",children:"Current supported schema version"})]}),e.jsx("div",{className:"badge badge-neutral",children:"v1.0"})]}),e.jsxs("div",{className:"alert alert-info py-2 text-[10px] leading-tight",children:[e.jsx(he,{className:"w-3 h-3 flex-shrink-0"}),e.jsxs("span",{children:["Discovery currently prioritizes relays with the ",e.jsx("b",{children:"NCC-Ready"})," badge. These relays have recently returned valid NCC events."]})]})]})]})})]})}function pt(){const{pubkey:a,logout:s,method:P}=me(),{tracked:h,findTracked:u}=ns(),[o,f]=n.useState("discovery"),[g,C]=n.useState(()=>localStorage.getItem("ncc_active_relay")),[w,k]=n.useState(()=>{const m=localStorage.getItem("ncc_active_service");return m?JSON.parse(m):null}),[v,x]=n.useState(null);n.useEffect(()=>{const m=async()=>{try{const O=new WebSocket(`ws://${window.location.host}/bridge?target=internal-ping`),l=setTimeout(()=>O.close(),2e3);O.onopen=()=>{clearTimeout(l),x(!0),O.close()},O.onerror=()=>{clearTimeout(l),x(!1)}}catch{x(!1)}};m();const p=setInterval(m,3e4);return()=>clearInterval(p)},[]);const c=(m,p)=>{if(C(m),localStorage.setItem("ncc_active_relay",m),p){const O={pubkey:p.pubkey,serviceId:p.id};k(O),localStorage.setItem("ncc_active_service",JSON.stringify(O))}f("feed")},i=()=>{s(),C(null),k(null),localStorage.removeItem("ncc_active_relay"),localStorage.removeItem("ncc_active_service")};return n.useEffect(()=>{var O,l;if(!w||!g)return;const m=u(w.pubkey,w.serviceId);if(!m)return;let p=(O=m.decryptedPayload)==null?void 0:O.endpoints;if(!p&&((l=m.latestEvent)!=null&&l.content.startsWith("{")))try{p=JSON.parse(m.latestEvent.content).endpoints}catch(I){console.error("Failed to parse NCC-05 content",I)}if(p&&p.length>0){const I=[...p].sort((R,r)=>R.priority-r.priority)[0];let j=I.url||I.uri;if(j.includes("://")||(j=j.includes(".onion")?`ws://${j}`:`wss://${j}`),j.startsWith("http")&&(j=j.replace("http","ws")),g.includes("/bridge?target=")){const R=decodeURIComponent(new URL(g).searchParams.get("target")||"");if(j!==R){const r=`ws://${window.location.host}/bridge?target=${encodeURIComponent(j)}`;console.log(`🚀 NCC Auto-Update: Relay endpoint changed from ${R} to ${j} (via Bridge)`),C(r),localStorage.setItem("ncc_active_relay",r)}}else j!==g&&(console.log(`🚀 NCC Auto-Update: Relay endpoint changed from ${g} to ${j}`),C(j),localStorage.setItem("ncc_active_relay",j))}},[h,w,g]),a?e.jsxs("div",{className:"min-h-screen bg-base-200",children:[e.jsxs("div",{className:"navbar bg-base-100 shadow-sm px-4",children:[e.jsx("div",{className:"flex-1",children:e.jsxs("a",{className:"btn btn-ghost text-xl gap-2",children:[e.jsx(qs,{className:"text-primary"}),"NCC Client ",e.jsx("span",{className:"text-xs opacity-50 font-normal",children:"PoC"})]})}),e.jsxs("div",{className:"flex-none gap-4",children:[e.jsxs("div",{className:`badge badge-sm gap-1 hidden sm:flex ${v===!0?"badge-success":v===!1?"badge-error":"badge-ghost"}`,children:[e.jsx("div",{className:`w-1.5 h-1.5 rounded-full ${v===!0?"bg-success-content animate-pulse":"bg-base-content opacity-30"}`}),v===!0?"Bridge":"Bridge Offline"]}),g&&e.jsxs("div",{className:"badge badge-success gap-2 hidden sm:flex",children:[e.jsx(Ve,{className:"w-3 h-3"}),g.includes("target=")?"Bridged Onion":g]}),e.jsxs("div",{className:"flex flex-col items-end text-xs hidden sm:flex",children:[e.jsx("span",{className:"opacity-70",children:P==="readonly"?"Read Only":"Authenticated"}),e.jsxs("span",{className:"font-mono",children:[a.slice(0,8),"...",a.slice(-4)]})]}),e.jsx("button",{className:"btn btn-ghost btn-circle",onClick:i,title:"Logout",children:e.jsx(Bs,{className:"w-5 h-5"})})]})]}),e.jsxs("div",{className:"container mx-auto p-4 max-w-4xl",children:[e.jsxs("div",{role:"tablist",className:"tabs tabs-boxed mb-6 bg-base-100 p-2 overflow-x-auto flex-nowrap",children:[e.jsx("a",{role:"tab",className:Q("tab",o==="discovery"&&"tab-active"),onClick:()=>f("discovery"),children:"Discovery (02+05)"}),e.jsxs("a",{role:"tab",className:Q("tab",o==="feed"&&"tab-active"),onClick:()=>f("feed"),children:["Feed ",g&&"🟢"]}),e.jsx("a",{role:"tab",className:Q("tab",o==="publish"&&"tab-active"),onClick:()=>f("publish"),children:"Publish"}),e.jsx("a",{role:"tab",className:Q("tab",o==="trust"&&"tab-active"),onClick:()=>f("trust"),children:"Trust Explorer"}),e.jsx("a",{role:"tab",className:Q("tab",o==="inventory"&&"tab-active"),onClick:()=>f("inventory"),children:"My Inventory"}),e.jsx("a",{role:"tab",className:Q("tab",o==="settings"&&"tab-active"),onClick:()=>f("settings"),children:"Settings"})]}),e.jsxs("div",{className:"fade-in",children:[o==="discovery"&&e.jsx(rt,{onConnect:c}),o==="feed"&&e.jsx(ct,{relayUrl:g}),o==="publish"&&(P==="readonly"?e.jsx("div",{className:"alert",children:"Read-only users cannot publish. Please login with NIP-07 or Private Key."}):e.jsx(ot,{})),o==="trust"&&e.jsx(it,{}),o==="inventory"&&e.jsx(ut,{}),o==="settings"&&e.jsx(mt,{})]})]})]}):e.jsx("div",{className:"min-h-screen bg-base-200 flex items-center justify-center p-4",children:e.jsx(et,{})})}function xt(){return e.jsx(Ys,{children:e.jsx(Zs,{children:e.jsx(at,{children:e.jsx(st,{children:e.jsx(tt,{children:e.jsx(pt,{})})})})})})}Te.createRoot(document.getElementById("root")).render(e.jsx(bs.StrictMode,{children:e.jsx(xt,{})}));
|