From 1862e2c411ecb12b633ab25672cd3c0decbe6b3e Mon Sep 17 00:00:00 2001 From: Silent Mode Date: Mon, 28 Sep 2026 01:21:47 +0200 Subject: [PATCH] feat(portal): the name's settings show what its subdomains serve, and let you change it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-name tab was a DNS record table: eight record types, of which the stack reads exactly one, and then only as a last resort when a name carries no content record. Everything else was signed, stored and read by nobody — furniture that looked like configuration. Meanwhile the thing a name owner actually has, a folder tree that already answers on matching subdomains, was not visible anywhere and could not be changed. The tab now leads with what answers today: the apex, every folder in the name's storage next to the subdomain it serves on, and which of those a rule overrides. Below it, the rules — point a subdomain at a different folder, redirect it, or switch it off. Classic DNS keeps its table, behind a disclosure that says plainly what those records do today and what they are waiting for. Nobody loses a record they published; they just stop being the first thing a name owner is asked to think about. The table gains a Host column, so records can belong to a subdomain rather than only the apex. Both halves are one signed manifest and one publish button — they always were one file, and two buttons for it only ever invited a half-saved state. Labels and values are separated in the generated rows so the words translate and the owner's own folder and URL do not. The signer accepted v1 manifests only, which would have rejected every publish from this screen. --- js/bns-register.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/bns-register.js b/js/bns-register.js index 7d8435d..721c883 100644 --- a/js/bns-register.js +++ b/js/bns-register.js @@ -4,4 +4,4 @@ import{generateBip39Mnemonic as Bn,deriveSeedFromBip39Mnemonic as Ae,deriveHdPri `))>=0;){let s=this.buf.slice(0,n).trim();if(this.buf=this.buf.slice(n+1),s)try{this._handle(JSON.parse(s))}catch{}}let o=this.buf.trim();if(o)try{let s=JSON.parse(o);this._handle(s),this.buf=""}catch{}}call(e,n=[]){let o=++this.id;return new Promise((s,r)=>{this.pending.set(o,{resolve:s,reject:r}),this.ws.send(JSON.stringify({id:o,method:e,params:n})+` `),setTimeout(()=>{this.pending.has(o)&&(this.pending.delete(o),r(new Error(`electrum timeout: ${e}`)))},2e4)})}close(){try{this.ws.close()}catch{}}};async function Le(t=Rt,e){let n=[];for(let o of t)try{return await new Zt(o,e).connect()}catch(s){n.push(`${o}: ${s?.message??s}`)}throw Fn(t.length,n)}function Fn(t,e){let n=new Error(`no electrum server reachable (tried ${t}). These use non-standard ports, which some networks and VPNs block: ${e.join(` - `)}`);return n.code="NO_ELECTRUM",n.failures=e,n}import{cashAddressToLockingBytecode as $n,lockingBytecodeToCashAddress as Mn,sha256 as Hn,hash160 as ps,binToHex as Kn,hexToBin as fs}from"@bitauth/libauth";function De(t){return Kn(Hn.hash(t).slice().reverse())}function L(t){let e=$n(t);if(typeof e=="string")throw new Error(`bad address "${t}": ${e}`);return e.bytecode}function Wn(t){return De(L(t))}function z(t){let e=L(t),n=String(t).includes(":")?t.split(":")[0]:T.prefix,o=Mn({bytecode:e,prefix:n,tokenSupport:!0});if(typeof o=="string")throw new Error(`cannot token-encode "${t}": ${o}`);return o.address}async function Ce(t,e){let n=L(e),o=De(n);return(await t.call("blockchain.scripthash.listunspent",[o,"include_tokens"])).map(r=>({txid:r.tx_hash,vout:r.tx_pos,satoshis:BigInt(r.value),height:r.height,address:e,lockingBytecode:n,token:r.token_data?{category:r.token_data.category,amount:BigInt(r.token_data.amount??0),nft:r.token_data.nft?{capability:r.token_data.nft.capability,commitment:r.token_data.nft.commitment}:void 0}:void 0}))}async function j(t,e){let n=[];for(let o of e)n.push(...await Ce(t,o));return n}async function st(t,e){return t.call("blockchain.transaction.broadcast",[e])}import{binToHex as Dt,hexToBin as X,utf8ToBin as ft,binToUtf8 as Ue,encodeTransaction as Gn,decodeTransaction as ws}from"@bitauth/libauth";var zn="BNS1",dt=T.beacon,ne=T.tldBeacon,B=600n,N=1000n,W=546n,te="bch",ee=200,qn=/^[a-z0-9-]{1,32}$/,Fe=/^[a-z0-9-]{1,16}$/;function Tt(t){let e=String(t).toLowerCase().trim().replace(/^\.+/,"").replace(/\.+$/,"");if(!Fe.test(e))throw new Error(`invalid TLD "${t}" (allowed: [a-z0-9-]{1,16})`);return e}var Lt=class extends Error{constructor(e){super(e),this.name="NoGenesisInputError",this.code="NO_GENESIS_INPUT"}},J=class extends Error{constructor(e,{needSats:n,haveSats:o}={}){super(e),this.name="InsufficientFundsError",this.code="INSUFFICIENT_FUNDS",this.needSats=n,this.haveSats=o}};function H(t){let e=String(t).toLowerCase().trim().replace(/\.$/,"").split(".").filter(Boolean),n,o;if(e.length===0)throw new Error(`invalid name "${t}"`);if(e.length===1?(n=e[0],o=te):(o=e[e.length-1],n=e[e.length-2]),!qn.test(n)||!Fe.test(o))throw new Error(`invalid name "${t}" (allowed: