texlite 0.9.0 → 0.9.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.
Files changed (51) hide show
  1. package/dist/client/assets/{AdminUsers-3CHb5012.js → AdminUsers-Dazar9cj.js} +1 -1
  2. package/dist/client/assets/{CitationLibraryDialog-zPpsUhWJ.js → CitationLibraryDialog-VSUiSPgG.js} +1 -1
  3. package/dist/client/assets/{Dashboard-CWfSLzD3.js → Dashboard-CoE5ESfb.js} +2 -2
  4. package/dist/client/assets/GitDialog-C9Loz4Al.js +3 -0
  5. package/dist/client/assets/HistoryDialog-3UNN_jhU.js +7 -0
  6. package/dist/client/assets/{LatexEditor-CM445Tk0.js → LatexEditor-Bq76v8sO.js} +2 -2
  7. package/dist/client/assets/{PdfPreview-BFVNczSk.js → PdfPreview-BKhcS-2c.js} +1 -1
  8. package/dist/client/assets/{ProjectIconPickerDialog-Cf0zBf8u.js → ProjectIconPickerDialog-BoWMjQVm.js} +1 -1
  9. package/dist/client/assets/{ProjectNavigationDialogs-TPbe11iR.js → ProjectNavigationDialogs-CZKTnxrl.js} +1 -1
  10. package/dist/client/assets/{ProjectSettings-CDQvIlQ4.js → ProjectSettings-DiOQVJ40.js} +1 -1
  11. package/dist/client/assets/ProjectWorkspace-DqLwkGpT.js +27 -0
  12. package/dist/client/assets/SelectionHistoryDialog-D3dO83lg.js +3 -0
  13. package/dist/client/assets/{SystemMetricsDialog-CuqHPUnn.js → SystemMetricsDialog-0zCwLtH_.js} +1 -1
  14. package/dist/client/assets/{TagManagementDialog-gRLM3lLx.js → TagManagementDialog-C6KDwtvd.js} +1 -1
  15. package/dist/client/assets/{WordCountDialog-B4PI0vEk.js → WordCountDialog-TwpyAP3m.js} +1 -1
  16. package/dist/client/assets/check-sZxOOKtS.js +1 -0
  17. package/dist/client/assets/chevron-left-32SrOwa5.js +1 -0
  18. package/dist/client/assets/{hard-drive-6uYFyezl.js → hard-drive-XHSiS_A7.js} +1 -1
  19. package/dist/client/assets/index-BRr3Kuxh.css +1 -0
  20. package/dist/client/assets/{index-C0t11tlT.js → index-BjzELSQ-.js} +3 -5
  21. package/dist/client/assets/{index-BRT5O-Hg.js → index-Cd6-F29b.js} +1 -1
  22. package/dist/client/assets/{key-round-DOAxDSfz.js → key-round-C-CXCWnz.js} +1 -1
  23. package/dist/client/assets/minimize-2-BMDPVaF-.js +1 -0
  24. package/dist/client/assets/{minus-9eVJnugf.js → minus-BIa7-KuM.js} +1 -1
  25. package/dist/client/assets/{plus-BGXipRoG.js → plus-BKDWy4Ui.js} +1 -1
  26. package/dist/client/assets/{refresh-cw-Dvp3O90f.js → refresh-cw-Bo7-a7-I.js} +1 -1
  27. package/dist/client/assets/{search-b1ORp1k8.js → search-Bz9Ob5mT.js} +1 -1
  28. package/dist/client/assets/{sigma-Bk0_MzWi.js → sigma-DxlHf9gv.js} +1 -1
  29. package/dist/client/assets/spellCheck-BfZEnpwY.js +1 -0
  30. package/dist/client/assets/{tags-JAkbmWns.js → tags-IMZehjzE.js} +1 -1
  31. package/dist/client/assets/{type-CE2DYkPH.js → type-DTWpFQNQ.js} +1 -1
  32. package/dist/client/assets/{user-plus-CKalKSsw.js → user-plus--aVpd8K6.js} +1 -1
  33. package/dist/client/assets/{x-Bq29njHL.js → x-Tbo3aA0J.js} +1 -1
  34. package/dist/client/index.html +2 -2
  35. package/dist/server/harper.js +205 -8
  36. package/dist/server/history.js +53 -3
  37. package/dist/server/i18n.js +8 -0
  38. package/dist/server/latexSpellMask.js +197 -43
  39. package/dist/server/routes/comments.js +13 -1
  40. package/dist/server/routes/projectHistory.js +13 -1
  41. package/dist/server/routes/projects.js +36 -4
  42. package/package.json +1 -1
  43. package/dist/client/assets/GitDialog-BUU2U_LV.js +0 -3
  44. package/dist/client/assets/HistoryDialog-B6aopsrw.js +0 -7
  45. package/dist/client/assets/ProjectWorkspace-C6GrvKN6.js +0 -27
  46. package/dist/client/assets/SelectionHistoryDialog-CyE0_YDs.js +0 -3
  47. package/dist/client/assets/check-BXvzrdoz.js +0 -1
  48. package/dist/client/assets/chevron-left-BB5MYb7g.js +0 -1
  49. package/dist/client/assets/index-DXWp2bzM.css +0 -1
  50. package/dist/client/assets/minimize-2-BWtbag2I.js +0 -1
  51. package/dist/client/assets/spellCheck-BJjWgnef.js +0 -1
@@ -1,4 +1,4 @@
1
- import{c as F}from"./index-C0t11tlT.js";import{g as B}from"./react-BVUjbTTn.js";const z=F("Clock3",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16.5 12",key:"1aq6pp"}]]);var R={exports:{}},C;function L(){return C||(C=1,(function(T){var f=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},p=-1,M=1,_=0;f.Diff=function(r,n){return[r,n]},f.prototype.diff_main=function(r,n,e,t){typeof t>"u"&&(this.Diff_Timeout<=0?t=Number.MAX_VALUE:t=new Date().getTime()+this.Diff_Timeout*1e3);var a=t;if(r==null||n==null)throw new Error("Null input. (diff_main)");if(r==n)return r?[new f.Diff(_,r)]:[];typeof e>"u"&&(e=!0);var i=e,s=this.diff_commonPrefix(r,n),h=r.substring(0,s);r=r.substring(s),n=n.substring(s),s=this.diff_commonSuffix(r,n);var l=r.substring(r.length-s);r=r.substring(0,r.length-s),n=n.substring(0,n.length-s);var g=this.diff_compute_(r,n,i,a);return h&&g.unshift(new f.Diff(_,h)),l&&g.push(new f.Diff(_,l)),this.diff_cleanupMerge(g),g},f.prototype.diff_compute_=function(r,n,e,t){var a;if(!r)return[new f.Diff(M,n)];if(!n)return[new f.Diff(p,r)];var i=r.length>n.length?r:n,s=r.length>n.length?n:r,h=i.indexOf(s);if(h!=-1)return a=[new f.Diff(M,i.substring(0,h)),new f.Diff(_,s),new f.Diff(M,i.substring(h+s.length))],r.length>n.length&&(a[0][0]=a[2][0]=p),a;if(s.length==1)return[new f.Diff(p,r),new f.Diff(M,n)];var l=this.diff_halfMatch_(r,n);if(l){var g=l[0],v=l[1],u=l[2],o=l[3],c=l[4],b=this.diff_main(g,u,e,t),w=this.diff_main(v,o,e,t);return b.concat([new f.Diff(_,c)],w)}return e&&r.length>100&&n.length>100?this.diff_lineMode_(r,n,t):this.diff_bisect_(r,n,t)},f.prototype.diff_lineMode_=function(r,n,e){var t=this.diff_linesToChars_(r,n);r=t.chars1,n=t.chars2;var a=t.lineArray,i=this.diff_main(r,n,!1,e);this.diff_charsToLines_(i,a),this.diff_cleanupSemantic(i),i.push(new f.Diff(_,""));for(var s=0,h=0,l=0,g="",v="";s<i.length;){switch(i[s][0]){case M:l++,v+=i[s][1];break;case p:h++,g+=i[s][1];break;case _:if(h>=1&&l>=1){i.splice(s-h-l,h+l),s=s-h-l;for(var u=this.diff_main(g,v,!1,e),o=u.length-1;o>=0;o--)i.splice(s,0,u[o]);s=s+u.length}l=0,h=0,g="",v="";break}s++}return i.pop(),i},f.prototype.diff_bisect_=function(r,n,e){for(var t=r.length,a=n.length,i=Math.ceil((t+a)/2),s=i,h=2*i,l=new Array(h),g=new Array(h),v=0;v<h;v++)l[v]=-1,g[v]=-1;l[s+1]=0,g[s+1]=0;for(var u=t-a,o=u%2!=0,c=0,b=0,w=0,I=0,m=0;m<i&&!(new Date().getTime()>e);m++){for(var D=-m+c;D<=m-b;D+=2){var A=s+D,k;D==-m||D!=m&&l[A-1]<l[A+1]?k=l[A+1]:k=l[A-1]+1;for(var y=k-D;k<t&&y<a&&r.charAt(k)==n.charAt(y);)k++,y++;if(l[A]=k,k>t)b+=2;else if(y>a)c+=2;else if(o){var E=s+u-D;if(E>=0&&E<h&&g[E]!=-1){var P=t-g[E];if(k>=P)return this.diff_bisectSplit_(r,n,k,y,e)}}}for(var d=-m+w;d<=m-I;d+=2){var E=s+d,P;d==-m||d!=m&&g[E-1]<g[E+1]?P=g[E+1]:P=g[E-1]+1;for(var S=P-d;P<t&&S<a&&r.charAt(t-P-1)==n.charAt(a-S-1);)P++,S++;if(g[E]=P,P>t)I+=2;else if(S>a)w+=2;else if(!o){var A=s+u-d;if(A>=0&&A<h&&l[A]!=-1){var k=l[A],y=s+k-A;if(P=t-P,k>=P)return this.diff_bisectSplit_(r,n,k,y,e)}}}}return[new f.Diff(p,r),new f.Diff(M,n)]},f.prototype.diff_bisectSplit_=function(r,n,e,t,a){var i=r.substring(0,e),s=n.substring(0,t),h=r.substring(e),l=n.substring(t),g=this.diff_main(i,s,!1,a),v=this.diff_main(h,l,!1,a);return g.concat(v)},f.prototype.diff_linesToChars_=function(r,n){var e=[],t={};e[0]="";function a(l){for(var g="",v=0,u=-1,o=e.length;u<l.length-1;){u=l.indexOf(`
1
+ import{c as F}from"./index-BjzELSQ-.js";import{g as B}from"./react-BVUjbTTn.js";const z=F("Clock3",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16.5 12",key:"1aq6pp"}]]);var R={exports:{}},C;function L(){return C||(C=1,(function(T){var f=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},p=-1,M=1,_=0;f.Diff=function(r,n){return[r,n]},f.prototype.diff_main=function(r,n,e,t){typeof t>"u"&&(this.Diff_Timeout<=0?t=Number.MAX_VALUE:t=new Date().getTime()+this.Diff_Timeout*1e3);var a=t;if(r==null||n==null)throw new Error("Null input. (diff_main)");if(r==n)return r?[new f.Diff(_,r)]:[];typeof e>"u"&&(e=!0);var i=e,s=this.diff_commonPrefix(r,n),h=r.substring(0,s);r=r.substring(s),n=n.substring(s),s=this.diff_commonSuffix(r,n);var l=r.substring(r.length-s);r=r.substring(0,r.length-s),n=n.substring(0,n.length-s);var g=this.diff_compute_(r,n,i,a);return h&&g.unshift(new f.Diff(_,h)),l&&g.push(new f.Diff(_,l)),this.diff_cleanupMerge(g),g},f.prototype.diff_compute_=function(r,n,e,t){var a;if(!r)return[new f.Diff(M,n)];if(!n)return[new f.Diff(p,r)];var i=r.length>n.length?r:n,s=r.length>n.length?n:r,h=i.indexOf(s);if(h!=-1)return a=[new f.Diff(M,i.substring(0,h)),new f.Diff(_,s),new f.Diff(M,i.substring(h+s.length))],r.length>n.length&&(a[0][0]=a[2][0]=p),a;if(s.length==1)return[new f.Diff(p,r),new f.Diff(M,n)];var l=this.diff_halfMatch_(r,n);if(l){var g=l[0],v=l[1],u=l[2],o=l[3],c=l[4],b=this.diff_main(g,u,e,t),w=this.diff_main(v,o,e,t);return b.concat([new f.Diff(_,c)],w)}return e&&r.length>100&&n.length>100?this.diff_lineMode_(r,n,t):this.diff_bisect_(r,n,t)},f.prototype.diff_lineMode_=function(r,n,e){var t=this.diff_linesToChars_(r,n);r=t.chars1,n=t.chars2;var a=t.lineArray,i=this.diff_main(r,n,!1,e);this.diff_charsToLines_(i,a),this.diff_cleanupSemantic(i),i.push(new f.Diff(_,""));for(var s=0,h=0,l=0,g="",v="";s<i.length;){switch(i[s][0]){case M:l++,v+=i[s][1];break;case p:h++,g+=i[s][1];break;case _:if(h>=1&&l>=1){i.splice(s-h-l,h+l),s=s-h-l;for(var u=this.diff_main(g,v,!1,e),o=u.length-1;o>=0;o--)i.splice(s,0,u[o]);s=s+u.length}l=0,h=0,g="",v="";break}s++}return i.pop(),i},f.prototype.diff_bisect_=function(r,n,e){for(var t=r.length,a=n.length,i=Math.ceil((t+a)/2),s=i,h=2*i,l=new Array(h),g=new Array(h),v=0;v<h;v++)l[v]=-1,g[v]=-1;l[s+1]=0,g[s+1]=0;for(var u=t-a,o=u%2!=0,c=0,b=0,w=0,I=0,m=0;m<i&&!(new Date().getTime()>e);m++){for(var D=-m+c;D<=m-b;D+=2){var A=s+D,k;D==-m||D!=m&&l[A-1]<l[A+1]?k=l[A+1]:k=l[A-1]+1;for(var y=k-D;k<t&&y<a&&r.charAt(k)==n.charAt(y);)k++,y++;if(l[A]=k,k>t)b+=2;else if(y>a)c+=2;else if(o){var E=s+u-D;if(E>=0&&E<h&&g[E]!=-1){var P=t-g[E];if(k>=P)return this.diff_bisectSplit_(r,n,k,y,e)}}}for(var d=-m+w;d<=m-I;d+=2){var E=s+d,P;d==-m||d!=m&&g[E-1]<g[E+1]?P=g[E+1]:P=g[E-1]+1;for(var S=P-d;P<t&&S<a&&r.charAt(t-P-1)==n.charAt(a-S-1);)P++,S++;if(g[E]=P,P>t)I+=2;else if(S>a)w+=2;else if(!o){var A=s+u-d;if(A>=0&&A<h&&l[A]!=-1){var k=l[A],y=s+k-A;if(P=t-P,k>=P)return this.diff_bisectSplit_(r,n,k,y,e)}}}}return[new f.Diff(p,r),new f.Diff(M,n)]},f.prototype.diff_bisectSplit_=function(r,n,e,t,a){var i=r.substring(0,e),s=n.substring(0,t),h=r.substring(e),l=n.substring(t),g=this.diff_main(i,s,!1,a),v=this.diff_main(h,l,!1,a);return g.concat(v)},f.prototype.diff_linesToChars_=function(r,n){var e=[],t={};e[0]="";function a(l){for(var g="",v=0,u=-1,o=e.length;u<l.length-1;){u=l.indexOf(`
2
2
  `,v),u==-1&&(u=l.length-1);var c=l.substring(v,u+1);(t.hasOwnProperty?t.hasOwnProperty(c):t[c]!==void 0)?g+=String.fromCharCode(t[c]):(o==i&&(c=l.substring(v),u=l.length),g+=String.fromCharCode(o),t[c]=o,e[o++]=c),v=u+1}return g}var i=4e4,s=a(r);i=65535;var h=a(n);return{chars1:s,chars2:h,lineArray:e}},f.prototype.diff_charsToLines_=function(r,n){for(var e=0;e<r.length;e++){for(var t=r[e][1],a=[],i=0;i<t.length;i++)a[i]=n[t.charCodeAt(i)];r[e][1]=a.join("")}},f.prototype.diff_commonPrefix=function(r,n){if(!r||!n||r.charAt(0)!=n.charAt(0))return 0;for(var e=0,t=Math.min(r.length,n.length),a=t,i=0;e<a;)r.substring(i,a)==n.substring(i,a)?(e=a,i=e):t=a,a=Math.floor((t-e)/2+e);return a},f.prototype.diff_commonSuffix=function(r,n){if(!r||!n||r.charAt(r.length-1)!=n.charAt(n.length-1))return 0;for(var e=0,t=Math.min(r.length,n.length),a=t,i=0;e<a;)r.substring(r.length-a,r.length-i)==n.substring(n.length-a,n.length-i)?(e=a,i=e):t=a,a=Math.floor((t-e)/2+e);return a},f.prototype.diff_commonOverlap_=function(r,n){var e=r.length,t=n.length;if(e==0||t==0)return 0;e>t?r=r.substring(e-t):e<t&&(n=n.substring(0,e));var a=Math.min(e,t);if(r==n)return a;for(var i=0,s=1;;){var h=r.substring(a-s),l=n.indexOf(h);if(l==-1)return i;s+=l,(l==0||r.substring(a-s)==n.substring(0,s))&&(i=s,s++)}},f.prototype.diff_halfMatch_=function(r,n){if(this.Diff_Timeout<=0)return null;var e=r.length>n.length?r:n,t=r.length>n.length?n:r;if(e.length<4||t.length*2<e.length)return null;var a=this;function i(b,w,I){for(var m=b.substring(I,I+Math.floor(b.length/4)),D=-1,A="",k,y,E,P;(D=w.indexOf(m,D+1))!=-1;){var d=a.diff_commonPrefix(b.substring(I),w.substring(D)),S=a.diff_commonSuffix(b.substring(0,I),w.substring(0,D));A.length<S+d&&(A=w.substring(D-S,D)+w.substring(D,D+d),k=b.substring(0,I-S),y=b.substring(I+d),E=w.substring(0,D-S),P=w.substring(D+d))}return A.length*2>=b.length?[k,y,E,P,A]:null}var s=i(e,t,Math.ceil(e.length/4)),h=i(e,t,Math.ceil(e.length/2)),l;if(!s&&!h)return null;h?s?l=s[4].length>h[4].length?s:h:l=h:l=s;var g,v,u,o;r.length>n.length?(g=l[0],v=l[1],u=l[2],o=l[3]):(u=l[0],o=l[1],g=l[2],v=l[3]);var c=l[4];return[g,v,u,o,c]},f.prototype.diff_cleanupSemantic=function(r){for(var n=!1,e=[],t=0,a=null,i=0,s=0,h=0,l=0,g=0;i<r.length;)r[i][0]==_?(e[t++]=i,s=l,h=g,l=0,g=0,a=r[i][1]):(r[i][0]==M?l+=r[i][1].length:g+=r[i][1].length,a&&a.length<=Math.max(s,h)&&a.length<=Math.max(l,g)&&(r.splice(e[t-1],0,new f.Diff(p,a)),r[e[t-1]+1][0]=M,t--,t--,i=t>0?e[t-1]:-1,s=0,h=0,l=0,g=0,a=null,n=!0)),i++;for(n&&this.diff_cleanupMerge(r),this.diff_cleanupSemanticLossless(r),i=1;i<r.length;){if(r[i-1][0]==p&&r[i][0]==M){var v=r[i-1][1],u=r[i][1],o=this.diff_commonOverlap_(v,u),c=this.diff_commonOverlap_(u,v);o>=c?(o>=v.length/2||o>=u.length/2)&&(r.splice(i,0,new f.Diff(_,u.substring(0,o))),r[i-1][1]=v.substring(0,v.length-o),r[i+1][1]=u.substring(o),i++):(c>=v.length/2||c>=u.length/2)&&(r.splice(i,0,new f.Diff(_,v.substring(0,c))),r[i-1][0]=M,r[i-1][1]=u.substring(0,u.length-c),r[i+1][0]=p,r[i+1][1]=v.substring(c),i++),i++}i++}},f.prototype.diff_cleanupSemanticLossless=function(r){function n(c,b){if(!c||!b)return 6;var w=c.charAt(c.length-1),I=b.charAt(0),m=w.match(f.nonAlphaNumericRegex_),D=I.match(f.nonAlphaNumericRegex_),A=m&&w.match(f.whitespaceRegex_),k=D&&I.match(f.whitespaceRegex_),y=A&&w.match(f.linebreakRegex_),E=k&&I.match(f.linebreakRegex_),P=y&&c.match(f.blanklineEndRegex_),d=E&&b.match(f.blanklineStartRegex_);return P||d?5:y||E?4:m&&!A&&k?3:A||k?2:m||D?1:0}for(var e=1;e<r.length-1;){if(r[e-1][0]==_&&r[e+1][0]==_){var t=r[e-1][1],a=r[e][1],i=r[e+1][1],s=this.diff_commonSuffix(t,a);if(s){var h=a.substring(a.length-s);t=t.substring(0,t.length-s),a=h+a.substring(0,a.length-s),i=h+i}for(var l=t,g=a,v=i,u=n(t,a)+n(a,i);a.charAt(0)===i.charAt(0);){t+=a.charAt(0),a=a.substring(1)+i.charAt(0),i=i.substring(1);var o=n(t,a)+n(a,i);o>=u&&(u=o,l=t,g=a,v=i)}r[e-1][1]!=l&&(l?r[e-1][1]=l:(r.splice(e-1,1),e--),r[e][1]=g,v?r[e+1][1]=v:(r.splice(e+1,1),e--))}e++}},f.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/,f.whitespaceRegex_=/\s/,f.linebreakRegex_=/[\r\n]/,f.blanklineEndRegex_=/\n\r?\n$/,f.blanklineStartRegex_=/^\r?\n\r?\n/,f.prototype.diff_cleanupEfficiency=function(r){for(var n=!1,e=[],t=0,a=null,i=0,s=!1,h=!1,l=!1,g=!1;i<r.length;)r[i][0]==_?(r[i][1].length<this.Diff_EditCost&&(l||g)?(e[t++]=i,s=l,h=g,a=r[i][1]):(t=0,a=null),l=g=!1):(r[i][0]==p?g=!0:l=!0,a&&(s&&h&&l&&g||a.length<this.Diff_EditCost/2&&s+h+l+g==3)&&(r.splice(e[t-1],0,new f.Diff(p,a)),r[e[t-1]+1][0]=M,t--,a=null,s&&h?(l=g=!0,t=0):(t--,i=t>0?e[t-1]:-1,l=g=!1),n=!0)),i++;n&&this.diff_cleanupMerge(r)},f.prototype.diff_cleanupMerge=function(r){r.push(new f.Diff(_,""));for(var n=0,e=0,t=0,a="",i="",s;n<r.length;)switch(r[n][0]){case M:t++,i+=r[n][1],n++;break;case p:e++,a+=r[n][1],n++;break;case _:e+t>1?(e!==0&&t!==0&&(s=this.diff_commonPrefix(i,a),s!==0&&(n-e-t>0&&r[n-e-t-1][0]==_?r[n-e-t-1][1]+=i.substring(0,s):(r.splice(0,0,new f.Diff(_,i.substring(0,s))),n++),i=i.substring(s),a=a.substring(s)),s=this.diff_commonSuffix(i,a),s!==0&&(r[n][1]=i.substring(i.length-s)+r[n][1],i=i.substring(0,i.length-s),a=a.substring(0,a.length-s))),n-=e+t,r.splice(n,e+t),a.length&&(r.splice(n,0,new f.Diff(p,a)),n++),i.length&&(r.splice(n,0,new f.Diff(M,i)),n++),n++):n!==0&&r[n-1][0]==_?(r[n-1][1]+=r[n][1],r.splice(n,1)):n++,t=0,e=0,a="",i="";break}r[r.length-1][1]===""&&r.pop();var h=!1;for(n=1;n<r.length-1;)r[n-1][0]==_&&r[n+1][0]==_&&(r[n][1].substring(r[n][1].length-r[n-1][1].length)==r[n-1][1]?(r[n][1]=r[n-1][1]+r[n][1].substring(0,r[n][1].length-r[n-1][1].length),r[n+1][1]=r[n-1][1]+r[n+1][1],r.splice(n-1,1),h=!0):r[n][1].substring(0,r[n+1][1].length)==r[n+1][1]&&(r[n-1][1]+=r[n+1][1],r[n][1]=r[n][1].substring(r[n+1][1].length)+r[n+1][1],r.splice(n+1,1),h=!0)),n++;h&&this.diff_cleanupMerge(r)},f.prototype.diff_xIndex=function(r,n){var e=0,t=0,a=0,i=0,s;for(s=0;s<r.length&&(r[s][0]!==M&&(e+=r[s][1].length),r[s][0]!==p&&(t+=r[s][1].length),!(e>n));s++)a=e,i=t;return r.length!=s&&r[s][0]===p?i:i+(n-a)},f.prototype.diff_prettyHtml=function(r){for(var n=[],e=/&/g,t=/</g,a=/>/g,i=/\n/g,s=0;s<r.length;s++){var h=r[s][0],l=r[s][1],g=l.replace(e,"&amp;").replace(t,"&lt;").replace(a,"&gt;").replace(i,"&para;<br>");switch(h){case M:n[s]='<ins style="background:#e6ffe6;">'+g+"</ins>";break;case p:n[s]='<del style="background:#ffe6e6;">'+g+"</del>";break;case _:n[s]="<span>"+g+"</span>";break}}return n.join("")},f.prototype.diff_text1=function(r){for(var n=[],e=0;e<r.length;e++)r[e][0]!==M&&(n[e]=r[e][1]);return n.join("")},f.prototype.diff_text2=function(r){for(var n=[],e=0;e<r.length;e++)r[e][0]!==p&&(n[e]=r[e][1]);return n.join("")},f.prototype.diff_levenshtein=function(r){for(var n=0,e=0,t=0,a=0;a<r.length;a++){var i=r[a][0],s=r[a][1];switch(i){case M:e+=s.length;break;case p:t+=s.length;break;case _:n+=Math.max(e,t),e=0,t=0;break}}return n+=Math.max(e,t),n},f.prototype.diff_toDelta=function(r){for(var n=[],e=0;e<r.length;e++)switch(r[e][0]){case M:n[e]="+"+encodeURI(r[e][1]);break;case p:n[e]="-"+r[e][1].length;break;case _:n[e]="="+r[e][1].length;break}return n.join(" ").replace(/%20/g," ")},f.prototype.diff_fromDelta=function(r,n){for(var e=[],t=0,a=0,i=n.split(/\t/g),s=0;s<i.length;s++){var h=i[s].substring(1);switch(i[s].charAt(0)){case"+":try{e[t++]=new f.Diff(M,decodeURI(h))}catch{throw new Error("Illegal escape in diff_fromDelta: "+h)}break;case"-":case"=":var l=parseInt(h,10);if(isNaN(l)||l<0)throw new Error("Invalid number in diff_fromDelta: "+h);var g=r.substring(a,a+=l);i[s].charAt(0)=="="?e[t++]=new f.Diff(_,g):e[t++]=new f.Diff(p,g);break;default:if(i[s])throw new Error("Invalid diff operation in diff_fromDelta: "+i[s])}}if(a!=r.length)throw new Error("Delta length ("+a+") does not equal source text length ("+r.length+").");return e},f.prototype.match_main=function(r,n,e){if(r==null||n==null||e==null)throw new Error("Null input. (match_main)");return e=Math.max(0,Math.min(e,r.length)),r==n?0:r.length?r.substring(e,e+n.length)==n?e:this.match_bitap_(r,n,e):-1},f.prototype.match_bitap_=function(r,n,e){if(n.length>this.Match_MaxBits)throw new Error("Pattern too long for this browser.");var t=this.match_alphabet_(n),a=this;function i(k,y){var E=k/n.length,P=Math.abs(e-y);return a.Match_Distance?E+P/a.Match_Distance:P?1:E}var s=this.Match_Threshold,h=r.indexOf(n,e);h!=-1&&(s=Math.min(i(0,h),s),h=r.lastIndexOf(n,e+n.length),h!=-1&&(s=Math.min(i(0,h),s)));var l=1<<n.length-1;h=-1;for(var g,v,u=n.length+r.length,o,c=0;c<n.length;c++){for(g=0,v=u;g<v;)i(c,e+v)<=s?g=v:u=v,v=Math.floor((u-g)/2+g);u=v;var b=Math.max(1,e-v+1),w=Math.min(e+v,r.length)+n.length,I=Array(w+2);I[w+1]=(1<<c)-1;for(var m=w;m>=b;m--){var D=t[r.charAt(m-1)];if(c===0?I[m]=(I[m+1]<<1|1)&D:I[m]=(I[m+1]<<1|1)&D|((o[m+1]|o[m])<<1|1)|o[m+1],I[m]&l){var A=i(c,m-1);if(A<=s)if(s=A,h=m-1,h>e)b=Math.max(1,2*e-h);else break}}if(i(c+1,e)>s)break;o=I}return h},f.prototype.match_alphabet_=function(r){for(var n={},e=0;e<r.length;e++)n[r.charAt(e)]=0;for(var e=0;e<r.length;e++)n[r.charAt(e)]|=1<<r.length-e-1;return n},f.prototype.patch_addContext_=function(r,n){if(n.length!=0){if(r.start2===null)throw Error("patch not initialized");for(var e=n.substring(r.start2,r.start2+r.length1),t=0;n.indexOf(e)!=n.lastIndexOf(e)&&e.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)t+=this.Patch_Margin,e=n.substring(r.start2-t,r.start2+r.length1+t);t+=this.Patch_Margin;var a=n.substring(r.start2-t,r.start2);a&&r.diffs.unshift(new f.Diff(_,a));var i=n.substring(r.start2+r.length1,r.start2+r.length1+t);i&&r.diffs.push(new f.Diff(_,i)),r.start1-=a.length,r.start2-=a.length,r.length1+=a.length+i.length,r.length2+=a.length+i.length}},f.prototype.patch_make=function(r,n,e){var t,a;if(typeof r=="string"&&typeof n=="string"&&typeof e>"u")t=r,a=this.diff_main(t,n,!0),a.length>2&&(this.diff_cleanupSemantic(a),this.diff_cleanupEfficiency(a));else if(r&&typeof r=="object"&&typeof n>"u"&&typeof e>"u")a=r,t=this.diff_text1(a);else if(typeof r=="string"&&n&&typeof n=="object"&&typeof e>"u")t=r,a=n;else if(typeof r=="string"&&typeof n=="string"&&e&&typeof e=="object")t=r,a=e;else throw new Error("Unknown call format to patch_make.");if(a.length===0)return[];for(var i=[],s=new f.patch_obj,h=0,l=0,g=0,v=t,u=t,o=0;o<a.length;o++){var c=a[o][0],b=a[o][1];switch(!h&&c!==_&&(s.start1=l,s.start2=g),c){case M:s.diffs[h++]=a[o],s.length2+=b.length,u=u.substring(0,g)+b+u.substring(g);break;case p:s.length1+=b.length,s.diffs[h++]=a[o],u=u.substring(0,g)+u.substring(g+b.length);break;case _:b.length<=2*this.Patch_Margin&&h&&a.length!=o+1?(s.diffs[h++]=a[o],s.length1+=b.length,s.length2+=b.length):b.length>=2*this.Patch_Margin&&h&&(this.patch_addContext_(s,v),i.push(s),s=new f.patch_obj,h=0,v=u,l=g);break}c!==M&&(l+=b.length),c!==p&&(g+=b.length)}return h&&(this.patch_addContext_(s,v),i.push(s)),i},f.prototype.patch_deepCopy=function(r){for(var n=[],e=0;e<r.length;e++){var t=r[e],a=new f.patch_obj;a.diffs=[];for(var i=0;i<t.diffs.length;i++)a.diffs[i]=new f.Diff(t.diffs[i][0],t.diffs[i][1]);a.start1=t.start1,a.start2=t.start2,a.length1=t.length1,a.length2=t.length2,n[e]=a}return n},f.prototype.patch_apply=function(r,n){if(r.length==0)return[n,[]];r=this.patch_deepCopy(r);var e=this.patch_addPadding(r);n=e+n+e,this.patch_splitMax(r);for(var t=0,a=[],i=0;i<r.length;i++){var s=r[i].start2+t,h=this.diff_text1(r[i].diffs),l,g=-1;if(h.length>this.Match_MaxBits?(l=this.match_main(n,h.substring(0,this.Match_MaxBits),s),l!=-1&&(g=this.match_main(n,h.substring(h.length-this.Match_MaxBits),s+h.length-this.Match_MaxBits),(g==-1||l>=g)&&(l=-1))):l=this.match_main(n,h,s),l==-1)a[i]=!1,t-=r[i].length2-r[i].length1;else{a[i]=!0,t=l-s;var v;if(g==-1?v=n.substring(l,l+h.length):v=n.substring(l,g+this.Match_MaxBits),h==v)n=n.substring(0,l)+this.diff_text2(r[i].diffs)+n.substring(l+h.length);else{var u=this.diff_main(h,v,!1);if(h.length>this.Match_MaxBits&&this.diff_levenshtein(u)/h.length>this.Patch_DeleteThreshold)a[i]=!1;else{this.diff_cleanupSemanticLossless(u);for(var o=0,c,b=0;b<r[i].diffs.length;b++){var w=r[i].diffs[b];w[0]!==_&&(c=this.diff_xIndex(u,o)),w[0]===M?n=n.substring(0,l+c)+w[1]+n.substring(l+c):w[0]===p&&(n=n.substring(0,l+c)+n.substring(l+this.diff_xIndex(u,o+w[1].length))),w[0]!==p&&(o+=w[1].length)}}}}}return n=n.substring(e.length,n.length-e.length),[n,a]},f.prototype.patch_addPadding=function(r){for(var n=this.Patch_Margin,e="",t=1;t<=n;t++)e+=String.fromCharCode(t);for(var t=0;t<r.length;t++)r[t].start1+=n,r[t].start2+=n;var a=r[0],i=a.diffs;if(i.length==0||i[0][0]!=_)i.unshift(new f.Diff(_,e)),a.start1-=n,a.start2-=n,a.length1+=n,a.length2+=n;else if(n>i[0][1].length){var s=n-i[0][1].length;i[0][1]=e.substring(i[0][1].length)+i[0][1],a.start1-=s,a.start2-=s,a.length1+=s,a.length2+=s}if(a=r[r.length-1],i=a.diffs,i.length==0||i[i.length-1][0]!=_)i.push(new f.Diff(_,e)),a.length1+=n,a.length2+=n;else if(n>i[i.length-1][1].length){var s=n-i[i.length-1][1].length;i[i.length-1][1]+=e.substring(0,s),a.length1+=s,a.length2+=s}return e},f.prototype.patch_splitMax=function(r){for(var n=this.Match_MaxBits,e=0;e<r.length;e++)if(!(r[e].length1<=n)){var t=r[e];r.splice(e--,1);for(var a=t.start1,i=t.start2,s="";t.diffs.length!==0;){var h=new f.patch_obj,l=!0;for(h.start1=a-s.length,h.start2=i-s.length,s!==""&&(h.length1=h.length2=s.length,h.diffs.push(new f.Diff(_,s)));t.diffs.length!==0&&h.length1<n-this.Patch_Margin;){var g=t.diffs[0][0],v=t.diffs[0][1];g===M?(h.length2+=v.length,i+=v.length,h.diffs.push(t.diffs.shift()),l=!1):g===p&&h.diffs.length==1&&h.diffs[0][0]==_&&v.length>2*n?(h.length1+=v.length,a+=v.length,l=!1,h.diffs.push(new f.Diff(g,v)),t.diffs.shift()):(v=v.substring(0,n-h.length1-this.Patch_Margin),h.length1+=v.length,a+=v.length,g===_?(h.length2+=v.length,i+=v.length):l=!1,h.diffs.push(new f.Diff(g,v)),v==t.diffs[0][1]?t.diffs.shift():t.diffs[0][1]=t.diffs[0][1].substring(v.length))}s=this.diff_text2(h.diffs),s=s.substring(s.length-this.Patch_Margin);var u=this.diff_text1(t.diffs).substring(0,this.Patch_Margin);u!==""&&(h.length1+=u.length,h.length2+=u.length,h.diffs.length!==0&&h.diffs[h.diffs.length-1][0]===_?h.diffs[h.diffs.length-1][1]+=u:h.diffs.push(new f.Diff(_,u))),l||r.splice(++e,0,h)}}},f.prototype.patch_toText=function(r){for(var n=[],e=0;e<r.length;e++)n[e]=r[e];return n.join("")},f.prototype.patch_fromText=function(r){var n=[];if(!r)return n;for(var e=r.split(`
3
3
  `),t=0,a=/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;t<e.length;){var i=e[t].match(a);if(!i)throw new Error("Invalid patch string: "+e[t]);var s=new f.patch_obj;for(n.push(s),s.start1=parseInt(i[1],10),i[2]===""?(s.start1--,s.length1=1):i[2]=="0"?s.length1=0:(s.start1--,s.length1=parseInt(i[2],10)),s.start2=parseInt(i[3],10),i[4]===""?(s.start2--,s.length2=1):i[4]=="0"?s.length2=0:(s.start2--,s.length2=parseInt(i[4],10)),t++;t<e.length;){var h=e[t].charAt(0);try{var l=decodeURI(e[t].substring(1))}catch{throw new Error("Illegal escape in patch_fromText: "+l)}if(h=="-")s.diffs.push(new f.Diff(p,l));else if(h=="+")s.diffs.push(new f.Diff(M,l));else if(h==" ")s.diffs.push(new f.Diff(_,l));else{if(h=="@")break;if(h!=="")throw new Error('Invalid patch mode "'+h+'" in: '+l)}t++}}return n},f.patch_obj=function(){this.diffs=[],this.start1=null,this.start2=null,this.length1=0,this.length2=0},f.patch_obj.prototype.toString=function(){var r,n;this.length1===0?r=this.start1+",0":this.length1==1?r=this.start1+1:r=this.start1+1+","+this.length1,this.length2===0?n=this.start2+",0":this.length2==1?n=this.start2+1:n=this.start2+1+","+this.length2;for(var e=["@@ -"+r+" +"+n+` @@
4
4
  `],t,a=0;a<this.diffs.length;a++){switch(this.diffs[a][0]){case M:t="+";break;case p:t="-";break;case _:t=" ";break}e[a+1]=t+encodeURI(this.diffs[a][1])+`
@@ -1 +1 @@
1
- import{c as a}from"./index-C0t11tlT.js";const c=a("KeyRound",[["path",{d:"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",key:"1s6t7t"}],["circle",{cx:"16.5",cy:"7.5",r:".5",fill:"currentColor",key:"w0ekpg"}]]);export{c as K};
1
+ import{c as a}from"./index-BjzELSQ-.js";const c=a("KeyRound",[["path",{d:"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",key:"1s6t7t"}],["circle",{cx:"16.5",cy:"7.5",r:".5",fill:"currentColor",key:"w0ekpg"}]]);export{c as K};
@@ -0,0 +1 @@
1
+ import{c as e}from"./index-BjzELSQ-.js";const n=e("Minimize2",[["polyline",{points:"4 14 10 14 10 20",key:"11kfnr"}],["polyline",{points:"20 10 14 10 14 4",key:"rlmsce"}],["line",{x1:"14",x2:"21",y1:"10",y2:"3",key:"o5lafz"}],["line",{x1:"3",x2:"10",y1:"21",y2:"14",key:"1atl0r"}]]);export{n as M};
@@ -1 +1 @@
1
- import{c as e}from"./index-C0t11tlT.js";const n=e("Maximize2",[["polyline",{points:"15 3 21 3 21 9",key:"mznyad"}],["polyline",{points:"9 21 3 21 3 15",key:"1avn1i"}],["line",{x1:"21",x2:"14",y1:"3",y2:"10",key:"ota7mn"}],["line",{x1:"3",x2:"10",y1:"21",y2:"14",key:"1atl0r"}]]);const a=e("Minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]);export{a as M,n as a};
1
+ import{c as e}from"./index-BjzELSQ-.js";const n=e("Maximize2",[["polyline",{points:"15 3 21 3 21 9",key:"mznyad"}],["polyline",{points:"9 21 3 21 3 15",key:"1avn1i"}],["line",{x1:"21",x2:"14",y1:"3",y2:"10",key:"ota7mn"}],["line",{x1:"3",x2:"10",y1:"21",y2:"14",key:"1atl0r"}]]);const a=e("Minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]);export{a as M,n as a};
@@ -1 +1 @@
1
- import{c as e}from"./index-C0t11tlT.js";const a=e("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);export{a as P};
1
+ import{c as e}from"./index-BjzELSQ-.js";const a=e("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);export{a as P};
@@ -1 +1 @@
1
- import{c as e}from"./index-C0t11tlT.js";const t=e("RefreshCw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);export{t as R};
1
+ import{c as e}from"./index-BjzELSQ-.js";const t=e("RefreshCw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);export{t as R};
@@ -1 +1 @@
1
- import{c}from"./index-C0t11tlT.js";const r=c("Search",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]]);export{r as S};
1
+ import{c}from"./index-BjzELSQ-.js";const r=c("Search",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]]);export{r as S};
@@ -1 +1 @@
1
- import{c as a}from"./index-C0t11tlT.js";const e=a("Sigma",[["path",{d:"M18 7V5a1 1 0 0 0-1-1H6.5a.5.5 0 0 0-.4.8l4.5 6a2 2 0 0 1 0 2.4l-4.5 6a.5.5 0 0 0 .4.8H17a1 1 0 0 0 1-1v-2",key:"wuwx1p"}]]);export{e as S};
1
+ import{c as a}from"./index-BjzELSQ-.js";const e=a("Sigma",[["path",{d:"M18 7V5a1 1 0 0 0-1-1H6.5a.5.5 0 0 0-.4.8l4.5 6a2 2 0 0 1 0 2.4l-4.5 6a.5.5 0 0 0 .4.8H17a1 1 0 0 0 1-1v-2",key:"wuwx1p"}]]);export{e as S};
@@ -0,0 +1 @@
1
+ import{f as w,A as L}from"./index-BjzELSQ-.js";import{c as y}from"./ProjectWorkspace-DqLwkGpT.js";import"./react-BVUjbTTn.js";import"./check-sZxOOKtS.js";import"./x-Tbo3aA0J.js";import"./search-Bz9Ob5mT.js";import"./user-plus--aVpd8K6.js";import"./refresh-cw-Bo7-a7-I.js";const S=5,f=new Map,k=12,C=y();let x=0;class p extends Error{constructor(){super("A newer writing check replaced this request."),this.name="HarperLintSupersededError"}}function D(e){return e instanceof p}function E(e){const t=[0];let n=0;for(const r of e)n+=r.length,t.push(n);return t}function d(e){return[...new Set(e.map(t=>t.trim()).filter(Boolean))].sort((t,n)=>t.localeCompare(n)).join("\0")}async function $(e,t,n,r){try{return(await w(`/api/projects/${e}/spellcheck`,{method:"POST",body:JSON.stringify({path:t,source:n,clientId:C,sequence:r})})).lints}catch(o){throw o instanceof L&&o.code==="SPELLCHECK_SUPERSEDED"?new p:o}}function v(e,t,n){if(!t.problem)return null;const r={from:t.start,to:t.end},o={from:n[t.start]??-1,to:n[t.end]??-1},i=c=>c.from>=0&&c.to>c.from&&c.to<=e.length,a=c=>i(c)&&e.slice(c.from,c.to)===t.problem;return a(o)?o:a(r)?r:null}function A(e,t,n){const r=v(e,t,n);if(!r)return null;const{from:o,to:i}=r,a=e.slice(o,i);if(!a.trim()||!/[A-Za-z]/.test(a)||t.kind==="Formatting")return null;const c=t.kind==="Spelling"||t.kind==="Typo"?"spelling":"grammar",u=t.suggestions.filter((m,s,l)=>s<S&&l.indexOf(m)===s);return{from:o,to:i,word:a,kind:c,message:t.message,suggestions:u}}function h(e,t){let n=2166136261;for(let r=0;r<t.length;r+=1)n^=t.charCodeAt(r),n=Math.imul(n,16777619);return`${e}\0${t.length}:${n>>>0}`}function g(e,t,n){const r=h(e,t),o=f.get(r);return!o||o.path!==e||o.source!==t||o.dictionary!==n?null:(f.delete(r),f.set(r,o),o.issues)}function H(e,t,n,r){const o=h(e,t);for(f.set(o,{path:e,source:t,dictionary:n,issues:r});f.size>k;){const i=f.keys().next().value;if(i===void 0)break;f.delete(i)}}async function R(e,t,n,r="main.tex"){const o=d(t),i=g(r,e,o);if(i)return i;const a=E(e),c=new Set(t.map(s=>s.trim().toLocaleLowerCase("en-US")).filter(Boolean)),u=new Set,m=n.map(s=>A(e,s,a)).filter(s=>!!s).filter(s=>s.kind!=="spelling"||!c.has(s.word.trim().toLocaleLowerCase("en-US"))).filter(s=>{const l=`${s.from}:${s.to}:${s.kind}`;return u.has(l)?!1:(u.add(l),!0)}).sort((s,l)=>s.from-l.from||s.to-l.to);return H(r,e,o,m),m}async function b(e,t,n,r){const o=d(r),i=g(t,n,o);if(i)return i;const a=await $(e,t,n,++x);return R(n,r,a,t)}function I(e,t,n,r=[]){return b(e,t,n,r)}export{p as HarperLintSupersededError,D as isHarperLintSupersededError,I as lintLatex,R as mapLatexLints};
@@ -1 +1 @@
1
- import{c as a}from"./index-C0t11tlT.js";const e=a("Tags",[["path",{d:"m15 5 6.3 6.3a2.4 2.4 0 0 1 0 3.4L17 19",key:"1cbfv1"}],["path",{d:"M9.586 5.586A2 2 0 0 0 8.172 5H3a1 1 0 0 0-1 1v5.172a2 2 0 0 0 .586 1.414L8.29 18.29a2.426 2.426 0 0 0 3.42 0l3.58-3.58a2.426 2.426 0 0 0 0-3.42z",key:"135mg7"}],["circle",{cx:"6.5",cy:"9.5",r:".5",fill:"currentColor",key:"5pm5xn"}]]);export{e as T};
1
+ import{c as a}from"./index-BjzELSQ-.js";const e=a("Tags",[["path",{d:"m15 5 6.3 6.3a2.4 2.4 0 0 1 0 3.4L17 19",key:"1cbfv1"}],["path",{d:"M9.586 5.586A2 2 0 0 0 8.172 5H3a1 1 0 0 0-1 1v5.172a2 2 0 0 0 .586 1.414L8.29 18.29a2.426 2.426 0 0 0 3.42 0l3.58-3.58a2.426 2.426 0 0 0 0-3.42z",key:"135mg7"}],["circle",{cx:"6.5",cy:"9.5",r:".5",fill:"currentColor",key:"5pm5xn"}]]);export{e as T};
@@ -1 +1 @@
1
- import{c as e}from"./index-C0t11tlT.js";const n=e("Type",[["polyline",{points:"4 7 4 4 20 4 20 7",key:"1nosan"}],["line",{x1:"9",x2:"15",y1:"20",y2:"20",key:"swin9y"}],["line",{x1:"12",x2:"12",y1:"4",y2:"20",key:"1tx1rr"}]]);export{n as T};
1
+ import{c as e}from"./index-BjzELSQ-.js";const n=e("Type",[["polyline",{points:"4 7 4 4 20 4 20 7",key:"1nosan"}],["line",{x1:"9",x2:"15",y1:"20",y2:"20",key:"swin9y"}],["line",{x1:"12",x2:"12",y1:"4",y2:"20",key:"1tx1rr"}]]);export{n as T};
@@ -1 +1 @@
1
- import{c as e}from"./index-C0t11tlT.js";const c=e("UserPlus",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["line",{x1:"19",x2:"19",y1:"8",y2:"14",key:"1bvyxn"}],["line",{x1:"22",x2:"16",y1:"11",y2:"11",key:"1shjgl"}]]);export{c as U};
1
+ import{c as e}from"./index-BjzELSQ-.js";const c=e("UserPlus",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["line",{x1:"19",x2:"19",y1:"8",y2:"14",key:"1bvyxn"}],["line",{x1:"22",x2:"16",y1:"11",y2:"11",key:"1shjgl"}]]);export{c as U};
@@ -1 +1 @@
1
- import{c as a}from"./index-C0t11tlT.js";const t=a("ArrowLeft",[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]]);const h=a("AtSign",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8",key:"7n84p3"}]]);const y=a("BookMarked",[["path",{d:"M10 2v8l3-3 3 3V2",key:"sqw3rj"}],["path",{d:"M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20",key:"k3hazp"}]]);const k=a("BookOpen",[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]]);const d=a("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);const c=a("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);const p=a("FileArchive",[["path",{d:"M10 12v-1",key:"v7bkov"}],["path",{d:"M10 18v-2",key:"1cjy8d"}],["path",{d:"M10 7V6",key:"dljcrl"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M15.5 22H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v16a2 2 0 0 0 .274 1.01",key:"gkbcor"}],["circle",{cx:"10",cy:"20",r:"2",key:"1xzdoj"}]]);const s=a("FileSearch",[["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M4.268 21a2 2 0 0 0 1.727 1H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3",key:"ms7g94"}],["path",{d:"m9 18-1.5-1.5",key:"1j6qii"}],["circle",{cx:"5",cy:"14",r:"3",key:"ufru5t"}]]);const r=a("FileText",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);const l=a("FolderOpen",[["path",{d:"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",key:"usdka0"}]]);const o=a("FolderPlus",[["path",{d:"M12 10v6",key:"1bos4e"}],["path",{d:"M9 13h6",key:"1uhe8q"}],["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",key:"1kt360"}]]);const n=a("Folder",[["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",key:"1kt360"}]]);const M=a("GitBranch",[["line",{x1:"6",x2:"6",y1:"3",y2:"15",key:"17qcm7"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}],["path",{d:"M18 9a9 9 0 0 1-9 9",key:"n2h4wq"}]]);const i=a("ListTree",[["path",{d:"M21 12h-8",key:"1bmf0i"}],["path",{d:"M21 6H8",key:"1pqkrb"}],["path",{d:"M21 18h-8",key:"1tm79t"}],["path",{d:"M3 6v4c0 1.1.9 2 2 2h3",key:"1ywdgy"}],["path",{d:"M3 10v6c0 1.1.9 2 2 2h3",key:"2wc746"}]]);const v=a("MessageSquare",[["path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z",key:"1lielz"}]]);const x=a("Pencil",[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]);const H=a("ScrollText",[["path",{d:"M15 12h-5",key:"r7krc0"}],["path",{d:"M15 8h-5",key:"1khuty"}],["path",{d:"M19 17V5a2 2 0 0 0-2-2H4",key:"zz82l3"}],["path",{d:"M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3",key:"1ph1d7"}]]);const m=a("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);const u=a("TriangleAlert",[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]]);const q=a("Upload",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"17 8 12 3 7 8",key:"t8dd8p"}],["line",{x1:"12",x2:"12",y1:"3",y2:"15",key:"widbto"}]]);const g=a("Users",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["path",{d:"M16 3.13a4 4 0 0 1 0 7.75",key:"1da9ce"}]]);const A=a("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);export{h as A,y as B,d as C,c as D,s as F,M as G,i as L,v as M,x as P,H as S,m as T,g as U,A as X,l as a,n as b,k as c,r as d,t as e,q as f,o as g,p as h,u as i};
1
+ import{c as a}from"./index-BjzELSQ-.js";const t=a("ArrowLeft",[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]]);const h=a("AtSign",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8",key:"7n84p3"}]]);const y=a("BookMarked",[["path",{d:"M10 2v8l3-3 3 3V2",key:"sqw3rj"}],["path",{d:"M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20",key:"k3hazp"}]]);const k=a("BookOpen",[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]]);const d=a("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);const c=a("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);const p=a("FileArchive",[["path",{d:"M10 12v-1",key:"v7bkov"}],["path",{d:"M10 18v-2",key:"1cjy8d"}],["path",{d:"M10 7V6",key:"dljcrl"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M15.5 22H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v16a2 2 0 0 0 .274 1.01",key:"gkbcor"}],["circle",{cx:"10",cy:"20",r:"2",key:"1xzdoj"}]]);const s=a("FileSearch",[["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M4.268 21a2 2 0 0 0 1.727 1H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3",key:"ms7g94"}],["path",{d:"m9 18-1.5-1.5",key:"1j6qii"}],["circle",{cx:"5",cy:"14",r:"3",key:"ufru5t"}]]);const r=a("FileText",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);const l=a("FolderOpen",[["path",{d:"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",key:"usdka0"}]]);const o=a("FolderPlus",[["path",{d:"M12 10v6",key:"1bos4e"}],["path",{d:"M9 13h6",key:"1uhe8q"}],["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",key:"1kt360"}]]);const n=a("Folder",[["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",key:"1kt360"}]]);const M=a("GitBranch",[["line",{x1:"6",x2:"6",y1:"3",y2:"15",key:"17qcm7"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}],["path",{d:"M18 9a9 9 0 0 1-9 9",key:"n2h4wq"}]]);const i=a("ListTree",[["path",{d:"M21 12h-8",key:"1bmf0i"}],["path",{d:"M21 6H8",key:"1pqkrb"}],["path",{d:"M21 18h-8",key:"1tm79t"}],["path",{d:"M3 6v4c0 1.1.9 2 2 2h3",key:"1ywdgy"}],["path",{d:"M3 10v6c0 1.1.9 2 2 2h3",key:"2wc746"}]]);const v=a("MessageSquare",[["path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z",key:"1lielz"}]]);const x=a("Pencil",[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]);const H=a("ScrollText",[["path",{d:"M15 12h-5",key:"r7krc0"}],["path",{d:"M15 8h-5",key:"1khuty"}],["path",{d:"M19 17V5a2 2 0 0 0-2-2H4",key:"zz82l3"}],["path",{d:"M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3",key:"1ph1d7"}]]);const m=a("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);const u=a("TriangleAlert",[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]]);const q=a("Upload",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"17 8 12 3 7 8",key:"t8dd8p"}],["line",{x1:"12",x2:"12",y1:"3",y2:"15",key:"widbto"}]]);const g=a("Users",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["path",{d:"M16 3.13a4 4 0 0 1 0 7.75",key:"1da9ce"}]]);const A=a("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);export{h as A,y as B,d as C,c as D,s as F,M as G,i as L,v as M,x as P,H as S,m as T,g as U,A as X,l as a,n as b,k as c,r as d,t as e,q as f,o as g,p as h,u as i};
@@ -10,9 +10,9 @@
10
10
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/iosevka@5.2.5/400.css" />
11
11
  <link rel="icon" type="image/svg+xml" href="/logo.svg" />
12
12
  <title>TexLite</title>
13
- <script type="module" crossorigin src="/assets/index-C0t11tlT.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-BjzELSQ-.js"></script>
14
14
  <link rel="modulepreload" crossorigin href="/assets/react-BVUjbTTn.js">
15
- <link rel="stylesheet" crossorigin href="/assets/index-DXWp2bzM.css">
15
+ <link rel="stylesheet" crossorigin href="/assets/index-BRr3Kuxh.css">
16
16
  </head>
17
17
  <body>
18
18
  <div id="root"></div>
@@ -11,12 +11,26 @@ const maxCachedSourceBytes = 512 * 1024;
11
11
  const maxCachedResults = 24;
12
12
  const cacheTtlMs = 15_000;
13
13
  const unavailableRetryMs = 15_000;
14
+ // A browser can send an older request after a newer one when HTTP requests
15
+ // race. Keep the latest sequence briefly so that late arrivals cannot replace
16
+ // a newer queued revision. The bound is intentionally generous for a small
17
+ // collaborative installation while keeping abandoned browser-page lanes from
18
+ // accumulating forever.
19
+ const laneSequenceRetentionMs = 10 * 60_000;
20
+ const maxTrackedLaneSequences = 512;
14
21
  export class HarperUnavailableError extends Error {
15
22
  constructor(message) {
16
23
  super(message);
17
24
  this.name = "HarperUnavailableError";
18
25
  }
19
26
  }
27
+ /** A newer source revision made a waiting writing check irrelevant. */
28
+ export class HarperLintSupersededError extends Error {
29
+ constructor() {
30
+ super("A newer writing check replaced this request.");
31
+ this.name = "HarperLintSupersededError";
32
+ }
33
+ }
20
34
  function lintCacheKey(source, filePath) {
21
35
  // Harper selects its parser from the input suffix, so equivalent text in a
22
36
  // .tex and a .sty file must not share a diagnostic result.
@@ -78,8 +92,20 @@ export class HarperService {
78
92
  availability = "unknown";
79
93
  lastUnavailableAt = 0;
80
94
  probePromise = null;
81
- queue = Promise.resolve();
95
+ /** One harper-cli process at a time; Harper itself is comparatively heavy. */
96
+ queueRunner = null;
97
+ // Set preserves insertion order, giving the scheduler FIFO behaviour while
98
+ // allowing a superseded waiting item to be removed immediately. An array
99
+ // would otherwise retain its complete source string until the active check
100
+ // finishes.
101
+ queued = new Set();
102
+ /** Only waiting work belongs here; a running process must finish safely. */
103
+ waitingByLane = new Map();
104
+ /** Latest accepted browser revision for each project/user/page/file lane. */
105
+ latestSequenceByLane = new Map();
82
106
  inFlight = new Map();
107
+ /** Lets coalesced browser lanes share one queued operation safely. */
108
+ scheduledByKey = new Map();
83
109
  cache = new Map();
84
110
  activeChild = null;
85
111
  disposed = false;
@@ -89,35 +115,206 @@ export class HarperService {
89
115
  async preload() {
90
116
  await this.ensureAvailable();
91
117
  }
92
- async lint(source, filePath = "main.tex") {
118
+ /**
119
+ * Schedule one host-side check. A lane represents one browser page's
120
+ * current file, so an edit can replace only its own stale waiting request
121
+ * without cancelling checks requested by collaborators.
122
+ */
123
+ async lint(source, filePath = "main.tex", lane, sequence) {
93
124
  if (this.disposed)
94
125
  throw new HarperUnavailableError("Harper service stopped.");
95
126
  const key = lintCacheKey(source, filePath);
127
+ const laneKey = lane || null;
128
+ if (laneKey && sequence !== undefined)
129
+ this.acceptLaneSequence(laneKey, sequence, key);
130
+ const waiting = laneKey ? this.waitingByLane.get(laneKey) : undefined;
131
+ // Repeated requests for the same queued revision share it. A newer
132
+ // revision replaces only work that has not started yet.
133
+ if (waiting?.key === key)
134
+ return waiting.promise;
135
+ if (laneKey && waiting)
136
+ this.releaseWaitingLane(laneKey, waiting);
96
137
  const cacheable = Buffer.byteLength(source, "utf8") <= maxCachedSourceBytes;
97
138
  const cached = cacheable ? this.cachedResult(key) : null;
98
139
  if (cached)
99
140
  return cached;
100
- const existing = cacheable ? this.inFlight.get(key) : undefined;
101
- if (existing)
141
+ // Result caching is deliberately size-bounded, but duplicate active work
142
+ // is still coalesced for large files. The latter is transient and avoids
143
+ // starting multiple expensive CLI processes for identical content.
144
+ const existing = this.inFlight.get(key);
145
+ if (existing) {
146
+ const scheduled = this.scheduledByKey.get(key);
147
+ if (laneKey && scheduled)
148
+ this.addWaitingLane(scheduled, laneKey);
149
+ else if (scheduled && !scheduled.started)
150
+ scheduled.hasUnscopedWaiter = true;
102
151
  return existing;
103
- const operation = this.queue.then(() => this.lintOnce(source, filePath));
104
- this.queue = operation.then(() => undefined, () => undefined);
152
+ }
153
+ let resolve;
154
+ let reject;
155
+ const operation = new Promise((resolveOperation, rejectOperation) => {
156
+ resolve = resolveOperation;
157
+ reject = rejectOperation;
158
+ });
159
+ const scheduled = {
160
+ key,
161
+ source,
162
+ filePath,
163
+ started: false,
164
+ cancelled: false,
165
+ lanes: laneKey ? new Set([laneKey]) : new Set(),
166
+ hasUnscopedWaiter: laneKey === null,
167
+ promise: operation,
168
+ resolve,
169
+ reject
170
+ };
171
+ this.inFlight.set(key, operation);
172
+ this.scheduledByKey.set(key, scheduled);
173
+ if (laneKey)
174
+ this.waitingByLane.set(laneKey, scheduled);
175
+ this.queued.add(scheduled);
176
+ this.startQueue();
105
177
  if (cacheable) {
106
- this.inFlight.set(key, operation);
107
178
  void operation.then((lints) => this.cacheResult(key, lints), () => undefined).finally(() => {
108
179
  if (this.inFlight.get(key) === operation)
109
180
  this.inFlight.delete(key);
181
+ if (this.scheduledByKey.get(key) === scheduled)
182
+ this.scheduledByKey.delete(key);
183
+ });
184
+ }
185
+ else {
186
+ // Attach a rejection handler even for uncached results. This keeps a
187
+ // superseded request from becoming an unhandled rejection when a client
188
+ // disconnects before it awaits the response.
189
+ void operation.catch(() => undefined).finally(() => {
190
+ if (this.inFlight.get(key) === operation)
191
+ this.inFlight.delete(key);
192
+ if (this.scheduledByKey.get(key) === scheduled)
193
+ this.scheduledByKey.delete(key);
110
194
  });
111
195
  }
112
196
  return operation;
113
197
  }
114
198
  async dispose() {
115
199
  this.disposed = true;
200
+ const stopped = new HarperUnavailableError("Harper service stopped.");
201
+ for (const scheduled of [...this.queued]) {
202
+ if (!scheduled.cancelled && !scheduled.started) {
203
+ scheduled.cancelled = true;
204
+ this.discardQueuedLint(scheduled);
205
+ scheduled.reject(stopped);
206
+ }
207
+ }
208
+ this.waitingByLane.clear();
209
+ this.latestSequenceByLane.clear();
116
210
  this.activeChild?.kill("SIGTERM");
117
- await this.queue.catch(() => undefined);
211
+ await this.queueRunner?.catch(() => undefined);
118
212
  this.inFlight.clear();
213
+ this.scheduledByKey.clear();
119
214
  this.cache.clear();
120
215
  }
216
+ addWaitingLane(scheduled, lane) {
217
+ if (scheduled.started || scheduled.cancelled)
218
+ return;
219
+ scheduled.lanes.add(lane);
220
+ this.waitingByLane.set(lane, scheduled);
221
+ }
222
+ releaseWaitingLane(lane, scheduled) {
223
+ if (this.waitingByLane.get(lane) === scheduled)
224
+ this.waitingByLane.delete(lane);
225
+ scheduled.lanes.delete(lane);
226
+ // The exact same queued source can be requested by multiple sessions.
227
+ // Discard it only after every interested lane has moved on.
228
+ if (scheduled.started || scheduled.cancelled || scheduled.hasUnscopedWaiter || scheduled.lanes.size > 0)
229
+ return;
230
+ this.cancelScheduledLint(scheduled);
231
+ }
232
+ cancelScheduledLint(scheduled) {
233
+ if (scheduled.started || scheduled.cancelled)
234
+ return;
235
+ scheduled.cancelled = true;
236
+ for (const lane of scheduled.lanes) {
237
+ if (this.waitingByLane.get(lane) === scheduled)
238
+ this.waitingByLane.delete(lane);
239
+ }
240
+ scheduled.lanes.clear();
241
+ // Remove this rejected promise immediately so a later return to the same
242
+ // text can enqueue fresh work instead of inheriting a stale rejection.
243
+ if (this.inFlight.get(scheduled.key) === scheduled.promise) {
244
+ this.inFlight.delete(scheduled.key);
245
+ }
246
+ if (this.scheduledByKey.get(scheduled.key) === scheduled) {
247
+ this.scheduledByKey.delete(scheduled.key);
248
+ }
249
+ this.discardQueuedLint(scheduled);
250
+ scheduled.reject(new HarperLintSupersededError());
251
+ }
252
+ /** Remove a waiting task and promptly release its potentially large text. */
253
+ discardQueuedLint(scheduled) {
254
+ this.queued.delete(scheduled);
255
+ scheduled.source = "";
256
+ scheduled.filePath = "";
257
+ }
258
+ /** Reject an out-of-order request before it can alter queued work. */
259
+ acceptLaneSequence(lane, sequence, key) {
260
+ if (!Number.isSafeInteger(sequence) || sequence <= 0) {
261
+ throw new HarperLintSupersededError();
262
+ }
263
+ const now = Date.now();
264
+ this.pruneLaneSequences(now);
265
+ const previous = this.latestSequenceByLane.get(lane);
266
+ if (previous && (sequence < previous.sequence || (sequence === previous.sequence && previous.key !== key))) {
267
+ throw new HarperLintSupersededError();
268
+ }
269
+ // Refresh insertion order so the bounded map evicts the least recently
270
+ // used abandoned page lane first.
271
+ this.latestSequenceByLane.delete(lane);
272
+ this.latestSequenceByLane.set(lane, { sequence, key, seenAt: now });
273
+ while (this.latestSequenceByLane.size > maxTrackedLaneSequences) {
274
+ const oldest = this.latestSequenceByLane.keys().next().value;
275
+ if (oldest === undefined)
276
+ break;
277
+ this.latestSequenceByLane.delete(oldest);
278
+ }
279
+ }
280
+ pruneLaneSequences(now) {
281
+ for (const [lane, state] of this.latestSequenceByLane) {
282
+ if (now - state.seenAt <= laneSequenceRetentionMs)
283
+ continue;
284
+ this.latestSequenceByLane.delete(lane);
285
+ }
286
+ }
287
+ startQueue() {
288
+ if (this.queueRunner)
289
+ return;
290
+ this.queueRunner = (async () => {
291
+ while (!this.disposed) {
292
+ const scheduled = this.queued.values().next().value;
293
+ if (!scheduled)
294
+ return;
295
+ this.queued.delete(scheduled);
296
+ if (scheduled.cancelled)
297
+ continue;
298
+ scheduled.started = true;
299
+ for (const lane of scheduled.lanes) {
300
+ if (this.waitingByLane.get(lane) === scheduled)
301
+ this.waitingByLane.delete(lane);
302
+ }
303
+ scheduled.lanes.clear();
304
+ try {
305
+ scheduled.resolve(await this.lintOnce(scheduled.source, scheduled.filePath));
306
+ }
307
+ catch (error) {
308
+ scheduled.reject(error);
309
+ }
310
+ }
311
+ })().finally(() => {
312
+ this.queueRunner = null;
313
+ // A request can arrive just after the loop observes an empty queue.
314
+ if (!this.disposed && this.queued.size)
315
+ this.startQueue();
316
+ });
317
+ }
121
318
  async ensureAvailable() {
122
319
  if (this.availability === "available")
123
320
  return;
@@ -193,6 +193,23 @@ export class ProjectHistoryService {
193
193
  .get(versionId, projectId);
194
194
  return row ? parseManifest(row.manifest_json) : null;
195
195
  }
196
+ /**
197
+ * A short autosave window deliberately coalesces updates into one row. A
198
+ * client that has been inspecting that row must not restore newer contents
199
+ * it has not reviewed, so verify the manifest fingerprint immediately
200
+ * before a restore mutates the project.
201
+ */
202
+ assertSnapshotHash(projectId, versionId, expectedHash) {
203
+ if (!expectedHash)
204
+ return;
205
+ const row = this.db.prepare("SELECT manifest_json FROM project_history_versions WHERE id = ? AND project_id = ?")
206
+ .get(versionId, projectId);
207
+ if (!row)
208
+ throw httpError(404, "HISTORY_VERSION_NOT_FOUND");
209
+ if (historySnapshotHash(row.manifest_json) !== expectedHash) {
210
+ throw httpError(409, "HISTORY_VERSION_CHANGED");
211
+ }
212
+ }
196
213
  /**
197
214
  * Validate a single-file restore before the project enters maintenance.
198
215
  * restore() repeats the target check while the exclusive operation is held
@@ -229,7 +246,7 @@ export class ProjectHistoryService {
229
246
  const entry = this.manifest(projectId, versionId)?.files[filePath];
230
247
  if (!entry || entry.size > MAX_TEXT_PREVIEW_BYTES)
231
248
  return null;
232
- return fs.readFileSync(this.objectPath(projectId, entry.digest), "utf8");
249
+ return this.readStoredObject(projectId, entry.digest, filePath);
233
250
  }
234
251
  restore(projectId, versionId, filePathInput) {
235
252
  const manifest = this.manifest(projectId, versionId);
@@ -245,7 +262,7 @@ export class ProjectHistoryService {
245
262
  fs.mkdirSync(path.dirname(target), { recursive: true, mode: 0o700 });
246
263
  const temporary = `${target}.history-${randomUUID()}.tmp`;
247
264
  try {
248
- fs.copyFileSync(this.objectPath(projectId, entry.digest), temporary);
265
+ this.copyStoredObject(projectId, entry.digest, filePath, temporary);
249
266
  fs.chmodSync(temporary, 0o600);
250
267
  fs.renameSync(temporary, target);
251
268
  }
@@ -340,6 +357,35 @@ export class ProjectHistoryService {
340
357
  throw new Error("Invalid history object digest");
341
358
  return path.join(outputRoot(this.config, projectId), ".texlite", "history", "objects", digest.slice(0, 2), digest);
342
359
  }
360
+ /**
361
+ * A history manifest can outlive a damaged or manually removed object. Keep
362
+ * that operational failure distinct from an absent path in the snapshot so
363
+ * the UI can tell the user why viewing or restoring it is impossible.
364
+ */
365
+ readStoredObject(projectId, digest, filePath) {
366
+ try {
367
+ return fs.readFileSync(this.objectPath(projectId, digest), "utf8");
368
+ }
369
+ catch (error) {
370
+ this.rethrowHistoryObjectError(error, filePath);
371
+ }
372
+ }
373
+ copyStoredObject(projectId, digest, filePath, target) {
374
+ try {
375
+ fs.copyFileSync(this.objectPath(projectId, digest), target);
376
+ }
377
+ catch (error) {
378
+ this.rethrowHistoryObjectError(error, filePath);
379
+ }
380
+ }
381
+ rethrowHistoryObjectError(error, filePath) {
382
+ const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string"
383
+ ? error.code : "";
384
+ if (code === "ENOENT" || code === "ENOTDIR" || code === "EISDIR") {
385
+ throw httpError(410, "HISTORY_OBJECT_MISSING", { path: filePath });
386
+ }
387
+ throw error;
388
+ }
343
389
  storedObjectDigests(projectId) {
344
390
  const objectsRoot = path.join(outputRoot(this.config, projectId), ".texlite", "history", "objects");
345
391
  if (!fs.existsSync(objectsRoot))
@@ -493,7 +539,7 @@ export class ProjectHistoryService {
493
539
  for (const [filePath, entry] of Object.entries(manifest.files)) {
494
540
  const target = path.join(temporary, safeRelativePath(filePath));
495
541
  fs.mkdirSync(path.dirname(target), { recursive: true, mode: 0o700 });
496
- fs.copyFileSync(this.objectPath(projectId, entry.digest), target);
542
+ this.copyStoredObject(projectId, entry.digest, filePath, target);
497
543
  fs.chmodSync(target, 0o600);
498
544
  }
499
545
  fs.renameSync(live, backup);
@@ -581,6 +627,7 @@ function versionJson(row) {
581
627
  const files = Object.values(manifest.files);
582
628
  return {
583
629
  id: row.id,
630
+ snapshotHash: historySnapshotHash(row.manifest_json),
584
631
  reason: row.reason,
585
632
  label: row.label,
586
633
  createdAt: row.created_at,
@@ -594,3 +641,6 @@ function versionJson(row) {
594
641
  totalSize: files.reduce((sum, file) => sum + file.size, 0)
595
642
  };
596
643
  }
644
+ function historySnapshotHash(manifestJson) {
645
+ return createHash("sha256").update(manifestJson, "utf8").digest("hex");
646
+ }
@@ -16,6 +16,7 @@ const enMessages = {
16
16
  COMMENT_FILE_NOT_FOUND: "The file for this comment does not exist.",
17
17
  COMMENT_NOT_FOUND: "The comment does not exist.",
18
18
  COMMENT_RANGE_INVALID: "The comment source range is invalid.",
19
+ COMMENT_SOURCE_CHANGED: "The source changed while this comment was being prepared. Reselect the passage and try again.",
19
20
  COMMENT_UPDATE_EMPTY: "There is no comment change to save.",
20
21
  COMPILE_ARTIFACT_NOT_FOUND: "The compiled artifact does not exist.",
21
22
  COMPILE_ARTIFACTS_NOT_FOUND: "No compiled artifacts are available yet.",
@@ -45,9 +46,11 @@ const enMessages = {
45
46
  GIT_UNAVAILABLE: "Git is not available on this server.",
46
47
  HARPER_UNAVAILABLE: "Harper spelling and grammar checking is temporarily unavailable.",
47
48
  HISTORY_FILE_NOT_FOUND: "The historical file does not exist.",
49
+ HISTORY_OBJECT_MISSING: "A stored file for this snapshot is missing. It can no longer be viewed or restored.",
48
50
  HISTORY_FILE_PREVIEW_UNSUPPORTED: "This historical file cannot be compared as text.",
49
51
  HISTORY_TARGET_CONFLICT: "The historical version cannot be restored to the requested path.",
50
52
  HISTORY_VERSION_NOT_FOUND: "The history version does not exist.",
53
+ HISTORY_VERSION_CHANGED: "The selected project snapshot changed while it was being reviewed. Refresh it before restoring.",
51
54
  SELECTION_HISTORY_SOURCE_CHANGED: "The source changed while opening selection history. Wait for synchronization, then select the passage and open its history again.",
52
55
  INVALID_PATH: "The file path is invalid.",
53
56
  LAST_ADMIN: "At least one active administrator must remain.",
@@ -89,6 +92,7 @@ const enMessages = {
89
92
  SOURCE_FLUSH_FAILED: "Some source files could not be saved. The project operation was cancelled.",
90
93
  SPELLCHECK_SOURCE_INVALID: "The source to check is invalid.",
91
94
  SPELLCHECK_SOURCE_TOO_LARGE: "The source to check is too large.",
95
+ SPELLCHECK_SUPERSEDED: "A newer writing check replaced this request.",
92
96
  SYNCTEX_EXTERNAL_PATH: "SyncTeX returned a source path outside the project.",
93
97
  SYNCTEX_NOT_AVAILABLE: "No SyncTeX data is available. Compile the project again.",
94
98
  SYMLINK_FORBIDDEN: "Symbolic links are not allowed in project sources.",
@@ -144,6 +148,7 @@ const zhMessages = {
144
148
  COMMENT_FILE_NOT_FOUND: "批注对应的文件不存在。",
145
149
  COMMENT_NOT_FOUND: "批注不存在。",
146
150
  COMMENT_RANGE_INVALID: "批注的源码区间无效。",
151
+ COMMENT_SOURCE_CHANGED: "准备批注时源码已发生变化。请重新选择文本后再试。",
147
152
  COMMENT_UPDATE_EMPTY: "没有可保存的批注修改。",
148
153
  COMPILE_ARTIFACT_NOT_FOUND: "编译产物不存在。",
149
154
  COMPILE_ARTIFACTS_NOT_FOUND: "尚无可用的编译产物。",
@@ -173,9 +178,11 @@ const zhMessages = {
173
178
  GIT_UNAVAILABLE: "服务器未安装 Git。",
174
179
  HARPER_UNAVAILABLE: "Harper 拼写与语法检查暂不可用。",
175
180
  HISTORY_FILE_NOT_FOUND: "历史文件不存在。",
181
+ HISTORY_OBJECT_MISSING: "该快照的已存储文件缺失,无法再查看或恢复。",
176
182
  HISTORY_FILE_PREVIEW_UNSUPPORTED: "该历史文件不能作为文本比较。",
177
183
  HISTORY_TARGET_CONFLICT: "无法将历史版本恢复到所请求的路径。",
178
184
  HISTORY_VERSION_NOT_FOUND: "历史版本不存在。",
185
+ HISTORY_VERSION_CHANGED: "查看期间该项目快照已发生变化。请刷新后再恢复。",
179
186
  SELECTION_HISTORY_SOURCE_CHANGED: "打开选区历史时源码已发生变化。请等待同步完成,重新选择文本后再打开历史。",
180
187
  INVALID_PATH: "文件路径无效。",
181
188
  LAST_ADMIN: "系统必须保留至少一名可用管理员。",
@@ -217,6 +224,7 @@ const zhMessages = {
217
224
  SOURCE_FLUSH_FAILED: "部分源码未能保存至磁盘,项目操作已取消。",
218
225
  SPELLCHECK_SOURCE_INVALID: "待检查源码格式不正确。",
219
226
  SPELLCHECK_SOURCE_TOO_LARGE: "待检查源码过大。",
227
+ SPELLCHECK_SUPERSEDED: "更新的写作检查已替代此请求。",
220
228
  SYNCTEX_EXTERNAL_PATH: "SyncTeX 返回了项目外部的源码路径。",
221
229
  SYNCTEX_NOT_AVAILABLE: "尚无可用的 SyncTeX 数据,请重新编译。",
222
230
  SYMLINK_FORBIDDEN: "项目源码中不允许使用符号链接。",