Files appear instantly but download only when you open them.
- Anything you add or change syncs back to your server as usual.
`),cv=W(`
`),lv=W(`
Checking your files…
folders checked so far
`),uv=W(`
Loading…
`),dv=W(`
No folders here.
`),fv=W(`
`),pv=W(``),mv=W(`
Download these first
Tick the folders you need straight away. They download before everything else, and the rest follows.
`),hv=W(`
`),gv=W(`
`),_v=W(`
Keep the files already in this folder?
There are already files in
`),vv=W(`
↔
📁
Local Folder
`,1),yv=W(`
Loading account…
`),bv=W(``);function xv(e,t){Je(t,!0);let n=[],r=N(null),i=N(``),a=N(0),o=N(`everything`),s=N(!1),c=N(``);(async()=>{P(r,await lu(),!0),P(i,H(r).defaultDir,!0),P(a,H(r).freeBytes,!0),!H(r).onDemandSupport&&H(o)===`ondemand`&&P(o,`everything`)})();function l(e){if(!e||e<0)return`—`;let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r0))} ${t[r]}`}async function u(){let e=await Vu(H(i));e&&(P(i,e,!0),P(a,await tu(e),!0))}let d=N(null),f=N(!1),p=N(0),m=!1,h=null;async function g(){P(s,!0),P(c,``),H(o)===`ondemand`&&(P(f,!0),m=!1,P(p,0),h=setInterval(async()=>{P(p,(await Yl())?.adoptScanDirs||0,!0)},1500));let e=H(o)===`everything`&&H(x).length?`everything:`+JSON.stringify(H(x)):H(o),n=await Ll(H(i),e);if(h&&=(clearInterval(h),null),P(f,!1),P(s,!1),m){m=!1;return}if(n){if(H(o)===`ondemand`&&n.startsWith(`{`))try{let e=JSON.parse(n);if(e.error){P(c,e.error,!0);return}P(d,e,!0);return}catch{}P(c,n,!0);return}H(o)===`choose`&&await Mu(),t.done()}async function _(){m=!0,P(f,!1),await Dd(`ondemand-cancel`)}async function v(){P(d,null),P(s,!0);let e=await Dd(`ondemand-adopt`);if(P(s,!1),e){P(c,e,!0);return}t.done()}async function y(){P(d,null),await Dd(`ondemand-cancel`)}function b(){t.done()}let x=N(F([])),S=N(!1),C=N(``),w=N(F([])),ee=N(!1);async function te(e){P(C,e.replace(/^\/+|\/+$/g,``),!0),P(ee,!0),P(w,(await jl(H(C))??[]).filter(e=>e.isDir),!0),P(ee,!1)}function ne(){P(S,!0),te(``)}function re(){H(C)&&te(H(C).split(`/`).slice(0,-1).join(`/`))}function ie(e){P(x,H(x).includes(e)?H(x).filter(t=>t!==e):[...H(x),e],!0)}let ae=M(()=>H(x).length<=3?H(x).join(`, `):`${H(x).slice(0,3).join(`, `)} and ${H(x).length-3} more`);var oe=bv(),se=I(oe),ce=e=>{var t=vv(),m=L(t),h=I(m),oe=I(h),se=I(oe,!0);O(oe);var ce=R(oe,2),le=I(ce,!0);O(ce);var T=R(ce,2),ue=I(T,!0);O(T),O(h);var de=R(h,4),fe=R(I(de),4),pe=I(fe,!0);O(fe);var me=R(fe,2),he=I(me);O(me);var ge=R(me,2);O(de),O(m);var _e=R(m,2),ve=I(_e);let ye;var be=I(ve);X(be),be.value=be.__value=`everything`;var xe=R(be,2),Se=R(I(xe)),Ce=e=>{var t=rv(),n=I(t);O(t),z(e=>K(n,`(${e??``})`),[()=>l(H(r).accountBytes)]),G(e,t)};q(Se,e=>{H(r).accountBytes>0&&e(Ce)}),O(xe),O(ve);var we=R(ve,2),Te=e=>{var t=ov(),n=I(t),r=e=>{var t=iv(),n=L(t),r=R(I(n)),i=I(r,!0);O(r),O(n);var a=R(n,2);z(e=>{Z(n,`title`,e),K(i,H(ae)),a.disabled=H(s)},[()=>H(x).join(`, `)]),U(`click`,a,ne),G(e,t)},i=e=>{var t=av();z(()=>t.disabled=H(s)),U(`click`,t,ne),G(e,t)};q(n,e=>{H(x).length?e(r):e(i,-1)}),O(t),G(e,t)};q(we,e=>{H(o)===`everything`&&e(Te)});var Ee=R(we,2);let De;var Oe=I(Ee);X(Oe),Oe.value=Oe.__value=`choose`,k(2),O(Ee);var ke=R(Ee,2);let Ae;var je=I(ke);X(je),je.value=je.__value=`ondemand`,k(2),O(ke);var E=R(ke,2),Me=e=>{G(e,sv())};q(E,e=>{H(o)===`ondemand`&&e(Me)}),O(_e);var D=R(_e,2),Ne=e=>{var t=cv(),n=I(t,!0);O(t),z(()=>K(n,H(c))),G(e,t)};q(D,e=>{H(c)&&e(Ne)});var Pe=R(D,2),Fe=I(Pe),Ie=R(Fe,2),Le=I(Ie,!0);O(Ie),O(Pe);var Re=R(Pe,2),ze=e=>{var t=lv(),n=I(t),r=R(I(n),2),i=I(r);O(r);var a=R(r,2),o=I(a),s=I(o,!0);O(o),k(),O(a);var c=R(a,2),l=I(c);O(c),O(n),O(t),z(()=>{K(i,`${Jp.name??``} is comparing everything in this folder with your server before setting up. On a large account this can take several minutes. Nothing is changed until you confirm.`),K(s,H(p))}),U(`click`,l,_),G(e,t)};q(Re,e=>{H(f)&&e(ze)});var Be=R(Re,2),Ve=e=>{var t=mv(),n=I(t),r=R(I(n),4),i=I(r),a=R(i,2),o=I(a);O(a),O(r);var s=R(r,2),c=I(s),l=e=>{G(e,uv())},u=e=>{G(e,dv())};q(c,e=>{H(ee)?e(l):H(w).length===0&&e(u,1)}),J(R(c,2),17,()=>H(w),e=>e.path,(e,t)=>{var n=fv(),r=I(n);X(r);var i=R(r,2),a=I(i);O(i),O(n),z(e=>{xi(r,e),Z(i,`title`,`Open ${H(t).name??``}`),K(a,`📁 ${H(t).name??``}`)},[()=>H(x).includes(H(t).path)]),U(`change`,r,()=>ie(H(t).path)),U(`click`,i,()=>te(H(t).path)),G(e,n)}),O(s);var d=R(s,2),f=I(d),p=I(f);O(f);var m=R(f,2),h=e=>{var t=pv();U(`click`,t,()=>P(x,[],!0)),G(e,t)};q(m,e=>{H(x).length&&e(h)});var g=R(m,2);O(d),O(n),O(t),z(()=>{i.disabled=!H(C),Z(a,`title`,`/`+H(C)),K(o,`/${H(C)??``}`),K(p,`${H(x).length??``} chosen`)}),U(`click`,i,re),U(`click`,g,()=>P(S,!1)),G(e,t)};q(Be,e=>{H(S)&&e(Ve)});var He=R(Be,2),Ue=e=>{var t=_v(),n=I(t),r=R(I(n),2),a=R(I(r)),o=I(a,!0);O(a);var s=R(a);O(r);var c=R(r,2),u=I(c),f=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).keep),K(i,` already ${H(d).keep===1?`matches`:`match`} your server — kept on this PC.`)}),G(e,t)};q(u,e=>{H(d).keep&&e(f)});var p=R(u,2),m=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).replace),K(i,` ${H(d).replace===1?`is an online-only leftover`:`are online-only leftovers`} from another app — replaced with ${H(d).replace===1?`a ${Jp.name} placeholder`:`${Jp.name} placeholders`}.`)}),G(e,t)};q(p,e=>{H(d).replace&&e(m)});var h=R(p,2),g=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).upload),K(i,` ${H(d).upload===1?`isn’t`:`aren’t`} on your server yet — uploaded.`)}),G(e,t)};q(h,e=>{H(d).upload&&e(g)});var _=R(h,2),b=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).conflict),K(i,` ${H(d).conflict===1?`differs`:`differ`} from your server — both versions kept.`)}),G(e,t)};q(_,e=>{H(d).conflict&&e(b)}),O(c);var x=R(c,2),S=e=>{var t=gv(),n=I(t);O(t),z(e=>K(n,`Upload size: ${e??``}`),[()=>l(H(d).uploadBytes)]),G(e,t)};q(x,e=>{H(d).uploadBytes&&e(S)});var C=R(x,2),w=I(C),ee=R(w,2);O(C),O(n),O(t),z(()=>{K(o,H(i)),K(s,`. ${Jp.name??``} can keep them where they are instead of downloading everything again.`)}),U(`click`,w,y),U(`click`,ee,v),G(e,t)};q(He,e=>{H(d)&&e(Ue)}),z((e,t,n)=>{K(se,e),K(le,H(r).user),K(ue,t),Z(fe,`title`,H(i)),K(pe,H(i)),K(he,`${n??``} free`),ge.disabled=H(s),ye=Y(ve,1,`opt svelte-1wxc8fs`,null,ye,{sel:H(o)===`everything`}),be.disabled=H(s),De=Y(Ee,1,`opt svelte-1wxc8fs`,null,De,{sel:H(o)===`choose`}),Oe.disabled=H(s),Ae=Y(ke,1,`opt svelte-1wxc8fs`,null,Ae,{sel:H(o)===`ondemand`,off:!H(r).onDemandSupport}),je.disabled=H(s)||!H(r).onDemandSupport,Fe.disabled=H(s),Ie.disabled=H(s)||!H(i),K(Le,H(s)?`Setting up…`:`Connect`)},[()=>(H(r).user||`?`).charAt(0).toUpperCase(),()=>H(r).server.replace(/^https?:\/\//,``),()=>l(H(a))]),U(`click`,ge,u),Di(n,[],be,()=>H(o),e=>P(o,e)),Di(n,[],Oe,()=>H(o),e=>P(o,e)),Di(n,[],je,()=>H(o),e=>P(o,e)),U(`click`,Fe,b),U(`click`,Ie,g),G(e,t)},le=e=>{G(e,yv())};q(se,e=>{H(r)?e(ce):e(le,-1)}),O(oe),G(e,oe),Ye()}jr([`click`,`change`]);var Sv=W(`
Sign in again
`,1),Cv=W(`
Sign in to Nextcloud
`,1),wv=W(``),Tv=W(`
`),Ev=W(``),Dv=W(`
`);function Ov(e,t){Je(t,!0);let n=`Enter your Nextcloud server address to begin.`,r=N(``),i=N(n),a=N(!1),o=N(`signin`),s=N(null),c=N(!1),l=M(()=>!!H(s)&&!H(c));async function u(){let e=await Bd();P(s,e?.id?e:null,!0),P(c,!1),H(a)||(P(r,H(s)?H(s).server:``,!0),P(i,H(s)?``:n,!0))}u(),ns(`login:target`,u),ns(`login:error`,e=>{H(a)&&(P(i,`Sign-in failed: `+e.data),P(a,!1))}),ns(`login:done`,async e=>{if(P(a,!1),e.data===!0){P(i,`Signed in again.`),await Il();return}await $l(),P(o,`setup`)});async function d(){if(!H(r).trim())return;P(a,!0),P(i,`Connecting…`);let e=await Tl(H(r));if(e.startsWith(`error:`)){P(i,e,!0),P(a,!1);return}P(i,`Finish signing in in the browser that just opened. This window steps aside until you have.`)}function f(){P(a,!1),P(i,H(l)?``:n,!0)}function p(){zd(),P(c,!0),P(r,``),P(i,n)}var m=Vr(),h=L(m),g=e=>{xv(e,{done:()=>Il()})},_=e=>{var t=Dv(),n=I(t),o=e=>{var t=Sv(),n=R(L(t),2),r=I(n,!0);O(n);var i=R(n,2),o=I(i);O(i);var c=R(i,2);z(()=>{K(r,H(s).address),K(o,`${Jp.name??``} can't sign in to this account any more, for example because its access was
+ Anything you add or change syncs back to your server as usual.
`),cv=W(`
`),lv=W(`
Checking your files…
folders checked so far
`),uv=W(`
Loading…
`),dv=W(`
No folders here.
`),fv=W(`
`),pv=W(``),mv=W(`
Download these first
Tick the folders you need straight away. They download before everything else, and the rest follows.
`),hv=W(`
`),gv=W(`
`),_v=W(`
Keep the files already in this folder?
There are already files in
`),vv=W(`
↔
📁
Local Folder
`,1),yv=W(`
Loading account…
`),bv=W(``);function xv(e,t){Je(t,!0);let n=[],r=N(null),i=N(``),a=N(0),o=N(`everything`),s=N(!1),c=N(``);(async()=>{P(r,await lu(),!0),P(i,H(r).defaultDir,!0),P(a,H(r).freeBytes,!0),!H(r).onDemandSupport&&H(o)===`ondemand`&&P(o,`everything`)})();function l(e){if(!e||e<0)return`—`;let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r0))} ${t[r]}`}async function u(){let e=await Vu(H(i));e&&(P(i,e,!0),P(a,await tu(e),!0))}let d=N(null),f=N(!1),p=N(0),m=!1,h=null;async function g(){P(s,!0),P(c,``),H(o)===`ondemand`&&(P(f,!0),m=!1,P(p,0),h=setInterval(async()=>{P(p,(await Yl())?.adoptScanDirs||0,!0)},1500));let e=H(o)===`everything`&&H(x).length?`everything:`+JSON.stringify(H(x)):H(o),n=await Ll(H(i),e);if(h&&=(clearInterval(h),null),P(f,!1),P(s,!1),m){m=!1;return}if(n){if(H(o)===`ondemand`&&n.startsWith(`{`))try{let e=JSON.parse(n);if(e.error){P(c,e.error,!0);return}P(d,e,!0);return}catch{}P(c,n,!0);return}H(o)===`choose`&&await Mu(),t.done()}async function _(){m=!0,P(f,!1),await Dd(`ondemand-cancel`)}async function v(){P(d,null),P(s,!0);let e=await Dd(`ondemand-adopt`);if(P(s,!1),e){P(c,e,!0);return}t.done()}async function y(){P(d,null),await Dd(`ondemand-cancel`)}function b(){t.done()}let x=N(F([])),S=N(!1),C=N(``),w=N(F([])),ee=N(!1);async function te(e){P(C,e.replace(/^\/+|\/+$/g,``),!0),P(ee,!0),P(w,(await jl(H(C))??[]).filter(e=>e.isDir),!0),P(ee,!1)}function ne(){P(S,!0),te(``)}function re(){H(C)&&te(H(C).split(`/`).slice(0,-1).join(`/`))}function ie(e){P(x,H(x).includes(e)?H(x).filter(t=>t!==e):[...H(x),e],!0)}let ae=M(()=>H(x).length<=3?H(x).join(`, `):`${H(x).slice(0,3).join(`, `)} and ${H(x).length-3} more`);var oe=bv(),se=I(oe),ce=e=>{var t=vv(),m=L(t),h=I(m),oe=I(h),se=I(oe,!0);O(oe);var ce=R(oe,2),le=I(ce,!0);O(ce);var T=R(ce,2),ue=I(T,!0);O(T),O(h);var de=R(h,4),fe=R(I(de),4),pe=I(fe,!0);O(fe);var me=R(fe,2),he=I(me);O(me);var ge=R(me,2);O(de),O(m);var _e=R(m,2),ve=I(_e);let ye;var be=I(ve);X(be),be.value=be.__value=`everything`;var xe=R(be,2),Se=R(I(xe)),Ce=e=>{var t=rv(),n=I(t);O(t),z(e=>K(n,`(${e??``})`),[()=>l(H(r).accountBytes)]),G(e,t)};q(Se,e=>{H(r).accountBytes>0&&e(Ce)}),O(xe),O(ve);var we=R(ve,2),Te=e=>{var t=ov(),n=I(t),r=e=>{var t=iv(),n=L(t),r=R(I(n)),i=I(r,!0);O(r),O(n);var a=R(n,2);z(e=>{Z(n,`title`,e),K(i,H(ae)),a.disabled=H(s)},[()=>H(x).join(`, `)]),U(`click`,a,ne),G(e,t)},i=e=>{var t=av();z(()=>t.disabled=H(s)),U(`click`,t,ne),G(e,t)};q(n,e=>{H(x).length?e(r):e(i,-1)}),O(t),G(e,t)};q(we,e=>{H(o)===`everything`&&e(Te)});var Ee=R(we,2);let De;var Oe=I(Ee);X(Oe),Oe.value=Oe.__value=`choose`,k(2),O(Ee);var ke=R(Ee,2);let Ae;var je=I(ke);X(je),je.value=je.__value=`ondemand`,k(2),O(ke);var E=R(ke,2),Me=e=>{G(e,sv())};q(E,e=>{H(o)===`ondemand`&&e(Me)}),O(_e);var D=R(_e,2),Ne=e=>{var t=cv(),n=I(t,!0);O(t),z(()=>K(n,H(c))),G(e,t)};q(D,e=>{H(c)&&e(Ne)});var Pe=R(D,2),Fe=I(Pe),Ie=R(Fe,2),Le=I(Ie,!0);O(Ie),O(Pe);var Re=R(Pe,2),ze=e=>{var t=lv(),n=I(t),r=R(I(n),2),i=I(r);O(r);var a=R(r,2),o=I(a),s=I(o,!0);O(o),k(),O(a);var c=R(a,2),l=I(c);O(c),O(n),O(t),z(()=>{K(i,`${Jp.name??``} is comparing everything in this folder with your server before setting up. On a large account this can take several minutes. Nothing is changed until you confirm.`),K(s,H(p))}),U(`click`,l,_),G(e,t)};q(Re,e=>{H(f)&&e(ze)});var Be=R(Re,2),Ve=e=>{var t=mv(),n=I(t),r=R(I(n),4),i=I(r),a=R(i,2),o=I(a);O(a),O(r);var s=R(r,2),c=I(s),l=e=>{G(e,uv())},u=e=>{G(e,dv())};q(c,e=>{H(ee)?e(l):H(w).length===0&&e(u,1)}),J(R(c,2),17,()=>H(w),e=>e.path,(e,t)=>{var n=fv(),r=I(n);X(r);var i=R(r,2),a=I(i);O(i),O(n),z(e=>{xi(r,e),Z(i,`title`,`Open ${H(t).name??``}`),K(a,`📁 ${H(t).name??``}`)},[()=>H(x).includes(H(t).path)]),U(`change`,r,()=>ie(H(t).path)),U(`click`,i,()=>te(H(t).path)),G(e,n)}),O(s);var d=R(s,2),f=I(d),p=I(f);O(f);var m=R(f,2),h=e=>{var t=pv();U(`click`,t,()=>P(x,[],!0)),G(e,t)};q(m,e=>{H(x).length&&e(h)});var g=R(m,2);O(d),O(n),O(t),z(()=>{i.disabled=!H(C),Z(a,`title`,`/`+H(C)),K(o,`/${H(C)??``}`),K(p,`${H(x).length??``} chosen`)}),U(`click`,i,re),U(`click`,g,()=>P(S,!1)),G(e,t)};q(Be,e=>{H(S)&&e(Ve)});var He=R(Be,2),Ue=e=>{var t=_v(),n=I(t),r=R(I(n),2),a=R(I(r)),o=I(a,!0);O(a);var s=R(a);O(r);var c=R(r,2),u=I(c),f=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).keep),K(i,` already ${H(d).keep===1?`matches`:`match`} your server — kept on this PC.`)}),G(e,t)};q(u,e=>{H(d).keep&&e(f)});var p=R(u,2),m=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).replace),K(i,` ${H(d).replace===1?`is an online-only leftover`:`are online-only leftovers`} from another app — replaced with ${H(d).replace===1?`a ${Jp.name} placeholder`:`${Jp.name} placeholders`}.`)}),G(e,t)};q(p,e=>{H(d).replace&&e(m)});var h=R(p,2),g=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).upload),K(i,` ${H(d).upload===1?`isn’t`:`aren’t`} on your server yet — uploaded.`)}),G(e,t)};q(h,e=>{H(d).upload&&e(g)});var _=R(h,2),b=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).conflict),K(i,` ${H(d).conflict===1?`differs`:`differ`} from your server — both versions kept.`)}),G(e,t)};q(_,e=>{H(d).conflict&&e(b)}),O(c);var x=R(c,2),S=e=>{var t=gv(),n=I(t);O(t),z(e=>K(n,`Upload size: ${e??``}`),[()=>l(H(d).uploadBytes)]),G(e,t)};q(x,e=>{H(d).uploadBytes&&e(S)});var C=R(x,2),w=I(C),ee=R(w,2);O(C),O(n),O(t),z(()=>{K(o,H(i)),K(s,`. ${Jp.name??``} can keep them where they are instead of downloading everything again.`)}),U(`click`,w,y),U(`click`,ee,v),G(e,t)};q(He,e=>{H(d)&&e(Ue)}),z((e,t,n)=>{K(se,e),K(le,H(r).user),K(ue,t),Z(fe,`title`,H(i)),K(pe,H(i)),K(he,`${n??``} free`),ge.disabled=H(s),ye=Y(ve,1,`opt svelte-1wxc8fs`,null,ye,{sel:H(o)===`everything`}),be.disabled=H(s),De=Y(Ee,1,`opt svelte-1wxc8fs`,null,De,{sel:H(o)===`choose`}),Oe.disabled=H(s),Ae=Y(ke,1,`opt svelte-1wxc8fs`,null,Ae,{sel:H(o)===`ondemand`,off:!H(r).onDemandSupport}),je.disabled=H(s)||!H(r).onDemandSupport,Fe.disabled=H(s),Ie.disabled=H(s)||!H(i),K(Le,H(s)?`Setting up…`:`Connect`)},[()=>(H(r).user||`?`).charAt(0).toUpperCase(),()=>H(r).server.replace(/^https?:\/\//,``),()=>l(H(a))]),U(`click`,ge,u),Di(n,[],be,()=>H(o),e=>P(o,e)),Di(n,[],Oe,()=>H(o),e=>P(o,e)),Di(n,[],je,()=>H(o),e=>P(o,e)),U(`click`,Fe,b),U(`click`,Ie,g),G(e,t)},le=e=>{G(e,yv())};q(se,e=>{H(r)?e(ce):e(le,-1)}),O(oe),G(e,oe),Ye()}jr([`click`,`change`]);var Sv=W(`
Sign in again
`,1),Cv=W(`
Sign in to Nextcloud
`,1),wv=W(``),Tv=W(`
`),Ev=W(``),Dv=W(`
`);function Ov(e,t){Je(t,!0);let n=`Enter your Nextcloud server address to begin.`,r=N(``),i=N(n),a=N(!1),o=N(`signin`),s=N(null),c=N(!1),l=M(()=>!!H(s)&&!H(c));async function u(){let e=await Bd();P(s,e?.id?e:null,!0),P(c,!1),H(a)||(P(r,H(s)?H(s).server:``,!0),P(i,H(s)?``:n,!0))}u(),ns(`login:target`,u),ns(`login:error`,e=>{H(a)&&(P(i,`Sign-in failed: `+e.data),P(a,!1))}),ns(`login:done`,async e=>{if(P(a,!1),e.data===!0){P(i,`Signed in again.`),await Il();return}await $l(),P(o,`setup`)});async function d(){if(!H(r).trim())return;P(a,!0),P(i,`Connecting…`);let e=await Tl(H(r));if(e.startsWith(`error:`)){P(i,`Sign-in failed: `+e.slice(6).trim()),P(a,!1);return}P(i,`Finish signing in in the browser that just opened. This window steps aside until you have.`)}function f(){P(a,!1),P(i,H(l)?``:n,!0)}function p(){zd(),P(c,!0),P(r,``),P(i,n)}var m=Vr(),h=L(m),g=e=>{xv(e,{done:()=>Il()})},_=e=>{var t=Dv(),n=I(t),o=e=>{var t=Sv(),n=R(L(t),2),r=I(n,!0);O(n);var i=R(n,2),o=I(i);O(i);var c=R(i,2);z(()=>{K(r,H(s).address),K(o,`${Jp.name??``} can't sign in to this account any more, for example because its access was
removed in Nextcloud. Sign in again and it carries on where it left off: your folders and
settings are kept, and nothing needs setting up again.`),c.disabled=H(a)}),U(`click`,c,d),G(e,t)},c=e=>{var t=Cv(),n=R(L(t),2);X(n);var i=R(n,2);z(()=>{n.disabled=H(a),i.disabled=H(a)}),U(`keydown`,n,e=>e.key===`Enter`&&d()),Ti(n,()=>H(r),e=>P(r,e)),U(`click`,i,d),G(e,t)};q(n,e=>{H(l)&&H(s)?e(o):e(c,-1)});var u=R(n,2),m=e=>{var t=wv();U(`click`,t,f),G(e,t)};q(u,e=>{H(a)&&e(m)});var h=R(u,2),g=e=>{var t=Tv(),n=I(t,!0);O(t),z(()=>K(n,H(i))),G(e,t)};q(h,e=>{H(i)&&e(g)});var _=R(h,2),v=e=>{var t=Ev();U(`click`,t,p),G(e,t)};q(_,e=>{H(l)&&!H(a)&&e(v)}),O(t),G(e,t)};q(h,e=>{H(o)===`setup`?e(g):e(_,-1)}),G(e,m),Ye()}jr([`click`,`keydown`]);var kv=W(`
`),Av=W(`
Not shared yet.
`),jv=W(`
`),Mv=W(`
`),Nv=W(`
`),Pv=W(`
Sharing
Shares
Create public link
Share with a user
`);function Fv(e,t){Je(t,!0);let n=N(``),r=N(F([])),i=N(``),a=N(!1),o=N(``),s=N(``),c=N(``),l=N(!1),u=N(``),d=N(!1);async function f(){P(n,await jd(),!0),P(r,await Ad()??[],!0)}f(),ns(`share:target`,()=>{P(i,``),P(o,``),f()});let p=e=>e.replace(/\/+$/,``).split(`/`).pop()||e,m=e=>(e&2)!=0,h=e=>e===3;async function g(e){P(i,``),P(a,!0);let t=await e();return P(a,!1),t?(P(i,t,!0),!1):(await f(),!0)}async function _(){await g(()=>Vl(H(s).trim(),H(c).trim(),H(l)))&&(P(s,``),P(c,``),P(l,!1))}async function v(){await g(()=>Hl(H(u),H(d)))&&(P(u,``),P(d,!1))}let y=e=>g(()=>Gl(e));async function b(e,t){await Bl(e),P(o,t,!0),setTimeout(()=>{H(o)===t&&P(o,``)},1500)}let x=e=>Iu(e);var S=Pv(),C=I(S),w=R(I(C),2),ee=I(w);O(w);var te=R(w,2),ne=I(te);O(te),O(C);var re=R(C,2),ie=I(re),ae=e=>{var t=kv(),n=I(t,!0);O(t),z(()=>K(n,H(i))),G(e,t)};q(ie,e=>{H(i)&&e(ae)});var oe=R(ie,4),se=e=>{G(e,Av())},ce=e=>{var t=Vr();J(L(t),17,()=>H(r),Yr,(e,t)=>{var n=Nv(),r=I(n),i=I(r),s=I(i),c=e=>{G(e,Br(`🔗 Public link`))},l=M(()=>h(H(t).type)),u=e=>{var n=Br();z(()=>K(n,`👤 ${H(t).shareWith??``}`)),G(e,n)};q(s,e=>{H(l)?e(c):e(u,-1)}),O(i);var d=R(i,2),f=I(d,!0);O(d);var p=R(d,2);O(r);var g=R(r,2),_=e=>{var n=jv(),r=I(n);X(r);var i=R(r,2),a=I(i,!0);O(i);var s=R(i,2);O(n),z(()=>{bi(r,H(t).url),K(a,H(o)===H(t).id?`Copied!`:`Copy`)}),U(`click`,i,()=>b(H(t).url,H(t).id)),U(`click`,s,()=>x(H(t).url)),G(e,n)},v=M(()=>h(H(t).type)&&H(t).url);q(g,e=>{H(v)&&e(_)});var S=R(g,2),C=e=>{var n=Mv(),r=I(n);O(n),z(e=>K(r,`Expires ${e??``}`),[()=>H(t).expiration.slice(0,10)]),G(e,n)};q(S,e=>{H(t).expiration&&e(C)}),O(n),z(e=>{K(f,e),p.disabled=H(a)},[()=>m(H(t).permissions)?`Can edit`:`View only`]),U(`click`,p,()=>y(H(t).id)),G(e,n)}),G(e,t)};q(oe,e=>{H(r).length===0?e(se):e(ce,-1)});var le=R(oe,4),T=I(le),ue=R(I(T));X(ue),O(T);var de=R(T,2),fe=R(I(de));X(fe),O(de);var pe=R(de,2),me=I(pe);X(me),k(),O(pe);var he=R(pe,2);O(le);var ge=R(le,4),_e=I(ge),ve=R(I(_e));X(ve),O(_e);var ye=R(_e,2),be=I(ye);X(be),k(),O(ye);var xe=R(ye,2);O(ge),O(re),O(S),z(e=>{Z(w,`title`,H(n)),K(ee,`📄 ${e??``}`),K(ne,`/${H(n)??``}`),he.disabled=H(a),xe.disabled=H(a)},[()=>p(H(n))]),Ti(ue,()=>H(s),e=>P(s,e)),Ti(fe,()=>H(c),e=>P(c,e)),Oi(me,()=>H(l),e=>P(l,e)),U(`click`,he,_),U(`keydown`,ve,e=>e.key===`Enter`&&v()),Ti(ve,()=>H(u),e=>P(u,e)),Oi(be,()=>H(d),e=>P(d,e)),U(`click`,xe,v),G(e,S),Ye()}jr([`click`,`keydown`]);var Iv=W(`
`),Lv=W(`
Loading…
`),Rv=W(`
No previous versions. Nextcloud keeps versions as a file changes over time.
`),zv=W(`
`),Bv=W(`
Restoring makes that version the current file (the present copy is kept as a version too).
Files appear instantly but download only when you open them.
- Anything you add or change syncs back to your server as usual.
`),cv=W(`
`),lv=W(`
Checking your files…
folders checked so far
`),uv=W(`
Loading…
`),dv=W(`
No folders here.
`),fv=W(`
`),pv=W(``),mv=W(`
Download these first
Tick the folders you need straight away. They download before everything else, and the rest follows.
`),hv=W(`
`),gv=W(`
`),_v=W(`
Keep the files already in this folder?
There are already files in
`),vv=W(`
↔
📁
Local Folder
`,1),yv=W(`
Loading account…
`),bv=W(``);function xv(e,t){Je(t,!0);let n=[],r=N(null),i=N(``),a=N(0),o=N(`everything`),s=N(!1),c=N(``);(async()=>{P(r,await lu(),!0),P(i,H(r).defaultDir,!0),P(a,H(r).freeBytes,!0),!H(r).onDemandSupport&&H(o)===`ondemand`&&P(o,`everything`)})();function l(e){if(!e||e<0)return`—`;let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r0))} ${t[r]}`}async function u(){let e=await Vu(H(i));e&&(P(i,e,!0),P(a,await tu(e),!0))}let d=N(null),f=N(!1),p=N(0),m=!1,h=null;async function g(){P(s,!0),P(c,``),H(o)===`ondemand`&&(P(f,!0),m=!1,P(p,0),h=setInterval(async()=>{P(p,(await Yl())?.adoptScanDirs||0,!0)},1500));let e=H(o)===`everything`&&H(x).length?`everything:`+JSON.stringify(H(x)):H(o),n=await Ll(H(i),e);if(h&&=(clearInterval(h),null),P(f,!1),P(s,!1),m){m=!1;return}if(n){if(H(o)===`ondemand`&&n.startsWith(`{`))try{let e=JSON.parse(n);if(e.error){P(c,e.error,!0);return}P(d,e,!0);return}catch{}P(c,n,!0);return}H(o)===`choose`&&await Mu(),t.done()}async function _(){m=!0,P(f,!1),await Dd(`ondemand-cancel`)}async function v(){P(d,null),P(s,!0);let e=await Dd(`ondemand-adopt`);if(P(s,!1),e){P(c,e,!0);return}t.done()}async function y(){P(d,null),await Dd(`ondemand-cancel`)}function b(){t.done()}let x=N(F([])),S=N(!1),C=N(``),w=N(F([])),ee=N(!1);async function te(e){P(C,e.replace(/^\/+|\/+$/g,``),!0),P(ee,!0),P(w,(await jl(H(C))??[]).filter(e=>e.isDir),!0),P(ee,!1)}function ne(){P(S,!0),te(``)}function re(){H(C)&&te(H(C).split(`/`).slice(0,-1).join(`/`))}function ie(e){P(x,H(x).includes(e)?H(x).filter(t=>t!==e):[...H(x),e],!0)}let ae=M(()=>H(x).length<=3?H(x).join(`, `):`${H(x).slice(0,3).join(`, `)} and ${H(x).length-3} more`);var oe=bv(),se=I(oe),ce=e=>{var t=vv(),m=L(t),h=I(m),oe=I(h),se=I(oe,!0);O(oe);var ce=R(oe,2),le=I(ce,!0);O(ce);var T=R(ce,2),ue=I(T,!0);O(T),O(h);var de=R(h,4),fe=R(I(de),4),pe=I(fe,!0);O(fe);var me=R(fe,2),he=I(me);O(me);var ge=R(me,2);O(de),O(m);var _e=R(m,2),ve=I(_e);let ye;var be=I(ve);X(be),be.value=be.__value=`everything`;var xe=R(be,2),Se=R(I(xe)),Ce=e=>{var t=rv(),n=I(t);O(t),z(e=>K(n,`(${e??``})`),[()=>l(H(r).accountBytes)]),G(e,t)};q(Se,e=>{H(r).accountBytes>0&&e(Ce)}),O(xe),O(ve);var we=R(ve,2),Te=e=>{var t=ov(),n=I(t),r=e=>{var t=iv(),n=L(t),r=R(I(n)),i=I(r,!0);O(r),O(n);var a=R(n,2);z(e=>{Z(n,`title`,e),K(i,H(ae)),a.disabled=H(s)},[()=>H(x).join(`, `)]),U(`click`,a,ne),G(e,t)},i=e=>{var t=av();z(()=>t.disabled=H(s)),U(`click`,t,ne),G(e,t)};q(n,e=>{H(x).length?e(r):e(i,-1)}),O(t),G(e,t)};q(we,e=>{H(o)===`everything`&&e(Te)});var Ee=R(we,2);let De;var Oe=I(Ee);X(Oe),Oe.value=Oe.__value=`choose`,k(2),O(Ee);var ke=R(Ee,2);let Ae;var je=I(ke);X(je),je.value=je.__value=`ondemand`,k(2),O(ke);var E=R(ke,2),Me=e=>{G(e,sv())};q(E,e=>{H(o)===`ondemand`&&e(Me)}),O(_e);var D=R(_e,2),Ne=e=>{var t=cv(),n=I(t,!0);O(t),z(()=>K(n,H(c))),G(e,t)};q(D,e=>{H(c)&&e(Ne)});var Pe=R(D,2),Fe=I(Pe),Ie=R(Fe,2),Le=I(Ie,!0);O(Ie),O(Pe);var Re=R(Pe,2),ze=e=>{var t=lv(),n=I(t),r=R(I(n),2),i=I(r);O(r);var a=R(r,2),o=I(a),s=I(o,!0);O(o),k(),O(a);var c=R(a,2),l=I(c);O(c),O(n),O(t),z(()=>{K(i,`${Jp.name??``} is comparing everything in this folder with your server before setting up. On a large account this can take several minutes. Nothing is changed until you confirm.`),K(s,H(p))}),U(`click`,l,_),G(e,t)};q(Re,e=>{H(f)&&e(ze)});var Be=R(Re,2),Ve=e=>{var t=mv(),n=I(t),r=R(I(n),4),i=I(r),a=R(i,2),o=I(a);O(a),O(r);var s=R(r,2),c=I(s),l=e=>{G(e,uv())},u=e=>{G(e,dv())};q(c,e=>{H(ee)?e(l):H(w).length===0&&e(u,1)}),J(R(c,2),17,()=>H(w),e=>e.path,(e,t)=>{var n=fv(),r=I(n);X(r);var i=R(r,2),a=I(i);O(i),O(n),z(e=>{xi(r,e),Z(i,`title`,`Open ${H(t).name??``}`),K(a,`📁 ${H(t).name??``}`)},[()=>H(x).includes(H(t).path)]),U(`change`,r,()=>ie(H(t).path)),U(`click`,i,()=>te(H(t).path)),G(e,n)}),O(s);var d=R(s,2),f=I(d),p=I(f);O(f);var m=R(f,2),h=e=>{var t=pv();U(`click`,t,()=>P(x,[],!0)),G(e,t)};q(m,e=>{H(x).length&&e(h)});var g=R(m,2);O(d),O(n),O(t),z(()=>{i.disabled=!H(C),Z(a,`title`,`/`+H(C)),K(o,`/${H(C)??``}`),K(p,`${H(x).length??``} chosen`)}),U(`click`,i,re),U(`click`,g,()=>P(S,!1)),G(e,t)};q(Be,e=>{H(S)&&e(Ve)});var He=R(Be,2),Ue=e=>{var t=_v(),n=I(t),r=R(I(n),2),a=R(I(r)),o=I(a,!0);O(a);var s=R(a);O(r);var c=R(r,2),u=I(c),f=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).keep),K(i,` already ${H(d).keep===1?`matches`:`match`} your server — kept on this PC.`)}),G(e,t)};q(u,e=>{H(d).keep&&e(f)});var p=R(u,2),m=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).replace),K(i,` ${H(d).replace===1?`is an online-only leftover`:`are online-only leftovers`} from another app — replaced with ${H(d).replace===1?`a ${Jp.name} placeholder`:`${Jp.name} placeholders`}.`)}),G(e,t)};q(p,e=>{H(d).replace&&e(m)});var h=R(p,2),g=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).upload),K(i,` ${H(d).upload===1?`isn’t`:`aren’t`} on your server yet — uploaded.`)}),G(e,t)};q(h,e=>{H(d).upload&&e(g)});var _=R(h,2),b=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).conflict),K(i,` ${H(d).conflict===1?`differs`:`differ`} from your server — both versions kept.`)}),G(e,t)};q(_,e=>{H(d).conflict&&e(b)}),O(c);var x=R(c,2),S=e=>{var t=gv(),n=I(t);O(t),z(e=>K(n,`Upload size: ${e??``}`),[()=>l(H(d).uploadBytes)]),G(e,t)};q(x,e=>{H(d).uploadBytes&&e(S)});var C=R(x,2),w=I(C),ee=R(w,2);O(C),O(n),O(t),z(()=>{K(o,H(i)),K(s,`. ${Jp.name??``} can keep them where they are instead of downloading everything again.`)}),U(`click`,w,y),U(`click`,ee,v),G(e,t)};q(He,e=>{H(d)&&e(Ue)}),z((e,t,n)=>{K(se,e),K(le,H(r).user),K(ue,t),Z(fe,`title`,H(i)),K(pe,H(i)),K(he,`${n??``} free`),ge.disabled=H(s),ye=Y(ve,1,`opt svelte-1wxc8fs`,null,ye,{sel:H(o)===`everything`}),be.disabled=H(s),De=Y(Ee,1,`opt svelte-1wxc8fs`,null,De,{sel:H(o)===`choose`}),Oe.disabled=H(s),Ae=Y(ke,1,`opt svelte-1wxc8fs`,null,Ae,{sel:H(o)===`ondemand`,off:!H(r).onDemandSupport}),je.disabled=H(s)||!H(r).onDemandSupport,Fe.disabled=H(s),Ie.disabled=H(s)||!H(i),K(Le,H(s)?`Setting up…`:`Connect`)},[()=>(H(r).user||`?`).charAt(0).toUpperCase(),()=>H(r).server.replace(/^https?:\/\//,``),()=>l(H(a))]),U(`click`,ge,u),Di(n,[],be,()=>H(o),e=>P(o,e)),Di(n,[],Oe,()=>H(o),e=>P(o,e)),Di(n,[],je,()=>H(o),e=>P(o,e)),U(`click`,Fe,b),U(`click`,Ie,g),G(e,t)},le=e=>{G(e,yv())};q(se,e=>{H(r)?e(ce):e(le,-1)}),O(oe),G(e,oe),Ye()}jr([`click`,`change`]);var Sv=W(`
Sign in again
`,1),Cv=W(`
Sign in to Nextcloud
`,1),wv=W(``),Tv=W(`
`),Ev=W(``),Dv=W(`
`);function Ov(e,t){Je(t,!0);let n=`Enter your Nextcloud server address to begin.`,r=N(``),i=N(n),a=N(!1),o=N(`signin`),s=N(null),c=N(!1),l=M(()=>!!H(s)&&!H(c));async function u(){let e=await Bd();P(s,e?.id?e:null,!0),P(c,!1),H(a)||(P(r,H(s)?H(s).server:``,!0),P(i,H(s)?``:n,!0))}u(),ns(`login:target`,u),ns(`login:error`,e=>{H(a)&&(P(i,`Sign-in failed: `+e.data),P(a,!1))}),ns(`login:done`,async e=>{if(P(a,!1),e.data===!0){P(i,`Signed in again.`),await Il();return}await $l(),P(o,`setup`)});async function d(){if(!H(r).trim())return;P(a,!0),P(i,`Connecting…`);let e=await Tl(H(r));if(e.startsWith(`error:`)){P(i,e,!0),P(a,!1);return}P(i,`Finish signing in in the browser that just opened. This window steps aside until you have.`)}function f(){P(a,!1),P(i,H(l)?``:n,!0)}function p(){zd(),P(c,!0),P(r,``),P(i,n)}var m=Vr(),h=L(m),g=e=>{xv(e,{done:()=>Il()})},_=e=>{var t=Dv(),n=I(t),o=e=>{var t=Sv(),n=R(L(t),2),r=I(n,!0);O(n);var i=R(n,2),o=I(i);O(i);var c=R(i,2);z(()=>{K(r,H(s).address),K(o,`${Jp.name??``} can't sign in to this account any more, for example because its access was
+ Anything you add or change syncs back to your server as usual.`),cv=W(`
`),lv=W(`
Checking your files…
folders checked so far
`),uv=W(`
Loading…
`),dv=W(`
No folders here.
`),fv=W(`
`),pv=W(``),mv=W(`
Download these first
Tick the folders you need straight away. They download before everything else, and the rest follows.
`),hv=W(`
`),gv=W(`
`),_v=W(`
Keep the files already in this folder?
There are already files in
`),vv=W(`
↔
📁
Local Folder
`,1),yv=W(`
Loading account…
`),bv=W(``);function xv(e,t){Je(t,!0);let n=[],r=N(null),i=N(``),a=N(0),o=N(`everything`),s=N(!1),c=N(``);(async()=>{P(r,await lu(),!0),P(i,H(r).defaultDir,!0),P(a,H(r).freeBytes,!0),!H(r).onDemandSupport&&H(o)===`ondemand`&&P(o,`everything`)})();function l(e){if(!e||e<0)return`—`;let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r0))} ${t[r]}`}async function u(){let e=await Vu(H(i));e&&(P(i,e,!0),P(a,await tu(e),!0))}let d=N(null),f=N(!1),p=N(0),m=!1,h=null;async function g(){P(s,!0),P(c,``),H(o)===`ondemand`&&(P(f,!0),m=!1,P(p,0),h=setInterval(async()=>{P(p,(await Yl())?.adoptScanDirs||0,!0)},1500));let e=H(o)===`everything`&&H(x).length?`everything:`+JSON.stringify(H(x)):H(o),n=await Ll(H(i),e);if(h&&=(clearInterval(h),null),P(f,!1),P(s,!1),m){m=!1;return}if(n){if(H(o)===`ondemand`&&n.startsWith(`{`))try{let e=JSON.parse(n);if(e.error){P(c,e.error,!0);return}P(d,e,!0);return}catch{}P(c,n,!0);return}H(o)===`choose`&&await Mu(),t.done()}async function _(){m=!0,P(f,!1),await Dd(`ondemand-cancel`)}async function v(){P(d,null),P(s,!0);let e=await Dd(`ondemand-adopt`);if(P(s,!1),e){P(c,e,!0);return}t.done()}async function y(){P(d,null),await Dd(`ondemand-cancel`)}function b(){t.done()}let x=N(F([])),S=N(!1),C=N(``),w=N(F([])),ee=N(!1);async function te(e){P(C,e.replace(/^\/+|\/+$/g,``),!0),P(ee,!0),P(w,(await jl(H(C))??[]).filter(e=>e.isDir),!0),P(ee,!1)}function ne(){P(S,!0),te(``)}function re(){H(C)&&te(H(C).split(`/`).slice(0,-1).join(`/`))}function ie(e){P(x,H(x).includes(e)?H(x).filter(t=>t!==e):[...H(x),e],!0)}let ae=M(()=>H(x).length<=3?H(x).join(`, `):`${H(x).slice(0,3).join(`, `)} and ${H(x).length-3} more`);var oe=bv(),se=I(oe),ce=e=>{var t=vv(),m=L(t),h=I(m),oe=I(h),se=I(oe,!0);O(oe);var ce=R(oe,2),le=I(ce,!0);O(ce);var T=R(ce,2),ue=I(T,!0);O(T),O(h);var de=R(h,4),fe=R(I(de),4),pe=I(fe,!0);O(fe);var me=R(fe,2),he=I(me);O(me);var ge=R(me,2);O(de),O(m);var _e=R(m,2),ve=I(_e);let ye;var be=I(ve);X(be),be.value=be.__value=`everything`;var xe=R(be,2),Se=R(I(xe)),Ce=e=>{var t=rv(),n=I(t);O(t),z(e=>K(n,`(${e??``})`),[()=>l(H(r).accountBytes)]),G(e,t)};q(Se,e=>{H(r).accountBytes>0&&e(Ce)}),O(xe),O(ve);var we=R(ve,2),Te=e=>{var t=ov(),n=I(t),r=e=>{var t=iv(),n=L(t),r=R(I(n)),i=I(r,!0);O(r),O(n);var a=R(n,2);z(e=>{Z(n,`title`,e),K(i,H(ae)),a.disabled=H(s)},[()=>H(x).join(`, `)]),U(`click`,a,ne),G(e,t)},i=e=>{var t=av();z(()=>t.disabled=H(s)),U(`click`,t,ne),G(e,t)};q(n,e=>{H(x).length?e(r):e(i,-1)}),O(t),G(e,t)};q(we,e=>{H(o)===`everything`&&e(Te)});var Ee=R(we,2);let De;var Oe=I(Ee);X(Oe),Oe.value=Oe.__value=`choose`,k(2),O(Ee);var ke=R(Ee,2);let Ae;var je=I(ke);X(je),je.value=je.__value=`ondemand`,k(2),O(ke);var E=R(ke,2),Me=e=>{G(e,sv())};q(E,e=>{H(o)===`ondemand`&&e(Me)}),O(_e);var D=R(_e,2),Ne=e=>{var t=cv(),n=I(t,!0);O(t),z(()=>K(n,H(c))),G(e,t)};q(D,e=>{H(c)&&e(Ne)});var Pe=R(D,2),Fe=I(Pe),Ie=R(Fe,2),Le=I(Ie,!0);O(Ie),O(Pe);var Re=R(Pe,2),ze=e=>{var t=lv(),n=I(t),r=R(I(n),2),i=I(r);O(r);var a=R(r,2),o=I(a),s=I(o,!0);O(o),k(),O(a);var c=R(a,2),l=I(c);O(c),O(n),O(t),z(()=>{K(i,`${Jp.name??``} is comparing everything in this folder with your server before setting up. On a large account this can take several minutes. Nothing is changed until you confirm.`),K(s,H(p))}),U(`click`,l,_),G(e,t)};q(Re,e=>{H(f)&&e(ze)});var Be=R(Re,2),Ve=e=>{var t=mv(),n=I(t),r=R(I(n),4),i=I(r),a=R(i,2),o=I(a);O(a),O(r);var s=R(r,2),c=I(s),l=e=>{G(e,uv())},u=e=>{G(e,dv())};q(c,e=>{H(ee)?e(l):H(w).length===0&&e(u,1)}),J(R(c,2),17,()=>H(w),e=>e.path,(e,t)=>{var n=fv(),r=I(n);X(r);var i=R(r,2),a=I(i);O(i),O(n),z(e=>{xi(r,e),Z(i,`title`,`Open ${H(t).name??``}`),K(a,`📁 ${H(t).name??``}`)},[()=>H(x).includes(H(t).path)]),U(`change`,r,()=>ie(H(t).path)),U(`click`,i,()=>te(H(t).path)),G(e,n)}),O(s);var d=R(s,2),f=I(d),p=I(f);O(f);var m=R(f,2),h=e=>{var t=pv();U(`click`,t,()=>P(x,[],!0)),G(e,t)};q(m,e=>{H(x).length&&e(h)});var g=R(m,2);O(d),O(n),O(t),z(()=>{i.disabled=!H(C),Z(a,`title`,`/`+H(C)),K(o,`/${H(C)??``}`),K(p,`${H(x).length??``} chosen`)}),U(`click`,i,re),U(`click`,g,()=>P(S,!1)),G(e,t)};q(Be,e=>{H(S)&&e(Ve)});var He=R(Be,2),Ue=e=>{var t=_v(),n=I(t),r=R(I(n),2),a=R(I(r)),o=I(a,!0);O(a);var s=R(a);O(r);var c=R(r,2),u=I(c),f=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).keep),K(i,` already ${H(d).keep===1?`matches`:`match`} your server — kept on this PC.`)}),G(e,t)};q(u,e=>{H(d).keep&&e(f)});var p=R(u,2),m=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).replace),K(i,` ${H(d).replace===1?`is an online-only leftover`:`are online-only leftovers`} from another app — replaced with ${H(d).replace===1?`a ${Jp.name} placeholder`:`${Jp.name} placeholders`}.`)}),G(e,t)};q(p,e=>{H(d).replace&&e(m)});var h=R(p,2),g=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).upload),K(i,` ${H(d).upload===1?`isn’t`:`aren’t`} on your server yet — uploaded.`)}),G(e,t)};q(h,e=>{H(d).upload&&e(g)});var _=R(h,2),b=e=>{var t=hv(),n=I(t),r=I(n,!0);O(n);var i=R(n);O(t),z(()=>{K(r,H(d).conflict),K(i,` ${H(d).conflict===1?`differs`:`differ`} from your server — both versions kept.`)}),G(e,t)};q(_,e=>{H(d).conflict&&e(b)}),O(c);var x=R(c,2),S=e=>{var t=gv(),n=I(t);O(t),z(e=>K(n,`Upload size: ${e??``}`),[()=>l(H(d).uploadBytes)]),G(e,t)};q(x,e=>{H(d).uploadBytes&&e(S)});var C=R(x,2),w=I(C),ee=R(w,2);O(C),O(n),O(t),z(()=>{K(o,H(i)),K(s,`. ${Jp.name??``} can keep them where they are instead of downloading everything again.`)}),U(`click`,w,y),U(`click`,ee,v),G(e,t)};q(He,e=>{H(d)&&e(Ue)}),z((e,t,n)=>{K(se,e),K(le,H(r).user),K(ue,t),Z(fe,`title`,H(i)),K(pe,H(i)),K(he,`${n??``} free`),ge.disabled=H(s),ye=Y(ve,1,`opt svelte-1wxc8fs`,null,ye,{sel:H(o)===`everything`}),be.disabled=H(s),De=Y(Ee,1,`opt svelte-1wxc8fs`,null,De,{sel:H(o)===`choose`}),Oe.disabled=H(s),Ae=Y(ke,1,`opt svelte-1wxc8fs`,null,Ae,{sel:H(o)===`ondemand`,off:!H(r).onDemandSupport}),je.disabled=H(s)||!H(r).onDemandSupport,Fe.disabled=H(s),Ie.disabled=H(s)||!H(i),K(Le,H(s)?`Setting up…`:`Connect`)},[()=>(H(r).user||`?`).charAt(0).toUpperCase(),()=>H(r).server.replace(/^https?:\/\//,``),()=>l(H(a))]),U(`click`,ge,u),Di(n,[],be,()=>H(o),e=>P(o,e)),Di(n,[],Oe,()=>H(o),e=>P(o,e)),Di(n,[],je,()=>H(o),e=>P(o,e)),U(`click`,Fe,b),U(`click`,Ie,g),G(e,t)},le=e=>{G(e,yv())};q(se,e=>{H(r)?e(ce):e(le,-1)}),O(oe),G(e,oe),Ye()}jr([`click`,`change`]);var Sv=W(`
Sign in again
`,1),Cv=W(`
Sign in to Nextcloud
`,1),wv=W(``),Tv=W(`
`),Ev=W(``),Dv=W(`
`);function Ov(e,t){Je(t,!0);let n=`Enter your Nextcloud server address to begin.`,r=N(``),i=N(n),a=N(!1),o=N(`signin`),s=N(null),c=N(!1),l=M(()=>!!H(s)&&!H(c)),u=N(``),d=N(!1);async function f(){let e=await Bd();P(s,e?.id?e:null,!0),P(c,!1),H(a)||(P(r,H(s)?H(s).server:H(u),!0),P(i,H(s)?``:n,!0))}f(),(async()=>{let e=await Uu();e?.serverUrl&&(P(u,e.serverUrl,!0),P(d,e.lockServer,!0),!H(a)&&!H(s)&&(H(d)||!H(r))&&P(r,H(u),!0))})(),ns(`login:target`,f),ns(`login:error`,e=>{H(a)&&(P(i,`Sign-in failed: `+e.data),P(a,!1))}),ns(`login:done`,async e=>{if(P(a,!1),e.data===!0){P(i,`Signed in again.`),await Il();return}await $l(),P(o,`setup`)});async function p(){if(!H(r).trim())return;P(a,!0),P(i,`Connecting…`);let e=await Tl(H(r));if(e.startsWith(`error:`)){P(i,e,!0),P(a,!1);return}P(i,`Finish signing in in the browser that just opened. This window steps aside until you have.`)}function m(){P(a,!1),P(i,H(l)?``:n,!0)}function h(){zd(),P(c,!0),P(r,H(u),!0),P(i,n)}var g=Vr(),_=L(g),v=e=>{xv(e,{done:()=>Il()})},y=e=>{var t=Dv(),n=I(t),o=e=>{var t=Sv(),n=R(L(t),2),r=I(n,!0);O(n);var i=R(n,2),o=I(i);O(i);var c=R(i,2);z(()=>{K(r,H(s).address),K(o,`${Jp.name??``} can't sign in to this account any more, for example because its access was
removed in Nextcloud. Sign in again and it carries on where it left off: your folders and
- settings are kept, and nothing needs setting up again.`),c.disabled=H(a)}),U(`click`,c,d),G(e,t)},c=e=>{var t=Cv(),n=R(L(t),2);X(n);var i=R(n,2);z(()=>{n.disabled=H(a),i.disabled=H(a)}),U(`keydown`,n,e=>e.key===`Enter`&&d()),Ti(n,()=>H(r),e=>P(r,e)),U(`click`,i,d),G(e,t)};q(n,e=>{H(l)&&H(s)?e(o):e(c,-1)});var u=R(n,2),m=e=>{var t=wv();U(`click`,t,f),G(e,t)};q(u,e=>{H(a)&&e(m)});var h=R(u,2),g=e=>{var t=Tv(),n=I(t,!0);O(t),z(()=>K(n,H(i))),G(e,t)};q(h,e=>{H(i)&&e(g)});var _=R(h,2),v=e=>{var t=Ev();U(`click`,t,p),G(e,t)};q(_,e=>{H(l)&&!H(a)&&e(v)}),O(t),G(e,t)};q(h,e=>{H(o)===`setup`?e(g):e(_,-1)}),G(e,m),Ye()}jr([`click`,`keydown`]);var kv=W(`
`),Av=W(`
Not shared yet.
`),jv=W(`
`),Mv=W(`
`),Nv=W(`
`),Pv=W(`
Sharing
Shares
Create public link
Share with a user
`);function Fv(e,t){Je(t,!0);let n=N(``),r=N(F([])),i=N(``),a=N(!1),o=N(``),s=N(``),c=N(``),l=N(!1),u=N(``),d=N(!1);async function f(){P(n,await jd(),!0),P(r,await Ad()??[],!0)}f(),ns(`share:target`,()=>{P(i,``),P(o,``),f()});let p=e=>e.replace(/\/+$/,``).split(`/`).pop()||e,m=e=>(e&2)!=0,h=e=>e===3;async function g(e){P(i,``),P(a,!0);let t=await e();return P(a,!1),t?(P(i,t,!0),!1):(await f(),!0)}async function _(){await g(()=>Vl(H(s).trim(),H(c).trim(),H(l)))&&(P(s,``),P(c,``),P(l,!1))}async function v(){await g(()=>Hl(H(u),H(d)))&&(P(u,``),P(d,!1))}let y=e=>g(()=>Gl(e));async function b(e,t){await Bl(e),P(o,t,!0),setTimeout(()=>{H(o)===t&&P(o,``)},1500)}let x=e=>Iu(e);var S=Pv(),C=I(S),w=R(I(C),2),ee=I(w);O(w);var te=R(w,2),ne=I(te);O(te),O(C);var re=R(C,2),ie=I(re),ae=e=>{var t=kv(),n=I(t,!0);O(t),z(()=>K(n,H(i))),G(e,t)};q(ie,e=>{H(i)&&e(ae)});var oe=R(ie,4),se=e=>{G(e,Av())},ce=e=>{var t=Vr();J(L(t),17,()=>H(r),Yr,(e,t)=>{var n=Nv(),r=I(n),i=I(r),s=I(i),c=e=>{G(e,Br(`🔗 Public link`))},l=M(()=>h(H(t).type)),u=e=>{var n=Br();z(()=>K(n,`👤 ${H(t).shareWith??``}`)),G(e,n)};q(s,e=>{H(l)?e(c):e(u,-1)}),O(i);var d=R(i,2),f=I(d,!0);O(d);var p=R(d,2);O(r);var g=R(r,2),_=e=>{var n=jv(),r=I(n);X(r);var i=R(r,2),a=I(i,!0);O(i);var s=R(i,2);O(n),z(()=>{bi(r,H(t).url),K(a,H(o)===H(t).id?`Copied!`:`Copy`)}),U(`click`,i,()=>b(H(t).url,H(t).id)),U(`click`,s,()=>x(H(t).url)),G(e,n)},v=M(()=>h(H(t).type)&&H(t).url);q(g,e=>{H(v)&&e(_)});var S=R(g,2),C=e=>{var n=Mv(),r=I(n);O(n),z(e=>K(r,`Expires ${e??``}`),[()=>H(t).expiration.slice(0,10)]),G(e,n)};q(S,e=>{H(t).expiration&&e(C)}),O(n),z(e=>{K(f,e),p.disabled=H(a)},[()=>m(H(t).permissions)?`Can edit`:`View only`]),U(`click`,p,()=>y(H(t).id)),G(e,n)}),G(e,t)};q(oe,e=>{H(r).length===0?e(se):e(ce,-1)});var le=R(oe,4),T=I(le),ue=R(I(T));X(ue),O(T);var de=R(T,2),fe=R(I(de));X(fe),O(de);var pe=R(de,2),me=I(pe);X(me),k(),O(pe);var he=R(pe,2);O(le);var ge=R(le,4),_e=I(ge),ve=R(I(_e));X(ve),O(_e);var ye=R(_e,2),be=I(ye);X(be),k(),O(ye);var xe=R(ye,2);O(ge),O(re),O(S),z(e=>{Z(w,`title`,H(n)),K(ee,`📄 ${e??``}`),K(ne,`/${H(n)??``}`),he.disabled=H(a),xe.disabled=H(a)},[()=>p(H(n))]),Ti(ue,()=>H(s),e=>P(s,e)),Ti(fe,()=>H(c),e=>P(c,e)),Oi(me,()=>H(l),e=>P(l,e)),U(`click`,he,_),U(`keydown`,ve,e=>e.key===`Enter`&&v()),Ti(ve,()=>H(u),e=>P(u,e)),Oi(be,()=>H(d),e=>P(d,e)),U(`click`,xe,v),G(e,S),Ye()}jr([`click`,`keydown`]);var Iv=W(`
`),Lv=W(`
Loading…
`),Rv=W(`
No previous versions. Nextcloud keeps versions as a file changes over time.
`),zv=W(`
`),Bv=W(`
Restoring makes that version the current file (the present copy is kept as a version too).
`);function $v(e,t){Je(t,!0);let n=N(``),r=N(null),i=N(null);Dn(()=>{let e=Yp.current;e&&(P(n,e.value,!0),queueMicrotask(()=>{e.kind===`text`&&H(i)?(H(i).focus(),H(i).select()):H(r)?.focus()}))});function a(){let e=Yp.current;e&&Qp(e.kind===`ask`?!0:e.kind===`text`?H(n):void 0)}function o(){let e=Yp.current;e&&Qp(e.kind===`ask`?!1:e.kind===`text`?null:void 0)}function s(e){Yp.current&&(e.key===`Escape`?(e.preventDefault(),o()):e.key===`Enter`&&Yp.current.kind===`text`&&(e.preventDefault(),a()))}var c=Vr();Ar(`keydown`,on,s);var l=L(c),u=e=>{let t=M(()=>Yp.current);var s=Qv(),c=I(s),l=I(c),u=I(l,!0);O(l);var d=R(l,2),f=e=>{var n=Yv(),r=I(n,!0);O(n),z(()=>K(r,H(t).message)),G(e,n)};q(d,e=>{H(t).message&&e(f)});var p=R(d,2),m=e=>{var t=Xv();X(t),Ni(t,e=>P(i,e),()=>H(i)),Ti(t,()=>H(n),e=>P(n,e)),G(e,t)};q(p,e=>{H(t).kind===`text`&&e(m)});var h=R(p,2),g=I(h),_=e=>{var n=Zv(),r=I(n,!0);O(n),z(()=>K(r,H(t).cancel)),U(`click`,n,o),G(e,n)};q(g,e=>{H(t).kind!==`tell`&&e(_)});var v=R(g,2);let y;var b=I(v,!0);O(v),Ni(v,e=>P(r,e),()=>H(r)),O(h),O(c),O(s),z(()=>{K(u,H(t).title),y=Y(v,1,`primary svelte-11qie5r`,null,y,{danger:H(t).danger}),K(b,H(t).ok)}),U(`click`,v,a),G(e,s)};q(l,e=>{Yp.current&&e(u)}),G(e,c),Ye()}jr([`click`]);var ey=W(` `,1);function ty(e,t){Je(t,!0);let n=N(F(window.location.hash.replace(`#`,``)));window.addEventListener(`hashchange`,()=>{P(n,window.location.hash.replace(`#`,``),!0)});let r=window.matchMedia(`(prefers-color-scheme: dark)`),i=`system`,a=``;function o(){let e;e=i===`dark`?!0:i===`light`?!1:a===`dark`?!0:a===`light`?!1:r.matches,e?document.documentElement.setAttribute(`data-theme`,`dark`):document.documentElement.removeAttribute(`data-theme`)}r.addEventListener(`change`,o),ns(`theme`,e=>{i=e.data||`system`,o()}),(async()=>{i=await du(),o()})();let s=0;async function c(){let e=++s;for(let t=0;t<12&&e===s;t++){let e=await wu();if(e){a=e,o();return}await new Promise(e=>setTimeout(e,1e3))}}c();function l(e,t){let n=e.replace(`#`,``);return n.length===6?`#`+[0,2,4].map(e=>Math.max(0,Math.round(parseInt(n.slice(e,e+2),16)*t))).map(e=>e.toString(16).padStart(2,`0`)).join(``):e}function u(e){let t=document.documentElement;e&&/^#[0-9a-fA-F]{6}$/.test(e)?(t.style.setProperty(`--accent`,e),t.style.setProperty(`--accent-dark`,l(e,.88))):(t.style.removeProperty(`--accent`),t.style.removeProperty(`--accent-dark`))}ns(`accent`,e=>{u(e.data||``),c()}),(async()=>{for(let e=0;e<12;e++){try{let e=await qd();if(e&&/^#[0-9a-fA-F]{6}$/.test(e)){u(e);return}}catch{}await new Promise(e=>setTimeout(e,1e3))}})();var d=ey(),f=L(d),p=e=>{Jv(e,{})},m=M(()=>H(n).startsWith(`appsplash`)),h=e=>{yh(e,{})},g=e=>{nv(e,{})},_=M(()=>H(n).startsWith(`settings`)),v=e=>{Ov(e,{})},y=e=>{Fv(e,{})},b=e=>{Hv(e,{})},x=e=>{Wv(e,{})},S=e=>{qp(e,{})};q(f,e=>{H(m)?e(p):H(n)===`status`?e(h,1):H(_)?e(g,2):H(n)===`login`?e(v,3):H(n)===`share`?e(y,4):H(n)===`versions`?e(b,5):H(n)===`logs`?e(x,6):e(S,-1)}),$v(R(f,2),{}),G(e,d),Ye()}Hr(ty,{target:document.getElementById(`app`)});
\ No newline at end of file
diff --git a/cmd/nimbo-gui/frontend/dist/index.html b/cmd/nimbo-gui/frontend/dist/index.html
index 570dd7f..de0cefb 100644
--- a/cmd/nimbo-gui/frontend/dist/index.html
+++ b/cmd/nimbo-gui/frontend/dist/index.html
@@ -6,7 +6,7 @@
Wails + Svelte + TS
-
+
diff --git a/cmd/nimbo-gui/frontend/src/Login.svelte b/cmd/nimbo-gui/frontend/src/Login.svelte
index 23cb077..c7fb315 100644
--- a/cmd/nimbo-gui/frontend/src/Login.svelte
+++ b/cmd/nimbo-gui/frontend/src/Login.svelte
@@ -18,16 +18,29 @@
let different = $state(false);
const again = $derived(!!target && !different);
+ // A server preset (admin policy, or a partner build's brand.json) fills the
+ // address in; a locked one also stops it being changed, since sign-in goes
+ // to that server whatever is typed (Deck d1010).
+ let preset = $state("");
+ let locked = $state(false);
+
async function loadTarget() {
const t = await App.SignInTarget();
target = t?.id ? t : null;
different = false;
if (!busy) {
- server = target ? target.server : "";
+ server = target ? target.server : preset;
msg = target ? "" : startMsg;
}
}
loadTarget();
+ (async () => {
+ const p = await App.PolicyInfo();
+ if (!p?.serverUrl) return;
+ preset = p.serverUrl;
+ locked = p.lockServer;
+ if (!busy && !target && (locked || !server)) server = preset;
+ })();
Events.On("login:target", loadTarget);
Events.On("login:error", (e: any) => { if (!busy) return; msg = "Sign-in failed: " + e.data; busy = false; });
@@ -65,7 +78,7 @@
function signInSomeoneElse() {
App.SignInSomeoneElse(); // the grant may now be for any account
different = true;
- server = "";
+ server = preset;
msg = startMsg;
}
@@ -83,7 +96,8 @@
{:else}
Sign in to Nextcloud
- e.key === "Enter" && login()} />
{/if}
diff --git a/cmd/nimbo-gui/service.go b/cmd/nimbo-gui/service.go
index 81cd1eb..4b1d2ae 100644
--- a/cmd/nimbo-gui/service.go
+++ b/cmd/nimbo-gui/service.go
@@ -778,14 +778,29 @@ func (a *App) refreshLicence() {
if info.Allows(license.TierBusiness) {
pol = policy.Load() // admin policy is a business-tier capability
}
+ pol = withBrandServer(pol, brand.Current)
a.licMu.Lock()
a.lic = info
a.pol = pol
a.licMu.Unlock()
}
+// withBrandServer adds a partner build's baked-in server preset and lock to
+// the policy (Deck d1010). It needs no licence: the partner paid for the build.
+// An admin policy's own server address wins over the brand's; a lock from
+// either side holds.
+func withBrandServer(p policy.Policy, b brand.Brand) policy.Policy {
+ if p.ServerURL == "" {
+ p.ServerURL = b.ServerURL
+ }
+ if b.LockServer && p.ServerURL != "" {
+ p.LockServer = true
+ }
+ return p
+}
+
// policyNow returns the effective admin policy (empty/permissive unless a
-// business licence is active).
+// business licence is active), plus a partner build's server lock.
func (a *App) policyNow() policy.Policy {
a.licMu.Lock()
defer a.licMu.Unlock()
diff --git a/internal/brand/brand.go b/internal/brand/brand.go
index ab3fc88..d1a3133 100644
--- a/internal/brand/brand.go
+++ b/internal/brand/brand.go
@@ -11,6 +11,7 @@ import (
"encoding/json"
"fmt"
"log/slog"
+ "net/url"
"strings"
)
@@ -31,6 +32,12 @@ type Brand struct {
APIBase string `json:"apiBase"` // GitHub releases API root for the update check
AccentHex string `json:"accentHex"` // brand accent (tray badge, UI accent fallback)
AppID string `json:"appId"` // MSIX Application Id (AUMID) + self-update task name + the config/data dir name (slugged)
+ // ServerURL presets the Nextcloud server the sign-in window offers, and
+ // LockServer pins sign-in to it, the same lock the HKLM admin policy gives
+ // but baked into a partner build, so it needs no licence key or registry
+ // step on a client's PC (Deck d1010). Both are empty in the stock build.
+ ServerURL string `json:"serverUrl,omitempty"`
+ LockServer bool `json:"lockServer,omitempty"`
}
// Current is the active brand for this build.
@@ -66,14 +73,37 @@ func (b Brand) Validate() error {
return nil
}
+// ValidateServer checks the server preset: an https address with a host, and
+// a lock only together with one. build-partner.ps1 refuses a brand that fails
+// it, so a broken one should never ship.
+func (b Brand) ValidateServer() error {
+ if b.ServerURL == "" {
+ if b.LockServer {
+ return fmt.Errorf("brand.json: lockServer is set but serverUrl is empty")
+ }
+ return nil
+ }
+ u, err := url.Parse(b.ServerURL)
+ if err != nil || u.Scheme != "https" || u.Host == "" {
+ return fmt.Errorf("brand.json: serverUrl %q must be an https:// address", b.ServerURL)
+ }
+ return nil
+}
+
// sanitize drops a former name that fails Validate, so such a build runs as a
// brand that was never renamed: its own Start-menu folder and labels, no
-// rename notice.
+// rename notice. A server preset that fails ValidateServer is dropped with its
+// lock: a lock to an unusable address would leave nobody able to sign in.
func sanitize(b Brand) Brand {
if err := b.Validate(); err != nil {
slog.Error("ignoring formerName", "err", err)
b.FormerName = ""
}
+ if err := b.ValidateServer(); err != nil {
+ slog.Error("ignoring serverUrl and lockServer", "err", err)
+ b.ServerURL, b.LockServer = "", false
+ }
+ b.ServerURL = strings.TrimRight(b.ServerURL, "/")
return b
}
diff --git a/internal/brand/brand_test.go b/internal/brand/brand_test.go
index 7779dee..e26df95 100644
--- a/internal/brand/brand_test.go
+++ b/internal/brand/brand_test.go
@@ -104,6 +104,38 @@ func TestValidateFormerName(t *testing.T) {
}
}
+func TestValidateServer(t *testing.T) {
+ for _, c := range []struct {
+ b Brand
+ ok bool
+ }{
+ {Brand{}, true},
+ {Brand{ServerURL: "https://cloud.acme.example"}, true},
+ {Brand{ServerURL: "https://acme.example/nextcloud", LockServer: true}, true},
+ {Brand{LockServer: true}, false},
+ {Brand{ServerURL: "http://cloud.acme.example", LockServer: true}, false},
+ {Brand{ServerURL: "cloud.acme.example"}, false},
+ } {
+ if err := c.b.ValidateServer(); (err == nil) != c.ok {
+ t.Errorf("%+v: ValidateServer() = %v, want ok=%v", c.b, err, c.ok)
+ }
+ }
+}
+
+// A lock to an unusable address is dropped with its address, not kept; a good
+// preset loses only a trailing slash.
+func TestSanitizeServer(t *testing.T) {
+ if b := sanitize(Brand{Name: "Acme", ServerURL: "http://x.example", LockServer: true}); b.ServerURL != "" || b.LockServer {
+ t.Errorf("bad preset kept: %+v", b)
+ }
+ if b := sanitize(Brand{Name: "Acme", ServerURL: "https://x.example/", LockServer: true}); b.ServerURL != "https://x.example" || !b.LockServer {
+ t.Errorf("good preset changed: %+v", b)
+ }
+ if s := stockBrand(); s.ServerURL != "" || s.LockServer {
+ t.Errorf("stock brand must not preset a server: %+v", s)
+ }
+}
+
// A brand that fails the check runs as never renamed rather than wearing the
// stock build's former name.
func TestSanitizeDropsBadFormerName(t *testing.T) {
diff --git a/packaging/whitelabel/README.md b/packaging/whitelabel/README.md
index 1a7d797..a2499a4 100644
--- a/packaging/whitelabel/README.md
+++ b/packaging/whitelabel/README.md
@@ -45,6 +45,8 @@ user-visible identity value:
| `feedUrl`, `apiBase` | the in-app update check + "Update now" target — point these at the partner's OWN release feed |
| `accentHex` | brand accent — **drives the app icon** (tile + cloud, auto-derived), plus the tray badge and UI accent fallback |
| `appId` | the MSIX Application Id used in the AUMID and the self-update task name — must match the manifest's `` |
+| `serverUrl` | optional: the partner's Nextcloud (`https://…`, a subfolder is fine). The sign-in window fills it in |
+| `lockServer` | optional, needs `serverUrl`: sign-in always goes to `serverUrl` and the address can't be changed. The same lock as the `ServerURL`/`LockServer` admin policy, but baked in, so it needs no business licence or registry step on each PC (for a partner's clients). If an admin policy on the PC also sets a server, the policy's address wins. `build-partner.ps1` refuses a lock without an https `serverUrl` |
| `formerName` | **Stock only: leave it out for partners.** The stock build's name before the rename to OtherSync ("Nimbo"). It keeps what existing stock installs made under the old name (the "Nimbo Apps" Start-menu folder, the `%LOCALAPPDATA%\Nimbo` sidebar icon folder, "Nimbo - " sidebar labels) and triggers the one-time "Nimbo is now OtherSync" notice. A partner brand carrying it would share those with stock and tell its users "Nimbo is now ". `build-partner.ps1` refuses a partner `brand.json` that sets it, unless `partner.json` has `"renamedFrom"` equal to it (a partner that really renamed its own product) |
## Steps to build a branded copy
diff --git a/packaging/whitelabel/build-partner.ps1 b/packaging/whitelabel/build-partner.ps1
index cce2226..d6dcaf1 100644
--- a/packaging/whitelabel/build-partner.ps1
+++ b/packaging/whitelabel/build-partner.ps1
@@ -46,6 +46,15 @@ $formerName = (Get-Content $brandSrc -Raw | ConvertFrom-Json).formerName
if ($formerName -and $formerName -ne $cfg.renamedFrom) {
throw "brand.json sets formerName '$formerName', which is the stock build's. Remove it from the partner's brand.json, or, if this partner really renamed its product from '$formerName', add `"renamedFrom`": `"$formerName`" to partner.json."
}
+# serverUrl / lockServer: the app drops a preset it can't use (and its lock),
+# which would ship a partner build that signs in anywhere. Refuse it here.
+$brandCfg = Get-Content $brandSrc -Raw | ConvertFrom-Json
+if ($brandCfg.lockServer -and -not $brandCfg.serverUrl) {
+ throw "brand.json sets lockServer but no serverUrl."
+}
+if ($brandCfg.serverUrl -and $brandCfg.serverUrl -notmatch '^https://[^/\s]+') {
+ throw "brand.json serverUrl '$($brandCfg.serverUrl)' must be an https:// address."
+}
# Make Go + windres reachable even if not on PATH.
function Ensure-Tool($exe, $candidates) {