basalt-sync 0.1.8 → 0.2.1

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.
package/README.md CHANGED
@@ -24,10 +24,24 @@ Any sync decision that appears in a shell is in the wrong file.
24
24
  bun install
25
25
  bun run test # everything, including against a real server
26
26
  bun run typecheck
27
+ bun run format # prettier, and CI fails on anything it would change
28
+ bun run stress # the hostile suite: kills, collisions, awkward names
27
29
  bun run bench # throughput and bandwidth, reported not asserted
28
30
  bun run bench:sync # a whole vault, timed and checked
29
31
  ```
30
32
 
33
+ `src/stress/*.stress.ts` is excluded from `bun run test` and has its own config.
34
+ It is not a slower copy of the unit tests: it kills the server while it is
35
+ committing, lets two devices edit the same twenty notes without either seeing
36
+ the other, and writes the filenames people actually have, emoji and right to
37
+ left and combining marks included. Every defect this project has found in
38
+ itself was silent and only appeared when the system ran, which is why this
39
+ exists and why CI runs it as its own job.
40
+
41
+ The benchmarks run under bun and the shipped CLI runs under node, which is not a
42
+ detail: two of the largest wins in `docs/benchmark.md` were each invisible under
43
+ one of the two engines. Anything measuring the chunker should be run under both.
44
+
31
45
  The tests need a Go toolchain. `src/core/server-harness.test.ts` builds
32
46
  `cmd/basaltd`, runs it on a loopback port, and talks to it with the real
33
47
  transport. Nothing is mocked, and its assertions are checked by asking the
@@ -37,7 +51,7 @@ correct server never would.
37
51
 
38
52
  ## The headless client
39
53
 
40
- `bun run build` produces `dist/basalt.mjs`: one 85 KB file with nothing to
54
+ `bun run build` produces `dist/basalt.mjs`: one 91 KB file with nothing to
41
55
  install beside it, because everything is bundled and the only imports that
42
56
  survive are `node:` builtins. The npm package declares no dependencies at all. The command is `basalt`; the server's is `basaltd`, so a homelab can run both.
43
57
 
package/dist/basalt.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- var qn=Object.create;var Ct=Object.defineProperty;var Zn=Object.getOwnPropertyDescriptor;var Xn=Object.getOwnPropertyNames;var Yn=Object.getPrototypeOf,Qn=Object.prototype.hasOwnProperty;var er=(t,e)=>()=>{try{return e||t((e={exports:{}}).exports,e),e.exports}catch(n){throw e=0,n}};var tr=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Xn(e))!Qn.call(t,i)&&i!==n&&Ct(t,i,{get:()=>e[i],enumerable:!(r=Zn(e,i))||r.enumerable});return t};var nr=(t,e,n)=>(n=t!=null?qn(Yn(t)):{},tr(e||!t||!t.__esModule?Ct(n,"default",{value:t,enumerable:!0}):n,t));var ln=er((Wi,me)=>{var d=function(){this.Diff_Timeout=1,this.Diff_EditCost=4,this.Match_Threshold=.5,this.Match_Distance=1e3,this.Patch_DeleteThreshold=.5,this.Patch_Margin=4,this.Match_MaxBits=32},C=-1,T=1,k=0;d.Diff=function(t,e){return[t,e]};d.prototype.diff_main=function(t,e,n,r){typeof r>"u"&&(this.Diff_Timeout<=0?r=Number.MAX_VALUE:r=new Date().getTime()+this.Diff_Timeout*1e3);var i=r;if(t==null||e==null)throw new Error("Null input. (diff_main)");if(t==e)return t?[new d.Diff(k,t)]:[];typeof n>"u"&&(n=!0);var s=n,o=this.diff_commonPrefix(t,e),a=t.substring(0,o);t=t.substring(o),e=e.substring(o),o=this.diff_commonSuffix(t,e);var l=t.substring(t.length-o);t=t.substring(0,t.length-o),e=e.substring(0,e.length-o);var c=this.diff_compute_(t,e,s,i);return a&&c.unshift(new d.Diff(k,a)),l&&c.push(new d.Diff(k,l)),this.diff_cleanupMerge(c),c};d.prototype.diff_compute_=function(t,e,n,r){var i;if(!t)return[new d.Diff(T,e)];if(!e)return[new d.Diff(C,t)];var s=t.length>e.length?t:e,o=t.length>e.length?e:t,a=s.indexOf(o);if(a!=-1)return i=[new d.Diff(T,s.substring(0,a)),new d.Diff(k,o),new d.Diff(T,s.substring(a+o.length))],t.length>e.length&&(i[0][0]=i[2][0]=C),i;if(o.length==1)return[new d.Diff(C,t),new d.Diff(T,e)];var l=this.diff_halfMatch_(t,e);if(l){var c=l[0],h=l[1],u=l[2],f=l[3],g=l[4],m=this.diff_main(c,u,n,r),v=this.diff_main(h,f,n,r);return m.concat([new d.Diff(k,g)],v)}return n&&t.length>100&&e.length>100?this.diff_lineMode_(t,e,r):this.diff_bisect_(t,e,r)};d.prototype.diff_lineMode_=function(t,e,n){var r=this.diff_linesToChars_(t,e);t=r.chars1,e=r.chars2;var i=r.lineArray,s=this.diff_main(t,e,!1,n);this.diff_charsToLines_(s,i),this.diff_cleanupSemantic(s),s.push(new d.Diff(k,""));for(var o=0,a=0,l=0,c="",h="";o<s.length;){switch(s[o][0]){case T:l++,h+=s[o][1];break;case C:a++,c+=s[o][1];break;case k:if(a>=1&&l>=1){s.splice(o-a-l,a+l),o=o-a-l;for(var u=this.diff_main(c,h,!1,n),f=u.length-1;f>=0;f--)s.splice(o,0,u[f]);o=o+u.length}l=0,a=0,c="",h="";break}o++}return s.pop(),s};d.prototype.diff_bisect_=function(t,e,n){for(var r=t.length,i=e.length,s=Math.ceil((r+i)/2),o=s,a=2*s,l=new Array(a),c=new Array(a),h=0;h<a;h++)l[h]=-1,c[h]=-1;l[o+1]=0,c[o+1]=0;for(var u=r-i,f=u%2!=0,g=0,m=0,v=0,x=0,w=0;w<s&&!(new Date().getTime()>n);w++){for(var A=-w+g;A<=w-m;A+=2){var b=o+A,S;A==-w||A!=w&&l[b-1]<l[b+1]?S=l[b+1]:S=l[b-1]+1;for(var M=S-A;S<r&&M<i&&t.charAt(S)==e.charAt(M);)S++,M++;if(l[b]=S,S>r)m+=2;else if(M>i)g+=2;else if(f){var $=o+u-A;if($>=0&&$<a&&c[$]!=-1){var E=r-c[$];if(S>=E)return this.diff_bisectSplit_(t,e,S,M,n)}}}for(var y=-w+v;y<=w-x;y+=2){var $=o+y,E;y==-w||y!=w&&c[$-1]<c[$+1]?E=c[$+1]:E=c[$-1]+1;for(var p=E-y;E<r&&p<i&&t.charAt(r-E-1)==e.charAt(i-p-1);)E++,p++;if(c[$]=E,E>r)x+=2;else if(p>i)v+=2;else if(!f){var b=o+u-y;if(b>=0&&b<a&&l[b]!=-1){var S=l[b],M=o+S-b;if(E=r-E,S>=E)return this.diff_bisectSplit_(t,e,S,M,n)}}}}return[new d.Diff(C,t),new d.Diff(T,e)]};d.prototype.diff_bisectSplit_=function(t,e,n,r,i){var s=t.substring(0,n),o=e.substring(0,r),a=t.substring(n),l=e.substring(r),c=this.diff_main(s,o,!1,i),h=this.diff_main(a,l,!1,i);return c.concat(h)};d.prototype.diff_linesToChars_=function(t,e){var n=[],r={};n[0]="";function i(l){for(var c="",h=0,u=-1,f=n.length;u<l.length-1;){u=l.indexOf(`
3
- `,h),u==-1&&(u=l.length-1);var g=l.substring(h,u+1);(r.hasOwnProperty?r.hasOwnProperty(g):r[g]!==void 0)?c+=String.fromCharCode(r[g]):(f==s&&(g=l.substring(h),u=l.length),c+=String.fromCharCode(f),r[g]=f,n[f++]=g),h=u+1}return c}var s=4e4,o=i(t);s=65535;var a=i(e);return{chars1:o,chars2:a,lineArray:n}};d.prototype.diff_charsToLines_=function(t,e){for(var n=0;n<t.length;n++){for(var r=t[n][1],i=[],s=0;s<r.length;s++)i[s]=e[r.charCodeAt(s)];t[n][1]=i.join("")}};d.prototype.diff_commonPrefix=function(t,e){if(!t||!e||t.charAt(0)!=e.charAt(0))return 0;for(var n=0,r=Math.min(t.length,e.length),i=r,s=0;n<i;)t.substring(s,i)==e.substring(s,i)?(n=i,s=n):r=i,i=Math.floor((r-n)/2+n);return i};d.prototype.diff_commonSuffix=function(t,e){if(!t||!e||t.charAt(t.length-1)!=e.charAt(e.length-1))return 0;for(var n=0,r=Math.min(t.length,e.length),i=r,s=0;n<i;)t.substring(t.length-i,t.length-s)==e.substring(e.length-i,e.length-s)?(n=i,s=n):r=i,i=Math.floor((r-n)/2+n);return i};d.prototype.diff_commonOverlap_=function(t,e){var n=t.length,r=e.length;if(n==0||r==0)return 0;n>r?t=t.substring(n-r):n<r&&(e=e.substring(0,n));var i=Math.min(n,r);if(t==e)return i;for(var s=0,o=1;;){var a=t.substring(i-o),l=e.indexOf(a);if(l==-1)return s;o+=l,(l==0||t.substring(i-o)==e.substring(0,o))&&(s=o,o++)}};d.prototype.diff_halfMatch_=function(t,e){if(this.Diff_Timeout<=0)return null;var n=t.length>e.length?t:e,r=t.length>e.length?e:t;if(n.length<4||r.length*2<n.length)return null;var i=this;function s(m,v,x){for(var w=m.substring(x,x+Math.floor(m.length/4)),A=-1,b="",S,M,$,E;(A=v.indexOf(w,A+1))!=-1;){var y=i.diff_commonPrefix(m.substring(x),v.substring(A)),p=i.diff_commonSuffix(m.substring(0,x),v.substring(0,A));b.length<p+y&&(b=v.substring(A-p,A)+v.substring(A,A+y),S=m.substring(0,x-p),M=m.substring(x+y),$=v.substring(0,A-p),E=v.substring(A+y))}return b.length*2>=m.length?[S,M,$,E,b]:null}var o=s(n,r,Math.ceil(n.length/4)),a=s(n,r,Math.ceil(n.length/2)),l;if(!o&&!a)return null;a?o?l=o[4].length>a[4].length?o:a:l=a:l=o;var c,h,u,f;t.length>e.length?(c=l[0],h=l[1],u=l[2],f=l[3]):(u=l[0],f=l[1],c=l[2],h=l[3]);var g=l[4];return[c,h,u,f,g]};d.prototype.diff_cleanupSemantic=function(t){for(var e=!1,n=[],r=0,i=null,s=0,o=0,a=0,l=0,c=0;s<t.length;)t[s][0]==k?(n[r++]=s,o=l,a=c,l=0,c=0,i=t[s][1]):(t[s][0]==T?l+=t[s][1].length:c+=t[s][1].length,i&&i.length<=Math.max(o,a)&&i.length<=Math.max(l,c)&&(t.splice(n[r-1],0,new d.Diff(C,i)),t[n[r-1]+1][0]=T,r--,r--,s=r>0?n[r-1]:-1,o=0,a=0,l=0,c=0,i=null,e=!0)),s++;for(e&&this.diff_cleanupMerge(t),this.diff_cleanupSemanticLossless(t),s=1;s<t.length;){if(t[s-1][0]==C&&t[s][0]==T){var h=t[s-1][1],u=t[s][1],f=this.diff_commonOverlap_(h,u),g=this.diff_commonOverlap_(u,h);f>=g?(f>=h.length/2||f>=u.length/2)&&(t.splice(s,0,new d.Diff(k,u.substring(0,f))),t[s-1][1]=h.substring(0,h.length-f),t[s+1][1]=u.substring(f),s++):(g>=h.length/2||g>=u.length/2)&&(t.splice(s,0,new d.Diff(k,h.substring(0,g))),t[s-1][0]=T,t[s-1][1]=u.substring(0,u.length-g),t[s+1][0]=C,t[s+1][1]=h.substring(g),s++),s++}s++}};d.prototype.diff_cleanupSemanticLossless=function(t){function e(g,m){if(!g||!m)return 6;var v=g.charAt(g.length-1),x=m.charAt(0),w=v.match(d.nonAlphaNumericRegex_),A=x.match(d.nonAlphaNumericRegex_),b=w&&v.match(d.whitespaceRegex_),S=A&&x.match(d.whitespaceRegex_),M=b&&v.match(d.linebreakRegex_),$=S&&x.match(d.linebreakRegex_),E=M&&g.match(d.blanklineEndRegex_),y=$&&m.match(d.blanklineStartRegex_);return E||y?5:M||$?4:w&&!b&&S?3:b||S?2:w||A?1:0}for(var n=1;n<t.length-1;){if(t[n-1][0]==k&&t[n+1][0]==k){var r=t[n-1][1],i=t[n][1],s=t[n+1][1],o=this.diff_commonSuffix(r,i);if(o){var a=i.substring(i.length-o);r=r.substring(0,r.length-o),i=a+i.substring(0,i.length-o),s=a+s}for(var l=r,c=i,h=s,u=e(r,i)+e(i,s);i.charAt(0)===s.charAt(0);){r+=i.charAt(0),i=i.substring(1)+s.charAt(0),s=s.substring(1);var f=e(r,i)+e(i,s);f>=u&&(u=f,l=r,c=i,h=s)}t[n-1][1]!=l&&(l?t[n-1][1]=l:(t.splice(n-1,1),n--),t[n][1]=c,h?t[n+1][1]=h:(t.splice(n+1,1),n--))}n++}};d.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;d.whitespaceRegex_=/\s/;d.linebreakRegex_=/[\r\n]/;d.blanklineEndRegex_=/\n\r?\n$/;d.blanklineStartRegex_=/^\r?\n\r?\n/;d.prototype.diff_cleanupEfficiency=function(t){for(var e=!1,n=[],r=0,i=null,s=0,o=!1,a=!1,l=!1,c=!1;s<t.length;)t[s][0]==k?(t[s][1].length<this.Diff_EditCost&&(l||c)?(n[r++]=s,o=l,a=c,i=t[s][1]):(r=0,i=null),l=c=!1):(t[s][0]==C?c=!0:l=!0,i&&(o&&a&&l&&c||i.length<this.Diff_EditCost/2&&o+a+l+c==3)&&(t.splice(n[r-1],0,new d.Diff(C,i)),t[n[r-1]+1][0]=T,r--,i=null,o&&a?(l=c=!0,r=0):(r--,s=r>0?n[r-1]:-1,l=c=!1),e=!0)),s++;e&&this.diff_cleanupMerge(t)};d.prototype.diff_cleanupMerge=function(t){t.push(new d.Diff(k,""));for(var e=0,n=0,r=0,i="",s="",o;e<t.length;)switch(t[e][0]){case T:r++,s+=t[e][1],e++;break;case C:n++,i+=t[e][1],e++;break;case k:n+r>1?(n!==0&&r!==0&&(o=this.diff_commonPrefix(s,i),o!==0&&(e-n-r>0&&t[e-n-r-1][0]==k?t[e-n-r-1][1]+=s.substring(0,o):(t.splice(0,0,new d.Diff(k,s.substring(0,o))),e++),s=s.substring(o),i=i.substring(o)),o=this.diff_commonSuffix(s,i),o!==0&&(t[e][1]=s.substring(s.length-o)+t[e][1],s=s.substring(0,s.length-o),i=i.substring(0,i.length-o))),e-=n+r,t.splice(e,n+r),i.length&&(t.splice(e,0,new d.Diff(C,i)),e++),s.length&&(t.splice(e,0,new d.Diff(T,s)),e++),e++):e!==0&&t[e-1][0]==k?(t[e-1][1]+=t[e][1],t.splice(e,1)):e++,r=0,n=0,i="",s="";break}t[t.length-1][1]===""&&t.pop();var a=!1;for(e=1;e<t.length-1;)t[e-1][0]==k&&t[e+1][0]==k&&(t[e][1].substring(t[e][1].length-t[e-1][1].length)==t[e-1][1]?(t[e][1]=t[e-1][1]+t[e][1].substring(0,t[e][1].length-t[e-1][1].length),t[e+1][1]=t[e-1][1]+t[e+1][1],t.splice(e-1,1),a=!0):t[e][1].substring(0,t[e+1][1].length)==t[e+1][1]&&(t[e-1][1]+=t[e+1][1],t[e][1]=t[e][1].substring(t[e+1][1].length)+t[e+1][1],t.splice(e+1,1),a=!0)),e++;a&&this.diff_cleanupMerge(t)};d.prototype.diff_xIndex=function(t,e){var n=0,r=0,i=0,s=0,o;for(o=0;o<t.length&&(t[o][0]!==T&&(n+=t[o][1].length),t[o][0]!==C&&(r+=t[o][1].length),!(n>e));o++)i=n,s=r;return t.length!=o&&t[o][0]===C?s:s+(e-i)};d.prototype.diff_prettyHtml=function(t){for(var e=[],n=/&/g,r=/</g,i=/>/g,s=/\n/g,o=0;o<t.length;o++){var a=t[o][0],l=t[o][1],c=l.replace(n,"&amp;").replace(r,"&lt;").replace(i,"&gt;").replace(s,"&para;<br>");switch(a){case T:e[o]='<ins style="background:#e6ffe6;">'+c+"</ins>";break;case C:e[o]='<del style="background:#ffe6e6;">'+c+"</del>";break;case k:e[o]="<span>"+c+"</span>";break}}return e.join("")};d.prototype.diff_text1=function(t){for(var e=[],n=0;n<t.length;n++)t[n][0]!==T&&(e[n]=t[n][1]);return e.join("")};d.prototype.diff_text2=function(t){for(var e=[],n=0;n<t.length;n++)t[n][0]!==C&&(e[n]=t[n][1]);return e.join("")};d.prototype.diff_levenshtein=function(t){for(var e=0,n=0,r=0,i=0;i<t.length;i++){var s=t[i][0],o=t[i][1];switch(s){case T:n+=o.length;break;case C:r+=o.length;break;case k:e+=Math.max(n,r),n=0,r=0;break}}return e+=Math.max(n,r),e};d.prototype.diff_toDelta=function(t){for(var e=[],n=0;n<t.length;n++)switch(t[n][0]){case T:e[n]="+"+encodeURI(t[n][1]);break;case C:e[n]="-"+t[n][1].length;break;case k:e[n]="="+t[n][1].length;break}return e.join(" ").replace(/%20/g," ")};d.prototype.diff_fromDelta=function(t,e){for(var n=[],r=0,i=0,s=e.split(/\t/g),o=0;o<s.length;o++){var a=s[o].substring(1);switch(s[o].charAt(0)){case"+":try{n[r++]=new d.Diff(T,decodeURI(a))}catch{throw new Error("Illegal escape in diff_fromDelta: "+a)}break;case"-":case"=":var l=parseInt(a,10);if(isNaN(l)||l<0)throw new Error("Invalid number in diff_fromDelta: "+a);var c=t.substring(i,i+=l);s[o].charAt(0)=="="?n[r++]=new d.Diff(k,c):n[r++]=new d.Diff(C,c);break;default:if(s[o])throw new Error("Invalid diff operation in diff_fromDelta: "+s[o])}}if(i!=t.length)throw new Error("Delta length ("+i+") does not equal source text length ("+t.length+").");return n};d.prototype.match_main=function(t,e,n){if(t==null||e==null||n==null)throw new Error("Null input. (match_main)");return n=Math.max(0,Math.min(n,t.length)),t==e?0:t.length?t.substring(n,n+e.length)==e?n:this.match_bitap_(t,e,n):-1};d.prototype.match_bitap_=function(t,e,n){if(e.length>this.Match_MaxBits)throw new Error("Pattern too long for this browser.");var r=this.match_alphabet_(e),i=this;function s(S,M){var $=S/e.length,E=Math.abs(n-M);return i.Match_Distance?$+E/i.Match_Distance:E?1:$}var o=this.Match_Threshold,a=t.indexOf(e,n);a!=-1&&(o=Math.min(s(0,a),o),a=t.lastIndexOf(e,n+e.length),a!=-1&&(o=Math.min(s(0,a),o)));var l=1<<e.length-1;a=-1;for(var c,h,u=e.length+t.length,f,g=0;g<e.length;g++){for(c=0,h=u;c<h;)s(g,n+h)<=o?c=h:u=h,h=Math.floor((u-c)/2+c);u=h;var m=Math.max(1,n-h+1),v=Math.min(n+h,t.length)+e.length,x=Array(v+2);x[v+1]=(1<<g)-1;for(var w=v;w>=m;w--){var A=r[t.charAt(w-1)];if(g===0?x[w]=(x[w+1]<<1|1)&A:x[w]=(x[w+1]<<1|1)&A|((f[w+1]|f[w])<<1|1)|f[w+1],x[w]&l){var b=s(g,w-1);if(b<=o)if(o=b,a=w-1,a>n)m=Math.max(1,2*n-a);else break}}if(s(g+1,n)>o)break;f=x}return a};d.prototype.match_alphabet_=function(t){for(var e={},n=0;n<t.length;n++)e[t.charAt(n)]=0;for(var n=0;n<t.length;n++)e[t.charAt(n)]|=1<<t.length-n-1;return e};d.prototype.patch_addContext_=function(t,e){if(e.length!=0){if(t.start2===null)throw Error("patch not initialized");for(var n=e.substring(t.start2,t.start2+t.length1),r=0;e.indexOf(n)!=e.lastIndexOf(n)&&n.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)r+=this.Patch_Margin,n=e.substring(t.start2-r,t.start2+t.length1+r);r+=this.Patch_Margin;var i=e.substring(t.start2-r,t.start2);i&&t.diffs.unshift(new d.Diff(k,i));var s=e.substring(t.start2+t.length1,t.start2+t.length1+r);s&&t.diffs.push(new d.Diff(k,s)),t.start1-=i.length,t.start2-=i.length,t.length1+=i.length+s.length,t.length2+=i.length+s.length}};d.prototype.patch_make=function(t,e,n){var r,i;if(typeof t=="string"&&typeof e=="string"&&typeof n>"u")r=t,i=this.diff_main(r,e,!0),i.length>2&&(this.diff_cleanupSemantic(i),this.diff_cleanupEfficiency(i));else if(t&&typeof t=="object"&&typeof e>"u"&&typeof n>"u")i=t,r=this.diff_text1(i);else if(typeof t=="string"&&e&&typeof e=="object"&&typeof n>"u")r=t,i=e;else if(typeof t=="string"&&typeof e=="string"&&n&&typeof n=="object")r=t,i=n;else throw new Error("Unknown call format to patch_make.");if(i.length===0)return[];for(var s=[],o=new d.patch_obj,a=0,l=0,c=0,h=r,u=r,f=0;f<i.length;f++){var g=i[f][0],m=i[f][1];switch(!a&&g!==k&&(o.start1=l,o.start2=c),g){case T:o.diffs[a++]=i[f],o.length2+=m.length,u=u.substring(0,c)+m+u.substring(c);break;case C:o.length1+=m.length,o.diffs[a++]=i[f],u=u.substring(0,c)+u.substring(c+m.length);break;case k:m.length<=2*this.Patch_Margin&&a&&i.length!=f+1?(o.diffs[a++]=i[f],o.length1+=m.length,o.length2+=m.length):m.length>=2*this.Patch_Margin&&a&&(this.patch_addContext_(o,h),s.push(o),o=new d.patch_obj,a=0,h=u,l=c);break}g!==T&&(l+=m.length),g!==C&&(c+=m.length)}return a&&(this.patch_addContext_(o,h),s.push(o)),s};d.prototype.patch_deepCopy=function(t){for(var e=[],n=0;n<t.length;n++){var r=t[n],i=new d.patch_obj;i.diffs=[];for(var s=0;s<r.diffs.length;s++)i.diffs[s]=new d.Diff(r.diffs[s][0],r.diffs[s][1]);i.start1=r.start1,i.start2=r.start2,i.length1=r.length1,i.length2=r.length2,e[n]=i}return e};d.prototype.patch_apply=function(t,e){if(t.length==0)return[e,[]];t=this.patch_deepCopy(t);var n=this.patch_addPadding(t);e=n+e+n,this.patch_splitMax(t);for(var r=0,i=[],s=0;s<t.length;s++){var o=t[s].start2+r,a=this.diff_text1(t[s].diffs),l,c=-1;if(a.length>this.Match_MaxBits?(l=this.match_main(e,a.substring(0,this.Match_MaxBits),o),l!=-1&&(c=this.match_main(e,a.substring(a.length-this.Match_MaxBits),o+a.length-this.Match_MaxBits),(c==-1||l>=c)&&(l=-1))):l=this.match_main(e,a,o),l==-1)i[s]=!1,r-=t[s].length2-t[s].length1;else{i[s]=!0,r=l-o;var h;if(c==-1?h=e.substring(l,l+a.length):h=e.substring(l,c+this.Match_MaxBits),a==h)e=e.substring(0,l)+this.diff_text2(t[s].diffs)+e.substring(l+a.length);else{var u=this.diff_main(a,h,!1);if(a.length>this.Match_MaxBits&&this.diff_levenshtein(u)/a.length>this.Patch_DeleteThreshold)i[s]=!1;else{this.diff_cleanupSemanticLossless(u);for(var f=0,g,m=0;m<t[s].diffs.length;m++){var v=t[s].diffs[m];v[0]!==k&&(g=this.diff_xIndex(u,f)),v[0]===T?e=e.substring(0,l+g)+v[1]+e.substring(l+g):v[0]===C&&(e=e.substring(0,l+g)+e.substring(l+this.diff_xIndex(u,f+v[1].length))),v[0]!==C&&(f+=v[1].length)}}}}}return e=e.substring(n.length,e.length-n.length),[e,i]};d.prototype.patch_addPadding=function(t){for(var e=this.Patch_Margin,n="",r=1;r<=e;r++)n+=String.fromCharCode(r);for(var r=0;r<t.length;r++)t[r].start1+=e,t[r].start2+=e;var i=t[0],s=i.diffs;if(s.length==0||s[0][0]!=k)s.unshift(new d.Diff(k,n)),i.start1-=e,i.start2-=e,i.length1+=e,i.length2+=e;else if(e>s[0][1].length){var o=e-s[0][1].length;s[0][1]=n.substring(s[0][1].length)+s[0][1],i.start1-=o,i.start2-=o,i.length1+=o,i.length2+=o}if(i=t[t.length-1],s=i.diffs,s.length==0||s[s.length-1][0]!=k)s.push(new d.Diff(k,n)),i.length1+=e,i.length2+=e;else if(e>s[s.length-1][1].length){var o=e-s[s.length-1][1].length;s[s.length-1][1]+=n.substring(0,o),i.length1+=o,i.length2+=o}return n};d.prototype.patch_splitMax=function(t){for(var e=this.Match_MaxBits,n=0;n<t.length;n++)if(!(t[n].length1<=e)){var r=t[n];t.splice(n--,1);for(var i=r.start1,s=r.start2,o="";r.diffs.length!==0;){var a=new d.patch_obj,l=!0;for(a.start1=i-o.length,a.start2=s-o.length,o!==""&&(a.length1=a.length2=o.length,a.diffs.push(new d.Diff(k,o)));r.diffs.length!==0&&a.length1<e-this.Patch_Margin;){var c=r.diffs[0][0],h=r.diffs[0][1];c===T?(a.length2+=h.length,s+=h.length,a.diffs.push(r.diffs.shift()),l=!1):c===C&&a.diffs.length==1&&a.diffs[0][0]==k&&h.length>2*e?(a.length1+=h.length,i+=h.length,l=!1,a.diffs.push(new d.Diff(c,h)),r.diffs.shift()):(h=h.substring(0,e-a.length1-this.Patch_Margin),a.length1+=h.length,i+=h.length,c===k?(a.length2+=h.length,s+=h.length):l=!1,a.diffs.push(new d.Diff(c,h)),h==r.diffs[0][1]?r.diffs.shift():r.diffs[0][1]=r.diffs[0][1].substring(h.length))}o=this.diff_text2(a.diffs),o=o.substring(o.length-this.Patch_Margin);var u=this.diff_text1(r.diffs).substring(0,this.Patch_Margin);u!==""&&(a.length1+=u.length,a.length2+=u.length,a.diffs.length!==0&&a.diffs[a.diffs.length-1][0]===k?a.diffs[a.diffs.length-1][1]+=u:a.diffs.push(new d.Diff(k,u))),l||t.splice(++n,0,a)}}};d.prototype.patch_toText=function(t){for(var e=[],n=0;n<t.length;n++)e[n]=t[n];return e.join("")};d.prototype.patch_fromText=function(t){var e=[];if(!t)return e;for(var n=t.split(`
4
- `),r=0,i=/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;r<n.length;){var s=n[r].match(i);if(!s)throw new Error("Invalid patch string: "+n[r]);var o=new d.patch_obj;for(e.push(o),o.start1=parseInt(s[1],10),s[2]===""?(o.start1--,o.length1=1):s[2]=="0"?o.length1=0:(o.start1--,o.length1=parseInt(s[2],10)),o.start2=parseInt(s[3],10),s[4]===""?(o.start2--,o.length2=1):s[4]=="0"?o.length2=0:(o.start2--,o.length2=parseInt(s[4],10)),r++;r<n.length;){var a=n[r].charAt(0);try{var l=decodeURI(n[r].substring(1))}catch{throw new Error("Illegal escape in patch_fromText: "+l)}if(a=="-")o.diffs.push(new d.Diff(C,l));else if(a=="+")o.diffs.push(new d.Diff(T,l));else if(a==" ")o.diffs.push(new d.Diff(k,l));else{if(a=="@")break;if(a!=="")throw new Error('Invalid patch mode "'+a+'" in: '+l)}r++}}return e};d.patch_obj=function(){this.diffs=[],this.start1=null,this.start2=null,this.length1=0,this.length2=0};d.patch_obj.prototype.toString=function(){var t,e;this.length1===0?t=this.start1+",0":this.length1==1?t=this.start1+1:t=this.start1+1+","+this.length1,this.length2===0?e=this.start2+",0":this.length2==1?e=this.start2+1:e=this.start2+1+","+this.length2;for(var n=["@@ -"+t+" +"+e+` @@
5
- `],r,i=0;i<this.diffs.length;i++){switch(this.diffs[i][0]){case T:r="+";break;case C:r="-";break;case k:r=" ";break}n[i+1]=r+encodeURI(this.diffs[i][1])+`
6
- `}return n.join("").replace(/%20/g," ")};me.exports=d;me.exports.diff_match_patch=d;me.exports.DIFF_DELETE=C;me.exports.DIFF_INSERT=T;me.exports.DIFF_EQUAL=k});import{hostname as bi}from"node:os";import{resolve as ki}from"node:path";import{createRequire as rr}from"module";var ir=rr("/"),fe,sr,or;try{fe=ir("worker_threads"),sr=fe.Worker,or=fe.isMarkedAsUntransferable}catch{}var N=Uint8Array,K=Uint16Array,at=Int32Array,ze=new N([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),Oe=new N([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),rt=new N([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),Dt=function(t,e){for(var n=new K(31),r=0;r<31;++r)n[r]=e+=1<<t[r-1];for(var i=new at(n[30]),r=1;r<30;++r)for(var s=n[r];s<n[r+1];++s)i[s]=s-n[r]<<5|r;return{b:n,r:i}},fe=Dt(ze,2),Ut=fe.b,it=fe.r;Ut[28]=258,it[258]=28;var zt=Dt(Oe,0),ar=zt.b,Tt=zt.r,st=new K(32768);for(_=0;_<32768;++_)ee=(_&43690)>>1|(_&21845)<<1,ee=(ee&52428)>>2|(ee&13107)<<2,ee=(ee&61680)>>4|(ee&3855)<<4,st[_]=((ee&65280)>>8|(ee&255)<<8)>>1;var ee,_,Y=(function(t,e,n){for(var r=t.length,i=0,s=new K(e);i<r;++i)t[i]&&++s[t[i]-1];var o=new K(e);for(i=1;i<e;++i)o[i]=o[i-1]+s[i-1]<<1;var a;if(n){a=new K(1<<e);var l=15-e;for(i=0;i<r;++i)if(t[i])for(var c=i<<4|t[i],h=e-t[i],u=o[t[i]-1]++<<h,f=u|(1<<h)-1;u<=f;++u)a[st[u]>>l]=c}else for(a=new K(r),i=0;i<r;++i)t[i]&&(a[i]=st[o[t[i]-1]++]>>15-t[i]);return a}),ie=new N(288);for(_=0;_<144;++_)ie[_]=8;var _;for(_=144;_<256;++_)ie[_]=9;var _;for(_=256;_<280;++_)ie[_]=7;var _;for(_=280;_<288;++_)ie[_]=8;var _,Ee=new N(32);for(_=0;_<32;++_)Ee[_]=5;var _,lr=Y(ie,9,0),hr=Y(ie,9,1),cr=Y(Ee,5,0),ur=Y(Ee,5,1),et=function(t){for(var e=t[0],n=1;n<t.length;++n)t[n]>e&&(e=t[n]);return e},q=function(t,e,n){var r=e/8|0;return(t[r]|t[r+1]<<8)>>(e&7)&n},tt=function(t,e){var n=e/8|0;return(t[n]|t[n+1]<<8|t[n+2]<<16)>>(e&7)},lt=function(t){return(t+7)/8|0},Ot=function(t,e,n){return(e==null||e<0)&&(e=0),(n==null||n>t.length)&&(n=t.length),new N(t.subarray(e,n))};var fr=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],ne=function(t,e,n){var r=new Error(e||fr[t]);if(r.code=t,Error.captureStackTrace&&Error.captureStackTrace(r,ne),!n)throw r;return r},dr=function(t,e,n,r){var i=t.length,s=r?r.length:0;if(!i||e.f&&!e.l)return n||new N(0);var o=!n,a=o||e.i!=2,l=e.i;o&&(n=new N(i*3));var c=function(we){var be=n.length;if(we>be){var ue=new N(Math.max(be*2,we));ue.set(n),n=ue}},h=e.f||0,u=e.p||0,f=e.b||0,g=e.l,m=e.d,v=e.m,x=e.n,w=i*8;do{if(!g){h=q(t,u,1);var A=q(t,u+1,3);if(u+=3,A)if(A==1)g=hr,m=ur,v=9,x=5;else if(A==2){var $=q(t,u,31)+257,E=q(t,u+10,15)+4,y=$+q(t,u+5,31)+1;u+=14;for(var p=new N(y),U=new N(19),D=0;D<E;++D)U[rt[D]]=q(t,u+D*3,7);u+=E*3;for(var F=et(U),re=(1<<F)-1,W=Y(U,F,1),D=0;D<y;){var B=W[q(t,u,re)];u+=B&15;var b=B>>4;if(b<16)p[D++]=b;else{var z=0,R=0;for(b==16?(R=3+q(t,u,3),u+=2,z=p[D-1]):b==17?(R=3+q(t,u,7),u+=3):b==18&&(R=11+q(t,u,127),u+=7);R--;)p[D++]=z}}var L=p.subarray(0,$),O=p.subarray($);v=et(L),x=et(O),g=Y(L,v,1),m=Y(O,x,1)}else ne(1);else{var b=lt(u)+4,S=t[b-4]|t[b-3]<<8,M=b+S;if(M>i){l&&ne(0);break}a&&c(f+S),n.set(t.subarray(b,M),f),e.b=f+=S,e.p=u=M*8,e.f=h;continue}if(u>w){l&&ne(0);break}}a&&c(f+131072);for(var ye=(1<<v)-1,G=(1<<x)-1,Q=u;;Q=u){var z=g[tt(t,u)&ye],V=z>>4;if(u+=z&15,u>w){l&&ne(0);break}if(z||ne(2),V<256)n[f++]=V;else if(V==256){Q=u,g=null;break}else{var J=V-254;if(V>264){var D=V-257,I=ze[D];J=q(t,u,(1<<I)-1)+Ut[D],u+=I}var X=m[tt(t,u)&G],he=X>>4;X||ne(3),u+=X&15;var O=ar[he];if(he>3){var I=Oe[he];O+=tt(t,u)&(1<<I)-1,u+=I}if(u>w){l&&ne(0);break}a&&c(f+131072);var ce=f+J;if(f<O){var De=s-O,Ue=Math.min(O,ce);for(De+f<0&&ne(3);f<Ue;++f)n[f]=r[De+f]}for(;f<ce;++f)n[f]=n[f-O]}}e.l=g,e.p=Q,e.b=f,e.f=h,g&&(h=1,e.m=v,e.d=m,e.n=x)}while(!h);return f!=n.length&&o?Ot(n,0,f):n.subarray(0,f)},te=function(t,e,n){n<<=e&7;var r=e/8|0;t[r]|=n,t[r+1]|=n>>8},ke=function(t,e,n){n<<=e&7;var r=e/8|0;t[r]|=n,t[r+1]|=n>>8,t[r+2]|=n>>16},nt=function(t,e){for(var n=[],r=0;r<t.length;++r)t[r]&&n.push({s:r,f:t[r]});var i=n.length,s=n.slice();if(!i)return{t:Nt,l:0};if(i==1){var o=new N(n[0].s+1);return o[n[0].s]=1,{t:o,l:1}}n.sort(function(M,$){return M.f-$.f}),n.push({s:-1,f:25001});var a=n[0],l=n[1],c=0,h=1,u=2;for(n[0]={s:-1,f:a.f+l.f,l:a,r:l};h!=i-1;)a=n[n[c].f<n[u].f?c++:u++],l=n[c!=h&&n[c].f<n[u].f?c++:u++],n[h++]={s:-1,f:a.f+l.f,l:a,r:l};for(var f=s[0].s,r=1;r<i;++r)s[r].s>f&&(f=s[r].s);var g=new K(f+1),m=ot(n[h-1],g,0);if(m>e){var r=0,v=0,x=m-e,w=1<<x;for(s.sort(function($,E){return g[E.s]-g[$.s]||$.f-E.f});r<i;++r){var A=s[r].s;if(g[A]>e)v+=w-(1<<m-g[A]),g[A]=e;else break}for(v>>=x;v>0;){var b=s[r].s;g[b]<e?v-=1<<e-g[b]++-1:++r}for(;r>=0&&v;--r){var S=s[r].s;g[S]==e&&(--g[S],++v)}m=e}return{t:new N(g),l:m}},ot=function(t,e,n){return t.s==-1?Math.max(ot(t.l,e,n+1),ot(t.r,e,n+1)):e[t.s]=n},Rt=function(t){for(var e=t.length;e&&!t[--e];);for(var n=new K(++e),r=0,i=t[0],s=1,o=function(l){n[r++]=l},a=1;a<=e;++a)if(t[a]==i&&a!=e)++s;else{if(!i&&s>2){for(;s>138;s-=138)o(32754);s>2&&(o(s>10?s-11<<5|28690:s-3<<5|12305),s=0)}else if(s>3){for(o(i),--s;s>6;s-=6)o(8304);s>2&&(o(s-3<<5|8208),s=0)}for(;s--;)o(i);s=1,i=t[a]}return{c:n.subarray(0,r),n:e}},Se=function(t,e){for(var n=0,r=0;r<e.length;++r)n+=t[r]*e[r];return n},Ft=function(t,e,n){var r=n.length,i=lt(e+2);t[i]=r&255,t[i+1]=r>>8,t[i+2]=t[i]^255,t[i+3]=t[i+1]^255;for(var s=0;s<r;++s)t[i+s+4]=n[s];return(i+4+r)*8},It=function(t,e,n,r,i,s,o,a,l,c,h){te(e,h++,n),++i[256];for(var u=nt(i,15),f=u.t,g=u.l,m=nt(s,15),v=m.t,x=m.l,w=Rt(f),A=w.c,b=w.n,S=Rt(v),M=S.c,$=S.n,E=new K(19),y=0;y<A.length;++y)++E[A[y]&31];for(var y=0;y<M.length;++y)++E[M[y]&31];for(var p=nt(E,7),U=p.t,D=p.l,F=19;F>4&&!U[rt[F-1]];--F);var re=c+5<<3,W=Se(i,ie)+Se(s,Ee)+o,B=Se(i,f)+Se(s,v)+o+14+3*F+Se(E,U)+2*E[16]+3*E[17]+7*E[18];if(l>=0&&re<=W&&re<=B)return Ft(e,h,t.subarray(l,l+c));var z,R,L,O;if(te(e,h,1+(B<W)),h+=2,B<W){z=Y(f,g,0),R=f,L=Y(v,x,0),O=v;var ye=Y(U,D,0);te(e,h,b-257),te(e,h+5,$-1),te(e,h+10,F-4),h+=14;for(var y=0;y<F;++y)te(e,h+3*y,U[rt[y]]);h+=3*F;for(var G=[A,M],Q=0;Q<2;++Q)for(var V=G[Q],y=0;y<V.length;++y){var J=V[y]&31;te(e,h,ye[J]),h+=U[J],J>15&&(te(e,h,V[y]>>5&127),h+=V[y]>>12)}}else z=lr,R=ie,L=cr,O=Ee;for(var y=0;y<a;++y){var I=r[y];if(I>255){var J=I>>18&31;ke(e,h,z[J+257]),h+=R[J+257],J>7&&(te(e,h,I>>23&31),h+=ze[J]);var X=I&31;ke(e,h,L[X]),h+=O[X],X>3&&(ke(e,h,I>>5&8191),h+=Oe[X])}else ke(e,h,z[I]),h+=R[I]}return ke(e,h,z[256]),h+R[256]},gr=new at([65540,131080,131088,131104,262176,1048704,1048832,2114560,2117632]),Nt=new N(0),mr=function(t,e,n,r,i,s){var o=s.z||t.length,a=new N(r+o+5*(1+Math.ceil(o/7e3))+i),l=a.subarray(r,a.length-i),c=s.l,h=(s.r||0)&7;if(e){h&&(l[0]=s.r>>3);for(var u=gr[e-1],f=u>>13,g=u&8191,m=(1<<n)-1,v=s.p||new K(32768),x=s.h||new K(m+1),w=Math.ceil(n/3),A=2*w,b=function(Qe){return(t[Qe]^t[Qe+1]<<w^t[Qe+2]<<A)&m},S=new at(25e3),M=new K(288),$=new K(32),E=0,y=0,p=s.i||0,U=0,D=s.w||0,F=0;p+2<o;++p){var re=b(p),W=p&32767,B=x[re];if(v[W]=B,x[re]=W,D<=p){var z=o-p;if((E>7e3||U>24576)&&(z>423||!c)){h=It(t,l,0,S,M,$,y,U,F,p-F,h),U=E=y=0,F=p;for(var R=0;R<286;++R)M[R]=0;for(var R=0;R<30;++R)$[R]=0}var L=2,O=0,ye=g,G=W-B&32767;if(z>2&&re==b(p-G))for(var Q=Math.min(f,z)-1,V=Math.min(32767,p),J=Math.min(258,z);G<=V&&--ye&&W!=B;){if(t[p+L]==t[p+L-G]){for(var I=0;I<J&&t[p+I]==t[p+I-G];++I);if(I>L){if(L=I,O=G,I>Q)break;for(var X=Math.min(G,I-2),he=0,R=0;R<X;++R){var ce=p-G+R&32767,De=v[ce],Ue=ce-De&32767;Ue>he&&(he=Ue,B=ce)}}}W=B,B=v[W],G+=W-B&32767}if(O){S[U++]=268435456|it[L]<<18|Tt[O];var we=it[L]&31,be=Tt[O]&31;y+=ze[we]+Oe[be],++M[257+we],++$[be],D=p+L,++E}else S[U++]=t[p],++M[t[p]]}}for(p=Math.max(p,D);p<o;++p)S[U++]=t[p],++M[t[p]];h=It(t,l,c,S,M,$,y,U,F,p-F,h),c||(s.r=h&7|l[h/8|0]<<3,h-=7,s.h=x,s.p=v,s.i=p,s.w=D)}else{for(var p=s.w||0;p<o+c;p+=65535){var ue=p+65535;ue>=o&&(l[h/8|0]=c,ue=o),h=Ft(l,h+1,t.subarray(p,ue))}s.i=o}return Ot(a,0,r+lt(h)+i)};var vr=function(t,e,n,r,i){if(!i&&(i={l:1},e.dictionary)){var s=e.dictionary.subarray(-32768),o=new N(s.length+t.length);o.set(s),o.set(t,s.length),t=o,i.w=s.length}return mr(t,e.level==null?6:e.level,e.mem==null?i.l?Math.ceil(Math.max(8,Math.min(13,Math.log(t.length)))*1.5):20:12+e.mem,n,r,i)};function ht(t,e){return vr(t,e||{},0,0)}function Bt(t,e){return dr(t,{i:2},e&&e.out,e&&e.dictionary)}var pr=typeof TextDecoder<"u"&&new TextDecoder,yr=0;try{pr.decode(Nt,{stream:!0}),yr=1}catch{}var Wt="basalt/hkdf-aes-gcm/1",oe=12,Ne=128,Vt=oe+Ne/8+1,Z=20,Jt=new TextEncoder,wr=new TextDecoder,Fe={auth:"basalt/auth/1",path:"basalt/path/1",content:"basalt/content/1",nonce:"basalt/nonce/1"};function Ae(){let t=globalThis.crypto;if(!t?.subtle)throw new Error("WebCrypto is unavailable, so this vault cannot be opened");return t.subtle}function Kt(){let t=globalThis.crypto;if(!t?.getRandomValues)throw new Error("no secure random source is available, so a vault cannot be created here");return t.getRandomValues(new Uint8Array(Z))}async function Ht(t){if(t.length<16)throw new Error(`root secret is ${t.length} bytes, need at least 16`);let e=Ae(),n=await e.importKey("raw",ae(t),"HKDF",!1,["deriveKey","deriveBits"]),r=l=>({name:"HKDF",hash:"SHA-256",salt:new Uint8Array(0),info:Jt.encode(l)}),[i,s,o,a]=await Promise.all([e.deriveBits(r(Fe.auth),n,256),e.deriveKey(r(Fe.path),n,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]),e.deriveKey(r(Fe.content),n,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]),e.deriveKey(r(Fe.nonce),n,{name:"HMAC",hash:"SHA-256"},!1,["sign"])]);return{auth:new Uint8Array(i),path:s,content:o,nonce:a}}async function jt(t,e,n){let r=Ae(),i=await br(e,n),s=await r.encrypt({name:"AES-GCM",iv:ae(i),tagLength:Ne},t,ae(n)),o=new Uint8Array(oe+s.byteLength);return o.set(i,0),o.set(new Uint8Array(s),oe),o}async function Gt(t,e){if(e.length<oe+Ne/8)throw new Error(`sealed value is ${e.length} bytes, too short to contain a nonce and a tag`);let n=Ae(),r=e.subarray(0,oe),i=e.subarray(oe);try{let s=await n.decrypt({name:"AES-GCM",iv:ae(r),tagLength:Ne},t,ae(i));return new Uint8Array(s)}catch(s){throw new Error("sealed value failed authentication, so it is not what was stored",{cause:s})}}async function br(t,e){let n=await Ae().sign("HMAC",t,ae(e));return new Uint8Array(n,0,oe)}async function Be(t,e){return xe(await jt(t.path,t.nonce,Jt.encode(e)))}async function Le(t,e){let n=await Gt(t.path,We(e));return wr.decode(n)}var qt=0,Zt=1;async function kr(t,e){let n=Sr(e)?ht(e,{level:6}):void 0,r=n!==void 0&&n.length<e.length,i=r?n:e,s=new Uint8Array(1+i.length);return s[0]=r?Zt:qt,s.set(i,1),jt(t.content,t.nonce,s)}function Sr(t){if(t.length===0)return!1;if(t.length<=Lt*2)return!0;let e=t.subarray(0,Lt);return ht(e,{level:6}).length<e.length}var Lt=4096;async function ge(t,e){return Promise.all([...e].map(async n=>{let r=await kr(t,n);return{name:await ct(r),bytes:r}}))}async function Xt(t,e){let n=await Gt(t.content,e);if(n.length===0)throw new Error("sealed chunk carries no marker byte");let r=n[0],i=n.subarray(1);if(r===qt)return i;if(r===Zt)try{return Bt(i)}catch(s){throw new Error("sealed chunk claims to be deflated and is not",{cause:s})}throw new Error(`sealed chunk has an unknown marker byte ${r}`)}async function ct(t){let e=await Ae().digest("SHA-256",ae(t));return Er(new Uint8Array(e))}function Yt(t){return xe(t.auth)}function ae(t){return t.slice().buffer}function Er(t){let e="";for(let n of t)e+=n.toString(16).padStart(2,"0");return e}var de="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";function xe(t){let e="";for(let n=0;n<t.length;n+=3){let r=t[n],i=n+1<t.length?t[n+1]:void 0,s=n+2<t.length?t[n+2]:void 0;if(e+=de[r>>2],e+=de[(r&3)<<4|(i??0)>>4],i===void 0||(e+=de[(i&15)<<2|(s??0)>>6],s===void 0))break;e+=de[s&63]}return e}var Ar=(()=>{let t=new Int16Array(128).fill(-1);for(let e=0;e<de.length;e++)t[de.charCodeAt(e)]=e;return t})();function We(t){let e=t.length,n=new Uint8Array(Math.floor(e*3/4)),r=0,i=0,s=0;for(let o=0;o<e;o++){let a=t.charCodeAt(o),l=a<128?Ar[a]:-1;if(l<0)throw new Error(`invalid base64url character ${JSON.stringify(t[o])} at position ${o}`);i=i<<6|l,s+=6,s>=8&&(s-=8,n[r++]=i>>s&255)}return n.subarray(0,r)}var se=48,le=31,Qt=1,en={min:512,avg:1024,max:4096},xr=64,Pr=en.avg,$r=64*1024;function Mr(t){let e=Math.sqrt(xr*Math.max(t,1)),n=Math.min($r,Math.max(Pr,Math.round(e/512)*512));return{min:Math.max(en.min,n/2),avg:n,max:n*4}}var ut={min:128*1024,avg:256*1024,max:1024*1024},_r=4*1024*1024;function tn(t,e,n=ut.max){(!Number.isFinite(n)||n<=0)&&(n=ut.max);let r=e&&t<_r?Mr(t):ut,i=Math.min(r.max,n-Vt),s=Math.max(i,se*4);return{min:Math.min(r.min,s),avg:Math.min(r.avg,s),max:s}}function nn(t,e,n){let r=n-1;for(;r>e&&(t[r]&192)===128;)r--;if(r<e)return n;let i=t[r],s=i<128?1:(i&224)===192?2:(i&240)===224?3:(i&248)===240?4:1;return n-r>=s?n:r>e?r:n}function*rn(t,e,n){let{min:r,avg:i,max:s}=e,o=t.length,a=1;for(let h=0;h<se-1;h++)a=Math.imul(a,le);let l=0,c=0;for(let h=0;h<o;h++){let u=t[h];h>=l+se?(c=c-Math.imul(t[h-se],a)|0,c=Math.imul(c,le),c=c+u|0):(c=Math.imul(c,le),c=c+u|0);let f=h-l+1,g=f>=r&&(c>>>0)%i===Qt;if(f>=s&&(g=!0),g){let m=n?nn(t,l,h+1):h+1;yield{offset:l,bytes:t.subarray(l,m)},l=m,c=0,h=m-1}}l<o&&(yield{offset:l,bytes:t.subarray(l,o)})}async function*sn(t,e,n){let{min:r,avg:i,max:s}=e,o=1;for(let f=0;f<se-1;f++)o=Math.imul(o,le);let a=new Uint8Array(Math.max(s,se*2)),l=0,c=0,h=0,u=()=>{let f=n?nn(a,0,l):l,g={offset:h,bytes:a.slice(0,f)};h+=f;let m=l-f;a.copyWithin(0,f,l),l=m,c=0;for(let v=0;v<m;v++)c=Math.imul(c,le),c=c+a[v]|0;return g};for await(let f of t)for(let g=0;g<f.length;g++){let m=f[g];a[l++]=m,l>=se+1?(c=c-Math.imul(a[l-1-se],o)|0,c=Math.imul(c,le),c=c+m|0):(c=Math.imul(c,le),c=c+m|0),(l>=s||l>=r&&(c>>>0)%i===Qt)&&(yield u())}if(l>0){let f={offset:h,bytes:a.slice(0,l)};h+=l,l=0,yield f}}var Cr=new Set(["md","txt","canvas","json","csv","yml","yaml","xml","html","css","js","ts","svg","bib","tex"]);function on(t){let e=t.lastIndexOf(".");return e<0?!1:Cr.has(t.slice(e+1).toLowerCase())}var Tr=new Set(["canvas","json"]);function an(t){let e=t.lastIndexOf(".");return e<0?!1:Tr.has(t.slice(e+1).toLowerCase())}var un=nr(ln(),1),Rr=-1,Ir=0,Dr=1;function hn(t){let e=[],n=0;for(let[r,i]of t)r===Ir?n+=i.length:r===Rr?(e.push({start:n,end:n+i.length}),n+=i.length):e.push({start:n,end:n});return e}function Ur(t,e){for(let n of t)for(let r of e){let i=n.start===n.end,s=r.start===r.end;if(!(i&&s)){if(i){if(r.start<n.start&&n.start<r.end)return n;continue}if(s){if(n.start<r.start&&r.start<n.end)return r;continue}if(n.start<r.end&&r.start<n.end)return n}}}function fn(t,e,n,r=()=>!0){if(e===n)return{kind:"take",text:e,why:"both sides already agree"};if(t===e)return{kind:"take",text:n,why:"no local change since the last sync"};if(t===n)return{kind:"take",text:e,why:"no remote change since the last sync"};let i=new un.diff_match_patch,s=i.diff_main(t,e,!0,0);s.length>2&&(i.diff_cleanupSemantic(s),i.diff_cleanupEfficiency(s));let o=i.diff_main(t,n,!0,0);o.length>2&&(i.diff_cleanupSemantic(o),i.diff_cleanupEfficiency(o));let a=Ur(hn(s),hn(o));if(a!==void 0)return{kind:"conflict",why:`both devices changed the same text, at characters ${a.start} to ${a.end} of the last synced version`};let l=cn(i,t,s,n),c=cn(i,t,o,e);if(l.failed>0||c.failed>0){let u=Math.max(l.failed,c.failed),f=Math.max(l.total,c.total);return{kind:"conflict",why:`${u} of ${f} changes could not be placed in the other version`}}if(!zr(l.text,c.text))return{kind:"conflict",why:"merging the two versions in either order gives different content, so at least one change was placed wrongly"};let h=Or(s,l.text);return h!==void 0?{kind:"conflict",why:`the merge reported success but ${Fr(h)} is not in the result`}:r(l.text)?{kind:"merged",text:l.text}:{kind:"conflict",why:"both sides merged cleanly and the result is no longer a valid file of its kind"}}function zr(t,e){if(t===e)return!0;let n=t.split(`
2
+ var lr=Object.create;var Wt=Object.defineProperty;var hr=Object.getOwnPropertyDescriptor;var cr=Object.getOwnPropertyNames;var ur=Object.getPrototypeOf,fr=Object.prototype.hasOwnProperty;var dr=(t,e)=>()=>{try{return e||t((e={exports:{}}).exports,e),e.exports}catch(n){throw e=0,n}};var gr=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of cr(e))!fr.call(t,i)&&i!==n&&Wt(t,i,{get:()=>e[i],enumerable:!(r=hr(e,i))||r.enumerable});return t};var mr=(t,e,n)=>(n=t!=null?lr(ur(t)):{},gr(e||!t||!t.__esModule?Wt(n,"default",{value:t,enumerable:!0}):n,t));var vn=dr((rs,we)=>{var d=function(){this.Diff_Timeout=1,this.Diff_EditCost=4,this.Match_Threshold=.5,this.Match_Distance=1e3,this.Patch_DeleteThreshold=.5,this.Patch_Margin=4,this.Match_MaxBits=32},T=-1,_=1,k=0;d.Diff=function(t,e){return[t,e]};d.prototype.diff_main=function(t,e,n,r){typeof r>"u"&&(this.Diff_Timeout<=0?r=Number.MAX_VALUE:r=new Date().getTime()+this.Diff_Timeout*1e3);var i=r;if(t==null||e==null)throw new Error("Null input. (diff_main)");if(t==e)return t?[new d.Diff(k,t)]:[];typeof n>"u"&&(n=!0);var s=n,o=this.diff_commonPrefix(t,e),a=t.substring(0,o);t=t.substring(o),e=e.substring(o),o=this.diff_commonSuffix(t,e);var l=t.substring(t.length-o);t=t.substring(0,t.length-o),e=e.substring(0,e.length-o);var h=this.diff_compute_(t,e,s,i);return a&&h.unshift(new d.Diff(k,a)),l&&h.push(new d.Diff(k,l)),this.diff_cleanupMerge(h),h};d.prototype.diff_compute_=function(t,e,n,r){var i;if(!t)return[new d.Diff(_,e)];if(!e)return[new d.Diff(T,t)];var s=t.length>e.length?t:e,o=t.length>e.length?e:t,a=s.indexOf(o);if(a!=-1)return i=[new d.Diff(_,s.substring(0,a)),new d.Diff(k,o),new d.Diff(_,s.substring(a+o.length))],t.length>e.length&&(i[0][0]=i[2][0]=T),i;if(o.length==1)return[new d.Diff(T,t),new d.Diff(_,e)];var l=this.diff_halfMatch_(t,e);if(l){var h=l[0],c=l[1],u=l[2],f=l[3],g=l[4],m=this.diff_main(h,u,n,r),p=this.diff_main(c,f,n,r);return m.concat([new d.Diff(k,g)],p)}return n&&t.length>100&&e.length>100?this.diff_lineMode_(t,e,r):this.diff_bisect_(t,e,r)};d.prototype.diff_lineMode_=function(t,e,n){var r=this.diff_linesToChars_(t,e);t=r.chars1,e=r.chars2;var i=r.lineArray,s=this.diff_main(t,e,!1,n);this.diff_charsToLines_(s,i),this.diff_cleanupSemantic(s),s.push(new d.Diff(k,""));for(var o=0,a=0,l=0,h="",c="";o<s.length;){switch(s[o][0]){case _:l++,c+=s[o][1];break;case T:a++,h+=s[o][1];break;case k:if(a>=1&&l>=1){s.splice(o-a-l,a+l),o=o-a-l;for(var u=this.diff_main(h,c,!1,n),f=u.length-1;f>=0;f--)s.splice(o,0,u[f]);o=o+u.length}l=0,a=0,h="",c="";break}o++}return s.pop(),s};d.prototype.diff_bisect_=function(t,e,n){for(var r=t.length,i=e.length,s=Math.ceil((r+i)/2),o=s,a=2*s,l=new Array(a),h=new Array(a),c=0;c<a;c++)l[c]=-1,h[c]=-1;l[o+1]=0,h[o+1]=0;for(var u=r-i,f=u%2!=0,g=0,m=0,p=0,x=0,w=0;w<s&&!(new Date().getTime()>n);w++){for(var A=-w+g;A<=w-m;A+=2){var b=o+A,S;A==-w||A!=w&&l[b-1]<l[b+1]?S=l[b+1]:S=l[b-1]+1;for(var M=S-A;S<r&&M<i&&t.charAt(S)==e.charAt(M);)S++,M++;if(l[b]=S,S>r)m+=2;else if(M>i)g+=2;else if(f){var $=o+u-A;if($>=0&&$<a&&h[$]!=-1){var E=r-h[$];if(S>=E)return this.diff_bisectSplit_(t,e,S,M,n)}}}for(var v=-w+p;v<=w-x;v+=2){var $=o+v,E;v==-w||v!=w&&h[$-1]<h[$+1]?E=h[$+1]:E=h[$-1]+1;for(var y=E-v;E<r&&y<i&&t.charAt(r-E-1)==e.charAt(i-y-1);)E++,y++;if(h[$]=E,E>r)x+=2;else if(y>i)p+=2;else if(!f){var b=o+u-v;if(b>=0&&b<a&&l[b]!=-1){var S=l[b],M=o+S-b;if(E=r-E,S>=E)return this.diff_bisectSplit_(t,e,S,M,n)}}}}return[new d.Diff(T,t),new d.Diff(_,e)]};d.prototype.diff_bisectSplit_=function(t,e,n,r,i){var s=t.substring(0,n),o=e.substring(0,r),a=t.substring(n),l=e.substring(r),h=this.diff_main(s,o,!1,i),c=this.diff_main(a,l,!1,i);return h.concat(c)};d.prototype.diff_linesToChars_=function(t,e){var n=[],r={};n[0]="";function i(l){for(var h="",c=0,u=-1,f=n.length;u<l.length-1;){u=l.indexOf(`
3
+ `,c),u==-1&&(u=l.length-1);var g=l.substring(c,u+1);(r.hasOwnProperty?r.hasOwnProperty(g):r[g]!==void 0)?h+=String.fromCharCode(r[g]):(f==s&&(g=l.substring(c),u=l.length),h+=String.fromCharCode(f),r[g]=f,n[f++]=g),c=u+1}return h}var s=4e4,o=i(t);s=65535;var a=i(e);return{chars1:o,chars2:a,lineArray:n}};d.prototype.diff_charsToLines_=function(t,e){for(var n=0;n<t.length;n++){for(var r=t[n][1],i=[],s=0;s<r.length;s++)i[s]=e[r.charCodeAt(s)];t[n][1]=i.join("")}};d.prototype.diff_commonPrefix=function(t,e){if(!t||!e||t.charAt(0)!=e.charAt(0))return 0;for(var n=0,r=Math.min(t.length,e.length),i=r,s=0;n<i;)t.substring(s,i)==e.substring(s,i)?(n=i,s=n):r=i,i=Math.floor((r-n)/2+n);return i};d.prototype.diff_commonSuffix=function(t,e){if(!t||!e||t.charAt(t.length-1)!=e.charAt(e.length-1))return 0;for(var n=0,r=Math.min(t.length,e.length),i=r,s=0;n<i;)t.substring(t.length-i,t.length-s)==e.substring(e.length-i,e.length-s)?(n=i,s=n):r=i,i=Math.floor((r-n)/2+n);return i};d.prototype.diff_commonOverlap_=function(t,e){var n=t.length,r=e.length;if(n==0||r==0)return 0;n>r?t=t.substring(n-r):n<r&&(e=e.substring(0,n));var i=Math.min(n,r);if(t==e)return i;for(var s=0,o=1;;){var a=t.substring(i-o),l=e.indexOf(a);if(l==-1)return s;o+=l,(l==0||t.substring(i-o)==e.substring(0,o))&&(s=o,o++)}};d.prototype.diff_halfMatch_=function(t,e){if(this.Diff_Timeout<=0)return null;var n=t.length>e.length?t:e,r=t.length>e.length?e:t;if(n.length<4||r.length*2<n.length)return null;var i=this;function s(m,p,x){for(var w=m.substring(x,x+Math.floor(m.length/4)),A=-1,b="",S,M,$,E;(A=p.indexOf(w,A+1))!=-1;){var v=i.diff_commonPrefix(m.substring(x),p.substring(A)),y=i.diff_commonSuffix(m.substring(0,x),p.substring(0,A));b.length<y+v&&(b=p.substring(A-y,A)+p.substring(A,A+v),S=m.substring(0,x-y),M=m.substring(x+v),$=p.substring(0,A-y),E=p.substring(A+v))}return b.length*2>=m.length?[S,M,$,E,b]:null}var o=s(n,r,Math.ceil(n.length/4)),a=s(n,r,Math.ceil(n.length/2)),l;if(!o&&!a)return null;a?o?l=o[4].length>a[4].length?o:a:l=a:l=o;var h,c,u,f;t.length>e.length?(h=l[0],c=l[1],u=l[2],f=l[3]):(u=l[0],f=l[1],h=l[2],c=l[3]);var g=l[4];return[h,c,u,f,g]};d.prototype.diff_cleanupSemantic=function(t){for(var e=!1,n=[],r=0,i=null,s=0,o=0,a=0,l=0,h=0;s<t.length;)t[s][0]==k?(n[r++]=s,o=l,a=h,l=0,h=0,i=t[s][1]):(t[s][0]==_?l+=t[s][1].length:h+=t[s][1].length,i&&i.length<=Math.max(o,a)&&i.length<=Math.max(l,h)&&(t.splice(n[r-1],0,new d.Diff(T,i)),t[n[r-1]+1][0]=_,r--,r--,s=r>0?n[r-1]:-1,o=0,a=0,l=0,h=0,i=null,e=!0)),s++;for(e&&this.diff_cleanupMerge(t),this.diff_cleanupSemanticLossless(t),s=1;s<t.length;){if(t[s-1][0]==T&&t[s][0]==_){var c=t[s-1][1],u=t[s][1],f=this.diff_commonOverlap_(c,u),g=this.diff_commonOverlap_(u,c);f>=g?(f>=c.length/2||f>=u.length/2)&&(t.splice(s,0,new d.Diff(k,u.substring(0,f))),t[s-1][1]=c.substring(0,c.length-f),t[s+1][1]=u.substring(f),s++):(g>=c.length/2||g>=u.length/2)&&(t.splice(s,0,new d.Diff(k,c.substring(0,g))),t[s-1][0]=_,t[s-1][1]=u.substring(0,u.length-g),t[s+1][0]=T,t[s+1][1]=c.substring(g),s++),s++}s++}};d.prototype.diff_cleanupSemanticLossless=function(t){function e(g,m){if(!g||!m)return 6;var p=g.charAt(g.length-1),x=m.charAt(0),w=p.match(d.nonAlphaNumericRegex_),A=x.match(d.nonAlphaNumericRegex_),b=w&&p.match(d.whitespaceRegex_),S=A&&x.match(d.whitespaceRegex_),M=b&&p.match(d.linebreakRegex_),$=S&&x.match(d.linebreakRegex_),E=M&&g.match(d.blanklineEndRegex_),v=$&&m.match(d.blanklineStartRegex_);return E||v?5:M||$?4:w&&!b&&S?3:b||S?2:w||A?1:0}for(var n=1;n<t.length-1;){if(t[n-1][0]==k&&t[n+1][0]==k){var r=t[n-1][1],i=t[n][1],s=t[n+1][1],o=this.diff_commonSuffix(r,i);if(o){var a=i.substring(i.length-o);r=r.substring(0,r.length-o),i=a+i.substring(0,i.length-o),s=a+s}for(var l=r,h=i,c=s,u=e(r,i)+e(i,s);i.charAt(0)===s.charAt(0);){r+=i.charAt(0),i=i.substring(1)+s.charAt(0),s=s.substring(1);var f=e(r,i)+e(i,s);f>=u&&(u=f,l=r,h=i,c=s)}t[n-1][1]!=l&&(l?t[n-1][1]=l:(t.splice(n-1,1),n--),t[n][1]=h,c?t[n+1][1]=c:(t.splice(n+1,1),n--))}n++}};d.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;d.whitespaceRegex_=/\s/;d.linebreakRegex_=/[\r\n]/;d.blanklineEndRegex_=/\n\r?\n$/;d.blanklineStartRegex_=/^\r?\n\r?\n/;d.prototype.diff_cleanupEfficiency=function(t){for(var e=!1,n=[],r=0,i=null,s=0,o=!1,a=!1,l=!1,h=!1;s<t.length;)t[s][0]==k?(t[s][1].length<this.Diff_EditCost&&(l||h)?(n[r++]=s,o=l,a=h,i=t[s][1]):(r=0,i=null),l=h=!1):(t[s][0]==T?h=!0:l=!0,i&&(o&&a&&l&&h||i.length<this.Diff_EditCost/2&&o+a+l+h==3)&&(t.splice(n[r-1],0,new d.Diff(T,i)),t[n[r-1]+1][0]=_,r--,i=null,o&&a?(l=h=!0,r=0):(r--,s=r>0?n[r-1]:-1,l=h=!1),e=!0)),s++;e&&this.diff_cleanupMerge(t)};d.prototype.diff_cleanupMerge=function(t){t.push(new d.Diff(k,""));for(var e=0,n=0,r=0,i="",s="",o;e<t.length;)switch(t[e][0]){case _:r++,s+=t[e][1],e++;break;case T:n++,i+=t[e][1],e++;break;case k:n+r>1?(n!==0&&r!==0&&(o=this.diff_commonPrefix(s,i),o!==0&&(e-n-r>0&&t[e-n-r-1][0]==k?t[e-n-r-1][1]+=s.substring(0,o):(t.splice(0,0,new d.Diff(k,s.substring(0,o))),e++),s=s.substring(o),i=i.substring(o)),o=this.diff_commonSuffix(s,i),o!==0&&(t[e][1]=s.substring(s.length-o)+t[e][1],s=s.substring(0,s.length-o),i=i.substring(0,i.length-o))),e-=n+r,t.splice(e,n+r),i.length&&(t.splice(e,0,new d.Diff(T,i)),e++),s.length&&(t.splice(e,0,new d.Diff(_,s)),e++),e++):e!==0&&t[e-1][0]==k?(t[e-1][1]+=t[e][1],t.splice(e,1)):e++,r=0,n=0,i="",s="";break}t[t.length-1][1]===""&&t.pop();var a=!1;for(e=1;e<t.length-1;)t[e-1][0]==k&&t[e+1][0]==k&&(t[e][1].substring(t[e][1].length-t[e-1][1].length)==t[e-1][1]?(t[e][1]=t[e-1][1]+t[e][1].substring(0,t[e][1].length-t[e-1][1].length),t[e+1][1]=t[e-1][1]+t[e+1][1],t.splice(e-1,1),a=!0):t[e][1].substring(0,t[e+1][1].length)==t[e+1][1]&&(t[e-1][1]+=t[e+1][1],t[e][1]=t[e][1].substring(t[e+1][1].length)+t[e+1][1],t.splice(e+1,1),a=!0)),e++;a&&this.diff_cleanupMerge(t)};d.prototype.diff_xIndex=function(t,e){var n=0,r=0,i=0,s=0,o;for(o=0;o<t.length&&(t[o][0]!==_&&(n+=t[o][1].length),t[o][0]!==T&&(r+=t[o][1].length),!(n>e));o++)i=n,s=r;return t.length!=o&&t[o][0]===T?s:s+(e-i)};d.prototype.diff_prettyHtml=function(t){for(var e=[],n=/&/g,r=/</g,i=/>/g,s=/\n/g,o=0;o<t.length;o++){var a=t[o][0],l=t[o][1],h=l.replace(n,"&amp;").replace(r,"&lt;").replace(i,"&gt;").replace(s,"&para;<br>");switch(a){case _:e[o]='<ins style="background:#e6ffe6;">'+h+"</ins>";break;case T:e[o]='<del style="background:#ffe6e6;">'+h+"</del>";break;case k:e[o]="<span>"+h+"</span>";break}}return e.join("")};d.prototype.diff_text1=function(t){for(var e=[],n=0;n<t.length;n++)t[n][0]!==_&&(e[n]=t[n][1]);return e.join("")};d.prototype.diff_text2=function(t){for(var e=[],n=0;n<t.length;n++)t[n][0]!==T&&(e[n]=t[n][1]);return e.join("")};d.prototype.diff_levenshtein=function(t){for(var e=0,n=0,r=0,i=0;i<t.length;i++){var s=t[i][0],o=t[i][1];switch(s){case _:n+=o.length;break;case T:r+=o.length;break;case k:e+=Math.max(n,r),n=0,r=0;break}}return e+=Math.max(n,r),e};d.prototype.diff_toDelta=function(t){for(var e=[],n=0;n<t.length;n++)switch(t[n][0]){case _:e[n]="+"+encodeURI(t[n][1]);break;case T:e[n]="-"+t[n][1].length;break;case k:e[n]="="+t[n][1].length;break}return e.join(" ").replace(/%20/g," ")};d.prototype.diff_fromDelta=function(t,e){for(var n=[],r=0,i=0,s=e.split(/\t/g),o=0;o<s.length;o++){var a=s[o].substring(1);switch(s[o].charAt(0)){case"+":try{n[r++]=new d.Diff(_,decodeURI(a))}catch{throw new Error("Illegal escape in diff_fromDelta: "+a)}break;case"-":case"=":var l=parseInt(a,10);if(isNaN(l)||l<0)throw new Error("Invalid number in diff_fromDelta: "+a);var h=t.substring(i,i+=l);s[o].charAt(0)=="="?n[r++]=new d.Diff(k,h):n[r++]=new d.Diff(T,h);break;default:if(s[o])throw new Error("Invalid diff operation in diff_fromDelta: "+s[o])}}if(i!=t.length)throw new Error("Delta length ("+i+") does not equal source text length ("+t.length+").");return n};d.prototype.match_main=function(t,e,n){if(t==null||e==null||n==null)throw new Error("Null input. (match_main)");return n=Math.max(0,Math.min(n,t.length)),t==e?0:t.length?t.substring(n,n+e.length)==e?n:this.match_bitap_(t,e,n):-1};d.prototype.match_bitap_=function(t,e,n){if(e.length>this.Match_MaxBits)throw new Error("Pattern too long for this browser.");var r=this.match_alphabet_(e),i=this;function s(S,M){var $=S/e.length,E=Math.abs(n-M);return i.Match_Distance?$+E/i.Match_Distance:E?1:$}var o=this.Match_Threshold,a=t.indexOf(e,n);a!=-1&&(o=Math.min(s(0,a),o),a=t.lastIndexOf(e,n+e.length),a!=-1&&(o=Math.min(s(0,a),o)));var l=1<<e.length-1;a=-1;for(var h,c,u=e.length+t.length,f,g=0;g<e.length;g++){for(h=0,c=u;h<c;)s(g,n+c)<=o?h=c:u=c,c=Math.floor((u-h)/2+h);u=c;var m=Math.max(1,n-c+1),p=Math.min(n+c,t.length)+e.length,x=Array(p+2);x[p+1]=(1<<g)-1;for(var w=p;w>=m;w--){var A=r[t.charAt(w-1)];if(g===0?x[w]=(x[w+1]<<1|1)&A:x[w]=(x[w+1]<<1|1)&A|((f[w+1]|f[w])<<1|1)|f[w+1],x[w]&l){var b=s(g,w-1);if(b<=o)if(o=b,a=w-1,a>n)m=Math.max(1,2*n-a);else break}}if(s(g+1,n)>o)break;f=x}return a};d.prototype.match_alphabet_=function(t){for(var e={},n=0;n<t.length;n++)e[t.charAt(n)]=0;for(var n=0;n<t.length;n++)e[t.charAt(n)]|=1<<t.length-n-1;return e};d.prototype.patch_addContext_=function(t,e){if(e.length!=0){if(t.start2===null)throw Error("patch not initialized");for(var n=e.substring(t.start2,t.start2+t.length1),r=0;e.indexOf(n)!=e.lastIndexOf(n)&&n.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)r+=this.Patch_Margin,n=e.substring(t.start2-r,t.start2+t.length1+r);r+=this.Patch_Margin;var i=e.substring(t.start2-r,t.start2);i&&t.diffs.unshift(new d.Diff(k,i));var s=e.substring(t.start2+t.length1,t.start2+t.length1+r);s&&t.diffs.push(new d.Diff(k,s)),t.start1-=i.length,t.start2-=i.length,t.length1+=i.length+s.length,t.length2+=i.length+s.length}};d.prototype.patch_make=function(t,e,n){var r,i;if(typeof t=="string"&&typeof e=="string"&&typeof n>"u")r=t,i=this.diff_main(r,e,!0),i.length>2&&(this.diff_cleanupSemantic(i),this.diff_cleanupEfficiency(i));else if(t&&typeof t=="object"&&typeof e>"u"&&typeof n>"u")i=t,r=this.diff_text1(i);else if(typeof t=="string"&&e&&typeof e=="object"&&typeof n>"u")r=t,i=e;else if(typeof t=="string"&&typeof e=="string"&&n&&typeof n=="object")r=t,i=n;else throw new Error("Unknown call format to patch_make.");if(i.length===0)return[];for(var s=[],o=new d.patch_obj,a=0,l=0,h=0,c=r,u=r,f=0;f<i.length;f++){var g=i[f][0],m=i[f][1];switch(!a&&g!==k&&(o.start1=l,o.start2=h),g){case _:o.diffs[a++]=i[f],o.length2+=m.length,u=u.substring(0,h)+m+u.substring(h);break;case T:o.length1+=m.length,o.diffs[a++]=i[f],u=u.substring(0,h)+u.substring(h+m.length);break;case k:m.length<=2*this.Patch_Margin&&a&&i.length!=f+1?(o.diffs[a++]=i[f],o.length1+=m.length,o.length2+=m.length):m.length>=2*this.Patch_Margin&&a&&(this.patch_addContext_(o,c),s.push(o),o=new d.patch_obj,a=0,c=u,l=h);break}g!==_&&(l+=m.length),g!==T&&(h+=m.length)}return a&&(this.patch_addContext_(o,c),s.push(o)),s};d.prototype.patch_deepCopy=function(t){for(var e=[],n=0;n<t.length;n++){var r=t[n],i=new d.patch_obj;i.diffs=[];for(var s=0;s<r.diffs.length;s++)i.diffs[s]=new d.Diff(r.diffs[s][0],r.diffs[s][1]);i.start1=r.start1,i.start2=r.start2,i.length1=r.length1,i.length2=r.length2,e[n]=i}return e};d.prototype.patch_apply=function(t,e){if(t.length==0)return[e,[]];t=this.patch_deepCopy(t);var n=this.patch_addPadding(t);e=n+e+n,this.patch_splitMax(t);for(var r=0,i=[],s=0;s<t.length;s++){var o=t[s].start2+r,a=this.diff_text1(t[s].diffs),l,h=-1;if(a.length>this.Match_MaxBits?(l=this.match_main(e,a.substring(0,this.Match_MaxBits),o),l!=-1&&(h=this.match_main(e,a.substring(a.length-this.Match_MaxBits),o+a.length-this.Match_MaxBits),(h==-1||l>=h)&&(l=-1))):l=this.match_main(e,a,o),l==-1)i[s]=!1,r-=t[s].length2-t[s].length1;else{i[s]=!0,r=l-o;var c;if(h==-1?c=e.substring(l,l+a.length):c=e.substring(l,h+this.Match_MaxBits),a==c)e=e.substring(0,l)+this.diff_text2(t[s].diffs)+e.substring(l+a.length);else{var u=this.diff_main(a,c,!1);if(a.length>this.Match_MaxBits&&this.diff_levenshtein(u)/a.length>this.Patch_DeleteThreshold)i[s]=!1;else{this.diff_cleanupSemanticLossless(u);for(var f=0,g,m=0;m<t[s].diffs.length;m++){var p=t[s].diffs[m];p[0]!==k&&(g=this.diff_xIndex(u,f)),p[0]===_?e=e.substring(0,l+g)+p[1]+e.substring(l+g):p[0]===T&&(e=e.substring(0,l+g)+e.substring(l+this.diff_xIndex(u,f+p[1].length))),p[0]!==T&&(f+=p[1].length)}}}}}return e=e.substring(n.length,e.length-n.length),[e,i]};d.prototype.patch_addPadding=function(t){for(var e=this.Patch_Margin,n="",r=1;r<=e;r++)n+=String.fromCharCode(r);for(var r=0;r<t.length;r++)t[r].start1+=e,t[r].start2+=e;var i=t[0],s=i.diffs;if(s.length==0||s[0][0]!=k)s.unshift(new d.Diff(k,n)),i.start1-=e,i.start2-=e,i.length1+=e,i.length2+=e;else if(e>s[0][1].length){var o=e-s[0][1].length;s[0][1]=n.substring(s[0][1].length)+s[0][1],i.start1-=o,i.start2-=o,i.length1+=o,i.length2+=o}if(i=t[t.length-1],s=i.diffs,s.length==0||s[s.length-1][0]!=k)s.push(new d.Diff(k,n)),i.length1+=e,i.length2+=e;else if(e>s[s.length-1][1].length){var o=e-s[s.length-1][1].length;s[s.length-1][1]+=n.substring(0,o),i.length1+=o,i.length2+=o}return n};d.prototype.patch_splitMax=function(t){for(var e=this.Match_MaxBits,n=0;n<t.length;n++)if(!(t[n].length1<=e)){var r=t[n];t.splice(n--,1);for(var i=r.start1,s=r.start2,o="";r.diffs.length!==0;){var a=new d.patch_obj,l=!0;for(a.start1=i-o.length,a.start2=s-o.length,o!==""&&(a.length1=a.length2=o.length,a.diffs.push(new d.Diff(k,o)));r.diffs.length!==0&&a.length1<e-this.Patch_Margin;){var h=r.diffs[0][0],c=r.diffs[0][1];h===_?(a.length2+=c.length,s+=c.length,a.diffs.push(r.diffs.shift()),l=!1):h===T&&a.diffs.length==1&&a.diffs[0][0]==k&&c.length>2*e?(a.length1+=c.length,i+=c.length,l=!1,a.diffs.push(new d.Diff(h,c)),r.diffs.shift()):(c=c.substring(0,e-a.length1-this.Patch_Margin),a.length1+=c.length,i+=c.length,h===k?(a.length2+=c.length,s+=c.length):l=!1,a.diffs.push(new d.Diff(h,c)),c==r.diffs[0][1]?r.diffs.shift():r.diffs[0][1]=r.diffs[0][1].substring(c.length))}o=this.diff_text2(a.diffs),o=o.substring(o.length-this.Patch_Margin);var u=this.diff_text1(r.diffs).substring(0,this.Patch_Margin);u!==""&&(a.length1+=u.length,a.length2+=u.length,a.diffs.length!==0&&a.diffs[a.diffs.length-1][0]===k?a.diffs[a.diffs.length-1][1]+=u:a.diffs.push(new d.Diff(k,u))),l||t.splice(++n,0,a)}}};d.prototype.patch_toText=function(t){for(var e=[],n=0;n<t.length;n++)e[n]=t[n];return e.join("")};d.prototype.patch_fromText=function(t){var e=[];if(!t)return e;for(var n=t.split(`
4
+ `),r=0,i=/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;r<n.length;){var s=n[r].match(i);if(!s)throw new Error("Invalid patch string: "+n[r]);var o=new d.patch_obj;for(e.push(o),o.start1=parseInt(s[1],10),s[2]===""?(o.start1--,o.length1=1):s[2]=="0"?o.length1=0:(o.start1--,o.length1=parseInt(s[2],10)),o.start2=parseInt(s[3],10),s[4]===""?(o.start2--,o.length2=1):s[4]=="0"?o.length2=0:(o.start2--,o.length2=parseInt(s[4],10)),r++;r<n.length;){var a=n[r].charAt(0);try{var l=decodeURI(n[r].substring(1))}catch{throw new Error("Illegal escape in patch_fromText: "+l)}if(a=="-")o.diffs.push(new d.Diff(T,l));else if(a=="+")o.diffs.push(new d.Diff(_,l));else if(a==" ")o.diffs.push(new d.Diff(k,l));else{if(a=="@")break;if(a!=="")throw new Error('Invalid patch mode "'+a+'" in: '+l)}r++}}return e};d.patch_obj=function(){this.diffs=[],this.start1=null,this.start2=null,this.length1=0,this.length2=0};d.patch_obj.prototype.toString=function(){var t,e;this.length1===0?t=this.start1+",0":this.length1==1?t=this.start1+1:t=this.start1+1+","+this.length1,this.length2===0?e=this.start2+",0":this.length2==1?e=this.start2+1:e=this.start2+1+","+this.length2;for(var n=["@@ -"+t+" +"+e+` @@
5
+ `],r,i=0;i<this.diffs.length;i++){switch(this.diffs[i][0]){case _:r="+";break;case T:r="-";break;case k:r=" ";break}n[i+1]=r+encodeURI(this.diffs[i][1])+`
6
+ `}return n.join("").replace(/%20/g," ")};we.exports=d;we.exports.diff_match_patch=d;we.exports.DIFF_DELETE=T;we.exports.DIFF_INSERT=_;we.exports.DIFF_EQUAL=k});import{hostname as Di}from"node:os";import{resolve as Ui}from"node:path";import{createRequire as pr}from"module";var yr=pr("/"),ye,vr,wr;try{ye=yr("worker_threads"),vr=ye.Worker,wr=ye.isMarkedAsUntransferable}catch{}var N=Uint8Array,J=Uint16Array,ft=Int32Array,Oe=new N([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),Ne=new N([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),lt=new N([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),Ht=function(t,e){for(var n=new J(31),r=0;r<31;++r)n[r]=e+=1<<t[r-1];for(var i=new ft(n[30]),r=1;r<30;++r)for(var s=n[r];s<n[r+1];++s)i[s]=s-n[r]<<5|r;return{b:n,r:i}},ye=Ht(Oe,2),Jt=ye.b,ht=ye.r;Jt[28]=258,ht[258]=28;var Kt=Ht(Ne,0),br=Kt.b,Bt=Kt.r,ct=new J(32768);for(C=0;C<32768;++C)te=(C&43690)>>1|(C&21845)<<1,te=(te&52428)>>2|(te&13107)<<2,te=(te&61680)>>4|(te&3855)<<4,ct[C]=((te&65280)>>8|(te&255)<<8)>>1;var te,C,Q=(function(t,e,n){for(var r=t.length,i=0,s=new J(e);i<r;++i)t[i]&&++s[t[i]-1];var o=new J(e);for(i=1;i<e;++i)o[i]=o[i-1]+s[i-1]<<1;var a;if(n){a=new J(1<<e);var l=15-e;for(i=0;i<r;++i)if(t[i])for(var h=i<<4|t[i],c=e-t[i],u=o[t[i]-1]++<<c,f=u|(1<<c)-1;u<=f;++u)a[ct[u]>>l]=h}else for(a=new J(r),i=0;i<r;++i)t[i]&&(a[i]=ct[o[t[i]-1]++]>>15-t[i]);return a}),oe=new N(288);for(C=0;C<144;++C)oe[C]=8;var C;for(C=144;C<256;++C)oe[C]=9;var C;for(C=256;C<280;++C)oe[C]=7;var C;for(C=280;C<288;++C)oe[C]=8;var C,Me=new N(32);for(C=0;C<32;++C)Me[C]=5;var C,kr=Q(oe,9,0),Sr=Q(oe,9,1),Er=Q(Me,5,0),Ar=Q(Me,5,1),st=function(t){for(var e=t[0],n=1;n<t.length;++n)t[n]>e&&(e=t[n]);return e},Z=function(t,e,n){var r=e/8|0;return(t[r]|t[r+1]<<8)>>(e&7)&n},ot=function(t,e){var n=e/8|0;return(t[n]|t[n+1]<<8|t[n+2]<<16)>>(e&7)},dt=function(t){return(t+7)/8|0},jt=function(t,e,n){return(e==null||e<0)&&(e=0),(n==null||n>t.length)&&(n=t.length),new N(t.subarray(e,n))};var xr=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],re=function(t,e,n){var r=new Error(e||xr[t]);if(r.code=t,Error.captureStackTrace&&Error.captureStackTrace(r,re),!n)throw r;return r},Pr=function(t,e,n,r){var i=t.length,s=r?r.length:0;if(!i||e.f&&!e.l)return n||new N(0);var o=!n,a=o||e.i!=2,l=e.i;o&&(n=new N(i*3));var h=function(Ae){var xe=n.length;if(Ae>xe){var pe=new N(Math.max(xe*2,Ae));pe.set(n),n=pe}},c=e.f||0,u=e.p||0,f=e.b||0,g=e.l,m=e.d,p=e.m,x=e.n,w=i*8;do{if(!g){c=Z(t,u,1);var A=Z(t,u+1,3);if(u+=3,A)if(A==1)g=Sr,m=Ar,p=9,x=5;else if(A==2){var $=Z(t,u,31)+257,E=Z(t,u+10,15)+4,v=$+Z(t,u+5,31)+1;u+=14;for(var y=new N(v),D=new N(19),z=0;z<E;++z)D[lt[z]]=Z(t,u+z*3,7);u+=E*3;for(var O=st(D),se=(1<<O)-1,L=Q(D,O,1),z=0;z<v;){var W=L[Z(t,u,se)];u+=W&15;var b=W>>4;if(b<16)y[z++]=b;else{var U=0,R=0;for(b==16?(R=3+Z(t,u,3),u+=2,U=y[z-1]):b==17?(R=3+Z(t,u,7),u+=3):b==18&&(R=11+Z(t,u,127),u+=7);R--;)y[z++]=U}}var B=y.subarray(0,$),F=y.subarray($);p=st(B),x=st(F),g=Q(B,p,1),m=Q(F,x,1)}else re(1);else{var b=dt(u)+4,S=t[b-4]|t[b-3]<<8,M=b+S;if(M>i){l&&re(0);break}a&&h(f+S),n.set(t.subarray(b,M),f),e.b=f+=S,e.p=u=M*8,e.f=c;continue}if(u>w){l&&re(0);break}}a&&h(f+131072);for(var Ee=(1<<p)-1,G=(1<<x)-1,ee=u;;ee=u){var U=g[ot(t,u)&Ee],V=U>>4;if(u+=U&15,u>w){l&&re(0);break}if(U||re(2),V<256)n[f++]=V;else if(V==256){ee=u,g=null;break}else{var H=V-254;if(V>264){var z=V-257,I=Oe[z];H=Z(t,u,(1<<I)-1)+Jt[z],u+=I}var Y=m[ot(t,u)&G],ge=Y>>4;Y||re(3),u+=Y&15;var F=br[ge];if(ge>3){var I=Ne[ge];F+=ot(t,u)&(1<<I)-1,u+=I}if(u>w){l&&re(0);break}a&&h(f+131072);var me=f+H;if(f<F){var Ue=s-F,Fe=Math.min(F,me);for(Ue+f<0&&re(3);f<Fe;++f)n[f]=r[Ue+f]}for(;f<me;++f)n[f]=n[f-F]}}e.l=g,e.p=ee,e.b=f,e.f=c,g&&(c=1,e.m=p,e.d=m,e.n=x)}while(!c);return f!=n.length&&o?jt(n,0,f):n.subarray(0,f)},ne=function(t,e,n){n<<=e&7;var r=e/8|0;t[r]|=n,t[r+1]|=n>>8},Pe=function(t,e,n){n<<=e&7;var r=e/8|0;t[r]|=n,t[r+1]|=n>>8,t[r+2]|=n>>16},at=function(t,e){for(var n=[],r=0;r<t.length;++r)t[r]&&n.push({s:r,f:t[r]});var i=n.length,s=n.slice();if(!i)return{t:qt,l:0};if(i==1){var o=new N(n[0].s+1);return o[n[0].s]=1,{t:o,l:1}}n.sort(function(M,$){return M.f-$.f}),n.push({s:-1,f:25001});var a=n[0],l=n[1],h=0,c=1,u=2;for(n[0]={s:-1,f:a.f+l.f,l:a,r:l};c!=i-1;)a=n[n[h].f<n[u].f?h++:u++],l=n[h!=c&&n[h].f<n[u].f?h++:u++],n[c++]={s:-1,f:a.f+l.f,l:a,r:l};for(var f=s[0].s,r=1;r<i;++r)s[r].s>f&&(f=s[r].s);var g=new J(f+1),m=ut(n[c-1],g,0);if(m>e){var r=0,p=0,x=m-e,w=1<<x;for(s.sort(function($,E){return g[E.s]-g[$.s]||$.f-E.f});r<i;++r){var A=s[r].s;if(g[A]>e)p+=w-(1<<m-g[A]),g[A]=e;else break}for(p>>=x;p>0;){var b=s[r].s;g[b]<e?p-=1<<e-g[b]++-1:++r}for(;r>=0&&p;--r){var S=s[r].s;g[S]==e&&(--g[S],++p)}m=e}return{t:new N(g),l:m}},ut=function(t,e,n){return t.s==-1?Math.max(ut(t.l,e,n+1),ut(t.r,e,n+1)):e[t.s]=n},Lt=function(t){for(var e=t.length;e&&!t[--e];);for(var n=new J(++e),r=0,i=t[0],s=1,o=function(l){n[r++]=l},a=1;a<=e;++a)if(t[a]==i&&a!=e)++s;else{if(!i&&s>2){for(;s>138;s-=138)o(32754);s>2&&(o(s>10?s-11<<5|28690:s-3<<5|12305),s=0)}else if(s>3){for(o(i),--s;s>6;s-=6)o(8304);s>2&&(o(s-3<<5|8208),s=0)}for(;s--;)o(i);s=1,i=t[a]}return{c:n.subarray(0,r),n:e}},$e=function(t,e){for(var n=0,r=0;r<e.length;++r)n+=t[r]*e[r];return n},Gt=function(t,e,n){var r=n.length,i=dt(e+2);t[i]=r&255,t[i+1]=r>>8,t[i+2]=t[i]^255,t[i+3]=t[i+1]^255;for(var s=0;s<r;++s)t[i+s+4]=n[s];return(i+4+r)*8},Vt=function(t,e,n,r,i,s,o,a,l,h,c){ne(e,c++,n),++i[256];for(var u=at(i,15),f=u.t,g=u.l,m=at(s,15),p=m.t,x=m.l,w=Lt(f),A=w.c,b=w.n,S=Lt(p),M=S.c,$=S.n,E=new J(19),v=0;v<A.length;++v)++E[A[v]&31];for(var v=0;v<M.length;++v)++E[M[v]&31];for(var y=at(E,7),D=y.t,z=y.l,O=19;O>4&&!D[lt[O-1]];--O);var se=h+5<<3,L=$e(i,oe)+$e(s,Me)+o,W=$e(i,f)+$e(s,p)+o+14+3*O+$e(E,D)+2*E[16]+3*E[17]+7*E[18];if(l>=0&&se<=L&&se<=W)return Gt(e,c,t.subarray(l,l+h));var U,R,B,F;if(ne(e,c,1+(W<L)),c+=2,W<L){U=Q(f,g,0),R=f,B=Q(p,x,0),F=p;var Ee=Q(D,z,0);ne(e,c,b-257),ne(e,c+5,$-1),ne(e,c+10,O-4),c+=14;for(var v=0;v<O;++v)ne(e,c+3*v,D[lt[v]]);c+=3*O;for(var G=[A,M],ee=0;ee<2;++ee)for(var V=G[ee],v=0;v<V.length;++v){var H=V[v]&31;ne(e,c,Ee[H]),c+=D[H],H>15&&(ne(e,c,V[v]>>5&127),c+=V[v]>>12)}}else U=kr,R=oe,B=Er,F=Me;for(var v=0;v<a;++v){var I=r[v];if(I>255){var H=I>>18&31;Pe(e,c,U[H+257]),c+=R[H+257],H>7&&(ne(e,c,I>>23&31),c+=Oe[H]);var Y=I&31;Pe(e,c,B[Y]),c+=F[Y],Y>3&&(Pe(e,c,I>>5&8191),c+=Ne[Y])}else Pe(e,c,U[I]),c+=R[I]}return Pe(e,c,U[256]),c+R[256]},$r=new ft([65540,131080,131088,131104,262176,1048704,1048832,2114560,2117632]),qt=new N(0),Mr=function(t,e,n,r,i,s){var o=s.z||t.length,a=new N(r+o+5*(1+Math.ceil(o/7e3))+i),l=a.subarray(r,a.length-i),h=s.l,c=(s.r||0)&7;if(e){c&&(l[0]=s.r>>3);for(var u=$r[e-1],f=u>>13,g=u&8191,m=(1<<n)-1,p=s.p||new J(32768),x=s.h||new J(m+1),w=Math.ceil(n/3),A=2*w,b=function(it){return(t[it]^t[it+1]<<w^t[it+2]<<A)&m},S=new ft(25e3),M=new J(288),$=new J(32),E=0,v=0,y=s.i||0,D=0,z=s.w||0,O=0;y+2<o;++y){var se=b(y),L=y&32767,W=x[se];if(p[L]=W,x[se]=L,z<=y){var U=o-y;if((E>7e3||D>24576)&&(U>423||!h)){c=Vt(t,l,0,S,M,$,v,D,O,y-O,c),D=E=v=0,O=y;for(var R=0;R<286;++R)M[R]=0;for(var R=0;R<30;++R)$[R]=0}var B=2,F=0,Ee=g,G=L-W&32767;if(U>2&&se==b(y-G))for(var ee=Math.min(f,U)-1,V=Math.min(32767,y),H=Math.min(258,U);G<=V&&--Ee&&L!=W;){if(t[y+B]==t[y+B-G]){for(var I=0;I<H&&t[y+I]==t[y+I-G];++I);if(I>B){if(B=I,F=G,I>ee)break;for(var Y=Math.min(G,I-2),ge=0,R=0;R<Y;++R){var me=y-G+R&32767,Ue=p[me],Fe=me-Ue&32767;Fe>ge&&(ge=Fe,W=me)}}}L=W,W=p[L],G+=L-W&32767}if(F){S[D++]=268435456|ht[B]<<18|Bt[F];var Ae=ht[B]&31,xe=Bt[F]&31;v+=Oe[Ae]+Ne[xe],++M[257+Ae],++$[xe],z=y+B,++E}else S[D++]=t[y],++M[t[y]]}}for(y=Math.max(y,z);y<o;++y)S[D++]=t[y],++M[t[y]];c=Vt(t,l,h,S,M,$,v,D,O,y-O,c),h||(s.r=c&7|l[c/8|0]<<3,c-=7,s.h=x,s.p=p,s.i=y,s.w=z)}else{for(var y=s.w||0;y<o+h;y+=65535){var pe=y+65535;pe>=o&&(l[c/8|0]=h,pe=o),c=Gt(l,c+1,t.subarray(y,pe))}s.i=o}return jt(a,0,r+dt(c)+i)};var Cr=function(t,e,n,r,i){if(!i&&(i={l:1},e.dictionary)){var s=e.dictionary.subarray(-32768),o=new N(s.length+t.length);o.set(s),o.set(t,s.length),t=o,i.w=s.length}return Mr(t,e.level==null?6:e.level,e.mem==null?i.l?Math.ceil(Math.max(8,Math.min(13,Math.log(t.length)))*1.5):20:12+e.mem,n,r,i)};function gt(t,e){return Cr(t,e||{},0,0)}function Zt(t,e){return Pr(t,{i:2},e&&e.out,e&&e.dictionary)}var Tr=typeof TextDecoder<"u"&&new TextDecoder,_r=0;try{Tr.decode(qt,{stream:!0}),_r=1}catch{}var Yt="basalt/hkdf-aes-gcm/1",he=12,We=128,Qt=he+We/8+1,X=20,Be=new TextEncoder,Rr=new TextDecoder,Ce={auth:"basalt/auth/1",path:"basalt/path/1",content:"basalt/content/1",nonce:"basalt/nonce/1",meta:"basalt/meta/1"};function ce(){let t=globalThis.crypto;if(!t?.subtle)throw new Error("WebCrypto is unavailable, so this vault cannot be opened");return t.subtle}function en(){let t=globalThis.crypto;if(!t?.getRandomValues)throw new Error("no secure random source is available, so a vault cannot be created here");return t.getRandomValues(new Uint8Array(X))}async function tn(t){if(t.length<16)throw new Error(`root secret is ${t.length} bytes, need at least 16`);let e=ce(),n=await e.importKey("raw",ie(t),"HKDF",!1,["deriveKey","deriveBits"]),r=h=>({name:"HKDF",hash:"SHA-256",salt:new Uint8Array(0),info:Be.encode(h)}),[i,s,o,a,l]=await Promise.all([e.deriveBits(r(Ce.auth),n,256),e.deriveKey(r(Ce.path),n,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]),e.deriveKey(r(Ce.content),n,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]),e.deriveKey(r(Ce.nonce),n,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),e.deriveKey(r(Ce.meta),n,{name:"HMAC",hash:"SHA-256"},!1,["sign"])]);return{auth:new Uint8Array(i),path:s,content:o,nonce:a,meta:l}}async function nn(t,e,n){let r=ce(),i=await Ir(e,n),s=await r.encrypt({name:"AES-GCM",iv:ie(i),tagLength:We},t,ie(n)),o=new Uint8Array(he+s.byteLength);return o.set(i,0),o.set(new Uint8Array(s),he),o}async function rn(t,e){if(e.length<he+We/8)throw new Error(`sealed value is ${e.length} bytes, too short to contain a nonce and a tag`);let n=ce(),r=e.subarray(0,he),i=e.subarray(he);try{let s=await n.decrypt({name:"AES-GCM",iv:ie(r),tagLength:We},t,ie(i));return new Uint8Array(s)}catch(s){throw new Error("sealed value failed authentication, so it is not what was stored",{cause:s})}}async function Ir(t,e){let n=await ce().sign("HMAC",t,ie(e));return new Uint8Array(n,0,he)}async function Le(t,e){return Te(await nn(t.path,t.nonce,Be.encode(e)))}async function Ve(t,e){let n=await rn(t.path,He(e));return Rr.decode(n)}var sn=0,on=1;async function zr(t,e){let n=Dr(e)?gt(e,{level:6}):void 0,r=n!==void 0&&n.length<e.length,i=r?n:e,s=new Uint8Array(1+i.length);return s[0]=r?on:sn,s.set(i,1),nn(t.content,t.nonce,s)}function Dr(t){if(t.length===0)return!1;if(t.length<=Xt*2)return!0;let e=t.subarray(0,Xt);return gt(e,{level:6}).length<e.length}var Xt=4096;async function ue(t,e){return Promise.all([...e].map(async n=>{let r=await zr(t,n);return{name:await mt(r),bytes:r}}))}async function an(t,e){let n=await rn(t.content,e);if(n.length===0)throw new Error("sealed chunk carries no marker byte");let r=n[0],i=n.subarray(1);if(r===sn)return i;if(r===on)try{return Zt(i)}catch(s){throw new Error("sealed chunk claims to be deflated and is not",{cause:s})}throw new Error(`sealed chunk has an unknown marker byte ${r}`)}async function mt(t){let e=await ce().digest("SHA-256",ie(t));return pt(new Uint8Array(e))}function ln(t){return Te(t.auth)}function ie(t){return t.byteOffset===0&&t.byteLength===t.buffer.byteLength?t.buffer:t.slice().buffer}function pt(t){let e="";for(let n of t)e+=n.toString(16).padStart(2,"0");return e}var ve="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";function Te(t){let e="";for(let n=0;n<t.length;n+=3){let r=t[n],i=n+1<t.length?t[n+1]:void 0,s=n+2<t.length?t[n+2]:void 0;if(e+=ve[r>>2],e+=ve[(r&3)<<4|(i??0)>>4],i===void 0||(e+=ve[(i&15)<<2|(s??0)>>6],s===void 0))break;e+=ve[s&63]}return e}var Ur=(()=>{let t=new Int16Array(128).fill(-1);for(let e=0;e<ve.length;e++)t[ve.charCodeAt(e)]=e;return t})();function He(t){let e=t.length,n=new Uint8Array(Math.floor(e*3/4)),r=0,i=0,s=0;for(let o=0;o<e;o++){let a=t.charCodeAt(o),l=a<128?Ur[a]:-1;if(l<0)throw new Error(`invalid base64url character ${JSON.stringify(t[o])} at position ${o}`);i=i<<6|l,s+=6,s>=8&&(s-=8,n[r++]=i>>s&255)}return n.subarray(0,r)}function Fr(t){let e=[t.path,String(t.size),String(t.ctime),String(t.mtime),t.folder?"1":"0",t.deleted?"1":"0",t.prev??"",t.parent,String(t.chunks.length),...t.chunks];return Be.encode(e.map(n=>`${n.length}:${n}`).join(""))}async function yt(t,e){let n=await ce().sign("HMAC",t.meta,ie(Fr(e)));return pt(new Uint8Array(n))}async function hn(t,e,n){let r=await yt(t,e);if(r.length!==n.length)return!1;let i=0;for(let s=0;s<r.length;s++)i|=r.charCodeAt(s)^n.charCodeAt(s);return i===0}async function cn(t){if(t==="")return"";let e=await ce().digest("SHA-256",ie(Be.encode(t)));return pt(new Uint8Array(e))}var ae=48,fe=31,Or=1;function un(t,e){let n=t>>>0;return Math.floor(n/e)*e===n-Or}var fn={min:512,avg:1024,max:4096},Nr=64,Wr=fn.avg,Br=64*1024;function Lr(t){let e=Math.sqrt(Nr*Math.max(t,1)),n=Math.min(Br,Math.max(Wr,Math.round(e/512)*512));return{min:Math.max(fn.min,n/2),avg:n,max:n*4}}var vt={min:128*1024,avg:256*1024,max:1024*1024},Vr=4*1024*1024;function dn(t,e,n=vt.max){(!Number.isFinite(n)||n<=0)&&(n=vt.max);let r=e&&t<Vr?Lr(t):vt,i=Math.min(r.max,n-Qt),s=Math.max(i,ae*4);return{min:Math.min(r.min,s),avg:Math.min(r.avg,s),max:s}}function gn(t,e,n){let r=n-1;for(;r>e&&(t[r]&192)===128;)r--;if(r<e)return n;let i=t[r],s=i<128?1:(i&224)===192?2:(i&240)===224?3:(i&248)===240?4:1;return n-r>=s?n:r>e?r:n}function*bt(t,e,n){let{min:r,avg:i,max:s}=e,o=t.length,a=1;for(let c=0;c<ae-1;c++)a=Math.imul(a,fe);let l=0,h=0;for(let c=0;c<o;c++){let u=t[c];c>=l+ae?(h=h-Math.imul(t[c-ae],a)|0,h=Math.imul(h,fe),h=h+u|0):(h=Math.imul(h,fe),h=h+u|0);let f=c-l+1,g=f>=r&&un(h,i);if(f>=s&&(g=!0),g){let m=n?gn(t,l,c+1):c+1;yield{offset:l,bytes:t.subarray(l,m)},l=m,h=0,c=m-1}}l<o&&(yield{offset:l,bytes:t.subarray(l,o)})}var wt=class{constructor(e,n,r){this.buf=e;this.sizes=n;this.pPowW=r}buf;sizes;pPowW;used=0;hash=0;scanTo(e,n){let{min:r,avg:i,max:s}=this.sizes,o=this.buf,a=this.pPowW,l=this.used,h=this.hash;for(let c=n;c<e.length;c++){let u=e[c];if(o[l++]=u,l>=ae+1?(h=h-Math.imul(o[l-1-ae],a)|0,h=Math.imul(h,fe),h=h+u|0):(h=Math.imul(h,fe),h=h+u|0),l>=s||l>=r&&un(h,i))return this.used=l,this.hash=h,c+1}return this.used=l,this.hash=h,-1}};async function*mn(t,e,n){let{max:r}=e,i=1;for(let u=0;u<ae-1;u++)i=Math.imul(i,fe);let s=new Uint8Array(Math.max(r,ae*2)),o=0,a=0,l=0,h=()=>{let u=n?gn(s,0,o):o,f={offset:l,bytes:s.slice(0,u)};l+=u;let g=o-u;s.copyWithin(0,u,o),o=g,a=0;for(let m=0;m<g;m++)a=Math.imul(a,fe),a=a+s[m]|0;return f},c=new wt(s,e,i);for await(let u of t){let f=0;for(;;){let g=c.scanTo(u,f);if(g<0)break;o=c.used,yield h(),c.used=o,c.hash=a,f=g}o=c.used}if(o>0){let u={offset:l,bytes:s.slice(0,o)};l+=o,o=0,yield u}}var Hr=new Set(["md","txt","canvas","json","csv","yml","yaml","xml","html","css","js","ts","svg","bib","tex"]);function pn(t){let e=t.lastIndexOf(".");return e<0?!1:Hr.has(t.slice(e+1).toLowerCase())}var Jr=new Set(["canvas","json"]);function yn(t){let e=t.lastIndexOf(".");return e<0?!1:Jr.has(t.slice(e+1).toLowerCase())}var kn=mr(vn(),1),Kr=-1,jr=0,Gr=1;function wn(t){let e=[],n=0;for(let[r,i]of t)r===jr?n+=i.length:r===Kr?(e.push({start:n,end:n+i.length}),n+=i.length):e.push({start:n,end:n});return e}function qr(t,e){for(let n of t)for(let r of e){let i=n.start===n.end,s=r.start===r.end;if(!(i&&s)){if(i){if(r.start<n.start&&n.start<r.end)return n;continue}if(s){if(n.start<r.start&&r.start<n.end)return r;continue}if(n.start<r.end&&r.start<n.end)return n}}}function Sn(t,e,n,r=()=>!0){if(e===n)return{kind:"take",text:e,why:"both sides already agree"};if(t===e)return{kind:"take",text:n,why:"no local change since the last sync"};if(t===n)return{kind:"take",text:e,why:"no remote change since the last sync"};let i=new kn.diff_match_patch,s=i.diff_main(t,e,!0,0);s.length>2&&(i.diff_cleanupSemantic(s),i.diff_cleanupEfficiency(s));let o=i.diff_main(t,n,!0,0);o.length>2&&(i.diff_cleanupSemantic(o),i.diff_cleanupEfficiency(o));let a=qr(wn(s),wn(o));if(a!==void 0)return{kind:"conflict",why:`both devices changed the same text, at characters ${a.start} to ${a.end} of the last synced version`};let l=bn(i,t,s,n),h=bn(i,t,o,e);if(l.failed>0||h.failed>0){let u=Math.max(l.failed,h.failed),f=Math.max(l.total,h.total);return{kind:"conflict",why:`${u} of ${f} changes could not be placed in the other version`}}if(!Zr(l.text,h.text))return{kind:"conflict",why:"merging the two versions in either order gives different content, so at least one change was placed wrongly"};let c=Xr(s,l.text);return c!==void 0?{kind:"conflict",why:`the merge reported success but ${Yr(c)} is not in the result`}:r(l.text)?{kind:"merged",text:l.text}:{kind:"conflict",why:"both sides merged cleanly and the result is no longer a valid file of its kind"}}function Zr(t,e){if(t===e)return!0;let n=t.split(`
7
7
  `).sort(),r=e.split(`
8
- `).sort();if(n.length!==r.length)return!1;for(let i=0;i<n.length;i++)if(n[i]!==r[i])return!1;return!0}function cn(t,e,n,r){let[i,s]=t.patch_apply(t.patch_make(e,n),r);return{text:i,failed:s.filter(o=>!o).length,total:s.length}}function Or(t,e){for(let[n,r]of t)if(n===Dr&&!e.includes(r))return r}function Fr(t){let e=t.replace(/\s+/g," ").trim(),n=e.length>60?`${e.slice(0,57)}...`:e;return`a local edit (${JSON.stringify(n)})`}function dn(t,e,n){let r=t.lastIndexOf("."),i=t.lastIndexOf("/"),s=r>i,o=s?t.slice(0,r):t,a=s?t.slice(r):"",l=(h,u=2)=>String(h).padStart(u,"0"),c=`${n.getFullYear()}${l(n.getMonth()+1)}${l(n.getDate())}${l(n.getHours())}${l(n.getMinutes())}`;return`${o} (Conflicted copy ${Nr(e)} ${c})${a}`}function Nr(t){return t.replace(/[-\\/:*?"<>|\s]/g,"-").replace(/-{2,}/g,"-").replace(/^[.\-\s]+|[.\-\s]+$/g,"").slice(0,32)||"device"}function ft(t){return{path:t,prev:"",folder:!1,ctime:0,mtime:0,size:0,hash:"",chunks:[],synchash:"",syncuid:0,synctime:0}}function gn(t){let{local:e,remote:n,index:r,mergeable:i}=t,s=r.synchash;return e?.folder||n?.folder?Br(e,n):e===void 0&&(n===void 0||n.deleted)?{kind:"nothing",why:"absent on both sides"}:n===void 0?{kind:"upload",why:"new file, the server has never held this path"}:e===void 0?Lr(n,r):n.deleted?e.hash===s&&s!==""?{kind:"deleteLocal",why:"deleted on another device and unchanged here"}:s===""?{kind:"upload",why:"deleted on the server but never synced from here"}:{kind:"upload",why:"deleted on another device but edited here, so the edit is kept and re-sent"}:e.hash===n.hash?{kind:"nothing",why:"the two sides hold the same content"}:s===""?{kind:"conflict",why:"both sides have content and there is no last-synced version to merge from"}:e.hash===s?{kind:"download",why:"changed on another device and unchanged here"}:n.hash===s?{kind:"upload",why:"changed here and unchanged on the server"}:i?{kind:"merge",why:"changed on both sides since the last sync"}:{kind:"conflict",why:"changed on both sides and this file cannot be merged"}}function Br(t,e){return t!==void 0&&t.folder?e===void 0?{kind:"upload",why:"new folder, the server has never held this path"}:e.deleted?{kind:"nothing",why:"folder deleted elsewhere; its files decide"}:e.folder?{kind:"nothing",why:"folder exists on both sides"}:{kind:"clash",why:"a folder here and a file of the same name on another device"}:e?.folder&&!e.deleted?t!==void 0?{kind:"clash",why:"a file here and a folder of the same name on another device"}:{kind:"createLocalFolder",why:"folder exists on the server and not here"}:{kind:"nothing",why:"folder absent on both sides"}}function Lr(t,e){let n=e.synchash;return t.deleted?{kind:"nothing",why:"deleted on both sides"}:n===""?{kind:"download",why:"new on the server"}:t.hash===n?{kind:"deleteRemote",why:"deleted here and unchanged on the server"}:{kind:"restoreLocal",why:"deleted here but changed on another device, so the newer content is restored"}}function dt(t,e,n){return t.hash===""||t.chunks.length===0?!0:t.mtime!==e||t.size!==n}function Pe(t,e){let n=Math.ceil(e.mtime),r=Math.ceil(e.ctime);if(e.folder){t.folder=!0,t.mtime=0,t.ctime=0,t.size=0,t.hash="",t.chunks=[];return}dt(t,n,Wr(e))&&(t.hash="",t.chunks=[]),t.folder=!1,t.mtime=n,t.ctime=r,t.size=e.size}function Wr(t){return t.size}function mn(t,e,n){t.path=n,t.prev===""&&(t.prev=e),t.prev===n&&(t.prev=""),t.synctime=0}function ve(t,e,n,r,i){t.hash=e,t.chunks=[...n],t.synchash=e,t.syncuid=r,t.synctime=i,t.prev=""}function vn(t,e){if(!t.synctime)return!0;let n=t.size>102400?30:t.size>10240?20:10;return e-t.synctime>n*1e3}var gt=1,pn=6e4,$e=256;function yn(t){return{size:t.size,ctime:t.ctime,mtime:t.mtime,folder:t.folder??!1,deleted:t.deleted??!1,...t.prev?{prev:t.prev}:{}}}var P=class extends Error{constructor(n,r){super(r);this.code=n;this.name="ProtocolError"}code;get fatal(){return["proto","auth","cursor","busy","protostate","badchunk","internal"].includes(this.code)}};function Vr(t){return t.startsWith("wss://")?`. If that server has no TLS in front of it, pair with ws://${t.slice(6)} instead`:""}var j=class extends Error{constructor(e){super(e),this.name="ConnectionError"}},Ve=class{constructor(e,n){this.url=e;this.opts=n}url;opts;socket;replyWaiter;replyTimer;bodyWaiter;bodyQueue=[];expecting=0;requestsSent=0;closed=!1;closeReason;cursor=0;notifying=Promise.resolve();log(e,...n){this.opts.log?.(e,...n)}get appliedCursor(){return this.cursor}async connect(){if(this.socket)throw new Error("already connected");let n=(this.opts.socketFactory??Jr)(this.url);n.binaryType="arraybuffer",this.socket=n,await new Promise((r,i)=>{n.onopen=()=>r(),n.onerror=()=>i(new j(`could not connect to ${this.url}${Vr(this.url)}`)),n.onclose=s=>i(new j(`connection closed before opening: ${wn(s)}`))}),n.onerror=()=>this.die(new j("the connection failed")),n.onclose=r=>this.die(new j(`the connection closed: ${wn(r)}`)),n.onmessage=r=>this.onFrame(r.data)}die(e){if(this.closed)return;this.closed=!0,this.closeReason=e,this.log("transport closed",e.message),this.disarmReply();let n=this.replyWaiter,r=this.bodyWaiter;this.replyWaiter=void 0,this.bodyWaiter=void 0,n?.reject(e),r?.reject(e);try{this.socket?.close()}catch{}try{this.opts.onClosed?.(e)}catch{}}disarmReply(){this.replyTimer!==void 0&&(clearTimeout(this.replyTimer),this.replyTimer=void 0)}close(){this.die(new j("closed by this device"))}get isClosed(){return this.closed}onFrame(e){if(typeof e=="string"){let i;try{i=JSON.parse(e)}catch{this.die(new P("protostate",`server sent a frame that is not JSON: ${e.slice(0,120)}`));return}this.onTextFrame(i);return}let n=Kr(e);if(n===void 0){this.die(new P("protostate","server sent a frame of an unexpected type"));return}let r=this.bodyWaiter;if(r){this.bodyWaiter=void 0,r.resolve(n);return}if(this.bodyQueue.length>=this.expecting){this.die(new P("protostate",`server sent a ${n.length} byte body with nothing outstanding to receive it`));return}this.bodyQueue.push(n)}onTextFrame(e){if(e.op==="batch"){this.queueNotification(()=>this.onBatchFrame(e));return}if(e.op==="caught-up"){let r=H(e.cursor);this.queueNotification(async()=>{if(r!==this.cursor){this.die(new P("protostate",`server says caught up at ${r}, this device reached ${this.cursor}`));return}this.opts.onCaughtUp?.(r)});return}let n=this.replyWaiter;if(!n){this.die(new P("protostate",`server sent an unexpected reply: ${JSON.stringify(e)}`));return}this.replyWaiter=void 0,n.resolve(e)}queueNotification(e){this.notifying=this.notifying.then(e).catch(n=>{this.die(n instanceof Error?n:new Error(String(n)))})}async onBatchFrame(e){let n=H(e.from),r=H(e.to),i=e.entries;if(!Array.isArray(i))throw new P("protostate",`batch ${n} to ${r} carries no entries array, so an empty batch cannot be told from a lost one`);let s=i;if(n!==this.cursor+1)throw new P("protostate",`batch covers ${n} to ${r} but this device has applied up to ${this.cursor}, so something was skipped`);if(r<n)throw new P("protostate",`batch covers an empty range, ${n} to ${r}`);for(let o of s){if(typeof o?.uid!="number"||!Number.isFinite(o.uid))throw new P("protostate",`batch ${n}..${r} contains an entry with no uid`);if(typeof o.path!="string"||o.path==="")throw new P("protostate",`batch ${n}..${r} contains uid ${o.uid} with no path`);if(!Array.isArray(o.chunks))throw new P("protostate",`batch ${n}..${r} contains uid ${o.uid} with no chunks array`);if(o.uid<n||o.uid>r)throw new P("protostate",`batch ${n}..${r} contains uid ${o.uid}`)}await this.opts.onBatch({from:n,to:r,entries:s}),this.cursor=r}send(e){if(this.closed||!this.socket)throw this.closeReason??new j("not connected");this.socket.send(JSON.stringify(e))}sendBody(e){if(this.closed||!this.socket)throw this.closeReason??new j("not connected");this.socket.send(e)}async request(e){if(this.replyWaiter)throw new Error("a request is already in flight");this.requestsSent++;let n=this.opts.timeoutMs??pn,r=await new Promise((i,s)=>{let o=setTimeout(()=>{this.die(new j(`no reply within ${n}ms`))},n);this.replyTimer=o,this.replyWaiter={resolve:a=>{this.disarmReply(),i(a)},reject:a=>{this.disarmReply(),s(a)}};try{this.send(e)}catch(a){this.disarmReply(),this.replyWaiter=void 0,s(a instanceof Error?a:new Error(String(a)))}});if(r.res==="err"){let i=new P(String(r.code??"unknown"),String(r.msg??"no message"));throw i.fatal&&this.die(i),i}return r}async body(){let e=this.bodyQueue.shift();if(e)return e;if(this.closed)throw this.closeReason??new j("not connected");return new Promise((n,r)=>{this.bodyWaiter={resolve:n,reject:r}})}async hello(e){this.cursor=e.cursor;let n=await this.request({op:"hello",proto:gt,crypto:Wt,vault:e.vault,token:e.token,device:e.device,cursor:e.cursor,...e.claim!==void 0?{claim:e.claim}:{}});if(n.res!=="ready")throw new P("protostate",`expected ready, got ${JSON.stringify(n)}`);let r={proto:H(n.proto),cursor:H(n.cursor),perFileMax:H(n.perFileMax),chunkMax:H(n.chunkMax),maxChunks:H(n.maxChunks)};if(r.proto!==gt)throw new P("proto",`server speaks protocol ${r.proto}, this client speaks ${gt}`);return this.log("ready",r),r}async put(e,n,r,i){let s=await this.request({op:"put",path:e,meta:yn(n),chunks:[...r]});if(s.res==="have")return{uid:H(s.uid),uploaded:0,bytes:0};if(s.res!=="want")throw new P("protostate",`expected want or have, got ${JSON.stringify(s)}`);let o=mt(s.chunks),a=new Set(r),l=0;for(let h of o){if(!a.has(h))throw new P("badchunk",`server asked for ${h}, which this put does not contain`);let u=await i(h);this.sendBody(u),l+=u.length}return{uid:await this.awaitAck(),uploaded:o.length,bytes:l}}async putMany(e,n){if(e.length===0)return{results:[],uploaded:0,bytes:0};if(e.length>$e)throw new P("toolarge",`${e.length} entries in one batch, the limit is ${$e}`);let r=await this.request({op:"putmany",entries:e.map(c=>({path:c.path,meta:yn(c.meta),chunks:[...c.names]}))}),i=r,s=0,o=0;if(r.res==="want"){let c=mt(r.chunks),h=new Set;for(let u of e)for(let f of u.names)h.add(f);for(let u of c){if(!h.has(u))throw new P("badchunk",`server asked for ${u}, which this batch does not contain`);let f=await n(u);this.sendBody(f),o+=f.length}s=c.length,i=await this.awaitReply()}if(i.res!=="acks")throw new P("protostate",`expected acks, got ${JSON.stringify(i)}`);let a=i.results;if(!Array.isArray(a)||a.length!==e.length)throw new P("protostate",`${e.length} entries went up and ${Array.isArray(a)?a.length:"no"} results came back`);let l=a.map(c=>{let h=c??{};return h.code!==void 0?{uid:0,error:new P(String(h.code),String(h.msg??"no message"))}:{uid:H(h.uid)}});for(let c of l)c.error?.fatal&&this.die(c.error);return{results:l,uploaded:s,bytes:o}}async awaitAck(){let e=await this.awaitReply();if(e.res!=="ack")throw new P("protostate",`expected ack, got ${JSON.stringify(e)}`);return H(e.uid)}async awaitReply(){let e=await new Promise((n,r)=>{if(this.closed){r(this.closeReason??new j("not connected"));return}let i=this.opts.timeoutMs??pn,s=setTimeout(()=>{this.die(new j(`no acknowledgement within ${i}ms`))},i);this.replyWaiter={resolve:o=>{clearTimeout(s),n(o)},reject:o=>{clearTimeout(s),r(o)}}});if(e.res==="err"){let n=new P(String(e.code??"unknown"),String(e.msg??"no message"));throw n.fatal&&this.die(n),n}return e}async get(e){let n=await this.request({op:"get",uid:e});if(n.res!=="chunks")throw new P("protostate",`expected chunks, got ${JSON.stringify(n)}`);return{uid:H(n.uid),size:H(n.size),chunks:mt(n.chunks)}}async history(e,n={}){let r=await this.request({op:"history",path:e,...n.before!==void 0?{before:n.before}:{},...n.limit!==void 0?{limit:n.limit}:{}});if(r.res!=="history")throw new P("protostate",`expected history, got ${JSON.stringify(r)}`);return bn(r.entries,"history")}async deleted(e){let n=await this.request({op:"deleted",...e!==void 0?{limit:e}:{}});if(n.res!=="deleted")throw new P("protostate",`expected deleted, got ${JSON.stringify(n)}`);return{entries:bn(n.entries,"deleted"),more:n.more===!0}}async fetch(e){if(e.length===0)return[];this.expecting+=e.length;let n=this.request({op:"fetch",chunks:[...e]}),r=[];try{for(let i=0;i<e.length;i++){let s=await Promise.race([this.body(),n.then(a=>{throw new P("protostate",`expected a chunk body, got ${JSON.stringify(a)}`)})]),o=await ct(s);if(o!==e[i])throw new P("badchunk",`asked for ${e[i]} and received ${s.length} bytes that hash to ${o}`);r.push(s)}}catch(i){throw this.expecting=0,this.disarmReply(),this.replyWaiter=void 0,i instanceof P&&i.code==="badchunk"&&this.die(i),i}return this.expecting=Math.max(0,this.expecting-e.length),this.disarmReply(),this.replyWaiter=void 0,r}async ping(){let e=await this.request({op:"ping"});if(e.res!=="pong")throw new P("protostate",`expected pong, got ${JSON.stringify(e)}`)}},Je=class{constructor(e=0,n=3e5,r=5e3,i=!0,s=Math.random){this.min=e;this.max=n;this.base=r;this.jitter=i;this.random=s}min;max;base;jitter;random;count=0;nextAt=0;success(e){this.count=0,this.nextAt=e+this.delay()}fail(e){this.count++,this.nextAt=e+this.delay()}delay(){if(this.count===0)return this.min;let e=this.base*Math.pow(2,this.count-1);return this.jitter&&(e*=.5+.5*this.random()),Math.floor(Math.min(this.max,this.min+e))}readyAt(){return this.nextAt}isReady(e){return e>=this.nextAt}get failures(){return this.count}};function Jr(t){let e=globalThis.WebSocket;if(!e)throw new Error("no WebSocket available in this environment");return new e(t)}function Kr(t){if(t instanceof Uint8Array)return t;if(t instanceof ArrayBuffer)return new Uint8Array(t);if(ArrayBuffer.isView(t))return new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}function H(t){return typeof t=="number"&&Number.isFinite(t)?t:0}function mt(t){return Array.isArray(t)?t.filter(e=>typeof e=="string"):[]}function wn(t){let e=t.code??0,n=t.reason?`, ${t.reason}`:"";return`code ${e}${n}`}function bn(t,e){if(!Array.isArray(t))throw new P("protostate",`${e} came back without a list of entries`);return t}function kn(t){let e=t.split("/");e.pop();let n=[],r="";for(let i of e)r=r?`${r}/${i}`:i,n.push(r);return n}function Me(t){return t.length===0?"-empty-":t.join(",")}function Hr(t){return t===""||t==="-empty-"?[]:t.split(",")}function Sn(){return{uploaded:0,downloaded:0,merged:0,conflicted:0,deletedLocally:0,deletedRemotely:0,restored:0,foldersCreated:0,unchanged:0,waiting:0,retrying:0,skipped:0,blocked:0,chunksSent:0,bytesSent:0}}var Ke=class{constructor(e){this.opts=e}opts;entries=new Map;remote=new Map;pending=new Set;retries=new Map;skipped=new Map;blocked=new Set;cannotStream=!1;outbox=[];outboxBytes=0;inbox=[];inboxBytes=0;limits;unsealed=new Map;cursor=0;syncing=!1;again=!1;started=!1;now(){return this.opts.now?.()??Date.now()}log(e,...n){this.opts.log?.(e,...n)}mergeable(e){return(this.opts.mergeable??on)(e)}sizesFor(e,n){return tn(e,n,this.limits?.chunkMax)}get coalesce(){return this.opts.coalesceWrites??!0}status(){let e=0;for(let n of this.entries.values())n.folder||e++;return{cursor:this.cursor,files:e,pending:this.pending.size,retrying:this.retries.size,skipped:this.skipped.size,syncing:this.syncing}}async start(){if(this.started)throw new Error("already started");this.started=!0;let e=await this.opts.store.load();if(e){this.cursor=e.cursor;for(let[r,i]of Object.entries(e.entries))this.entries.set(r,{...ft(r),...i});for(let[r,i]of Object.entries(e.remote))this.remote.set(r,i);for(let r of e.pending)this.pending.add(r);this.log("index loaded",{cursor:this.cursor,entries:this.entries.size,pending:this.pending.size})}let n=await this.opts.transport.hello({vault:this.opts.vaultId,token:this.opts.token,device:this.opts.device,cursor:this.cursor,...this.opts.claim!==void 0?{claim:this.opts.claim}:{}});return this.limits=n,this.log("connected",n),n}async acceptBatch(e){for(let n of e.entries){let r=await this.plaintextPath(n.path);if(this.remote.set(r,{uid:n.uid,folder:n.folder,deleted:n.deleted,mtime:n.mtime,size:n.size,hash:Me(n.chunks)}),this.pending.add(r),n.prev){let i=await this.plaintextPath(n.prev);this.remote.set(i,{uid:n.uid,folder:!1,deleted:!0,mtime:n.mtime,size:0,hash:""}),this.pending.add(i)}}this.cursor=e.to}async plaintextPath(e){let n=this.unsealed.get(e);if(n!==void 0)return n;let r=await Le(this.opts.keys,e);return this.unsealed.set(e,r),r}async sync(e={}){if(this.syncing)return this.again=!0,Sn();this.syncing=!0;try{let n=await this.pass(e);for(;this.again;){this.again=!1;let r=await this.pass(e);n=jr(n,r)}return n}finally{this.syncing=!1}}async pass(e={}){let n=Sn(),r=this.now(),i=e.coalesceWrites??this.coalesce;(this.outbox.length>0||this.inbox.length>0)&&(this.log("a pass ended early, discarding what it had queued",{writes:this.outbox.length,reads:this.inbox.length}),this.outbox=[],this.outboxBytes=0,this.inbox=[],this.inboxBytes=0);let s=await this.opts.vault.list(),o=new Map(s.map(h=>[h.path,h]));for(let h of s){let u=this.entryFor(h.path);Pe(u,h)}let a=new Set;for(let[h,u]of o)u.folder||a.add(h);let l=new Set,c=new Set([...o.keys(),...this.entries.keys(),...this.remote.keys()]);for(let h of[...c].sort()){let u=this.skipped.get(h);if(u){if(vt(this.entries.get(h))===u.fingerprint){n.skipped++;continue}this.skipped.delete(h),this.log("skipped file changed, trying again",h)}let f=kn(h).find(m=>a.has(m));if(f!==void 0&&!o.has(h)){l.add(h),this.blocked.has(h)||this.log("cannot be both",h,`${f} is a file here and a folder elsewhere`),n.blocked++;continue}let g=this.retries.get(h);if(g&&g.at>r){n.retrying++;continue}try{this.opts.onProgress?.(h),await this.reconcile(h,o.get(h),n,r,i),this.retries.delete(h)}catch(m){this.recordFailure(h,m,n)}}return await this.fill(n),await this.flush(n),this.opts.onProgress?.(void 0),this.blocked=l,this.prune(o),await this.save(),n}entryFor(e){let n=this.entries.get(e);return n||(n=ft(e),this.entries.set(e,n)),n}async reconcile(e,n,r,i,s){let o=this.entryFor(e),a=this.remote.get(e),l=this.limits?.perFileMax??0;if(n&&!n.folder&&l>0&&n.size>l){this.recordFailure(e,Xr(n.size,l),r);return}let c,h;n&&(!n.folder&&dt(o,Math.ceil(n.mtime),n.size)&&(h=await this.rehash(o,e,n.size)),c={folder:n.folder,mtime:o.mtime,size:o.size,hash:o.hash});let u=gn({local:c,remote:a,index:o,mergeable:this.mergeable(e)});if(s&&u.kind!=="nothing"&&c&&!n?.folder&&!vn(o,i)){r.waiting++;return}await this.act(e,u,o,c,a,r,h),this.pending.delete(e)}async rehash(e,n,r){let i=await this.streamScan(e,n,r);if(i)return i;let s=await this.opts.vault.read(n),o=this.mergeable(n),a=[...rn(s,this.sizesFor(s.length,o),o)],l=a.map(c=>c.bytes);if(s.length<=En){let c=await ge(this.opts.keys,l);return e.chunks=c.map(h=>h.name),e.hash=Me(e.chunks),e.size=s.length,{bytes:s,pieces:a,names:e.chunks,sealed:c}}return e.chunks=await this.namesOf(l),e.hash=Me(e.chunks),e.size=s.length,{bytes:s,pieces:a,names:e.chunks}}async streamScan(e,n,r){let i=this.opts.vault;if(!(!i.readBlocks||!i.readRange||this.cannotStream)&&!(r===void 0||r<=En))try{return await this.streamed(e,n,r)}catch(s){this.cannotStream=!0,this.log("streaming is not available here, reading whole files instead",n,{why:s.message});return}}async streamed(e,n,r){let i=this.opts.vault,s=this.mergeable(n),o=[],a=[],l=0;for await(let c of sn(i.readBlocks(n),this.sizesFor(r,s),s)){let h=await ge(this.opts.keys,[c.bytes]);o.push(h[0].name),a.push({start:c.offset,end:c.offset+c.bytes.length}),l+=c.bytes.length}return e.chunks=o,e.hash=Me(o),e.size=l,{names:o,spans:a,path:n,size:l}}namesOf(e){return qr(this.opts.keys,e)}async act(e,n,r,i,s,o,a){switch(n.kind){case"nothing":o.unchanged++,i&&s&&!s.deleted&&i.hash===s.hash&&ve(r,i.hash,r.chunks,s.uid,this.now());return;case"upload":await this.upload(e,r,o,!0,a);return;case"download":case"restoreLocal":{if(!s)return;await this.receive(e,r,s,n.kind,n.why,o);return}case"createLocalFolder":await this.opts.vault.mkdir(e),r.folder=!0,s&&ve(r,"",[],s.uid,this.now()),o.foldersCreated++;return;case"clash":this.skipped.set(e,{why:`${n.why}. Rename one of them, and it will sync.`,fingerprint:vt(r)}),o.skipped++,this.log("cannot be both",e,n.why);return;case"deleteLocal":await this.opts.vault.remove(e),this.entries.delete(e),o.deletedLocally++,this.log("deleted locally",e,n.why);return;case"deleteRemote":await this.queue({path:e,size:0,entry:{path:await this.sealedPath(e),meta:{size:0,ctime:0,mtime:this.now(),deleted:!0},names:[]},bodyOf:xn,commit:l=>{this.remote.set(e,{uid:l,folder:!1,deleted:!0,mtime:this.now(),size:0,hash:""}),this.entries.delete(e),o.deletedRemotely++,this.log("deleted on the server",e,n.why)}},o);return;case"merge":await this.merge(e,r,s,o);return;case"conflict":await this.conflict(e,r,s,o,n.why);return}}async upload(e,n,r,i=!1,s){if(n.folder){await this.queue({path:e,size:0,entry:{path:await this.sealedPath(e),meta:{size:0,ctime:0,mtime:0,folder:!0},names:[]},bodyOf:xn,commit:u=>{ve(n,"",[],u,this.now()),this.remote.set(e,{uid:u,folder:!0,deleted:!1,mtime:0,size:0,hash:""}),i&&r.uploaded++}},r);return}let o=await this.planUpload(n,e,s),a=n.hash,l=[...n.chunks],c=n.size,h=n.mtime;await this.queue({path:e,size:c,entry:{path:await this.sealedPath(e),meta:{size:c,ctime:n.ctime,mtime:h,...n.prev?{prev:await this.sealedPath(n.prev)}:{}},names:o.names},bodyOf:o.bodyOf,commit:u=>{ve(n,a,l,u,this.now()),this.remote.set(e,{uid:u,folder:!1,deleted:!1,mtime:h,size:c,hash:a}),i&&r.uploaded++,this.log("uploaded",e)}},r)}async queue(e,n){this.outbox.push(e),this.outboxBytes+=e.size,(this.outbox.length>=$e||this.outboxBytes>=An)&&await this.flush(n)}async flush(e){if(this.outbox.length===0)return;let n=this.outbox;this.outbox=[],this.outboxBytes=0;let r=new Map;for(let s of n)for(let o of s.entry.names)r.has(o)||r.set(o,s.bodyOf);let i;try{i=await this.opts.transport.putMany(n.map(s=>s.entry),async s=>{let o=r.get(s);if(!o)throw new Error(`server asked for ${s}, which no queued file contains`);return o(s)})}catch(s){for(let o of n)this.recordFailure(o.path,s,e);return}e.chunksSent+=i.uploaded,e.bytesSent+=i.bytes;for(let s=0;s<n.length;s++){let o=n[s],a=i.results[s];if(a.error){this.recordFailure(o.path,a.error,e);continue}o.commit(a.uid)}}async planUpload(e,n,r){let i=r??await this.scan(e,n);if(i.sealed){let c=new Map(i.sealed.map(h=>[h.name,h.bytes]));return{names:i.names,bodyOf:async h=>{let u=c.get(h);if(!u)throw new Error(`no sealed body for ${h} of ${n}`);return u}}}let s=this.opts.keys,o=this.opts.vault;if(i.spans){let c=new Map(i.names.map((h,u)=>[h,i.spans[u]]));return{names:i.names,bodyOf:async h=>{let u=c.get(h);if(!u)throw new Error(`no chunk named ${h} in ${n}`);let f=await o.readRange(i.path,u.start,u.end),g=await ge(s,[f]);if(g[0].name!==h)throw new Error(`${n} changed while it was being sent, so it was not sent`);return g[0].bytes}}}let a=new Map;for(let c=0;c<i.names.length;c++){let h=i.pieces[c];a.set(i.names[c],{start:h.offset,end:h.offset+h.bytes.length})}let l=i.bytes;return{names:i.names,bodyOf:async c=>{let h=a.get(c);if(!h)throw new Error(`no chunk named ${c} in ${n}`);return(await ge(s,[l.subarray(h.start,h.end)]))[0].bytes}}}scan(e,n){return this.rehash(e,n)}async receive(e,n,r,i,s,o){let a=Hr(r.hash);this.checkChunkCount(r.uid,a.length),this.inbox.push({path:e,entry:n,remote:r,chunks:a,kind:i,why:s}),this.inboxBytes+=r.size,(this.inbox.length>=$e||this.inboxBytes>=An)&&await this.fill(o)}async fill(e){if(this.inbox.length===0)return;let n=this.inbox;this.inbox=[],this.inboxBytes=0;let r=[],i=new Set;for(let o of n)for(let a of o.chunks)i.has(a)||(i.add(a),r.push(a));let s=new Map;if(r.length>0)try{let o=await this.opts.transport.fetch(r);for(let a=0;a<r.length;a++)s.set(r[a],o[a])}catch(o){for(let a of n)this.recordFailure(a.path,o,e);return}for(let o of n)try{await this.land(o,s),o.kind==="download"?e.downloaded++:e.restored++,this.log(o.kind,o.path,o.why)}catch(a){this.recordFailure(o.path,a,e)}}async land(e,n){let r=e.chunks.map(s=>{let o=n.get(s);if(!o)throw new Error(`the server did not send ${s}, which ${e.path} is made of`);return o}),i=await this.assemble(e.remote.uid,r);await this.opts.vault.write(e.path,i,{mtime:e.remote.mtime,ctime:e.remote.mtime}),Pe(e.entry,{folder:!1,mtime:e.remote.mtime,ctime:e.remote.mtime,size:i.length}),e.entry.chunks=[...e.chunks],e.entry.hash=Me(e.chunks),e.entry.size=i.length,ve(e.entry,e.entry.hash,e.entry.chunks,e.remote.uid,this.now())}async contentOf(e,n){let r=n!==void 0?{chunks:n}:await this.opts.transport.get(e);return r.chunks.length===0?new Uint8Array(0):(this.checkChunkCount(e,r.chunks.length),this.assemble(e,await this.opts.transport.fetch(r.chunks)))}checkChunkCount(e,n){let r=this.limits?.maxChunks??0;if(r>0&&n>r)throw new Error(`version ${e} names ${n} chunks, and this server said it stores at most ${r}`)}async assemble(e,n){if(n.length===0)return new Uint8Array(0);let r=[],i=0,s=this.limits?.perFileMax??0;for(let l of n){let c=await Xt(this.opts.keys,l);if(i+=c.length,s>0&&i>s)throw new Error(`version ${e} is over ${i} bytes, and this server said it stores at most ${s}`);r.push(c)}let o=new Uint8Array(i),a=0;for(let l of r)o.set(l,a),a+=l.length;return o}async merge(e,n,r,i){if(!r)return;let s=new TextDecoder("utf-8",{fatal:!0}),o,a,l;try{o=s.decode(await this.contentOf(n.syncuid)),a=s.decode(await this.opts.vault.read(e)),l=s.decode(await this.contentOf(r.uid))}catch{let u="one side is not valid UTF-8, so merging it would rewrite bytes nobody edited";this.log("merge refused",e,u),await this.conflict(e,n,r,i,u);return}let c=fn(o,a,l,an(e)?Yr:void 0);if(c.kind==="conflict"){this.log("merge refused",e,c.why),await this.conflict(e,n,r,i,c.why);return}let h=c.text;h!==a&&await this.opts.vault.write(e,new TextEncoder().encode(h),{mtime:this.now(),ctime:n.ctime}),Pe(n,{folder:!1,mtime:this.now(),ctime:n.ctime,size:h.length}),await this.upload(e,n,i),i.merged++,this.log("merged",e,c.kind==="merged"?"three-way":c.why)}freeConflictPath(e){return Zr(dn(e,this.opts.device,new Date(this.now())),n=>this.opts.vault.exists(n))}async conflict(e,n,r,i,s){if(!r)return;let o=await this.freeConflictPath(e),a=await this.contentOf(r.uid);await this.opts.vault.write(o,a,{mtime:r.mtime,ctime:r.mtime});let l=this.entryFor(o);Pe(l,{folder:!1,mtime:r.mtime,ctime:r.mtime,size:a.length}),await this.upload(o,l,i),await this.upload(e,n,i),i.conflicted++,this.log("kept both",e,{copy:o,why:s})}async sealedPath(e){let n=await Be(this.opts.keys,e);return this.unsealed.set(n,e),n}recordFailure(e,n,r){let i=n instanceof Error?n.message:String(n),s=n?.code;if(s!==void 0&&["badentry","badname","toolarge"].includes(s)){this.skipped.set(e,{why:i,fingerprint:vt(this.entries.get(e))}),r.skipped++,this.log("skipped for good",e,i);return}let a=this.retries.get(e)??{count:0,error:"",at:0};a.count++,a.error=i,a.at=this.now()+Math.min(3e5,5e3*Math.pow(2,a.count)),this.retries.set(e,a),r.retrying++,this.log("will retry",e,{attempt:a.count,error:i})}prune(e){for(let[n,r]of this.entries){if(e.has(n))continue;let i=this.remote.get(n);i&&!i.deleted||r.synchash===""&&r.hash===""&&this.entries.delete(n)}for(let[n,r]of this.remote)r.deleted&&(e.has(n)||this.entries.has(n)||this.pending.has(n)||this.remote.delete(n))}async save(){let e={};for(let[r,i]of this.entries)e[r]=i;let n={};for(let[r,i]of this.remote)n[r]=i;await this.opts.store.save({cursor:this.cursor,entries:e,remote:n,pending:[...this.pending]})}noteRename(e,n){let r=this.entries.get(e);r&&(this.entries.delete(e),mn(r,e,n),this.entries.set(n,r))}};function jr(t,e){let n={...t};for(let r of Object.keys(n))n[r]=t[r]+e[r];return n}function vt(t){return t?`${t.mtime}:${t.size}`:"gone"}var En=8*1024*1024,Gr=16;async function qr(t,e,n=Gr){let r=[];for(let i=0;i<e.length;i+=n){let s=await ge(t,e.slice(i,i+n));for(let o of s)r.push(o.name)}return r}var An=8*1024*1024;async function Zr(t,e){if(!await e(t))return t;let n=t.lastIndexOf("."),r=t.lastIndexOf("/"),i=n>r,s=i?t.slice(0,n):t,o=i?t.slice(n):"";for(let a=2;a<1e3;a++){let l=`${s} ${a}${o}`;if(!await e(l))return l}throw new Error(`cannot find an unused name beside ${t}`)}function Xr(t,e){let n=new Error(`${t} bytes, and this server said it stores at most ${e}, so it was not read`);return n.code="toolarge",n}async function xn(t){throw new Error(`this put has no bodies, and the server asked for ${t}`)}function Yr(t){try{return JSON.parse(t),!0}catch{return!1}}var Qr=150,_e=class{constructor(e){this.opts=e;let n;this.transport=new Ve(e.url,{onBatch:async r=>{await n.acceptBatch(r),r.entries.length>0&&this.soon()},onCaughtUp:()=>{this.caughtUp=!0},onClosed:r=>{this.endedWith=r,this.notifyEnded?.(r)},...e.timeoutMs!==void 0?{timeoutMs:e.timeoutMs}:{},...e.log!==void 0?{log:e.log}:{},...e.socketFactory!==void 0?{socketFactory:e.socketFactory}:{}}),n=new Ke({vault:e.vault,store:e.store,keys:e.keys,transport:this.transport,device:e.device,vaultId:e.vaultId,token:e.token,...e.claim!==void 0?{claim:e.claim}:{},...e.coalesceWrites!==void 0?{coalesceWrites:e.coalesceWrites}:{},...e.log!==void 0?{log:e.log}:{},...e.onProgress!==void 0?{onProgress:e.onProgress}:{}}),this.engine=n}opts;engine;transport;limits;soonTimer;caughtUp=!1;endedWith;notifyEnded;queue=Promise.resolve();serial(e){let n=this.queue.then(e,e);return this.queue=n.catch(()=>{}),n}get requestsSent(){return this.transport.requestsSent}get serverCursor(){return this.limits?.cursor??0}async connect(){await this.transport.connect(),this.limits=await this.engine.start();let e=this.opts.timeoutMs??3e4,n=Date.now()+e;for(;!this.caughtUp&&Date.now()<n;){if(this.endedWith)throw this.endedWith;await pt(25)}if(!this.caughtUp)throw new Error("the server never finished sending what it already had");return this.limits}async settle(e={},n=8){let r=await this.pass(e),i=r;for(let s=0;s<n&&ri(r);s++)await pt(60),r=await this.pass(e),i=ni(i,r);return i}pass(e){return this.serial(()=>this.engine.sync(e))}async runUntilClosed(e=3e4){if(this.endedWith)return this.endedWith;let n=this.opts.vault.watch?.(()=>{this.sync()}),r=setInterval(()=>{this.sync().then(()=>this.keepalive())},e);try{return await new Promise(i=>{this.notifyEnded=i})}finally{clearInterval(r),n?.()}}async keepalive(){try{await this.transport.ping()}catch{}}soon(){this.soonTimer===void 0&&(this.soonTimer=setTimeout(()=>{this.soonTimer=void 0,this.sync()},Qr))}async sync(e={}){try{return await this.pass(e)}catch(n){this.opts.log?.("sync failed",n.message);return}}async history(e,n={}){let r=await Be(this.opts.keys,e);return(await this.serial(()=>this.transport.history(r,n))).map(s=>this.asVersion(s,e))}async deleted(e){let n=await this.serial(()=>this.transport.deleted(e)),r=[];for(let i of n.entries)r.push({...this.asVersion(i,await Le(this.opts.keys,i.path)),restorable:i.restorable??0});return{notes:r,more:n.more}}async contentAt(e){return e.deleted||e.folder?new Uint8Array(0):this.serial(()=>this.engine.contentOf(e.uid))}async restore(e,n){if(e.deleted)throw new Error(`version ${e.uid} of ${e.path} is the deletion itself, not a version to restore`);if(e.folder){let o=n??e.path;return await this.opts.vault.mkdir(o),{path:o,bytes:0}}let r=await this.serial(()=>this.engine.contentOf(e.uid)),i=n??e.path,s=await this.opts.vault.exists(i)?ei(i,e):i;return await this.opts.vault.write(s,r,{mtime:e.mtime,ctime:e.ctime}),{path:s,bytes:r.length}}async newestContentVersion(e){return(await this.history(e,{limit:50})).find(r=>!r.deleted)}asVersion(e,n){return{uid:e.uid,path:n,size:e.size,ctime:e.ctime,mtime:e.mtime,folder:e.folder,deleted:e.deleted,device:e.device,chunks:e.chunks?.length??0}}close(){this.soonTimer!==void 0&&(clearTimeout(this.soonTimer),this.soonTimer=void 0),this.transport.close()}};function ei(t,e){let n=t.lastIndexOf("/"),r=n===-1?"":t.slice(0,n+1),i=n===-1?t:t.slice(n+1),s=i.lastIndexOf("."),o=s<=0?i:i.slice(0,s),a=s<=0?"":i.slice(s);return`${r}${o} (restored ${e.uid})${a}`}async function Pn(t,e={}){let n=new Je(0,3e5,5e3,!0);for(;e.keepGoing?.()??!0;){let r,i,s=!1;try{r=new _e(t),await r.connect(),s=!0,n.success(Date.now()),e.onClient?.(r),e.onSynced?.(await r.settle(),r.serverCursor),i=await r.runUntilClosed()}catch(l){i=l}finally{e.onClient?.(void 0),r?.close()}if(i&&ti(i)){e.onFatal?.(i);return}if(!(e.keepGoing?.()??!0))return;n.fail(Date.now());let o=n.delay(),a=i??new Error("the connection ended");s?e.onDisconnected?.(a,o):e.onUnreachable?.(a,o),await pt(o)}}function ti(t){return t instanceof P&&t.fatal}function ni(t,e){return{uploaded:t.uploaded+e.uploaded,downloaded:t.downloaded+e.downloaded,merged:t.merged+e.merged,conflicted:t.conflicted+e.conflicted,deletedLocally:t.deletedLocally+e.deletedLocally,deletedRemotely:t.deletedRemotely+e.deletedRemotely,restored:t.restored+e.restored,foldersCreated:t.foldersCreated+e.foldersCreated,chunksSent:t.chunksSent+e.chunksSent,bytesSent:t.bytesSent+e.bytesSent,unchanged:e.unchanged,waiting:e.waiting,retrying:e.retrying,skipped:e.skipped,blocked:e.blocked}}function ri(t){return t.uploaded+t.downloaded+t.merged+t.conflicted+t.deletedLocally+t.deletedRemotely+t.restored+t.foldersCreated+t.waiting>0}var pt=t=>new Promise(e=>setTimeout(e,t));var He="basalt2_",yt=2,Ce=4,$n=new TextEncoder,ii=new TextDecoder;function wt(t){if(t.secret.length!==Z)throw new Error(`a root secret is ${Z} bytes, not ${t.secret.length}`);let e=[$n.encode(t.url),$n.encode(t.vaultId)];for(let o of e)if(o.length>255)throw new Error("a pairing field is too long to encode");let n=1+Z+e.reduce((o,a)=>o+1+a.length,0),r=new Uint8Array(n);r[0]=yt,r.set(t.secret,1);let i=1+Z;for(let o of e)r[i++]=o.length,r.set(o,i),i+=o.length;let s=new Uint8Array(n+Ce);return s.set(r,0),s.set(_n(r),n),He+xe(s)}function Mn(t){let e=t.trim();if(e.startsWith("basalt1_"))throw new Error("this is a version 1 pairing string, from before the server token was folded into the root secret. Run basalt invite on a device that is already paired to get a current one.");if(!e.startsWith(He))throw new Error(`not a pairing string: it should start with ${He}`);let n;try{n=We(e.slice(He.length))}catch{throw new Error("this pairing string is damaged: it is not valid base64url")}if(n.length<1+Z+2+Ce)throw new Error("this pairing string is too short to be complete");let r=n.subarray(0,n.length-Ce),i=n.subarray(n.length-Ce),s=_n(r);for(let u=0;u<Ce;u++)if(i[u]!==s[u])throw new Error("this pairing string is damaged: it did not survive being copied");if(r[0]!==yt)throw new Error(`this pairing string is version ${r[0]}, and this device understands ${yt}`);let o=r.slice(1,1+Z),a=1+Z,l=u=>{if(a>=r.length)throw new Error(`this pairing string ends before its ${u}`);let f=r[a++];if(a+f>r.length)throw new Error(`this pairing string ends inside its ${u}`);let g=ii.decode(r.subarray(a,a+f));return a+=f,g},c=l("server address"),h=l("vault name");if(a!==r.length)throw new Error("this pairing string has more in it than it should");if(c===""||h==="")throw new Error("this pairing string has an empty field");return{url:c,secret:o,vaultId:h}}function _n(t){let e=4294967295;for(let n of t){e^=n;for(let r=0;r<8;r++)e=e&1?e>>>1^3988292384:e>>>1}return e=(e^4294967295)>>>0,new Uint8Array([e>>>24&255,e>>>16&255,e>>>8&255,e&255])}function Cn(t){return{url:t.url,vaultId:t.vaultId,device:t.device,secret:xe(t.secret),...t.bootstrap?{bootstrap:t.bootstrap}:{}}}function Tn(t,e){if(typeof t!="object"||t===null)throw new Error(`${e} does not hold a configuration`);let n=t,r=o=>{let a=n[o];if(typeof a!="string"||a==="")throw new Error(`${e} has no ${o}`);return a},i=We(r("secret"));if(i.length!==Z)throw new Error(`${e} holds a ${i.length} byte secret, and a root secret is ${Z}`);let s=n.bootstrap;return{url:r("url"),vaultId:r("vaultId"),device:r("device"),secret:i,...typeof s=="string"&&s!==""?{bootstrap:s}:{}}}function Rn(t){let e=t.trim().replace(/\/+$/,"");if(e==="")throw new Error("that is not a server address");if(e.startsWith("ws://")||e.startsWith("wss://"))return e;if(e.startsWith("http://"))return"ws://"+e.slice(7);if(e.startsWith("https://"))return"wss://"+e.slice(8);if(e.includes("://"))throw new Error(`a server address is ws:// or wss://, not ${e.split("://")[0]}://`);return"wss://"+e}import{constants as bt,watch as si}from"node:fs";import{access as kt,cp as oi,mkdir as je,open as Ge,readFile as On,readdir as ai,rename as Fn,rm as li,stat as hi,utimes as ci}from"node:fs/promises";import{basename as St,dirname as qe,join as In,relative as ui,resolve as Dn,sep as Un}from"node:path";var Nn=".trash",fi=new Set([".basalt",Nn,".git",".DS_Store","node_modules"]),Et=".obsidian";function At(t){let e=t.replace(/^\/+|\/+$/g,"");if(e===""||e.includes("/"))throw new Error(`refusing to sync: the config folder ${JSON.stringify(t)} is not a plain name`);return e}var Ze=class{root;ignore;constructor(e,n={}){this.root=Dn(e);let r=At(n.configDir??Et);this.ignore=new Set([...fi,r,...n.alsoIgnore??[]])}absolute(e){let n=Dn(this.root,e),r=ui(this.root,n);if(r===""||r.startsWith("..")||r.startsWith(`..${Un}`))throw new Error(`refusing a path outside the vault: ${e}`);return n}async list(){let e=[],n=async(r,i)=>{let s;try{s=await ai(r,{withFileTypes:!0})}catch(o){throw new Error(`cannot read ${r}: ${o.message}`)}for(let o of s){if(this.ignore.has(o.name)||zn(o.name))continue;let a=i?`${i}/${o.name}`:o.name,l=In(r,o.name);if(o.isDirectory())e.push({path:a,folder:!0,mtime:0,ctime:0,size:0}),await n(l,a);else if(o.isFile()){let c=await hi(l);e.push({path:a,folder:!1,mtime:c.mtimeMs,ctime:c.birthtimeMs||c.ctimeMs,size:c.size})}}};return await n(this.root,""),e}async read(e){return new Uint8Array(await On(this.absolute(e)))}async*readBlocks(e,n=1024*1024){let r=await Ge(this.absolute(e),"r");try{let i=new Uint8Array(n);for(;;){let{bytesRead:s}=await r.read(i,0,n,null);if(s===0)return;yield i.slice(0,s)}}finally{await r.close()}}async readRange(e,n,r){let i=await Ge(this.absolute(e),"r");try{let s=new Uint8Array(r-n),o=0;for(;o<s.length;){let{bytesRead:a}=await i.read(s,o,s.length-o,n+o);if(a===0)break;o+=a}return o===s.length?s:s.subarray(0,o)}finally{await i.close()}}async write(e,n,r){let i=this.absolute(e);if(await je(qe(i),{recursive:!0}),await Ln(i,n),r.mtime>0){let s=r.mtime/1e3;await ci(i,s,s)}}async remove(e){let n=this.absolute(e);try{await kt(n,bt.F_OK)}catch{return}let r=await this.freeTrashPath(e);await je(qe(r),{recursive:!0});try{await Fn(n,r);return}catch(i){if(i.code!=="EXDEV")throw i}await oi(n,r,{recursive:!0}),await li(n,{recursive:!0,force:!0})}async freeTrashPath(e){let n=In(this.root,Nn,e),r=St(e).lastIndexOf("."),[i,s]=r<=0?[n,""]:[n.slice(0,n.length-(St(e).length-r)),n.slice(n.length-(St(e).length-r))];for(let o=0;o<1e3;o++){let a=o===0?n:`${i} (${o})${s}`;try{await kt(a,bt.F_OK)}catch{return a}}throw new Error(`the trash already holds a thousand copies of ${e}`)}async mkdir(e){await je(this.absolute(e),{recursive:!0})}async exists(e){try{return await kt(this.absolute(e),bt.F_OK),!0}catch{return!1}}watch(e){let n,r="",i;try{i=si(this.root,{recursive:!0,persistent:!0},(s,o)=>{if(!o)return;let a=o.toString().split(Un).join("/");a.split("/").some(l=>this.ignore.has(l))||zn(a)||(r=a,n&&clearTimeout(n),n=setTimeout(()=>{n=void 0,e(r)},150))}),i.on("error",()=>{})}catch{return()=>{}}return()=>{n&&clearTimeout(n),i?.close()}}},Te=class{constructor(e){this.file=e}file;async load(){let e;try{e=await On(this.file,"utf8")}catch(n){if(n.code==="ENOENT")return;throw new Error(`cannot read the index at ${this.file}: ${n.message}`)}try{return JSON.parse(e)}catch(n){throw new Error(`the index at ${this.file} is not valid JSON, so it cannot be trusted: ${n.message}`)}}async save(e){await je(qe(this.file),{recursive:!0}),await Ln(this.file,new TextEncoder().encode(JSON.stringify(e)))}},Bn=".basalt-tmp-";function zn(t){return t.includes(Bn)}var di=0;async function gi(t){for(let e=0;e<64;e++){let n=`${t}${Bn}${(di++).toString(36)}${e?`-${e}`:""}`;try{return{tmp:n,handle:await Ge(n,"wx")}}catch(r){if(r.code!=="EEXIST")throw r}}throw new Error(`could not find an unused temporary name beside ${t}`)}async function Ln(t,e){let{tmp:n,handle:r}=await gi(t);try{await r.write(e),await r.sync()}finally{await r.close()}await Fn(n,t);let i=await Ge(qe(t),"r");try{await i.sync()}finally{await i.close()}}import{chmod as mi,mkdir as vi,readFile as pi,rename as yi,rm as Wn,writeFile as wi}from"node:fs/promises";import{join as xt}from"node:path";var Pt=".basalt",$t=t=>xt(t,Pt,"config.json"),Xe=t=>xt(t,Pt,"index.json");async function Re(t){let e=$t(t),n;try{n=await pi(e,"utf8")}catch(i){if(i.code==="ENOENT")return;throw new Error(`cannot read ${e}: ${i.message}`)}let r;try{r=JSON.parse(n)}catch(i){throw new Error(`${e} is not valid JSON, so it cannot be trusted: ${i.message}`)}return Tn(r,e)}async function Ye(t,e){let n=xt(t,Pt);await vi(n,{recursive:!0});let r=$t(t),i=`${r}.tmp`;await wi(i,JSON.stringify(Cn(e),null,2)+`
9
- `,{mode:384}),await mi(i,384),await yi(i,r)}async function Vn(t){await Wn($t(t),{force:!0}),await Wn(Xe(t),{force:!0})}var Jn=`basalt: self-hosted sync for Obsidian
8
+ `).sort();if(n.length!==r.length)return!1;for(let i=0;i<n.length;i++)if(n[i]!==r[i])return!1;return!0}function bn(t,e,n,r){let[i,s]=t.patch_apply(t.patch_make(e,n),r);return{text:i,failed:s.filter(o=>!o).length,total:s.length}}function Xr(t,e){for(let[n,r]of t)if(n===Gr&&!e.includes(r))return r}function Yr(t){let e=t.replace(/\s+/g," ").trim(),n=e.length>60?`${e.slice(0,57)}...`:e;return`a local edit (${JSON.stringify(n)})`}function En(t,e,n){let r=t.lastIndexOf("."),i=t.lastIndexOf("/"),s=r>i,o=s?t.slice(0,r):t,a=s?t.slice(r):"",l=(c,u=2)=>String(c).padStart(u,"0"),h=`${n.getFullYear()}${l(n.getMonth()+1)}${l(n.getDate())}${l(n.getHours())}${l(n.getMinutes())}`;return`${o} (Conflicted copy ${Qr(e)} ${h})${a}`}function Qr(t){return t.replace(/[-\\/:*?"<>|\s]/g,"-").replace(/-{2,}/g,"-").replace(/^[.\-\s]+|[.\-\s]+$/g,"").slice(0,32)||"device"}function kt(t){return{path:t,prev:"",folder:!1,ctime:0,mtime:0,size:0,hash:"",chunks:[],synchash:"",syncuid:0,synctime:0}}function An(t){let{local:e,remote:n,index:r,mergeable:i}=t,s=r.synchash;return e?.folder||n?.folder?ei(e,n):e===void 0&&(n===void 0||n.deleted)?{kind:"nothing",why:"absent on both sides"}:n===void 0?{kind:"upload",why:"new file, the server has never held this path"}:e===void 0?ti(n,r):n.deleted?e.hash===s&&s!==""?{kind:"deleteLocal",why:"deleted on another device and unchanged here"}:s===""?{kind:"upload",why:"deleted on the server but never synced from here"}:{kind:"upload",why:"deleted on another device but edited here, so the edit is kept and re-sent"}:e.hash===n.hash?{kind:"nothing",why:"the two sides hold the same content"}:s===""?{kind:"conflict",why:"both sides have content and there is no last-synced version to merge from"}:e.hash===s?{kind:"download",why:"changed on another device and unchanged here"}:n.hash===s?{kind:"upload",why:"changed here and unchanged on the server"}:i?{kind:"merge",why:"changed on both sides since the last sync"}:{kind:"conflict",why:"changed on both sides and this file cannot be merged"}}function ei(t,e){return t!==void 0&&t.folder?e===void 0?{kind:"upload",why:"new folder, the server has never held this path"}:e.deleted?{kind:"nothing",why:"folder deleted elsewhere; its files decide"}:e.folder?{kind:"nothing",why:"folder exists on both sides"}:{kind:"clash",why:"a folder here and a file of the same name on another device"}:e?.folder&&!e.deleted?t!==void 0?{kind:"clash",why:"a file here and a folder of the same name on another device"}:{kind:"createLocalFolder",why:"folder exists on the server and not here"}:{kind:"nothing",why:"folder absent on both sides"}}function ti(t,e){let n=e.synchash;return t.deleted?{kind:"nothing",why:"deleted on both sides"}:n===""?{kind:"download",why:"new on the server"}:t.hash===n?{kind:"deleteRemote",why:"deleted here and unchanged on the server"}:{kind:"restoreLocal",why:"deleted here but changed on another device, so the newer content is restored"}}function St(t,e,n){return t.hash===""||t.chunks.length===0?!0:t.mtime!==e||t.size!==n}function be(t,e){let n=Math.ceil(e.mtime),r=Math.ceil(e.ctime);if(e.folder){t.folder=!0,t.mtime=0,t.ctime=0,t.size=0,t.hash="",t.chunks=[];return}St(t,n,ni(e))&&(t.hash="",t.chunks=[]),t.folder=!1,t.mtime=n,t.ctime=r,t.size=e.size}function ni(t){return t.size}function xn(t,e,n){t.path=n,t.prev===""&&(t.prev=e),t.prev===n&&(t.prev=""),t.synctime=0}function de(t,e,n,r,i){t.hash=e,t.chunks=[...n],t.synchash=e,t.syncuid=r,t.synctime=i,t.prev=""}function Pn(t,e){if(!t.synctime)return!0;let n=t.size>102400?30:t.size>10240?20:10;return e-t.synctime>n*1e3}var Et=2,$n=6e4,_e=256;function Mn(t){return{size:t.size,ctime:t.ctime,mtime:t.mtime,folder:t.folder??!1,deleted:t.deleted??!1,...t.prev?{prev:t.prev}:{}}}var P=class extends Error{constructor(n,r){super(r);this.code=n;this.name="ProtocolError"}code;get fatal(){return["proto","auth","cursor","busy","protostate","badchunk","internal"].includes(this.code)}};function ri(t){return t.startsWith("wss://")?`. If that server has no TLS in front of it, pair with ws://${t.slice(6)} instead`:""}var j=class extends Error{constructor(e){super(e),this.name="ConnectionError"}},Je=class{constructor(e,n){this.url=e;this.opts=n}url;opts;socket;replyWaiter;replyTimer;bodyWaiter;bodyQueue=[];expecting=0;requestsSent=0;closed=!1;closeReason;cursor=0;notifying=Promise.resolve();log(e,...n){this.opts.log?.(e,...n)}get appliedCursor(){return this.cursor}async connect(){if(this.socket)throw new Error("already connected");let n=(this.opts.socketFactory??ii)(this.url);n.binaryType="arraybuffer",this.socket=n,await new Promise((r,i)=>{n.onopen=()=>r(),n.onerror=()=>i(new j(`could not connect to ${this.url}${ri(this.url)}`)),n.onclose=s=>i(new j(`connection closed before opening: ${Cn(s)}`))}),n.onerror=()=>this.die(new j("the connection failed")),n.onclose=r=>this.die(new j(`the connection closed: ${Cn(r)}`)),n.onmessage=r=>this.onFrame(r.data)}die(e){if(this.closed)return;this.closed=!0,this.closeReason=e,this.log("transport closed",e.message),this.disarmReply();let n=this.replyWaiter,r=this.bodyWaiter;this.replyWaiter=void 0,this.bodyWaiter=void 0,n?.reject(e),r?.reject(e);try{this.socket?.close()}catch{}try{this.opts.onClosed?.(e)}catch{}}disarmReply(){this.replyTimer!==void 0&&(clearTimeout(this.replyTimer),this.replyTimer=void 0)}close(){this.die(new j("closed by this device"))}get isClosed(){return this.closed}onFrame(e){if(typeof e=="string"){let i;try{i=JSON.parse(e)}catch{this.die(new P("protostate",`server sent a frame that is not JSON: ${e.slice(0,120)}`));return}this.onTextFrame(i);return}let n=si(e);if(n===void 0){this.die(new P("protostate","server sent a frame of an unexpected type"));return}let r=this.bodyWaiter;if(r){this.bodyWaiter=void 0,r.resolve(n);return}if(this.bodyQueue.length>=this.expecting){this.die(new P("protostate",`server sent a ${n.length} byte body with nothing outstanding to receive it`));return}this.bodyQueue.push(n)}onTextFrame(e){if(e.op==="batch"){this.queueNotification(()=>this.onBatchFrame(e));return}if(e.op==="caught-up"){let r=K(e.cursor);this.queueNotification(async()=>{if(r!==this.cursor){this.die(new P("protostate",`server says caught up at ${r}, this device reached ${this.cursor}`));return}this.opts.onCaughtUp?.(r)});return}let n=this.replyWaiter;if(!n){this.die(new P("protostate",`server sent an unexpected reply: ${JSON.stringify(e)}`));return}this.replyWaiter=void 0,n.resolve(e)}queueNotification(e){this.notifying=this.notifying.then(e).catch(n=>{this.die(n instanceof Error?n:new Error(String(n)))})}async onBatchFrame(e){let n=K(e.from),r=K(e.to),i=e.entries;if(!Array.isArray(i))throw new P("protostate",`batch ${n} to ${r} carries no entries array, so an empty batch cannot be told from a lost one`);let s=i;if(n!==this.cursor+1)throw new P("protostate",`batch covers ${n} to ${r} but this device has applied up to ${this.cursor}, so something was skipped`);if(r<n)throw new P("protostate",`batch covers an empty range, ${n} to ${r}`);for(let o of s){if(typeof o?.uid!="number"||!Number.isFinite(o.uid))throw new P("protostate",`batch ${n}..${r} contains an entry with no uid`);if(typeof o.path!="string"||o.path==="")throw new P("protostate",`batch ${n}..${r} contains uid ${o.uid} with no path`);if(!Array.isArray(o.chunks))throw new P("protostate",`batch ${n}..${r} contains uid ${o.uid} with no chunks array`);if(o.uid<n||o.uid>r)throw new P("protostate",`batch ${n}..${r} contains uid ${o.uid}`)}await this.opts.onBatch({from:n,to:r,entries:s}),this.cursor=r}send(e){if(this.closed||!this.socket)throw this.closeReason??new j("not connected");this.socket.send(JSON.stringify(e))}sendBody(e){if(this.closed||!this.socket)throw this.closeReason??new j("not connected");this.socket.send(e)}async request(e){if(this.replyWaiter)throw new Error("a request is already in flight");this.requestsSent++;let n=this.opts.timeoutMs??$n,r=await new Promise((i,s)=>{let o=setTimeout(()=>{this.die(new j(`no reply within ${n}ms`))},n);this.replyTimer=o,this.replyWaiter={resolve:a=>{this.disarmReply(),i(a)},reject:a=>{this.disarmReply(),s(a)}};try{this.send(e)}catch(a){this.disarmReply(),this.replyWaiter=void 0,s(a instanceof Error?a:new Error(String(a)))}});if(r.res==="err"){let i=new P(String(r.code??"unknown"),String(r.msg??"no message"));throw i.fatal&&this.die(i),i}return r}async body(){let e=this.bodyQueue.shift();if(e)return e;if(this.closed)throw this.closeReason??new j("not connected");return new Promise((n,r)=>{this.bodyWaiter={resolve:n,reject:r}})}async hello(e){this.cursor=e.cursor;let n=await this.request({op:"hello",proto:Et,crypto:Yt,vault:e.vault,token:e.token,device:e.device,cursor:e.cursor,...e.claim!==void 0?{claim:e.claim}:{}});if(n.res!=="ready")throw new P("protostate",`expected ready, got ${JSON.stringify(n)}`);let r={proto:K(n.proto),cursor:K(n.cursor),perFileMax:K(n.perFileMax),chunkMax:K(n.chunkMax),maxChunks:K(n.maxChunks)};if(r.proto!==Et)throw new P("proto",`server speaks protocol ${r.proto}, this client speaks ${Et}`);return this.log("ready",r),r}async put(e,n,r,i,s={mac:"",parent:""}){let o=await this.request({op:"put",path:e,meta:Mn(n),chunks:[...r],mac:s.mac,parent:s.parent});if(o.res==="have")return{uid:K(o.uid),uploaded:0,bytes:0};if(o.res!=="want")throw new P("protostate",`expected want or have, got ${JSON.stringify(o)}`);let a=At(o.chunks),l=new Set(r),h=0;for(let u of a){if(!l.has(u))throw new P("badchunk",`server asked for ${u}, which this put does not contain`);let f=await i(u);this.sendBody(f),h+=f.length}return{uid:await this.awaitAck(),uploaded:a.length,bytes:h}}async putMany(e,n){if(e.length===0)return{results:[],uploaded:0,bytes:0};if(e.length>_e)throw new P("toolarge",`${e.length} entries in one batch, the limit is ${_e}`);let r=await this.request({op:"putmany",entries:e.map(h=>({path:h.path,meta:Mn(h.meta),chunks:[...h.names],mac:h.mac,parent:h.parent}))}),i=r,s=0,o=0;if(r.res==="want"){let h=At(r.chunks),c=new Set;for(let u of e)for(let f of u.names)c.add(f);for(let u of h){if(!c.has(u))throw new P("badchunk",`server asked for ${u}, which this batch does not contain`);let f=await n(u);this.sendBody(f),o+=f.length}s=h.length,i=await this.awaitReply()}if(i.res!=="acks")throw new P("protostate",`expected acks, got ${JSON.stringify(i)}`);let a=i.results;if(!Array.isArray(a)||a.length!==e.length)throw new P("protostate",`${e.length} entries went up and ${Array.isArray(a)?a.length:"no"} results came back`);let l=a.map(h=>{let c=h??{};return c.code!==void 0?{uid:0,error:new P(String(c.code),String(c.msg??"no message"))}:{uid:K(c.uid)}});for(let h of l)h.error?.fatal&&this.die(h.error);return{results:l,uploaded:s,bytes:o}}async awaitAck(){let e=await this.awaitReply();if(e.res!=="ack")throw new P("protostate",`expected ack, got ${JSON.stringify(e)}`);return K(e.uid)}async awaitReply(){let e=await new Promise((n,r)=>{if(this.closed){r(this.closeReason??new j("not connected"));return}let i=this.opts.timeoutMs??$n,s=setTimeout(()=>{this.die(new j(`no acknowledgement within ${i}ms`))},i);this.replyWaiter={resolve:o=>{clearTimeout(s),n(o)},reject:o=>{clearTimeout(s),r(o)}}});if(e.res==="err"){let n=new P(String(e.code??"unknown"),String(e.msg??"no message"));throw n.fatal&&this.die(n),n}return e}async get(e){let n=await this.request({op:"get",uid:e});if(n.res!=="chunks")throw new P("protostate",`expected chunks, got ${JSON.stringify(n)}`);return{uid:K(n.uid),size:K(n.size),chunks:At(n.chunks)}}async history(e,n={}){let r=await this.request({op:"history",path:e,...n.before!==void 0?{before:n.before}:{},...n.limit!==void 0?{limit:n.limit}:{}});if(r.res!=="history")throw new P("protostate",`expected history, got ${JSON.stringify(r)}`);return Tn(r.entries,"history")}async deleted(e){let n=await this.request({op:"deleted",...e!==void 0?{limit:e}:{}});if(n.res!=="deleted")throw new P("protostate",`expected deleted, got ${JSON.stringify(n)}`);return{entries:Tn(n.entries,"deleted"),more:n.more===!0}}async fetch(e){if(e.length===0)return[];this.expecting+=e.length;let n=this.request({op:"fetch",chunks:[...e]}),r=[],i=[];try{for(let s=0;s<e.length;s++){let o=await Promise.race([this.body(),n.then(l=>{throw new P("protostate",`expected a chunk body, got ${JSON.stringify(l)}`)})]),a=e[s];i.push(mt(o).then(l=>{if(l!==a)throw new P("badchunk",`asked for ${a} and received ${o.length} bytes that hash to ${l}`)})),r.push(o)}await Promise.all(i)}catch(s){throw this.expecting=0,this.disarmReply(),this.replyWaiter=void 0,s instanceof P&&s.code==="badchunk"&&this.die(s),s}return this.expecting=Math.max(0,this.expecting-e.length),this.disarmReply(),this.replyWaiter=void 0,r}async ping(){let e=await this.request({op:"ping"});if(e.res!=="pong")throw new P("protostate",`expected pong, got ${JSON.stringify(e)}`)}},Ke=class{constructor(e=0,n=3e5,r=5e3,i=!0,s=Math.random){this.min=e;this.max=n;this.base=r;this.jitter=i;this.random=s}min;max;base;jitter;random;count=0;nextAt=0;success(e){this.count=0,this.nextAt=e+this.delay()}fail(e){this.count++,this.nextAt=e+this.delay()}delay(){if(this.count===0)return this.min;let e=this.base*Math.pow(2,this.count-1);return this.jitter&&(e*=.5+.5*this.random()),Math.floor(Math.min(this.max,this.min+e))}readyAt(){return this.nextAt}isReady(e){return e>=this.nextAt}get failures(){return this.count}};function ii(t){let e=globalThis.WebSocket;if(!e)throw new Error("no WebSocket available in this environment");return new e(t)}function si(t){if(t instanceof Uint8Array)return t;if(t instanceof ArrayBuffer)return new Uint8Array(t);if(ArrayBuffer.isView(t))return new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}function K(t){return typeof t=="number"&&Number.isFinite(t)?t:0}function At(t){return Array.isArray(t)?t.filter(e=>typeof e=="string"):[]}function Cn(t){let e=t.code??0,n=t.reason?`, ${t.reason}`:"";return`code ${e}${n}`}function Tn(t,e){if(!Array.isArray(t))throw new P("protostate",`${e} came back without a list of entries`);return t}function _n(t){let e=t.split("/");e.pop();let n=[],r="";for(let i of e)r=r?`${r}/${i}`:i,n.push(r);return n}function oi(t){let e={...t};return t.hash===q(t.chunks)&&delete e.hash,t.synchash===t.hash&&delete e.synchash,e}function ai(t,e){let n={...kt(t),...e};return e.hash===void 0&&(n.hash=q(n.chunks)),e.synchash===void 0&&(n.synchash=n.hash),n}function q(t){return t.length===0?"-empty-":t.join(",")}function li(t,e){if(t<e)throw new Error(`this server is at version ${t} and this device has already seen ${e}: refusing to sync, because a server behind its own clients is a restored backup or the wrong vault`)}var Rn={perFileMax:1<<28,maxChunks:65536};function In(t,e){return t>0?Math.min(t,e):e}function hi(t){if(!t.folder&&!t.deleted&&t.size>0&&t.chunks.length===0)throw new Error(`version ${t.uid} declares ${t.size} bytes and names no chunks, which cannot both be true`);if(t.chunks.length>0&&(t.folder||t.deleted)){let e=t.folder?"a folder":"a deletion";throw new Error(`version ${t.uid} is ${e} and names ${t.chunks.length} chunks`)}}function ci(t){return t===""||t==="-empty-"?[]:t.split(",")}var On=5;function zn(){return{uploaded:0,downloaded:0,merged:0,conflicted:0,deletedLocally:0,deletedRemotely:0,restored:0,foldersCreated:0,unchanged:0,waiting:0,retrying:0,skipped:0,blocked:0,inTheWay:[],chunksSent:0,bytesSent:0}}var je=class{constructor(e){this.opts=e}opts;entries=new Map;remote=new Map;pending=new Set;retries=new Map;skipped=new Map;blocked=new Set;cannotStream=!1;outbox=[];outboxBytes=0;inbox=[];inboxBytes=0;limits;unsealed=new Map;cursor=0;syncing=!1;again=!1;started=!1;now(){return this.opts.now?.()??Date.now()}log(e,...n){this.opts.log?.(e,...n)}mergeable(e){return(this.opts.mergeable??pn)(e)}sizesFor(e,n){return dn(e,n,this.limits?.chunkMax)}get coalesce(){return this.opts.coalesceWrites??!0}status(){let e=0;for(let n of this.entries.values())n.folder||e++;return{cursor:this.cursor,files:e,pending:this.pending.size,retrying:this.retries.size,skipped:this.skipped.size,syncing:this.syncing}}async start(){if(this.started)throw new Error("already started");this.started=!0;let e=await this.opts.store.load();if(e){this.cursor=e.cursor;for(let[r,i]of Object.entries(e.entries))this.entries.set(r,ai(r,i));for(let[r,i]of Object.entries(e.remote))this.remote.set(r,i);for(let r of e.pending)this.pending.add(r);this.log("index loaded",{cursor:this.cursor,entries:this.entries.size,pending:this.pending.size})}let n=await this.opts.transport.hello({vault:this.opts.vaultId,token:this.opts.token,device:this.opts.device,cursor:this.cursor,...this.opts.claim!==void 0?{claim:this.opts.claim}:{}});return li(n.cursor,this.cursor),this.limits=n,this.log("connected",n),n}async authFor(e,n){let r=await cn(n);return{mac:await yt(this.opts.keys,{path:e.path,size:e.meta.size,ctime:e.meta.ctime,mtime:e.meta.mtime,folder:e.meta.folder??!1,deleted:e.meta.deleted??!1,prev:e.meta.prev,chunks:e.names,parent:r}),parent:r}}async acceptBatch(e){let n=e.entries.map(l=>({path:l.path,size:l.size,ctime:l.ctime,mtime:l.mtime,folder:l.folder,deleted:l.deleted,prev:l.prev,chunks:l.chunks,parent:l.parent??""})),i=(await Promise.all(n.map((l,h)=>hn(this.opts.keys,l,e.entries[h].mac)))).indexOf(!1);if(i>=0)throw new Error(`version ${e.entries[i].uid} is not authenticated by this vault's key, so nothing that holds the key wrote it`);for(let l of e.entries)hi(l);let s=await Promise.all(e.entries.map(l=>this.plaintextPath(l.path))),o=await Promise.all(e.entries.map(l=>l.prev?this.plaintextPath(l.prev):void 0)),a=new Map;for(let l=0;l<e.entries.length;l++){let h=e.entries[l],c=s[l];if(a.set(c,{uid:h.uid,folder:h.folder,deleted:h.deleted,mtime:h.mtime,size:h.size,hash:q(h.chunks)}),h.prev){let u=o[l];a.set(u,{uid:h.uid,folder:!1,deleted:!0,mtime:h.mtime,size:0,hash:""})}}for(let[l,h]of a)this.remote.set(l,h),this.pending.add(l);this.cursor=e.to}async plaintextPath(e){let n=this.unsealed.get(e);if(n!==void 0)return n;let r=await Ve(this.opts.keys,e);return this.unsealed.set(e,r),r}async sync(e={}){if(this.syncing)return this.again=!0,zn();this.syncing=!0;try{let n=await this.pass(e);for(;this.again;){this.again=!1;let r=await this.pass(e);n=ui(n,r)}return n}finally{this.syncing=!1}}async pass(e={}){let n=zn(),r=this.now(),i=e.coalesceWrites??this.coalesce;(this.outbox.length>0||this.inbox.length>0)&&(this.log("a pass ended early, discarding what it had queued",{writes:this.outbox.length,reads:this.inbox.length}),this.outbox=[],this.outboxBytes=0,this.inbox=[],this.inboxBytes=0);let s=await this.opts.vault.list(),o=new Map(s.map(c=>[c.path,c]));for(let c of s){let u=this.entryFor(c.path);be(u,c)}let a=new Set;for(let[c,u]of o)u.folder||a.add(c);let l=new Set,h=new Set([...o.keys(),...this.entries.keys(),...this.remote.keys()]);for(let c of[...h].sort()){let u=this.skipped.get(c);if(u){if(xt(this.entries.get(c))===u.fingerprint){n.skipped++;continue}this.skipped.delete(c),this.log("skipped file changed, trying again",c)}let f=_n(c).find(m=>a.has(m));if(f!==void 0&&!o.has(c)){l.add(c),this.blocked.has(c)||this.log("cannot be both",c,`${f} is a file here and a folder elsewhere`),n.blocked++,n.inTheWay.length<On&&n.inTheWay.push({path:c,blockedBy:f});continue}let g=this.retries.get(c);if(g&&g.at>r){n.retrying++;continue}try{this.opts.onProgress?.(c),await this.reconcile(c,o.get(c),n,r,i),this.retries.delete(c)}catch(m){this.recordFailure(c,m,n)}}return this.wroteThisPass=[],await this.fill(n),await this.applyDeletes(n),this.wroteThisPass=[],await this.flush(n),this.opts.onProgress?.(void 0),this.blocked=l,this.prune(o),await this.opts.vault.flush?.(),await this.save(),n}entryFor(e){let n=this.entries.get(e);return n||(n=kt(e),this.entries.set(e,n)),n}async reconcile(e,n,r,i,s){let o=this.entryFor(e),a=this.remote.get(e),l=this.limits?.perFileMax??0;if(n&&!n.folder&&l>0&&n.size>l){this.recordFailure(e,gi(n.size,l),r);return}let h,c;n&&(!n.folder&&St(o,Math.ceil(n.mtime),n.size)&&(c=await this.rehash(o,e,n.size)),h={folder:n.folder,mtime:o.mtime,size:o.size,hash:o.hash});let u=An({local:h,remote:a,index:o,mergeable:this.mergeable(e)});if(s&&u.kind!=="nothing"&&h&&!n?.folder&&!Pn(o,i)){r.waiting++;return}await this.act(e,u,o,h,a,r,c),this.pending.delete(e)}async rehash(e,n,r){let i=await this.streamScan(e,n,r);if(i)return i;let s=await this.opts.vault.read(n),o=this.mergeable(n),a=[...bt(s,this.sizesFor(s.length,o),o)],l=a.map(h=>h.bytes);if(s.length<=Dn){let h=await ue(this.opts.keys,l);return e.chunks=h.map(c=>c.name),e.hash=q(e.chunks),e.size=s.length,{bytes:s,pieces:a,names:e.chunks,sealed:h}}return e.chunks=await this.namesOf(l),e.hash=q(e.chunks),e.size=s.length,{bytes:s,pieces:a,names:e.chunks}}async streamScan(e,n,r){let i=this.opts.vault;if(!(!i.readBlocks||!i.readRange||this.cannotStream)&&!(r===void 0||r<=Dn))try{return await this.streamed(e,n,r)}catch(s){this.cannotStream=!0,this.log("streaming is not available here, reading whole files instead",n,{why:s.message});return}}async streamed(e,n,r){let i=this.opts.vault,s=this.mergeable(n),o=[],a=[],l=0;for await(let h of mn(i.readBlocks(n),this.sizesFor(r,s),s)){let c=await ue(this.opts.keys,[h.bytes]);o.push(c[0].name),a.push({start:h.offset,end:h.offset+h.bytes.length}),l+=h.bytes.length}return e.chunks=o,e.hash=q(o),e.size=l,{names:o,spans:a,path:n,size:l}}namesOf(e){return fi(this.opts.keys,e)}async act(e,n,r,i,s,o,a){switch(n.kind){case"nothing":o.unchanged++,i&&s&&!s.deleted&&i.hash===s.hash&&de(r,i.hash,r.chunks,s.uid,this.now());return;case"upload":await this.upload(e,r,o,!0,a);return;case"download":case"restoreLocal":{if(!s)return;await this.receive(e,r,s,n.kind,n.why,o);return}case"createLocalFolder":await this.opts.vault.mkdir(e),r.folder=!0,s&&de(r,"",[],s.uid,this.now()),o.foldersCreated++;return;case"clash":this.skipped.set(e,{why:`${n.why}. Rename one of them, and it will sync.`,fingerprint:xt(r)}),o.skipped++,this.log("cannot be both",e,n.why);return;case"deleteLocal":this.pendingDeletes.push({path:e,why:n.why});return;case"deleteRemote":{let l=this.now(),h={path:await this.sealedPath(e),meta:{size:0,ctime:0,mtime:l,deleted:!0},names:[]};await this.queue({path:e,size:0,entry:{...h,...await this.authFor(h,r.synchash)},bodyOf:Fn,commit:c=>{this.remote.set(e,{uid:c,folder:!1,deleted:!0,mtime:this.now(),size:0,hash:""}),this.entries.delete(e),o.deletedRemotely++,this.log("deleted on the server",e,n.why)}},o);return}case"merge":await this.merge(e,r,s,o);return;case"conflict":await this.conflict(e,r,s,o,n.why);return}}async upload(e,n,r,i=!1,s){if(n.folder){let f={path:await this.sealedPath(e),meta:{size:0,ctime:0,mtime:0,folder:!0},names:[]};await this.queue({path:e,size:0,entry:{...f,...await this.authFor(f,"")},bodyOf:Fn,commit:g=>{de(n,"",[],g,this.now()),this.remote.set(e,{uid:g,folder:!0,deleted:!1,mtime:0,size:0,hash:""}),i&&r.uploaded++}},r);return}let o=await this.planUpload(n,e,s),a=n.hash,l=[...n.chunks],h=n.size,c=n.mtime,u={path:await this.sealedPath(e),meta:{size:h,ctime:n.ctime,mtime:c,...n.prev?{prev:await this.sealedPath(n.prev)}:{}},names:o.names};await this.queue({path:e,size:h,entry:{...u,...await this.authFor(u,n.synchash)},bodyOf:o.bodyOf,commit:f=>{de(n,a,l,f,this.now()),this.remote.set(e,{uid:f,folder:!1,deleted:!1,mtime:c,size:h,hash:a}),i&&r.uploaded++,this.log("uploaded",e)}},r)}async queue(e,n){this.outbox.push(e),this.outboxBytes+=e.size,(this.outbox.length>=_e||this.outboxBytes>=Un)&&await this.flush(n)}async flush(e){if(this.outbox.length===0)return;let n=this.outbox;this.outbox=[],this.outboxBytes=0;let r=new Map;for(let s of n)for(let o of s.entry.names)r.has(o)||r.set(o,s.bodyOf);let i;try{i=await this.opts.transport.putMany(n.map(s=>s.entry),async s=>{let o=r.get(s);if(!o)throw new Error(`server asked for ${s}, which no queued file contains`);return o(s)})}catch(s){for(let o of n)this.recordFailure(o.path,s,e);return}e.chunksSent+=i.uploaded,e.bytesSent+=i.bytes;for(let s=0;s<n.length;s++){let o=n[s],a=i.results[s];if(a.error){this.recordFailure(o.path,a.error,e);continue}o.commit(a.uid)}}async planUpload(e,n,r){let i=r??await this.scan(e,n);if(i.sealed){let h=new Map(i.sealed.map(c=>[c.name,c.bytes]));return{names:i.names,bodyOf:async c=>{let u=h.get(c);if(!u)throw new Error(`no sealed body for ${c} of ${n}`);return u}}}let s=this.opts.keys,o=this.opts.vault;if(i.spans){let h=new Map(i.names.map((c,u)=>[c,i.spans[u]]));return{names:i.names,bodyOf:async c=>{let u=h.get(c);if(!u)throw new Error(`no chunk named ${c} in ${n}`);let f=await o.readRange(i.path,u.start,u.end),g=await ue(s,[f]);if(g[0].name!==c)throw new Error(`${n} changed while it was being sent, so it was not sent`);return g[0].bytes}}}let a=new Map;for(let h=0;h<i.names.length;h++){let c=i.pieces[h];a.set(i.names[h],{start:c.offset,end:c.offset+c.bytes.length})}let l=i.bytes;return{names:i.names,bodyOf:async h=>{let c=a.get(h);if(!c)throw new Error(`no chunk named ${h} in ${n}`);return(await ue(s,[l.subarray(c.start,c.end)]))[0].bytes}}}scan(e,n){return this.rehash(e,n)}async receive(e,n,r,i,s,o){let a=ci(r.hash);this.checkChunkCount(r.uid,a.length),this.inbox.push({path:e,entry:n,remote:r,chunks:a,kind:i,why:s}),this.inboxBytes+=r.size,(this.inbox.length>=_e||this.inboxBytes>=Un)&&await this.fill(o)}async fill(e){if(this.inbox.length===0)return;let n=this.inbox;this.inbox=[],this.inboxBytes=0;let r=new Map,i=this.heldByContent();for(let l of n){let h=i.get(q(l.chunks));h!==void 0&&h!==l.path&&r.set(l,h)}let s=[],o=new Set;for(let l of n)if(!r.has(l))for(let h of l.chunks)o.has(h)||(o.add(h),s.push(h));let a=new Map;if(s.length>0)try{let l=await this.opts.transport.fetch(s);for(let h=0;h<s.length;h++)a.set(s[h],l[h])}catch(l){for(let h of n)this.recordFailure(h.path,l,e);return}for(let l of n)try{let h=r.get(l);if(h!==void 0&&await this.landFromLocal(l,h)){l.kind==="download"?e.downloaded++:e.restored++,this.log(l.kind,l.path,`${l.why}, from ${h} without asking`);continue}h!==void 0?await this.land(l,await this.fetchFor(l)):await this.land(l,a),l.kind==="download"?e.downloaded++:e.restored++,this.log(l.kind,l.path,l.why)}catch(h){this.recordFailure(l.path,h,e)}}pendingDeletes=[];wroteThisPass=[];async wouldUndoAWrite(e){let n=this.opts.vault;for(let r of this.wroteThisPass){if(r===e)continue;if(n.sameFile?await n.sameFile(r,e):r.normalize("NFC").toLowerCase()===e.normalize("NFC").toLowerCase())return r}}async applyDeletes(e){let n=this.pendingDeletes;this.pendingDeletes=[];for(let{path:r,why:i}of n)try{let s=await this.wouldUndoAWrite(r);if(s!==void 0){this.entries.delete(r),this.log("kept",r,`deleting it would remove ${s}, which is the same file`);continue}await this.opts.vault.remove(r),this.entries.delete(r),e.deletedLocally++,this.log("deleted locally",r,i)}catch(s){this.recordFailure(r,s,e)}}heldByContent(){let e=new Map;for(let[n,r]of this.entries)r.folder||r.hash===""||r.hash==="-empty-"||e.set(r.hash,n);return e}async fetchFor(e){let n=await this.opts.transport.fetch([...e.chunks]),r=new Map;return e.chunks.forEach((i,s)=>r.set(i,n[s])),r}async landFromLocal(e,n){let r;try{r=await this.opts.vault.read(n)}catch{return!1}if(r.length!==e.remote.size)return!1;let i=this.mergeable(n),s=[...bt(r,this.sizesFor(r.length,i),i)].map(a=>a.bytes),o=(await ue(this.opts.keys,s)).map(a=>a.name);return q(o)!==q(e.chunks)?!1:(await this.opts.vault.write(e.path,r,{mtime:e.remote.mtime,ctime:e.remote.mtime}),this.wroteThisPass.push(e.path),be(e.entry,{folder:!1,mtime:e.remote.mtime,ctime:e.remote.mtime,size:r.length}),e.entry.chunks=[...e.chunks],e.entry.hash=q(e.chunks),e.entry.size=r.length,de(e.entry,e.entry.hash,e.entry.chunks,e.remote.uid,this.now()),!0)}async land(e,n){let r=e.chunks.map(s=>{let o=n.get(s);if(!o)throw new Error(`the server did not send ${s}, which ${e.path} is made of`);return o}),i=await this.assemble(e.remote.uid,r);if(i.length!==e.remote.size)throw new Error(`version ${e.remote.uid} of ${e.path} assembled to ${i.length} bytes, not the ${e.remote.size} it declares`);await this.opts.vault.write(e.path,i,{mtime:e.remote.mtime,ctime:e.remote.mtime}),this.wroteThisPass.push(e.path),be(e.entry,{folder:!1,mtime:e.remote.mtime,ctime:e.remote.mtime,size:i.length}),e.entry.chunks=[...e.chunks],e.entry.hash=q(e.chunks),e.entry.size=i.length,de(e.entry,e.entry.hash,e.entry.chunks,e.remote.uid,this.now())}async contentOf(e,n,r){let i=n!==void 0?{chunks:n}:await this.opts.transport.get(e);if(r!==void 0&&q(i.chunks)!==r)throw new Error(`version ${e} is made of chunks this device did not record for it, so it is not the version it is being offered as`);return i.chunks.length===0?new Uint8Array(0):(this.checkChunkCount(e,i.chunks.length),this.assemble(e,await this.opts.transport.fetch(i.chunks)))}checkChunkCount(e,n){let r=In(this.limits?.maxChunks??0,Rn.maxChunks);if(n>r)throw new Error(`version ${e} names ${n} chunks, and this server said it stores at most ${r}`)}async assemble(e,n){if(n.length===0)return new Uint8Array(0);let r=[],i=0,s=In(this.limits?.perFileMax??0,Rn.perFileMax);for(let l=0;l<n.length;l+=Pt){let h=await Promise.all(n.slice(l,l+Pt).map(c=>an(this.opts.keys,c)));for(let c of h){if(i+=c.length,i>s)throw new Error(`version ${e} is over ${i} bytes, and this server said it stores at most ${s}`);r.push(c)}}let o=new Uint8Array(i),a=0;for(let l of r)o.set(l,a),a+=l.length;return o}async merge(e,n,r,i){if(!r)return;let s=new TextDecoder("utf-8",{fatal:!0}),o,a,l;try{o=s.decode(await this.contentOf(n.syncuid,void 0,n.synchash)),a=s.decode(await this.opts.vault.read(e)),l=s.decode(await this.contentOf(r.uid,void 0,r.hash))}catch{let u="one side is not valid UTF-8, so merging it would rewrite bytes nobody edited";this.log("merge refused",e,u),await this.conflict(e,n,r,i,u);return}let h=Sn(o,a,l,yn(e)?mi:void 0);if(h.kind==="conflict"){this.log("merge refused",e,h.why),await this.conflict(e,n,r,i,h.why);return}let c=h.text;c!==a&&await this.opts.vault.write(e,new TextEncoder().encode(c),{mtime:this.now(),ctime:n.ctime}),be(n,{folder:!1,mtime:this.now(),ctime:n.ctime,size:c.length}),await this.upload(e,n,i),i.merged++,this.log("merged",e,h.kind==="merged"?"three-way":h.why)}freeConflictPath(e){return di(En(e,this.opts.device,new Date(this.now())),n=>this.opts.vault.exists(n))}async conflict(e,n,r,i,s){if(!r)return;let o=await this.freeConflictPath(e),a=await this.contentOf(r.uid,void 0,r.hash);await this.opts.vault.write(o,a,{mtime:r.mtime,ctime:r.mtime});let l=this.entryFor(o);be(l,{folder:!1,mtime:r.mtime,ctime:r.mtime,size:a.length}),await this.upload(o,l,i),await this.upload(e,n,i),i.conflicted++,this.log("kept both",e,{copy:o,why:s})}async sealedPath(e){let n=await Le(this.opts.keys,e);return this.unsealed.set(n,e),n}recordFailure(e,n,r){let i=n instanceof Error?n.message:String(n),s=n?.code;if(s!==void 0&&["badentry","badname","toolarge"].includes(s)){this.skipped.set(e,{why:i,fingerprint:xt(this.entries.get(e))}),r.skipped++,this.log("skipped for good",e,i);return}let a=this.retries.get(e)??{count:0,error:"",at:0};a.count++,a.error=i,a.at=this.now()+Math.min(3e5,5e3*Math.pow(2,a.count)),this.retries.set(e,a),r.retrying++,this.log("will retry",e,{attempt:a.count,error:i})}prune(e){for(let[n,r]of this.entries){if(e.has(n))continue;let i=this.remote.get(n);i&&!i.deleted||r.synchash===""&&r.hash===""&&this.entries.delete(n)}for(let[n,r]of this.remote)r.deleted&&(e.has(n)||this.entries.has(n)||this.pending.has(n)||this.remote.delete(n))}async save(){let e={};for(let[r,i]of this.entries)e[r]=oi(i);let n={};for(let[r,i]of this.remote)n[r]=i;await this.opts.store.save({cursor:this.cursor,entries:e,remote:n,pending:[...this.pending]})}noteRename(e,n){let r=this.entries.get(e);if(!r)return;let i={...r,chunks:[...r.chunks]};xn(i,e,n),this.entries.set(n,i)}};function ui(t,e){let n={...t};for(let r of Object.keys(n))r!=="inTheWay"&&(n[r]=t[r]+e[r]);return n.inTheWay=[...t.inTheWay,...e.inTheWay].slice(0,On),n}function xt(t){return t?`${t.mtime}:${t.size}`:"gone"}var Dn=8*1024*1024,Pt=16;async function fi(t,e,n=Pt){let r=[];for(let i=0;i<e.length;i+=n){let s=await ue(t,e.slice(i,i+n));for(let o of s)r.push(o.name)}return r}var Un=8*1024*1024;async function di(t,e){if(!await e(t))return t;let n=t.lastIndexOf("."),r=t.lastIndexOf("/"),i=n>r,s=i?t.slice(0,n):t,o=i?t.slice(n):"";for(let a=2;a<1e3;a++){let l=`${s} ${a}${o}`;if(!await e(l))return l}throw new Error(`cannot find an unused name beside ${t}`)}function gi(t,e){let n=new Error(`${t} bytes, and this server said it stores at most ${e}, so it was not read`);return n.code="toolarge",n}async function Fn(t){throw new Error(`this put has no bodies, and the server asked for ${t}`)}function mi(t){try{return JSON.parse(t),!0}catch{return!1}}var pi=150,Re=class{constructor(e){this.opts=e;let n;this.transport=new Je(e.url,{onBatch:async r=>{await n.acceptBatch(r),r.entries.length>0&&this.soon()},onCaughtUp:()=>{this.caughtUp=!0},onClosed:r=>{this.endedWith=r,this.notifyEnded?.(r)},...e.timeoutMs!==void 0?{timeoutMs:e.timeoutMs}:{},...e.log!==void 0?{log:e.log}:{},...e.socketFactory!==void 0?{socketFactory:e.socketFactory}:{}}),n=new je({vault:e.vault,store:e.store,keys:e.keys,transport:this.transport,device:e.device,vaultId:e.vaultId,token:e.token,...e.claim!==void 0?{claim:e.claim}:{},...e.coalesceWrites!==void 0?{coalesceWrites:e.coalesceWrites}:{},...e.log!==void 0?{log:e.log}:{},...e.onProgress!==void 0?{onProgress:e.onProgress}:{}}),this.engine=n}opts;engine;transport;limits;soonTimer;caughtUp=!1;endedWith;notifyEnded;queue=Promise.resolve();serial(e){let n=this.queue.then(e,e);return this.queue=n.catch(()=>{}),n}get requestsSent(){return this.transport.requestsSent}get serverCursor(){return this.limits?.cursor??0}async connect(){await this.transport.connect(),this.limits=await this.engine.start();let e=this.opts.timeoutMs??3e4,n=Date.now()+e;for(;!this.caughtUp&&Date.now()<n;){if(this.endedWith)throw this.endedWith;await $t(25)}if(!this.caughtUp)throw new Error("the server never finished sending what it already had");return this.limits}async settle(e={},n=8){let r=await this.pass(e),i=r;for(let s=0;s<n&&bi(r);s++)await $t(60),r=await this.pass(e),i=wi(i,r);return i}pass(e){return this.serial(()=>this.engine.sync(e))}async runUntilClosed(e=3e4){if(this.endedWith)return this.endedWith;let n=this.opts.vault.watch?.(()=>{this.sync()}),r=setInterval(()=>{this.sync().then(()=>this.keepalive())},e);try{return await new Promise(i=>{this.notifyEnded=i})}finally{clearInterval(r),n?.()}}async keepalive(){try{await this.transport.ping()}catch{}}soon(){this.soonTimer===void 0&&(this.soonTimer=setTimeout(()=>{this.soonTimer=void 0,this.sync()},pi))}async sync(e={}){try{return await this.pass(e)}catch(n){this.opts.log?.("sync failed",n.message);return}}async history(e,n={}){let r=await Le(this.opts.keys,e);return(await this.serial(()=>this.transport.history(r,n))).map(s=>this.asVersion(s,e))}async deleted(e){let n=await this.serial(()=>this.transport.deleted(e)),r=[];for(let i of n.entries)r.push({...this.asVersion(i,await Ve(this.opts.keys,i.path)),restorable:i.restorable??0});return{notes:r,more:n.more}}async contentAt(e){return e.deleted||e.folder?new Uint8Array(0):this.serial(()=>this.engine.contentOf(e.uid))}async restore(e,n){if(e.deleted)throw new Error(`version ${e.uid} of ${e.path} is the deletion itself, not a version to restore`);if(e.folder){let o=n??e.path;return await this.opts.vault.mkdir(o),{path:o,bytes:0}}let r=await this.serial(()=>this.engine.contentOf(e.uid)),i=n??e.path,s=await this.opts.vault.exists(i)?yi(i,e):i;return await this.opts.vault.write(s,r,{mtime:e.mtime,ctime:e.ctime}),{path:s,bytes:r.length}}async newestContentVersion(e){return(await this.history(e,{limit:50})).find(r=>!r.deleted)}asVersion(e,n){return{uid:e.uid,path:n,size:e.size,ctime:e.ctime,mtime:e.mtime,folder:e.folder,deleted:e.deleted,device:e.device,chunks:e.chunks?.length??0}}close(){this.soonTimer!==void 0&&(clearTimeout(this.soonTimer),this.soonTimer=void 0),this.transport.close()}};function yi(t,e){let n=t.lastIndexOf("/"),r=n===-1?"":t.slice(0,n+1),i=n===-1?t:t.slice(n+1),s=i.lastIndexOf("."),o=s<=0?i:i.slice(0,s),a=s<=0?"":i.slice(s);return`${r}${o} (restored ${e.uid})${a}`}async function Nn(t,e={}){let n=new Ke(0,3e5,5e3,!0);for(;e.keepGoing?.()??!0;){let r,i,s=!1;try{r=new Re(t),await r.connect(),s=!0,n.success(Date.now()),e.onClient?.(r),e.onSynced?.(await r.settle(),r.serverCursor),i=await r.runUntilClosed()}catch(l){i=l}finally{e.onClient?.(void 0),r?.close()}if(i&&vi(i)){e.onFatal?.(i);return}if(!(e.keepGoing?.()??!0))return;n.fail(Date.now());let o=n.delay(),a=i??new Error("the connection ended");s?e.onDisconnected?.(a,o):e.onUnreachable?.(a,o),await $t(o)}}function vi(t){return t instanceof P&&t.fatal}function wi(t,e){return{uploaded:t.uploaded+e.uploaded,downloaded:t.downloaded+e.downloaded,merged:t.merged+e.merged,conflicted:t.conflicted+e.conflicted,deletedLocally:t.deletedLocally+e.deletedLocally,deletedRemotely:t.deletedRemotely+e.deletedRemotely,restored:t.restored+e.restored,foldersCreated:t.foldersCreated+e.foldersCreated,chunksSent:t.chunksSent+e.chunksSent,bytesSent:t.bytesSent+e.bytesSent,unchanged:e.unchanged,waiting:e.waiting,retrying:e.retrying,skipped:e.skipped,blocked:e.blocked,inTheWay:e.inTheWay}}function bi(t){return t.uploaded+t.downloaded+t.merged+t.conflicted+t.deletedLocally+t.deletedRemotely+t.restored+t.foldersCreated+t.waiting>0}var $t=t=>new Promise(e=>setTimeout(e,t));var Ge="basalt2_",Mt=2,Ie=4,Wn=new TextEncoder,ki=new TextDecoder;function Ct(t){if(t.secret.length!==X)throw new Error(`a root secret is ${X} bytes, not ${t.secret.length}`);let e=[Wn.encode(t.url),Wn.encode(t.vaultId)];for(let o of e)if(o.length>255)throw new Error("a pairing field is too long to encode");let n=1+X+e.reduce((o,a)=>o+1+a.length,0),r=new Uint8Array(n);r[0]=Mt,r.set(t.secret,1);let i=1+X;for(let o of e)r[i++]=o.length,r.set(o,i),i+=o.length;let s=new Uint8Array(n+Ie);return s.set(r,0),s.set(Ln(r),n),Ge+Te(s)}function Bn(t){let e=t.trim();if(e.startsWith("basalt1_"))throw new Error("this is a version 1 pairing string, from before the server token was folded into the root secret. Run basalt invite on a device that is already paired to get a current one.");if(!e.startsWith(Ge))throw new Error(`not a pairing string: it should start with ${Ge}`);let n;try{n=He(e.slice(Ge.length))}catch{throw new Error("this pairing string is damaged: it is not valid base64url")}if(n.length<1+X+2+Ie)throw new Error("this pairing string is too short to be complete");let r=n.subarray(0,n.length-Ie),i=n.subarray(n.length-Ie),s=Ln(r);for(let u=0;u<Ie;u++)if(i[u]!==s[u])throw new Error("this pairing string is damaged: it did not survive being copied");if(r[0]!==Mt)throw new Error(`this pairing string is version ${r[0]}, and this device understands ${Mt}`);let o=r.slice(1,1+X),a=1+X,l=u=>{if(a>=r.length)throw new Error(`this pairing string ends before its ${u}`);let f=r[a++];if(a+f>r.length)throw new Error(`this pairing string ends inside its ${u}`);let g=ki.decode(r.subarray(a,a+f));return a+=f,g},h=l("server address"),c=l("vault name");if(a!==r.length)throw new Error("this pairing string has more in it than it should");if(h===""||c==="")throw new Error("this pairing string has an empty field");return{url:h,secret:o,vaultId:c}}function Ln(t){let e=4294967295;for(let n of t){e^=n;for(let r=0;r<8;r++)e=e&1?e>>>1^3988292384:e>>>1}return e=(e^4294967295)>>>0,new Uint8Array([e>>>24&255,e>>>16&255,e>>>8&255,e&255])}function Vn(t){return{url:t.url,vaultId:t.vaultId,device:t.device,secret:Te(t.secret),...t.bootstrap?{bootstrap:t.bootstrap}:{}}}function Hn(t,e){if(typeof t!="object"||t===null)throw new Error(`${e} does not hold a configuration`);let n=t,r=o=>{let a=n[o];if(typeof a!="string"||a==="")throw new Error(`${e} has no ${o}`);return a},i=He(r("secret"));if(i.length!==X)throw new Error(`${e} holds a ${i.length} byte secret, and a root secret is ${X}`);let s=n.bootstrap;return{url:r("url"),vaultId:r("vaultId"),device:r("device"),secret:i,...typeof s=="string"&&s!==""?{bootstrap:s}:{}}}function Jn(t){let e=t.trim().replace(/\/+$/,"");if(e==="")throw new Error("that is not a server address");if(e.startsWith("ws://")||e.startsWith("wss://"))return e;if(e.startsWith("http://"))return"ws://"+e.slice(7);if(e.startsWith("https://"))return"wss://"+e.slice(8);if(e.includes("://"))throw new Error(`a server address is ws:// or wss://, not ${e.split("://")[0]}://`);return"wss://"+e}import{constants as Tt,watch as Si}from"node:fs";import{access as _t,cp as Ei,mkdir as Qe,open as et,readFile as Zn,readdir as Kn,realpath as jn,rename as Rt,rm as Ai,stat as qe,utimes as xi}from"node:fs/promises";import{basename as Ze,dirname as le,join as Xe,relative as Pi,resolve as Gn,sep as Ye}from"node:path";var Xn=".trash",$i=new Set([".basalt",Xn,".git",".DS_Store","node_modules"]),It=".obsidian";function zt(t){let e=t.replace(/^\/+|\/+$/g,"");if(e===""||e.includes("/"))throw new Error(`refusing to sync: the config folder ${JSON.stringify(t)} is not a plain name`);return e}var tt=class{root;ignore;constructor(e,n={}){this.root=Gn(e);let r=zt(n.configDir??It);this.ignore=new Set([...$i,r,...n.alsoIgnore??[]])}realRootOnce;unflushed=new Set;async flush(){let e=[...this.unflushed];this.unflushed.clear(),await Promise.all(e.map(n=>er(n)))}async insideForReal(e){let n=await(this.realRootOnce??=jn(this.root)),r=le(e);for(;;){let i=await jn(r).catch(o=>{if(o.code!=="ENOENT")throw o});if(i!==void 0){if(i!==n&&!i.startsWith(n+Ye))throw new Error(`refusing a path that leaves the vault through a link: ${e}`);return}let s=le(r);if(s===r)return;r=s}}absolute(e){let n=Gn(this.root,e),r=Pi(this.root,n);if(r===""||r===".."||r.startsWith(`..${Ye}`))throw new Error(`refusing a path outside the vault: ${e}`);let i=r.split(Ye)[0];if(this.ignore.has(i))throw new Error(`refusing to write inside ${i}, which is never synced: ${e}`);return n}async list(){let e=async(n,r)=>{let i;try{i=await Kn(n,{withFileTypes:!0})}catch(h){throw new Error(`cannot read ${n}: ${h.message}`)}let s=i.filter(h=>!this.ignore.has(h.name)&&!qn(h.name)&&(h.isDirectory()||h.isFile())),o=await Promise.all(s.map(h=>h.isFile()?qe(Xe(n,h.name)):void 0)),a=await Promise.all(s.map(h=>h.isDirectory()?e(Xe(n,h.name),r?`${r}/${h.name}`:h.name):void 0)),l=[];for(let h=0;h<s.length;h++){let c=s[h],u=r?`${r}/${c.name}`:c.name;if(c.isDirectory())l.push({path:u,folder:!0,mtime:0,ctime:0,size:0}),l.push(...a[h]);else{let f=o[h];l.push({path:u,folder:!1,mtime:f.mtimeMs,ctime:f.birthtimeMs||f.ctimeMs,size:f.size})}}return l};return e(this.root,"")}async read(e){return new Uint8Array(await Zn(this.absolute(e)))}async*readBlocks(e,n=1024*1024){let r=await et(this.absolute(e),"r");try{let i=new Uint8Array(n);for(;;){let{bytesRead:s}=await r.read(i,0,n,null);if(s===0)return;yield i.slice(0,s)}}finally{await r.close()}}async readRange(e,n,r){let i=await et(this.absolute(e),"r");try{let s=new Uint8Array(r-n),o=0;for(;o<s.length;){let{bytesRead:a}=await i.read(s,o,s.length-o,n+o);if(a===0)break;o+=a}return o===s.length?s:s.subarray(0,o)}finally{await i.close()}}async write(e,n,r){let i=this.absolute(e);if(await this.insideForReal(i),await Qe(le(i),{recursive:!0}),await this.matchCase(i),await Qn(i,n,!1),this.unflushed.add(le(i)),r.mtime>0){let s=r.mtime/1e3;await xi(i,s,s)}}async matchCase(e){let n;try{n=await qe(e)}catch{return}if(n.isDirectory())return;let r=le(e),i=Ze(e),s;try{s=await Kn(r)}catch{return}if(s.includes(i))return;let o=i.normalize("NFC").toLowerCase(),a=s.find(l=>l.normalize("NFC").toLowerCase()===o);a!==void 0&&await Rt(Xe(r,a),e)}async remove(e){let n=this.absolute(e);await this.insideForReal(n);try{await _t(n,Tt.F_OK)}catch{return}let r=await this.freeTrashPath(e);await Qe(le(r),{recursive:!0});try{await Rt(n,r);return}catch(i){if(i.code!=="EXDEV")throw i}await Ei(n,r,{recursive:!0}),await Ai(n,{recursive:!0,force:!0})}async freeTrashPath(e){let n=Xe(this.root,Xn,e),r=Ze(e).lastIndexOf("."),[i,s]=r<=0?[n,""]:[n.slice(0,n.length-(Ze(e).length-r)),n.slice(n.length-(Ze(e).length-r))];for(let o=0;o<1e3;o++){let a=o===0?n:`${i} (${o})${s}`;try{await _t(a,Tt.F_OK)}catch{return a}}throw new Error(`the trash already holds a thousand copies of ${e}`)}async mkdir(e){let n=this.absolute(e);await this.insideForReal(n),await Qe(n,{recursive:!0})}async exists(e){try{return await _t(this.absolute(e),Tt.F_OK),!0}catch{return!1}}async sameFile(e,n){if(e===n)return!0;try{let[r,i]=await Promise.all([qe(this.absolute(e)),qe(this.absolute(n))]);return r.dev===i.dev&&r.ino===i.ino}catch{return!1}}watch(e){let n,r="",i;try{i=Si(this.root,{recursive:!0,persistent:!0},(s,o)=>{if(!o)return;let a=o.toString().split(Ye).join("/");a.split("/").some(l=>this.ignore.has(l))||qn(a)||(r=a,n&&clearTimeout(n),n=setTimeout(()=>{n=void 0,e(r)},150))}),i.on("error",()=>{})}catch{return()=>{}}return()=>{n&&clearTimeout(n),i?.close()}}},ze=class{constructor(e){this.file=e}file;lastWritten;async load(){let e;try{e=await Zn(this.file,"utf8")}catch(n){if(n.code==="ENOENT")return;throw new Error(`cannot read the index at ${this.file}: ${n.message}`)}try{return JSON.parse(e)}catch(n){throw new Error(`the index at ${this.file} is not valid JSON, so it cannot be trusted: ${n.message}`)}}async save(e){let n=JSON.stringify(e);n!==this.lastWritten&&(await Qe(le(this.file),{recursive:!0}),await Qn(this.file,new TextEncoder().encode(n)),this.lastWritten=n)}},Yn=".basalt-tmp-";function qn(t){return t.includes(Yn)}var Mi=0;async function Ci(t){for(let e=0;e<64;e++){let n=`${t}${Yn}${(Mi++).toString(36)}${e?`-${e}`:""}`;try{return{tmp:n,handle:await et(n,"wx")}}catch(r){if(r.code!=="EEXIST")throw r}}throw new Error(`could not find an unused temporary name beside ${t}`)}async function Qn(t,e,n=!0){let{tmp:r,handle:i}=await Ci(t);try{await i.write(e),await i.sync()}finally{await i.close()}await Rt(r,t),n&&await er(le(t))}async function er(t){let e=await et(t,"r");try{await e.sync()}finally{await e.close()}}import{chmod as Ti,mkdir as _i,readFile as Ri,rename as Ii,rm as tr,writeFile as zi}from"node:fs/promises";import{join as Dt}from"node:path";var Ut=".basalt",Ft=t=>Dt(t,Ut,"config.json"),nt=t=>Dt(t,Ut,"index.json");async function De(t){let e=Ft(t),n;try{n=await Ri(e,"utf8")}catch(i){if(i.code==="ENOENT")return;throw new Error(`cannot read ${e}: ${i.message}`)}let r;try{r=JSON.parse(n)}catch(i){throw new Error(`${e} is not valid JSON, so it cannot be trusted: ${i.message}`)}return Hn(r,e)}async function rt(t,e){let n=Dt(t,Ut);await _i(n,{recursive:!0});let r=Ft(t),i=`${r}.tmp`;await zi(i,JSON.stringify(Vn(e),null,2)+`
9
+ `,{mode:384}),await Ti(i,384),await Ii(i,r)}async function nr(t){await tr(Ft(t),{force:!0}),await tr(nt(t),{force:!0})}var rr=`basalt: self-hosted sync for Obsidian
10
10
 
11
11
  basalt init --server URL --token TOKEN claim a new vault, with the server's first-run token
12
12
  basalt pair PAIRING-STRING pair this vault with an existing one
@@ -30,6 +30,6 @@ Options
30
30
  --limit N how many versions history shows (default: 20)
31
31
  --config-dir DIR Obsidian's config folder, if it is not .obsidian
32
32
  --ignore NAME a top-level name never to sync, repeatable
33
- `;async function Hn(t,e){let n;try{n=Ri(t)}catch(r){return e.err(String(r.message)),2}if(n.help||n.command===void 0)return e.out(Jn),n.command===void 0&&!n.help?2:0;try{switch(n.command){case"init":return await Si(n,e);case"pair":return await Ei(n,e);case"invite":return await Ai(n,e);case"sync":return await xi(n,e);case"status":return await $i(n,e);case"deleted":return await Mi(n,e);case"history":return await _i(n,e);case"restore":return await Ci(n,e);case"unlink":return await Ti(n,e);default:return e.err(`no such command: ${n.command}`),e.err(Jn),2}}catch(r){let i=r instanceof Error?r.message:String(r);return n.json?e.out(JSON.stringify({ok:!1,error:i})):e.err(`basalt: ${i}`),1}}async function Si(t,e){if(!t.server||!t.token)throw new Error("init needs --server and --token, from the server's first run");if(await Re(t.dir))throw new Error(`${t.dir} is already paired. Use unlink first if that is really what you want.`);let n={url:Rn(t.server),vaultId:t.vaultId,device:t.device,secret:Kt(),bootstrap:t.token};await Ye(t.dir,n);let r=wt(n);return t.json?e.out(JSON.stringify({ok:!0,paired:t.dir,device:n.device,pairing:r})):(e.out(`Paired ${t.dir} as "${n.device}".`),e.out(""),e.out("Give this to every other device. Anyone who has it has the vault:"),e.out(""),e.out(` ${r}`),e.out(""),e.out("It is the only copy. The server cannot reissue it, because the server"),e.out("has never seen the secret in it.")),0}async function Ei(t,e){if(!t.rest[0])throw new Error("pair needs the string another device printed");if(await Re(t.dir))throw new Error(`${t.dir} is already paired. Use unlink first if that is really what you want.`);let r={...Mn(t.rest[0]),device:t.device};return await Ye(t.dir,r),t.json?e.out(JSON.stringify({ok:!0,paired:t.dir,device:r.device,url:r.url})):e.out(`Paired ${t.dir} with ${r.url} as "${r.device}". Run basalt sync.`),0}async function Ai(t,e){let n=await pe(t.dir),r=wt(n);return t.json?e.out(JSON.stringify({ok:!0,pairing:r})):(e.out(r),e.err("Anyone who has that string has this vault.")),0}async function xi(t,e){let n=await pe(t.dir);if(t.watch)return await Pi(n,t,e);let r=await Ie(n,t,e);try{let i=await r.settle();return Gn(i,t,e,r.serverCursor),i.skipped>0||i.retrying>0?1:0}finally{r.close()}}async function Pi(t,e,n){let r;return await Pn(await jn(t,e,n),{onSynced:(i,s)=>{Gn(i,e,n,s),e.json||n.err("Watching for changes. Ctrl-C to stop.")},onDisconnected:(i,s)=>{n.err(`Disconnected: ${i.message}. Trying again in ${Kn(s)}.`)},onUnreachable:(i,s)=>{n.err(`Cannot reach the server: ${i.message}. Trying again in ${Kn(s)}.`)},onFatal:i=>{r=i}}),r?(n.err(`basalt: ${r.message}`),n.err("That will not fix itself by trying again."),1):0}async function $i(t,e){let n=await pe(t.dir),r=await new Te(Xe(t.dir)).load(),i={vault:t.dir,device:n.device,server:n.url,vaultId:n.vaultId,cursor:r?.cursor??0,tracked:r?Object.keys(r.entries).length:0,pending:r?.pending.length??0},s;try{let o=await Ie(n,t,e);s={reachable:!0,cursor:o.serverCursor,behind:Math.max(0,o.serverCursor-i.cursor)},o.close()}catch(o){s={reachable:!1,error:o.message}}return t.json?(e.out(JSON.stringify({ok:!0,...i,server:s})),s.reachable?0:1):(e.out(`vault ${i.vault}`),e.out(`device ${i.device}`),e.out(`server ${i.server} (vault "${i.vaultId}")`),e.out(`tracked ${i.tracked} files`),e.out(`cursor ${i.cursor}`),i.pending>0&&e.out(`pending ${i.pending} files with work outstanding`),s.reachable?(e.out(s.behind===0?"state up to date with the server":`state ${s.behind} changes behind`),0):(e.out(`state cannot reach the server: ${s.error}`),1))}async function Mi(t,e){let n=await pe(t.dir),r=await Ie(n,t,e);try{let i=await r.deleted(t.limit>20?t.limit:void 0);if(t.json)return e.out(JSON.stringify({ok:!0,deleted:i.notes,more:i.more})),0;if(i.notes.length===0)return e.out("Nothing has been deleted from this vault."),0;let s=0;for(let a of i.notes){let l=a.restorable===0?" (content purged)":"";a.restorable===0&&s++,e.out(`${Mt(a.mtime)} ${a.device.padEnd(12)} ${a.path}${l}`)}e.out("");let o=i.notes.length-s;return s===0?e.out(`${o} deleted, all still recoverable. basalt restore PATH brings one back.`):e.out(`${i.notes.length} deleted. ${o} can be restored; ${s} had their history purged and cannot be.`),i.more&&e.out("There are older deletions than these. --limit N shows more."),0}finally{r.close()}}async function _i(t,e){let n=t.rest[0];if(!n)throw new Error("history needs the path of a note");let r=await pe(t.dir),i=await Ie(r,t,e);try{let s=await i.history(n,{limit:t.limit});if(t.json)return e.out(JSON.stringify({ok:!0,path:n,versions:s})),0;if(s.length===0)return e.out(`The server holds no versions of ${n}.`),0;for(let o of s){let a=o.deleted?"deleted":o.folder?"folder":`${_t(o.size)}`;e.out(`${String(o.uid).padStart(7)} ${Mt(o.mtime)} ${o.device.padEnd(12)} ${a}`)}return e.out(""),e.out("basalt restore PATH --uid N brings one of these back."),0}finally{i.close()}}async function Ci(t,e){let n=t.rest[0];if(!n)throw new Error("restore needs the path of a note");let r=await pe(t.dir),i=await Ie(r,t,e);try{let s;if(t.uid!==void 0){if(s=(await i.history(n,{limit:500})).find(c=>c.uid===t.uid),!s)throw new Error(`the server has no version ${t.uid} of ${n}`)}else if(s=await i.newestContentVersion(n),!s)throw new Error(`the server holds no version of ${n} with any content in it`);let o=await i.restore(s,t.to),a=await i.settle({coalesceWrites:!1});return t.json?(e.out(JSON.stringify({ok:!0,path:o.path,uid:s.uid,bytes:o.bytes,sync:a})),0):(e.out(`Restored version ${s.uid} of ${n} (${_t(o.bytes)}, from ${Mt(s.mtime)}).`),o.path!==(t.to??n)&&e.out(`Written to ${o.path}, because something is already at ${t.to??n}.`),a.uploaded>0&&e.out("Sent to the server, so your other devices will pick it up."),0)}finally{i.close()}}async function Ti(t,e){let n=await Re(t.dir).catch(()=>{});return await Vn(t.dir),t.json?e.out(JSON.stringify({ok:!0,unlinked:t.dir,wasPaired:n!==void 0})):(e.out(`Forgot the pairing for ${t.dir}. Every note is where it was.`),e.out("Nothing was removed from the server.")),0}async function Ie(t,e,n){let r=new _e(await jn(t,e,n));if(await r.connect(),t.bootstrap){let{bootstrap:i,...s}=t;await Ye(e.dir,s)}return r}async function jn(t,e,n){let r=await Ht(t.secret),i=Yt(r);return{vault:new Ze(e.dir,{configDir:e.configDir,alsoIgnore:e.ignore}),store:new Te(Xe(e.dir)),keys:r,url:t.url,token:t.bootstrap??i,claim:i,vaultId:t.vaultId,device:t.device,timeoutMs:e.timeout,coalesceWrites:e.watch,...e.watch&&n?{onProgress:s=>{s!==void 0&&n.err(` ... ${s}`)}}:{},...e.verbose&&n?{log:(s,...o)=>n.err(` ${s} ${o.map(Ii).join(" ")}`.trimEnd())}:{}}}function Gn(t,e,n,r){if(e.json){n.out(JSON.stringify({ok:!0,...t,serverCursor:r}));return}let i=[],s=(o,a)=>{o>0&&i.push(`${String(o).padStart(5)} ${a}`)};if(s(t.uploaded,"uploaded"),s(t.downloaded,"downloaded"),s(t.merged,"merged"),s(t.conflicted,"kept both versions"),s(t.deletedLocally,"deleted here"),s(t.deletedRemotely,"deleted on the server"),s(t.restored,"brought back, having been edited elsewhere"),s(t.foldersCreated,"folders created"),s(t.waiting,"waiting for a write to settle"),s(t.retrying,"failed, will try again"),s(t.skipped,"cannot sync and will not be retried"),s(t.blocked,"waiting on a name that is a file here and a folder elsewhere"),i.length===0)n.out("Nothing to do. Everything here matches the server.");else for(let o of i)n.out(o);t.chunksSent>0&&n.out(`${String(t.chunksSent).padStart(5)} chunks sent, ${_t(t.bytesSent)}`),t.conflicted>0&&n.err('Look for files with "Conflicted copy" in the name. Both versions are kept.')}function Ri(t){let e={rest:[],dir:process.cwd(),device:bi().split(".")[0]||"device",vaultId:"default",json:!1,watch:!1,limit:20,verbose:!1,help:!1,timeout:3e4,configDir:Et,ignore:[]},n=new Set(["--dir","--device","--vault-id","--server","--token","--timeout","--uid","--to","--limit","--config-dir","--ignore"]);for(let r=0;r<t.length;r++){let i=t[r],s;if(n.has(i)&&(s=t[++r],s===void 0||s.startsWith("--")))throw new Error(`${i} needs a value`);switch(i){case"--dir":e.dir=ki(s);break;case"--device":e.device=s;break;case"--vault-id":e.vaultId=s;break;case"--server":e.server=s;break;case"--token":e.token=s;break;case"--timeout":{let o=Number(s);if(!Number.isFinite(o)||o<=0)throw new Error(`--timeout wants a number of milliseconds, not ${s}`);e.timeout=o;break}case"--uid":{let o=Number(s);if(!Number.isInteger(o)||o<=0)throw new Error(`--uid wants a version number, not ${s}`);e.uid=o;break}case"--to":e.to=s;break;case"--config-dir":e.configDir=At(s);break;case"--ignore":e.ignore.push(s);break;case"--limit":{let o=Number(s);if(!Number.isInteger(o)||o<=0)throw new Error(`--limit wants a count, not ${s}`);e.limit=o;break}case"--json":e.json=!0;break;case"--watch":e.watch=!0;break;case"--verbose":case"-v":e.verbose=!0;break;case"--help":case"-h":e.help=!0;break;default:if(i.startsWith("-"))throw new Error(`no such option: ${i}`);e.command===void 0?e.command=i:e.rest.push(i)}}return e}async function pe(t){let e=await Re(t);if(!e)throw new Error(`${t} is not paired. Run basalt init or basalt pair first.`);return e}function Mt(t){if(!Number.isFinite(t)||t<=0)return"unknown ";let e=new Date(t),n=r=>String(r).padStart(2,"0");return`${e.getFullYear()}-${n(e.getMonth()+1)}-${n(e.getDate())} ${n(e.getHours())}:${n(e.getMinutes())}`}function Kn(t){return`${Math.max(1,Math.round(t/1e3))}s`}function _t(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KiB`:`${(t/(1024*1024)).toFixed(1)} MiB`}function Ii(t){return typeof t=="string"?t:JSON.stringify(t)}var Di=await Hn(process.argv.slice(2),{out:t=>process.stdout.write(t+`
33
+ `;async function sr(t,e){let n;try{n=ji(t)}catch(r){return e.err(String(r.message)),2}if(n.help||n.command===void 0)return e.out(rr),n.command===void 0&&!n.help?2:0;try{switch(n.command){case"init":return await Fi(n,e);case"pair":return await Oi(n,e);case"invite":return await Ni(n,e);case"sync":return await Wi(n,e);case"status":return await Li(n,e);case"deleted":return await Vi(n,e);case"history":return await Hi(n,e);case"restore":return await Ji(n,e);case"unlink":return await Ki(n,e);default:return e.err(`no such command: ${n.command}`),e.err(rr),2}}catch(r){let i=r instanceof Error?r.message:String(r);return n.json?e.out(JSON.stringify({ok:!1,error:i})):e.err(`basalt: ${i}`),1}}async function Fi(t,e){if(!t.server||!t.token)throw new Error("init needs --server and --token, from the server's first run");if(await De(t.dir))throw new Error(`${t.dir} is already paired. Use unlink first if that is really what you want.`);let n={url:Jn(t.server),vaultId:t.vaultId,device:t.device,secret:en(),bootstrap:t.token};await rt(t.dir,n),(await ke(n,t,e)).close();let i=Ct(n);return t.json?e.out(JSON.stringify({ok:!0,paired:t.dir,device:n.device,pairing:i})):(e.out(`Paired ${t.dir} as "${n.device}".`),e.out(""),e.out("Give this to every other device. Anyone who has it has the vault:"),e.out(""),e.out(` ${i}`),e.out(""),e.out("It is the only copy. The server cannot reissue it, because the server"),e.out("has never seen the secret in it.")),0}async function Oi(t,e){if(!t.rest[0])throw new Error("pair needs the string another device printed");if(await De(t.dir))throw new Error(`${t.dir} is already paired. Use unlink first if that is really what you want.`);let r={...Bn(t.rest[0]),device:t.device};return await rt(t.dir,r),t.json?e.out(JSON.stringify({ok:!0,paired:t.dir,device:r.device,url:r.url})):e.out(`Paired ${t.dir} with ${r.url} as "${r.device}". Run basalt sync.`),0}async function Ni(t,e){let n=await Se(t.dir),r=Ct(n);return t.json?e.out(JSON.stringify({ok:!0,pairing:r})):(e.out(r),e.err("Anyone who has that string has this vault.")),0}async function Wi(t,e){let n=await Se(t.dir);if(t.watch)return await Bi(n,t,e);let r=await ke(n,t,e);try{let i=await r.settle();return ar(i,t,e,r.serverCursor),i.skipped>0||i.retrying>0?1:0}finally{r.close()}}async function Bi(t,e,n){let r;return await Nn(await or(t,e,n),{onSynced:(i,s)=>{ar(i,e,n,s),e.json||n.err("Watching for changes. Ctrl-C to stop.")},onDisconnected:(i,s)=>{n.err(`Disconnected: ${i.message}. Trying again in ${ir(s)}.`)},onUnreachable:(i,s)=>{n.err(`Cannot reach the server: ${i.message}. Trying again in ${ir(s)}.`)},onFatal:i=>{r=i}}),r?(n.err(`basalt: ${r.message}`),n.err("That will not fix itself by trying again."),1):0}async function Li(t,e){let n=await Se(t.dir),r=await new ze(nt(t.dir)).load(),i={vault:t.dir,device:n.device,server:n.url,vaultId:n.vaultId,cursor:r?.cursor??0,tracked:r?Object.keys(r.entries).length:0,pending:r?.pending.length??0},s;try{let o=await ke(n,t,e);s={reachable:!0,cursor:o.serverCursor,behind:o.serverCursor-i.cursor},o.close()}catch(o){s={reachable:!1,error:o.message}}return t.json?(e.out(JSON.stringify({ok:!0,...i,server:s})),s.reachable?0:1):(e.out(`vault ${i.vault}`),e.out(`device ${i.device}`),e.out(`server ${i.server} (vault "${i.vaultId}")`),e.out(`tracked ${i.tracked} files`),e.out(`cursor ${i.cursor}`),i.pending>0&&e.out(`pending ${i.pending} files with work outstanding`),s.reachable?(e.out(s.behind!==0?`state ${s.behind} changes behind`:i.pending>0?`state caught up with the server, with ${i.pending} still not applied here`:"state up to date with the server"),0):(e.out(`state cannot reach the server: ${s.error}`),1))}async function Vi(t,e){let n=await Se(t.dir),r=await ke(n,t,e);try{let i=await r.deleted(t.limit>20?t.limit:void 0);if(t.json)return e.out(JSON.stringify({ok:!0,deleted:i.notes,more:i.more})),0;if(i.notes.length===0)return e.out("Nothing has been deleted from this vault."),0;let s=0;for(let a of i.notes){let l=a.restorable===0?" (content purged)":"";a.restorable===0&&s++,e.out(`${Ot(a.mtime)} ${a.device.padEnd(12)} ${a.path}${l}`)}e.out("");let o=i.notes.length-s;return s===0?e.out(`${o} deleted, all still recoverable. basalt restore PATH brings one back.`):e.out(`${i.notes.length} deleted. ${o} can be restored; ${s} had their history purged and cannot be.`),i.more&&e.out("There are older deletions than these. --limit N shows more."),0}finally{r.close()}}async function Hi(t,e){let n=t.rest[0];if(!n)throw new Error("history needs the path of a note");let r=await Se(t.dir),i=await ke(r,t,e);try{let s=await i.history(n,{limit:t.limit});if(t.json)return e.out(JSON.stringify({ok:!0,path:n,versions:s})),0;if(s.length===0)return e.out(`The server holds no versions of ${n}.`),0;for(let o of s){let a=o.deleted?"deleted":o.folder?"folder":`${Nt(o.size)}`;e.out(`${String(o.uid).padStart(7)} ${Ot(o.mtime)} ${o.device.padEnd(12)} ${a}`)}return e.out(""),e.out("basalt restore PATH --uid N brings one of these back."),0}finally{i.close()}}async function Ji(t,e){let n=t.rest[0];if(!n)throw new Error("restore needs the path of a note");let r=await Se(t.dir),i=await ke(r,t,e);try{let s;if(t.uid!==void 0){if(s=(await i.history(n,{limit:500})).find(h=>h.uid===t.uid),!s)throw new Error(`the server has no version ${t.uid} of ${n}`)}else if(s=await i.newestContentVersion(n),!s)throw new Error(`the server holds no version of ${n} with any content in it`);let o=await i.restore(s,t.to),a=await i.settle({coalesceWrites:!1});return t.json?(e.out(JSON.stringify({ok:!0,path:o.path,uid:s.uid,bytes:o.bytes,sync:a})),0):(e.out(`Restored version ${s.uid} of ${n} (${Nt(o.bytes)}, from ${Ot(s.mtime)}).`),o.path!==(t.to??n)&&e.out(`Written to ${o.path}, because something is already at ${t.to??n}.`),a.uploaded>0&&e.out("Sent to the server, so your other devices will pick it up."),0)}finally{i.close()}}async function Ki(t,e){let n=await De(t.dir).catch(()=>{});return await nr(t.dir),t.json?e.out(JSON.stringify({ok:!0,unlinked:t.dir,wasPaired:n!==void 0})):(e.out(`Forgot the pairing for ${t.dir}. Every note is where it was.`),e.out("Nothing was removed from the server.")),0}async function ke(t,e,n){let r=new Re(await or(t,e,n));if(await r.connect(),t.bootstrap){let{bootstrap:i,...s}=t;await rt(e.dir,s)}return r}async function or(t,e,n){let r=await tn(t.secret),i=ln(r);return{vault:new tt(e.dir,{configDir:e.configDir,alsoIgnore:e.ignore}),store:new ze(nt(e.dir)),keys:r,url:t.url,token:t.bootstrap??i,claim:i,vaultId:t.vaultId,device:t.device,timeoutMs:e.timeout,coalesceWrites:e.watch,...e.watch&&n?{onProgress:s=>{s!==void 0&&n.err(` ... ${s}`)}}:{},...e.verbose&&n?{log:(s,...o)=>n.err(` ${s} ${o.map(Gi).join(" ")}`.trimEnd())}:{}}}function ar(t,e,n,r){if(e.json){n.out(JSON.stringify({ok:!0,...t,serverCursor:r}));return}let i=[],s=(o,a)=>{o>0&&i.push(`${String(o).padStart(5)} ${a}`)};if(s(t.uploaded,"uploaded"),s(t.downloaded,"downloaded"),s(t.merged,"merged"),s(t.conflicted,"kept both versions"),s(t.deletedLocally,"deleted here"),s(t.deletedRemotely,"deleted on the server"),s(t.restored,"brought back, having been edited elsewhere"),s(t.foldersCreated,"folders created"),s(t.waiting,"waiting for a write to settle"),s(t.retrying,"failed, will try again"),s(t.skipped,"cannot sync and will not be retried"),s(t.blocked,"waiting on a name that is a file here and a folder elsewhere"),i.length===0)n.out("Nothing to do. Everything here matches the server.");else for(let o of i)n.out(o);if(t.inTheWay.length>0){n.out("");let o=[...new Set(t.inTheWay.map(l=>l.blockedBy))];for(let l of o)n.out(` "${l}" is a file here and a folder on another device.`);let a=t.inTheWay.map(l=>l.path);n.out(` Waiting to be written: ${a.join(", ")}${t.blocked>a.length?", \u2026":""}`),n.out(" Rename one of them, on whichever device meant the other thing.")}t.chunksSent>0&&n.out(`${String(t.chunksSent).padStart(5)} chunks sent, ${Nt(t.bytesSent)}`),t.conflicted>0&&n.err('Look for files with "Conflicted copy" in the name. Both versions are kept.')}function ji(t){let e={rest:[],dir:process.cwd(),device:Di().split(".")[0]||"device",vaultId:"default",json:!1,watch:!1,limit:20,verbose:!1,help:!1,timeout:3e4,configDir:It,ignore:[]},n=new Set(["--dir","--device","--vault-id","--server","--token","--timeout","--uid","--to","--limit","--config-dir","--ignore"]);for(let r=0;r<t.length;r++){let i=t[r],s;if(n.has(i)&&(s=t[++r],s===void 0||s.startsWith("--")))throw new Error(`${i} needs a value`);switch(i){case"--dir":e.dir=Ui(s);break;case"--device":e.device=s;break;case"--vault-id":e.vaultId=s;break;case"--server":e.server=s;break;case"--token":e.token=s;break;case"--timeout":{let o=Number(s);if(!Number.isFinite(o)||o<=0)throw new Error(`--timeout wants a number of milliseconds, not ${s}`);e.timeout=o;break}case"--uid":{let o=Number(s);if(!Number.isInteger(o)||o<=0)throw new Error(`--uid wants a version number, not ${s}`);e.uid=o;break}case"--to":e.to=s;break;case"--config-dir":e.configDir=zt(s);break;case"--ignore":e.ignore.push(s);break;case"--limit":{let o=Number(s);if(!Number.isInteger(o)||o<=0)throw new Error(`--limit wants a count, not ${s}`);e.limit=o;break}case"--json":e.json=!0;break;case"--watch":e.watch=!0;break;case"--verbose":case"-v":e.verbose=!0;break;case"--help":case"-h":e.help=!0;break;default:if(i.startsWith("-"))throw new Error(`no such option: ${i}`);e.command===void 0?e.command=i:e.rest.push(i)}}return e}async function Se(t){let e=await De(t);if(!e)throw new Error(`${t} is not paired. Run basalt init or basalt pair first.`);return e}function Ot(t){if(!Number.isFinite(t)||t<=0)return"unknown ";let e=new Date(t),n=r=>String(r).padStart(2,"0");return`${e.getFullYear()}-${n(e.getMonth()+1)}-${n(e.getDate())} ${n(e.getHours())}:${n(e.getMinutes())}`}function ir(t){return`${Math.max(1,Math.round(t/1e3))}s`}function Nt(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KiB`:`${(t/(1024*1024)).toFixed(1)} MiB`}function Gi(t){return typeof t=="string"?t:JSON.stringify(t)}var qi=await sr(process.argv.slice(2),{out:t=>process.stdout.write(t+`
34
34
  `),err:t=>process.stderr.write(t+`
35
- `)});process.exit(Di);
35
+ `)});process.exit(qi);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basalt-sync",
3
- "version": "0.1.8",
3
+ "version": "0.2.1",
4
4
  "description": "Headless Obsidian vault sync for a Basalt server.",
5
5
  "keywords": [
6
6
  "obsidian",
@@ -29,24 +29,28 @@
29
29
  ],
30
30
  "type": "module",
31
31
  "scripts": {
32
+ "bench": "bun run bench.ts",
33
+ "bench:sync": "bun run bench-sync.ts",
32
34
  "build": "node esbuild.config.mjs production",
35
+ "build:cli": "node esbuild.config.mjs production",
33
36
  "dev": "node esbuild.config.mjs",
37
+ "format": "prettier --config ../.prettierrc --write \"src/**/*.ts\" \"*.ts\" \"*.mjs\"",
38
+ "format:check": "prettier --config ../.prettierrc --check \"src/**/*.ts\" \"*.ts\" \"*.mjs\"",
34
39
  "test": "vitest run",
35
40
  "test:watch": "vitest",
36
41
  "typecheck": "tsc --noEmit",
37
- "bench": "bun run bench.ts",
38
- "build:cli": "node esbuild.config.mjs production",
39
- "bench:sync": "bun run bench-sync.ts"
42
+ "stress": "vitest run --config vitest.stress.config.ts"
40
43
  },
41
44
  "devDependencies": {
42
45
  "@types/diff-match-patch": "^1.0.36",
43
46
  "@types/node": "^24.10.13",
44
- "diff-match-patch": "^1.0.5",
47
+ "diff-match-patch": "1.0.5",
45
48
  "esbuild": "^0.28.1",
46
- "fflate": "^0.8.3",
49
+ "fflate": "0.8.3",
47
50
  "obsidian": "^1.13.1",
48
51
  "typescript": "^5.9.3",
49
- "vitest": "^4.1.8"
52
+ "vitest": "^4.1.8",
53
+ "prettier": "^3.6.2"
50
54
  },
51
55
  "bin": {
52
56
  "basalt": "./dist/basalt.mjs"