From 8f07308342bb79d91ff1a949879fbde52acbeec4 Mon Sep 17 00:00:00 2001 From: Anna Claire Fields <58918237+franklovefrank@users.noreply.github.com> Date: Tue, 16 Jun 2026 14:18:28 +0200 Subject: [PATCH] Acf pnp migration master (#34040) GitOrigin-RevId: 418eab9bc733f27a6e0f8f04a2a8e21c2f5a491f --- .../patches/esmock-npm-2.7.3-83624b28f6.patch | 9 + .yarnrc.yml | 67 +- dockerfiles/cypress/Dockerfile | 1 - libraries/access-token-encryptor/package.json | 6 + libraries/fetch-utils/package.json | 2 + libraries/logger/package.json | 6 + libraries/metrics/package.json | 3 + libraries/mongo-utils/package.json | 6 + libraries/o-error/package.json | 1 + libraries/object-persistor/package.json | 6 + libraries/overleaf-editor-core/package.json | 8 + libraries/promise-utils/package.json | 2 + libraries/ranges-tracker/package.json | 3 + libraries/redis-wrapper/package.json | 2 + libraries/settings/Settings.js | 14 +- libraries/settings/package.json | 2 + libraries/stream-utils/package.json | 2 + libraries/validation-tools/package.json | 3 + package.json | 14 +- server-ce/Dockerfile | 9 +- server-ce/test/.gitignore | 1 + server-ce/test/Dockerfile | 1 - server-ce/test/cypress.config.ts | 5 +- server-ce/test/docker-compose.yml | 20 +- server-ce/test/package.json | 9 +- services/chat/Dockerfile | 5 +- services/chat/Makefile | 8 +- services/chat/docker-compose.yml | 12 +- services/chat/package.json | 2 + .../test/acceptance/js/helpers/MongoHelper.js | 2 +- services/clsi/Dockerfile | 15 +- services/clsi/Makefile | 8 +- services/clsi/docker-compose.yml | 12 +- services/clsi/package.json | 2 + services/docstore/Dockerfile | 5 +- services/docstore/Makefile | 8 +- services/docstore/docker-compose.yml | 12 +- services/docstore/package.json | 3 + .../test/acceptance/js/helpers/MongoHelper.js | 2 +- services/document-updater/Dockerfile | 5 +- services/document-updater/Makefile | 8 +- services/document-updater/docker-compose.yml | 12 +- services/document-updater/package.json | 5 + .../flush_projects_with_no_history_id.js | 5 +- .../test/acceptance/js/helpers/MongoHelper.js | 2 +- services/filestore/Dockerfile | 7 +- services/filestore/Makefile | 8 +- services/filestore/docker-compose.yml | 12 +- services/filestore/package.json | 2 + services/history-v1/Dockerfile | 5 +- services/history-v1/Makefile | 8 +- services/history-v1/docker-compose.yml | 12 +- services/history-v1/package.json | 6 + .../storage/scripts/back_fill_file_hash.mjs | 5 +- .../scripts/fix_string_backedUpBlobs_ids.mjs | 4 +- .../js/storage/back_fill_file_hash.test.mjs | 5 +- .../js/storage/recover_zip.test.mjs | 2 +- services/history-v1/test/setup.js | 2 +- services/notifications/Dockerfile | 5 +- services/notifications/Makefile | 8 +- services/notifications/docker-compose.yml | 12 +- services/notifications/package.json | 3 + .../test/acceptance/js/MongoHelper.ts | 2 +- services/project-history/Dockerfile | 11 +- services/project-history/Makefile | 10 +- services/project-history/buildscript.txt | 1 + services/project-history/docker-compose.yml | 12 +- services/project-history/package.json | 6 +- .../test/acceptance/js/helpers/MongoHelper.js | 2 +- services/real-time/Dockerfile | 5 +- services/real-time/Makefile | 8 +- services/real-time/docker-compose.yml | 12 +- services/real-time/package.json | 3 + services/web/.gitignore | 1 + services/web/.storybook/main.ts | 3 + services/web/Dockerfile | 1 - services/web/Makefile | 7 +- services/web/bin/check_extracted_translations | 2 +- services/web/cypress.config.ts | 5 +- services/web/docker-compose.yml | 31 +- services/web/package.json | 29 +- .../checkSanitize/checkSanitizeOptions.mjs | 2 +- .../scripts/materialize-cypress-reporter.js | 113 +++ services/web/test/acceptance/bootstrap.js | 12 + .../DeleteOrphanedDocsOnlineCheckTests.mjs | 3 +- .../acceptance/src/helpers/MongoHelper.mjs | 2 +- .../test/unit/src/Settings/Settings.test.mjs | 2 + services/web/tsconfig.json | 3 + services/web/types/uppy-utils.d.ts | 11 + services/web/webpack.config.js | 25 +- tools/migrations/package.json | 3 + tsconfig.backend.json | 1 + yarn.lock | 930 ++++++++++++++++-- 93 files changed, 1490 insertions(+), 209 deletions(-) create mode 100644 .yarn/patches/esmock-npm-2.7.3-83624b28f6.patch create mode 100644 services/web/scripts/materialize-cypress-reporter.js create mode 100644 services/web/types/uppy-utils.d.ts diff --git a/.yarn/patches/esmock-npm-2.7.3-83624b28f6.patch b/.yarn/patches/esmock-npm-2.7.3-83624b28f6.patch new file mode 100644 index 0000000000..a9004a1bbe --- /dev/null +++ b/.yarn/patches/esmock-npm-2.7.3-83624b28f6.patch @@ -0,0 +1,9 @@ +diff --git a/src/esmock.js b/src/esmock.js +index 964b5a2c70ae730c0495871395ec65ad0d8bdf3e..73189c2c93d4c154a6c9cd5a1734cd874d2ae162 100644 +--- a/src/esmock.js ++++ b/src/esmock.js +@@ -1,3 +1,3 @@ + var Ye=Object.defineProperty;var et=(e,t)=>{for(var s in t)Ye(e,s,{get:t[s],enumerable:!0})};import Xe from"node:module";var v={};et(v,{default:()=>C,getSource:()=>St,globalPreload:()=>ht,initialize:()=>bt,load:()=>ue,resolve:()=>It});import ct from"node:fs";import ne from"node:module";import nt from"process";var tt=(e,t)=>new Error(`invalid moduleId: "${e}" (used by ${t})`),st=(e,t)=>new Error(`un-mocked moduleId: "${e}" (used by ${t})`),ot=()=>new Error("For versions of node prior to v20.6.0, the loader chain process must include esmock. start the process using --loader=esmock."),rt=(e,t)=>new Error(`no mocks provided for module: "${e}" (used by ${t})`),f={errModuleIdNotFound:tt,errModuleIdNotMocked:st,errMissingLoader:ot,errModuleIdNoDefs:rt};var[Y,it]=nt.versions.node.split(".").map(e=>+e),ie=Y<16||Y===16&&it<12,g=import.meta.url,at=/\?esmkgdefs=.*/,ae=/.*\?esmkgdefs=/,R=/#-#esmkdefs/,ee=/^file:\/\/\/import\?/,lt=/file:\/\/\/import\?([^#]*)/,pt=/\bimport,|,import\b|\bimport\b/g,O=/esmkTreeId=\d*/,ut=/esmkModuleId=([^&]*)/,te=/\?esmk=\d*/,I=/.*exportNames=(.*)/,mt=/.*#-#/,dt=/isesm=true/,ft=/isfound=false/,gt=/^(commonjs|module)$/,kt=/strict=3/,se=/^(#![^\n]*\n)/,yt=e=>e.indexOf("+")>=0?e.replace(/(?!\\)\+/g,"\\+"):e,oe=(e,t)=>new RegExp(`.*(${yt(e)}(\\?${t}(?:(?!#-#).)*)).*`),E=global.mockKeys=global.mockKeys||{},S=global.mockKeysSource=global.mockKeysSource||{};var ht=!ne.register&&(({port:e})=>(e.addEventListener("message",t=>t.data.keysource?S[t.data.keysource]=t.data.source:E[t.data.key]=t.data.keylong),e.unref(),"global.postMessageEsmk = d => port.postMessage(d)")),bt=ne.register&&(e=>{e&&e.port&&e.port.on("message",t=>{t.keysource?S[t.keysource]=t.source:E[t.key]=t.keylong})}),re=e=>{let[t,s]=e.match(lt)||[];return[t,I.test(s)&&s.replace(I,"$1").split(",")]},jt=e=>{let t=e.split(R)[1]||"",s=re(t),o=e.replace(ae,""),r=re(o);return[s[0]||r[0],[...new Set([s[1]||[],r[1]||[]].flat())]]},le=e=>te.test(e)&&E[e.match(te)[0].split("=")[1]],ce=async(e,t,s)=>s.parentURL&&(s.conditions.slice(-1)[0]==="node-addons"||s.importAssertions||ie)?e(t,s):e(t),It=async(e,t,s)=>{let{parentURL:o}=t,r=le(o)||o;if(!O.test(r))return ce(s,e,t);let[c]=String(r).match(O),[n,l]=r.split(R),a=n&&n.replace(ae,"");if(r.includes(`esmkModuleId=${e}&isfound=false`)){let b=oe(`file:///${e}`,c),j=(a.match(b)||l.match(b)||[])[2];if(j)return{shortCircuit:!0,url:g+j}}if(ee.test(e))return{shortCircuit:!0,url:e.replace(ee,g+"?")};let u=await ce(s,e,t),m=oe(u.url,c),d=m.test(l)&&l.replace(m,"$1")||m.test(a)&&a.replace(m,"$1");if(d?u.url=dt.test(d)?d:g+"#-#"+d:a&&a!=="0"&&(u.url.startsWith("node:")||(u.url+="?esmkgdefs="+a)),kt.test(r)&&!d)throw f.errModuleIdNotMocked(u.url,r.split("?")[0]);return u},pe=g+"?esmock-loader=true",C=(e=>async()=>e=e||(await import(pe)).default===!0)(),ue=async(e,t,s)=>{if(e===pe)return{format:"module",shortCircuit:!0,responseURL:e,source:"export default true"};let o=le(e)||e,r=o&&(o.match(O)||[])[0];if(r){let[n,l]=jt(o);if(l&&l.length){let a=await s(e,t);if(!gt.test(a.format))return a;let u=a.source===null||a.source===void 0,m=String(u?ct.readFileSync(new URL(e)):a.source),d=(m.match(se)||[])[0]||"",b=d?m.replace(se,""):m,j=a.format==="commonjs"?`const {${l}} = global.esmockCacheGet("${n}");`:`import {${l}} from '${n}';`;return{format:a.format,shortCircuit:!0,responseURL:encodeURI(e),source:d+j+b}}}if(R.test(e))return s(e,t);e=e.replace(at,""),e.startsWith(g)&&(e=e.replace(mt,""),ft.test(e)&&(e=e.replace(g,`file:///${e.match(ut)[1]}`)));let c=I.test(e)&&e.replace(I,"$1").replace(pt,"").split(",");return c&&c[0]?S[e]?{format:"json",shortCircuit:!0,responseURL:encodeURI(e),source:S[e]}:{format:"module",shortCircuit:!0,responseURL:encodeURI(e),source:c.map(n=>n==="default"?`export default global.esmockCacheGet("${e}").default`:`export const ${n} = global.esmockCacheGet("${e}").${n}`).join(` +-`)}:(r&&!e.includes(r)&&(e=e+"?esmk="+r.split("=")[1]),s(e,t))},St=ie&&ue;import Ve from"fs";import Qt from"url";import ye from"fs";import he from"url";import i from"path";import be from"module";var je=be.createRequire(import.meta.url),me=ye.realpathSync.native,Ie=new RegExp("^(?:node:)?("+be.builtinModules.join("|").replace("/","/")+")$"),G=/^\.?\.?([a-zA-Z]:)?(\/|\\)/,W=/^.\.?(?=\/|\\)/,de=/\\/g,Mt=/index.[tj]sx?$/,wt=/[\\/]resolvewithplus[\\/]/,fe=/\.js$/,$t=/\.ts$/,xt=/(^@[^/]*\/[^/]*|^[^/]*)\/?(.*)$/,F=/^#/,Se=/(\*)/g,Me=/([./])/g,Ot=/^node:/,Rt=/^file:/,we=[".js",".mjs",".ts",".tsx",".json",".node"],Et=we.map(e=>`index${e}`),ge="node_modules",w="package.json",$e="node",M="default",Ct="browser",xe="import",P=":spectype",Oe="module",Re="import",Ee="commonjs",vt="require",K=".",z=e=>e&&typeof e=="object",A={},T=e=>({[Oe]:Re,[Ee]:vt})[e]||null,Kt=e=>Ot.test(e)?e:`node:${e}`,Nt=e=>e&&he.pathToFileURL(e).href,Ft=e=>Ie.test(e),Pt=e=>Rt.test(e)?he.fileURLToPath(e):e,At=e=>i.resolve(i.extname(e)?i.dirname(e):e)+i.sep,D=e=>de.test(e)?e.replace(de,i.posix.sep):e,k=(e,t)=>{try{t=ye.statSync(e)}catch{t=!1}return t&&(t.isFile()||t.isFIFO())},Ce=(e,t)=>t.packagejsonmap&&t.packagejsonmap[e]||k(e)&&je(e),Tt=(e,t)=>{let s=t.find(o=>k(e+o))||null;return s&&e+s},Dt=(e,t)=>{let s=t.find(o=>k(i.join(e,o)))||null;return s&&i.join(e,s)},ve=(e,t=e.split(i.sep))=>{let s=(o,r=[[],[]])=>{if(!o.length)return r[1];if(o[0]===ge&&wt.test(e))return s(o.slice(1),r);let c=r[0].length?i.join(r[0].slice(-1)[0],o[0]):o[0]||i.sep;return r[0].push(c),r[1].push(i.resolve(i.join(c,ge))),s(o.slice(1),r)};return s(t)},Gt=e=>{let t=e.split(i.sep).slice(1).reduce((s,o,r)=>(s.push(i.resolve(i.join(r?s[r-1]:i.sep,o))),s),[]).reverse().find(s=>k(i.join(s,w)));return t&&i.join(t,w)},Wt=e=>(String(e).match(xt)||[]).slice(1),ke=(e,t)=>new RegExp("^"+e.replace(Me,"\\$1").replace(Se,".*")+"$").test(t),zt=(e,t,s)=>{let o=new RegExp(e.replace(Me,"\\$1").replace(Se,"(.*)")),r=(s.match(o)||[])[1];return r&&t.replace("*",r)},Ut=(e,t,s)=>{let o=t.indexOf("*")||0,r=t.slice(0,o),c=t.slice(o+1);if(!(e.startsWith(r)&&e.endsWith(c)))return null;let n=e.slice(-c.length).slice(r.length);return s.replace("*",n)},Ke=(e,t,s,o,r=!1)=>{if(ke(e,s))if(String(t).includes("*"))ke(t,s)?r=s:e.includes("*")&&e!==t&&(r=zt(e,t,s));else{if(z(t)&&e.includes("*")){let c=Object.keys(t).reduce((n,l)=>(n[l]=Ut(s,e,t[l]),n),{});return p(c,s,o)}r=r||t}return r},Ne=(e,t,s,o,r=e[0])=>e.length?(F.test(s)?F.test(r):W.test(r))&&(typeof t[r]=="string"||z(t[r]))&&Ke(r,t[r],s,o)||Ne(e.slice(1),t,s,o):null,p=(e,t,s={})=>{let o=s.priority||[$e,M],r=!1;return typeof e=="string"?e:(!r&&Array.isArray(e)&&(r=e.reduce((c,n)=>c||p(n,t,s),null)),!r&&z(e)&&(typeof e[t]=="string"&&(r=e[t]),r||(r=o.reduce((c,n)=>c||(n=n===P?G.test(t)?T(s.packagejsontype):t:n,p(e[n],t,s)),!1)),!r&&e[M]&&(r=p(e[M],t)),!r&&e[t]&&(r=p(e[t],t,s)),r||(r=Ne(Object.keys(e),e,t,s)),!r&&e[K]&&(o.includes(t)?r=o.reduce((c,n)=>c||(n=n===P?T(s.packagejsontype):n,p(e[K],n,s)),!1):r=p(e[K],t,s))),r)},$=(e,t={})=>{var s=null,o=t.istypescript&&fe.test(e)&&e.replace(fe,".ts");return k(o)?s=o:k(e)?s=e:s=Tt(e,we),s},U=e=>e.type||"exports"in e&&Oe||Ee,N=(e,t={},s="")=>{let o=s?i.join(s,e):e;return $(o,t)||!Mt.test(e)&&$(i.join(o,"index"))},Bt=(e,t={},s="",o=!1)=>{let r=U(e);return t.isspectype!==!1&&(o=e[r]||e[T(r)],o=o&&N(o,t,s)),!o&&(t.priority||[]).includes(Re)&&e.module&&(o=N(e.module,t,s)),!o&&e.main&&(o=N(e.main,t,s)),o||null},Fe=(e,t={},s="",o)=>{let r=U(e),c=Object.assign({packagejsontype:r},t);return t.isbrowser&&e.browser&&(o=p(e.browser,xe,c),o=o&&!G.test(o)?i.join(s,o):o),o||(o=Bt(e,c,s)),o},Pe=(e,t)=>{let s=i.join(e,w),o=Ce(s,t);return(o?Fe(o,t,e):!1)||Dt(e,Et)},Ae=(e,t,s)=>{let o=W.test(e)?i.join(t,e):e;return $(o,s)||Pe(o,s)},Jt=(e,t,s,o)=>{let r=s&&s.imports,c=p(r,t,o);return c&&(W.test(c)?i.join(e,c):De(c,e,{isposixpath:!0}))},_t=(e,t,s,o,r)=>{let c=p(o&&o.exports,s?"./"+s:xe,r);return c&&i.join(e,t,c)},qt=(e,t,s,o)=>{let r=i.join(e,t,w),c=Ce(r,o),n=c&&U(c);return c&&_t(e,t,s,c,Object.assign({packagejsontype:n},o))},Vt=(e,t,s)=>{let o=Gt(t),r=i.dirname(o);return o&&Jt(r,e,je(o),s)},Zt=(e,t,s)=>{let[o,r]=Wt(e);if(F.test(o))return Vt(e,t,s);let c=ve(t);return(function n(l,a){return a--?qt(i.join(l[a]),o,r,s)||Ae(i.join(l[a],e),null,s)||n(c,a):null})(c,c.length)},Ht=(e,t,s)=>{var o=null;return t=typeof t=="string"?At(Pt(decodeURI(t))):process.cwd(),Ie.test(e)?o=Kt(e):(o=G.test(e)?Ae(D(e),t,s):Zt(e,t,s),o=o&&(s.isposixpath?me(o):Nt(D(me(o))))),o},Te=(e,t,s)=>{let o=(r,c)=>typeof r=="boolean"?r:c;return s=s||{},s.istypescript=o(s.istypescript,$t.test(t)),s.isbrowser=o(s.isbrowser,!1),s.isspectype=o(s.isspectype,!0),s.packagejsonmap=s.packagejsonmap||null,Array.isArray(s.priority)||(s.priority=s.isbrowser?[Ct]:[],s.priority.push(P),s.priority.push($e),s.priority.push(M)),s},De=(e,t,s)=>{let o=A[e+t];return o||(s=Te(e,t,s),o=Ht(e,t,s),A[e+t]=o)},x=Object.assign(De,{pathToPosix:D,getasnode_module_paths:ve,getesmkeyvalmatch:Ke,getasfilesync:$,getasdirsync:Pe,gettargetindex:Fe,iscoremodule:Ft,createopts:Te,esmparse:p,cache:A});var Ge=/(^\s*|[});\n]\s*)(import\s+(['"]|(\*\s+as\s+)?[^"'()\n;]+\s+from\s+['"]|\{)|export\s+\*\s+from\s+["']|export\s+(\{|default|function|class|var|const|let|async\s+function))/;import We from"node:module";import ze from"node:worker_threads";var B=ze.MessageChannel&&new ze.MessageChannel,Ue=(e=>()=>(typeof e=="boolean"||(e=!!We.register)&&We.register("./esmockLoader.js",{parentURL:import.meta.url,data:{port:B.port2},transferList:[B.port2]}),e))(),J=Object.assign(e=>{Ue()?B.port1.postMessage(e):typeof global.postMessageEsmk=="function"&&global.postMessageEsmk(e)},{register:Ue});var _={isESM:{},mockDefs:{}},Be=(e,t)=>(J({keysource:e,source:t}),global.mockKeysSource[String(e)]=t);var Je=(e,t)=>(J({key:e,keylong:t}),global.mockKeys[String(e)]=t),q=e=>global.mockKeys[String(e)],V=(e,t)=>global.esmockCache.mockDefs[e]=t,Lt=e=>global.esmockCache.mockDefs[e],_e=e=>_.isESM[e],qe=(e,t)=>_.isESM[e]=t;Object.assign(global,{esmockCache:_,esmockCacheGet:Lt,esmockTreeIdGet:q,mockKeys:global.mockKeys||{},mockKeysSource:global.mockKeysSource||{}});var Z=e=>typeof e=="object"&&e,H=e=>Z(e)&&"default"in e,Xt=/^\.?\.?([a-zA-Z]:)?(\/|\\)/,Yt=((e=0)=>()=>++e)(),es=Object.getPrototypeOf({}),ts=e=>Object.getPrototypeOf(e)===es,Ze=x.iscoremodule,Q=/\.json$/i,ss=/(^|,)(static|module\.exports)($|,)/g,os=(e,t)=>ts(e)?Object.assign({},e,t):Object.assign(Object.keys(e).reduce((s,o)=>(Object.defineProperty(s,o,{value:e[o],writable:!0}),s),Object.create(e)),t),rs=(e,t)=>Z(e)&&Z(t)?os(e,t):t,cs=(e,t,s)=>s===null||Q.test(s)?Object.assign({},e||{},t):Array.isArray(t)?{default:t.slice()}:(t=Object.assign({},e||{},{default:rs(H(e)&&e.default,H(t)?t.default:t)},t),!Ze(s)&&Object.isExtensible(t.default)&&(t.default.default=t.default),t),ns=(e,t)=>(t=_e(e),typeof t=="boolean"||(t=!Ze(e)&&Xt.test(e)&&Ge.test(Ve.readFileSync(e,"utf-8")),qe(e,t)),t),is=(e,t)=>{let s=H(e)&&e.default;return/boolean|string|number/.test(typeof s)?e:Object.isExtensible(s)?Object.assign(s,e,{esmkTreeId:t}):Object.assign({},s,e,{esmkTreeId:t})},as=e=>{let t=c=>c==="null"||V(c,null),s=q(e.split("esmk=")[1]),[o,r]=s.split("#-#esmkdefs=");String(r).split("#-#").forEach(t),String(o.split("esmkgdefs=")[1]).split("#-#").forEach(t)},ls=async e=>Q.test(e)?JSON.parse(Ve.readFileSync(new Qt.URL(e),"utf-8")):import(e),ps=async(e,t,s,o,r)=>{t=cs(r.strict||!o||await ls(o),t,o);let c=(o||"file:///"+s)+"?"+["esmkTreeId="+e,"esmkModuleId="+s,"isfound="+!!o,"isesm="+ns(o),"exportNames="+Object.keys(t).sort().join().replace(ss,n=>n.startsWith(",")&&n.endsWith(",")?",":"")].join("&");return Q.test(o)&&Be(c,JSON.stringify(t)),V(c,t),c},L=async(e,t,s,o,r,c,n)=>{if(o=o||Object.keys(s),n=o[0],c=c||[],!n)return c;let l=r.resolver(n,e);if(!l&&r.isModuleNotFoundError!==!1&&n!=="import")throw f.errModuleIdNotFound(n,e);return c.push(await ps(t,s[n],n,l,r)),L(e,t,s,o.slice(1),r,c)},us=async(e,t,s,o,r)=>{let c=r.resolver(e,t);if(!c)throw f.errModuleIdNotFound(e,t);let n=o?Object.keys(o):[],l=s?Object.keys(s):[];if(r.strict===3&&!n.length&&!l.length)throw f.errModuleIdNoDefs(e,t);let a=typeof r.id=="number"?r.id:Yt(),u=`${c}?key=${a}&strict=${r.strict}?`+["esmkgdefs="+(n.length&&(await L(t,a,o,n,r)).join("#-#")||0),"esmkdefs=",l.length&&(await L(t,a,s,l,r)).join("#-#")||0].join("#-#");return Je(String(a),u),c+`?esmk=${a}`},h=Object.assign(us,{purge:as,sanitize:is});import{isBuiltin as ms}from"node:module";import{pathToFileURL as ds}from"node:url";var He=process.versions.pnp&&(await import("pnpapi")).default,Le=He&&((e,t)=>{if(ms(e))return e.startsWith("node:")?e:`node:${e}`;if(e==="import")return null;let s=null;try{s=He.resolveRequest(e,t)}catch{}return s!==null?ds(s).href:null});var fs=/^.*(\(|at )(.*):[\d]*:[\d]*.*$/,gs=Le||x,Qe=(e,t)=>(e=typeof e[1]=="string"?e:[e[0],new Error().stack.split(` ++`)}:(r&&!e.includes(r)&&(e=e+"?esmk="+r.split("=")[1]),s(e,t))},St=ie&&ue;import Ve from"fs";import Qt from"url";import ye from"fs";import he from"url";import i from"path";import be from"module";var je=be.createRequire(import.meta.url),me=ye.realpathSync.native,Ie=new RegExp("^(?:node:)?("+be.builtinModules.join("|").replace("/","/")+")$"),G=/^\.?\.?([a-zA-Z]:)?(\/|\\)/,W=/^.\.?(?=\/|\\)/,de=/\\/g,Mt=/index.[tj]sx?$/,wt=/[\\/]resolvewithplus[\\/]/,fe=/\.js$/,$t=/\.ts$/,xt=/(^@[^/]*\/[^/]*|^[^/]*)\/?(.*)$/,F=/^#/,Se=/(\*)/g,Me=/([./])/g,Ot=/^node:/,Rt=/^file:/,we=[".js",".mjs",".ts",".tsx",".json",".node"],Et=we.map(e=>`index${e}`),ge="node_modules",w="package.json",$e="node",M="default",Ct="browser",xe="import",P=":spectype",Oe="module",Re="import",Ee="commonjs",vt="require",K=".",z=e=>e&&typeof e=="object",A={},T=e=>({[Oe]:Re,[Ee]:vt})[e]||null,Kt=e=>Ot.test(e)?e:`node:${e}`,Nt=e=>e&&he.pathToFileURL(e).href,Ft=e=>Ie.test(e),Pt=e=>Rt.test(e)?he.fileURLToPath(e):e,At=e=>i.resolve(i.extname(e)?i.dirname(e):e)+i.sep,D=e=>de.test(e)?e.replace(de,i.posix.sep):e,k=(e,t)=>{try{t=ye.statSync(e)}catch{t=!1}return t&&(t.isFile()||t.isFIFO())},Ce=(e,t)=>t.packagejsonmap&&t.packagejsonmap[e]||k(e)&&je(e),Tt=(e,t)=>{let s=t.find(o=>k(e+o))||null;return s&&e+s},Dt=(e,t)=>{let s=t.find(o=>k(i.join(e,o)))||null;return s&&i.join(e,s)},ve=(e,t=e.split(i.sep))=>{let s=(o,r=[[],[]])=>{if(!o.length)return r[1];if(o[0]===ge&&wt.test(e))return s(o.slice(1),r);let c=r[0].length?i.join(r[0].slice(-1)[0],o[0]):o[0]||i.sep;return r[0].push(c),r[1].push(i.resolve(i.join(c,ge))),s(o.slice(1),r)};return s(t)},Gt=e=>{let t=e.split(i.sep).slice(1).reduce((s,o,r)=>(s.push(i.resolve(i.join(r?s[r-1]:i.sep,o))),s),[]).reverse().find(s=>k(i.join(s,w)));return t&&i.join(t,w)},Wt=e=>(String(e).match(xt)||[]).slice(1),ke=(e,t)=>new RegExp("^"+e.replace(Me,"\\$1").replace(Se,".*")+"$").test(t),zt=(e,t,s)=>{let o=new RegExp(e.replace(Me,"\\$1").replace(Se,"(.*)")),r=(s.match(o)||[])[1];return r&&t.replace("*",r)},Ut=(e,t,s)=>{let o=t.indexOf("*")||0,r=t.slice(0,o),c=t.slice(o+1);if(!(e.startsWith(r)&&e.endsWith(c)))return null;let n=e.slice(-c.length).slice(r.length);return s.replace("*",n)},Ke=(e,t,s,o,r=!1)=>{if(ke(e,s))if(String(t).includes("*"))ke(t,s)?r=s:e.includes("*")&&e!==t&&(r=zt(e,t,s));else{if(z(t)&&e.includes("*")){let c=Object.keys(t).reduce((n,l)=>(n[l]=Ut(s,e,t[l]),n),{});return p(c,s,o)}r=r||t}return r},Ne=(e,t,s,o,r=e[0])=>e.length?(F.test(s)?F.test(r):W.test(r))&&(typeof t[r]=="string"||z(t[r]))&&Ke(r,t[r],s,o)||Ne(e.slice(1),t,s,o):null,p=(e,t,s={})=>{let o=s.priority||[$e,M],r=!1;return typeof e=="string"?e:(!r&&Array.isArray(e)&&(r=e.reduce((c,n)=>c||p(n,t,s),null)),!r&&z(e)&&(typeof e[t]=="string"&&(r=e[t]),r||(r=o.reduce((c,n)=>c||(n=n===P?G.test(t)?T(s.packagejsontype):t:n,p(e[n],t,s)),!1)),!r&&e[M]&&(r=p(e[M],t)),!r&&e[t]&&(r=p(e[t],t,s)),r||(r=Ne(Object.keys(e),e,t,s)),!r&&e[K]&&(o.includes(t)?r=o.reduce((c,n)=>c||(n=n===P?T(s.packagejsontype):n,p(e[K],n,s)),!1):r=p(e[K],t,s))),r)},$=(e,t={})=>{var s=null,o=t.istypescript&&fe.test(e)&&e.replace(fe,".ts");return k(o)?s=o:k(e)?s=e:s=Tt(e,we),s},U=e=>e.type||"exports"in e&&Oe||Ee,N=(e,t={},s="")=>{let o=s?i.join(s,e):e;return $(o,t)||!Mt.test(e)&&$(i.join(o,"index"))},Bt=(e,t={},s="",o=!1)=>{let r=U(e);return t.isspectype!==!1&&(o=e[r]||e[T(r)],o=o&&N(o,t,s)),!o&&(t.priority||[]).includes(Re)&&e.module&&(o=N(e.module,t,s)),!o&&e.main&&(o=N(e.main,t,s)),o||null},Fe=(e,t={},s="",o)=>{let r=U(e),c=Object.assign({packagejsontype:r},t);return t.isbrowser&&e.browser&&(o=p(e.browser,xe,c),o=o&&!G.test(o)?i.join(s,o):o),o||(o=Bt(e,c,s)),o},Pe=(e,t)=>{let s=i.join(e,w),o=Ce(s,t);return(o?Fe(o,t,e):!1)||Dt(e,Et)},Ae=(e,t,s)=>{let o=W.test(e)?i.join(t,e):e;return $(o,s)||Pe(o,s)},Jt=(e,t,s,o)=>{let r=s&&s.imports,c=p(r,t,o);return c&&(W.test(c)?i.join(e,c):De(c,e,{isposixpath:!0}))},_t=(e,t,s,o,r)=>{let c=p(o&&o.exports,s?"./"+s:xe,r);return c&&i.join(e,t,c)},qt=(e,t,s,o)=>{let r=i.join(e,t,w),c=Ce(r,o),n=c&&U(c);return c&&_t(e,t,s,c,Object.assign({packagejsontype:n},o))},Vt=(e,t,s)=>{let o=Gt(t),r=i.dirname(o);return o&&Jt(r,e,je(o),s)},Zt=(e,t,s)=>{let[o,r]=Wt(e);if(F.test(o))return Vt(e,t,s);let c=ve(t);return(function n(l,a){return a--?qt(i.join(l[a]),o,r,s)||Ae(i.join(l[a],e),null,s)||n(c,a):null})(c,c.length)},Ht=(e,t,s)=>{var o=null;return t=typeof t=="string"?At(Pt(decodeURI(t))):process.cwd(),Ie.test(e)?o=Kt(e):(o=G.test(e)?Ae(D(e),t,s):Zt(e,t,s),o=o&&(s.isposixpath?me(o):Nt(D(me(o))))),o},Te=(e,t,s)=>{let o=(r,c)=>typeof r=="boolean"?r:c;return s=s||{},s.istypescript=o(s.istypescript,$t.test(t)),s.isbrowser=o(s.isbrowser,!1),s.isspectype=o(s.isspectype,!0),s.packagejsonmap=s.packagejsonmap||null,Array.isArray(s.priority)||(s.priority=s.isbrowser?[Ct]:[],s.priority.push(P),s.priority.push($e),s.priority.push(M)),s},De=(e,t,s)=>{let o=A[e+t];return o||(s=Te(e,t,s),o=Ht(e,t,s),A[e+t]=o)},x=Object.assign(De,{pathToPosix:D,getasnode_module_paths:ve,getesmkeyvalmatch:Ke,getasfilesync:$,getasdirsync:Pe,gettargetindex:Fe,iscoremodule:Ft,createopts:Te,esmparse:p,cache:A});var Ge=/(^\s*|[});\n]\s*)(import\s+(['"]|(\*\s+as\s+)?[^"'()\n;]+\s+from\s+['"]|\{)|export\s+\*\s+from\s+["']|export\s+(\{|default|function|class|var|const|let|async\s+function))/;import We from"node:module";import ze from"node:worker_threads";var B=ze.MessageChannel&&new ze.MessageChannel,Ue=(e=>()=>(typeof e=="boolean"||(e=!!We.register)&&We.register("./esmockLoader.js",{parentURL:import.meta.url,data:{port:B.port2},transferList:[B.port2]}),e))(),J=Object.assign(e=>{Ue()?B.port1.postMessage(e):typeof global.postMessageEsmk=="function"&&global.postMessageEsmk(e)},{register:Ue});var _={isESM:{},mockDefs:{}},Be=(e,t)=>(J({keysource:e,source:t}),global.mockKeysSource[String(e)]=t);var Je=(e,t)=>(J({key:e,keylong:t}),global.mockKeys[String(e)]=t),q=e=>global.mockKeys[String(e)],V=(e,t)=>global.esmockCache.mockDefs[e]=t,Lt=e=>global.esmockCache.mockDefs[e],_e=e=>_.isESM[e],qe=(e,t)=>_.isESM[e]=t;Object.assign(global,{esmockCache:_,esmockCacheGet:Lt,esmockTreeIdGet:q,mockKeys:global.mockKeys||{},mockKeysSource:global.mockKeysSource||{}});var Z=e=>typeof e=="object"&&e,H=e=>Z(e)&&"default"in e,Xt=/^\.?\.?([a-zA-Z]:)?(\/|\\)/,Yt=((e=0)=>()=>++e)(),es=Object.getPrototypeOf({}),ts=e=>Object.getPrototypeOf(e)===es,Ze=x.iscoremodule,Q=/\.json$/i,ss=/(^|,)(static|module\.exports)($|,)/g,os=(e,t)=>ts(e)?Object.assign({},e,t):Object.assign(Object.keys(e).reduce((s,o)=>(Object.defineProperty(s,o,{value:e[o],writable:!0}),s),Object.create(e)),t),rs=(e,t)=>Z(e)&&Z(t)?os(e,t):t,cs=(e,t,s)=>s===null||Q.test(s)?Object.assign({},e||{},t):Array.isArray(t)?{default:t.slice()}:(t=Object.assign({},e||{},{default:rs(H(e)&&e.default,H(t)?t.default:t)},t),!Ze(s)&&Object.isExtensible(t.default)&&(t.default.default=t.default),t),ns=(e,t)=>(t=_e(e),typeof t=="boolean"||(t=!Ze(e)&&Xt.test(e)&&Ge.test(Ve.readFileSync(e,"utf-8")),qe(e,t)),t),is=(e,t)=>{let s=H(e)&&e.default;return/boolean|string|number/.test(typeof s)?e:Object.isExtensible(s)?Object.assign(s,e,{esmkTreeId:t}):Object.assign({},s,e,{esmkTreeId:t})},as=e=>{let t=c=>c==="null"||V(c,null),s=q(e.split("esmk=")[1]),[o,r]=s.split("#-#esmkdefs=");String(r).split("#-#").forEach(t),String(o.split("esmkgdefs=")[1]).split("#-#").forEach(t)},ls=async e=>Q.test(e)?JSON.parse(Ve.readFileSync(new Qt.URL(e),"utf-8")):import(e),ps=async(e,t,s,o,r)=>{t=cs(r.strict||!o||await ls(o),t,o);let c=(o||"file:///"+s)+"?"+["esmkTreeId="+e,"esmkModuleId="+s,"isfound="+!!o,"isesm="+ns(o),"exportNames="+Object.keys(t).sort().join().replace(ss,n=>n.startsWith(",")&&n.endsWith(",")?",":"")].join("&");return Q.test(o)&&Be(c,JSON.stringify(t)),V(c,t),c},L=async(e,t,s,o,r,c,n)=>{if(o=o||Object.keys(s),n=o[0],c=c||[],!n)return c;let l=r.resolver(n,e);if(!l&&r.isModuleNotFoundError!==!1&&n!=="import")throw f.errModuleIdNotFound(n,e);return c.push(await ps(t,s[n],n,l,r)),L(e,t,s,o.slice(1),r,c)},us=async(e,t,s,o,r)=>{let c=r.resolver(e,t);if(!c)throw f.errModuleIdNotFound(e,t);let n=o?Object.keys(o):[],l=s?Object.keys(s):[];if(r.strict===3&&!n.length&&!l.length)throw f.errModuleIdNoDefs(e,t);let a=typeof r.id=="number"?r.id:Yt(),u=`${c}?key=${a}&strict=${r.strict}?`+["esmkgdefs="+(n.length&&(await L(t,a,o,n,r)).join("#-#")||0),"esmkdefs=",l.length&&(await L(t,a,s,l,r)).join("#-#")||0].join("#-#");return Je(String(a),u),c+`?esmk=${a}`},h=Object.assign(us,{purge:as,sanitize:is});import{isBuiltin as ms}from"node:module";import{pathToFileURL as ds}from"node:url";import{fileURLToPath as _pnpFutp}from"node:url";var He=process.versions.pnp&&(await import("pnpapi")).default,Le=He&&((e,t)=>{if(ms(e))return e.startsWith("node:")?e:`node:${e}`;if(e==="import")return null;let s=null;try{let _t=t&&t.startsWith("file://")?_pnpFutp(t):t;s=He.resolveRequest(e,_t)}catch{}return s!==null?ds(s).href:null});var fs=/^.*(\(|at )(.*):[\d]*:[\d]*.*$/,gs=Le||x,Qe=(e,t)=>(e=typeof e[1]=="string"?e:[e[0],new Error().stack.split(` + `)[3].replace(fs,"$2"),...e.slice(1)],e[4]={resolver:gs,...e[4],...t},e);var y=e=>async(...t)=>{let[s,o,r,c,n]=Qe(t,e);if(!Xe.register&&!await C())throw f.errMissingLoader();let l=await h(s,o,r,c,n),a=await import(l);return n.purge!==!1&&h.purge(l),h.sanitize(a,l)},X=e=>e&&/object|function/.test(typeof e)&&"esmkTreeId"in e&&h.purge(e.esmkTreeId),ks=Object.assign(y({strict:1}),{purge:X,p:y({strict:1,purge:!1})}),ys=Object.assign(y({strict:3}),{purge:X,p:y({strict:3,purge:!1})}),eo=Object.assign(y(),{purge:X,p:y({purge:!1}),strict:ks,strictest:ys});var hs=Xe.register?{}:v,{load:to,resolve:so,getSource:oo,initialize:ro,globalPreload:co}=hs;export{eo as default,oo as getSource,co as globalPreload,ro as initialize,to as load,so as resolve,ks as strict,ys as strictest}; diff --git a/.yarnrc.yml b/.yarnrc.yml index 00da118190..65f9c62abc 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -7,10 +7,75 @@ enableScripts: true enableTelemetry: false -nodeLinker: node-modules +nodeLinker: pnp npmMinimalAgeGate: 3d +packageExtensions: + "bootstrap@*": + dependencies: + "@popperjs/core": "*" + jquery: "*" + "@overleaf/settings@*": + peerDependencies: + "@overleaf/logger": "*" + "mongodb@*": + peerDependencies: + aws4: "*" + "bunyan@*": + peerDependencies: + source-map-support: "*" + "mocha-multi-reporters@*": + peerDependencies: + mocha-junit-reporter: "*" + "mongodb-legacy@*": + peerDependencies: + mongodb: "*" + "knex@*": + dependencies: + pg-query-stream: "*" + "zod-validation-error@*": + peerDependencies: + zod: "*" + "@vitejs/plugin-react@*": + peerDependencies: + vite: "*" + "@babel/preset-env@*": + peerDependencies: + core-js: "*" + "express@*": + dependencies: + pug: "*" + "postcss-loader@*": + peerDependencies: + autoprefixer: "*" + tailwindcss: "*" + "@ai-sdk/gateway@*": + peerDependencies: + zod: "*" + "@ai-sdk/provider-utils@*": + peerDependencies: + zod: "*" + "ai@*": + peerDependencies: + zod: "*" + "@uppy/react@*": + peerDependencies: + "@uppy/status-bar": "*" + "inversify@*": + dependencies: + reflect-metadata: "*" + "sinon-mongoose@*": + dependencies: + mongoose: "*" + "react-linkify@*": + peerDependencies: + react: "*" + "debug@*": + peerDependenciesMeta: + supports-color: + optional: true + supportedArchitectures: cpu: - current diff --git a/dockerfiles/cypress/Dockerfile b/dockerfiles/cypress/Dockerfile index b6042a0ea3..d3725193a0 100644 --- a/dockerfiles/cypress/Dockerfile +++ b/dockerfiles/cypress/Dockerfile @@ -3,7 +3,6 @@ ARG USER_UID=1000 ARG USER_GID=1000 # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 diff --git a/libraries/access-token-encryptor/package.json b/libraries/access-token-encryptor/package.json index 0564415b79..38a658a780 100644 --- a/libraries/access-token-encryptor/package.json +++ b/libraries/access-token-encryptor/package.json @@ -3,6 +3,10 @@ "version": "3.0.0", "description": "", "main": "index.js", + "exports": { + ".": "./index.js", + "./*": "./*" + }, "scripts": { "test": "yarn run lint && yarn run types:check && yarn run test:unit", "lint": "eslint --cache --cache-location ../../.cache/eslint/ --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .", @@ -17,8 +21,10 @@ "lodash": "^4.18.1" }, "devDependencies": { + "@types/node": "^24.5.2", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/fetch-utils/package.json b/libraries/fetch-utils/package.json index bbde709617..5dc0729ba3 100644 --- a/libraries/fetch-utils/package.json +++ b/libraries/fetch-utils/package.json @@ -14,10 +14,12 @@ "author": "Overleaf (https://www.overleaf.com)", "license": "AGPL-3.0-only", "devDependencies": { + "@types/node": "^24.5.2", "@types/node-fetch": "^2.6.13", "body-parser": "1.20.4", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "express": "4.22.1", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", diff --git a/libraries/logger/package.json b/libraries/logger/package.json index bdd86292df..f029ac21e4 100644 --- a/libraries/logger/package.json +++ b/libraries/logger/package.json @@ -7,6 +7,10 @@ "url": "https://github.com/overleaf/overleaf" }, "main": "index.js", + "exports": { + ".": "./index.js", + "./*": "./*" + }, "license": "AGPL-3.0-only", "version": "3.1.1", "scripts": { @@ -24,7 +28,9 @@ "bunyan": "^1.8.14" }, "devDependencies": { + "@types/node": "^24.5.2", "chai": "^4.3.6", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index bd04dbd6fd..b7725b877f 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -21,8 +21,11 @@ "yn": "^3.1.1" }, "devDependencies": { + "@overleaf/logger": "workspace:*", + "@types/node": "^24.5.2", "bunyan": "^1.0.0", "chai": "^4.3.6", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/mongo-utils/package.json b/libraries/mongo-utils/package.json index 74561728b4..7fd0520714 100644 --- a/libraries/mongo-utils/package.json +++ b/libraries/mongo-utils/package.json @@ -3,6 +3,10 @@ "version": "0.0.1", "description": "utilities to help working with mongo", "main": "index.js", + "exports": { + ".": "./index.js", + "./*": "./*" + }, "scripts": { "test": "yarn run lint && yarn run types:check && yarn run test:unit", "test:unit": "mocha --exit test/**/*.{js,cjs}", @@ -18,7 +22,9 @@ "mongodb-legacy": "6.1.3" }, "devDependencies": { + "@types/node": "^24.5.2", "chai": "^4.3.6", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/o-error/package.json b/libraries/o-error/package.json index f0d2617788..4d07f93a5c 100644 --- a/libraries/o-error/package.json +++ b/libraries/o-error/package.json @@ -32,6 +32,7 @@ "@types/chai": "^4.3.0", "@types/node": "^24.5.2", "chai": "^4.3.6", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/object-persistor/package.json b/libraries/object-persistor/package.json index ed553c207a..7af023439f 100644 --- a/libraries/object-persistor/package.json +++ b/libraries/object-persistor/package.json @@ -3,6 +3,10 @@ "version": "1.0.2", "description": "Module for storing objects in multiple backends, with fallback on 404 to assist migration between them", "main": "index.js", + "exports": { + ".": "./index.js", + "./*": "./*" + }, "scripts": { "test": "yarn run lint && yarn run types:check && yarn run test:unit", "test:unit": "mocha --exit test/**/*.{js,cjs}", @@ -33,8 +37,10 @@ "tiny-async-pool": "^1.1.0" }, "devDependencies": { + "@types/node": "^24.5.2", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/overleaf-editor-core/package.json b/libraries/overleaf-editor-core/package.json index 4c7718199d..37f6691a7d 100644 --- a/libraries/overleaf-editor-core/package.json +++ b/libraries/overleaf-editor-core/package.json @@ -3,6 +3,10 @@ "version": "1.0.0", "description": "Library shared between the editor server and clients.", "main": "index.js", + "exports": { + ".": "./index.js", + "./*": "./*" + }, "scripts": { "test": "yarn run lint && yarn run types:check && yarn run test:unit", "lint": "eslint --cache --cache-location ../../.cache/eslint/ --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .", @@ -16,8 +20,12 @@ "private": true, "devDependencies": { "@types/check-types": "^7.3.7", + "@types/lodash": "^4.17.24", + "@types/mocha": "^10.0.6", + "@types/node": "^24.5.2", "@types/path-browserify": "^1.0.3", "chai": "^3.3.0", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/promise-utils/package.json b/libraries/promise-utils/package.json index 833135292c..eb93fc9b3a 100644 --- a/libraries/promise-utils/package.json +++ b/libraries/promise-utils/package.json @@ -14,8 +14,10 @@ "author": "Overleaf (https://www.overleaf.com)", "license": "AGPL-3.0-only", "devDependencies": { + "@types/node": "^24.5.2", "chai": "^4.3.10", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/ranges-tracker/package.json b/libraries/ranges-tracker/package.json index 1509a9a99a..45086979d7 100644 --- a/libraries/ranges-tracker/package.json +++ b/libraries/ranges-tracker/package.json @@ -17,7 +17,10 @@ "types:check": "tsc --noEmit" }, "devDependencies": { + "@types/node": "^24.5.2", "chai": "^4.3.6", + "core-js": "~3.46.0", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/redis-wrapper/package.json b/libraries/redis-wrapper/package.json index 544d9b89c4..5c04bfe38f 100644 --- a/libraries/redis-wrapper/package.json +++ b/libraries/redis-wrapper/package.json @@ -32,7 +32,9 @@ "devDependencies": { "@overleaf/logger": "workspace:*", "@overleaf/o-error": "workspace:*", + "@types/node": "^24.5.2", "chai": "^4.3.6", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/settings/Settings.js b/libraries/settings/Settings.js index d028e633e8..24311bf557 100644 --- a/libraries/settings/Settings.js +++ b/libraries/settings/Settings.js @@ -1,6 +1,7 @@ /* eslint-disable no-console */ const fs = require('node:fs') const Path = require('node:path') +const { createRequire } = require('node:module') const { merge } = require('./merge') const CWD = process.cwd() @@ -16,6 +17,15 @@ if (SHARELATEX_CONFIG && SHARELATEX_CONFIG !== OVERLEAF_CONFIG) { ) } +// Under Yarn PnP, require() resolves dependencies based on the issuer package. +// Config files live in the consuming service (e.g. web), not in @overleaf/settings, +// so we create a require function anchored at each config file's location to ensure +// dependencies resolve from the service's PnP scope rather than this library's. +function requireFromFile(filePath) { + const absPath = Path.resolve(filePath) + return createRequire(absPath)(absPath) +} + let settings let settingsExist = false const defaultsPath = @@ -25,7 +35,7 @@ const defaultsPath = pathIfExists(Path.join(ENTRY_POINT_DIR, 'config/settings.defaults.js')) if (defaultsPath) { console.log(`Using default settings from ${defaultsPath}`) - settings = require(defaultsPath) + settings = requireFromFile(defaultsPath) settingsExist = true } else { settings = {} @@ -37,7 +47,7 @@ const overridesPath = pathIfExists(Path.join(CWD, `config/settings.${NODE_ENV}.js`)) if (overridesPath) { console.log(`Using settings from ${overridesPath}`) - settings = merge(require(overridesPath), settings) + settings = merge(requireFromFile(overridesPath), settings) settingsExist = true } diff --git a/libraries/settings/package.json b/libraries/settings/package.json index e3b8aa4d5e..5392e9dfa1 100644 --- a/libraries/settings/package.json +++ b/libraries/settings/package.json @@ -13,6 +13,8 @@ "types:check": "tsc --noEmit" }, "devDependencies": { + "@types/node": "^24.5.2", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/stream-utils/package.json b/libraries/stream-utils/package.json index a130a00257..2e75501e70 100644 --- a/libraries/stream-utils/package.json +++ b/libraries/stream-utils/package.json @@ -14,8 +14,10 @@ "author": "Overleaf (https://www.overleaf.com)", "license": "AGPL-3.0-only", "devDependencies": { + "@types/node": "^24.5.2", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/libraries/validation-tools/package.json b/libraries/validation-tools/package.json index 4668ce48f7..c70269faa3 100644 --- a/libraries/validation-tools/package.json +++ b/libraries/validation-tools/package.json @@ -24,6 +24,9 @@ "zod-validation-error": "^4.0.1" }, "devDependencies": { + "@types/express": "4.17.23", + "@types/node": "^24.5.2", + "eslint": "^10.4.0", "typescript": "^5.0.4", "vitest": "4.1.5" } diff --git a/package.json b/package.json index fff7e1383f..8ddb9a740d 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "eslint-plugin-promise": "^7.2.1", "eslint-plugin-unicorn": "^56.0.0", "globals": "^17.6.0", + "js-yaml": "^4.1.1", "prettier": "3.7.4", "prettier-plugin-groovy": "0.2.1", "typescript": "^5.9.3" @@ -131,6 +132,7 @@ "cache-flow": "1.9.0", "focus-trap-react": "11.0.4", "jose": "4.15.5", + "js-yaml": "^4.1.1", "nodemailer": "8.0.5", "on-headers": "1.0.2", "pug": "3.0.3", @@ -196,6 +198,7 @@ }, "workspaces": [ "jobs/mirror-documentation", + "jobs/wiki-algolia", "libraries/*", "server-ce/test", "services/analytics", @@ -212,6 +215,7 @@ "services/history-v1", "services/idp", "services/latexqc", + "services/linked-url-proxy", "services/notifications", "services/project-history", "services/real-time", @@ -223,5 +227,13 @@ "tools/npm-overrides-helper", "tools/saas-e2e", "tools/migrations" - ] + ], + "dependenciesMeta": { + "cypress-multi-reporters@2.0.5": { + "unplugged": true + }, + "esmock@2.7.3": { + "unplugged": true + } + } } diff --git a/server-ce/Dockerfile b/server-ce/Dockerfile index b76f50c15f..41e1919551 100644 --- a/server-ce/Dockerfile +++ b/server-ce/Dockerfile @@ -10,13 +10,12 @@ WORKDIR /overleaf # Add required source files for yarn install # ------------------------------------------- -COPY --parents libraries/*/package.json .yarn/patches/ services/*/package.json tools/migrations/ package.json yarn.lock .yarnrc.yml /overleaf/ +COPY --parents libraries/*/package.json .yarn/patches/ services/*/package.json tools/migrations/ package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY server-ce/genScript.js server-ce/services.js /overleaf/ # Pre-install yarn via corepack so it is available at runtime for all users # ------------------------------------------------------------------------- # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -34,10 +33,14 @@ COPY --parents libraries/ services/ tools/migrations/ /overleaf/ RUN --mount=type=cache,target=/root/.cache \ --mount=type=cache,target=/root/.yarn/berry/cache,id=server-ce-yarn-cache \ --mount=type=cache,target=/usr/local/share/.cache/yarn,id=server-ce-yarn-fallback-cache \ - --mount=type=cache,target=/overleaf/services/web/node_modules/.cache,id=server-ce-webpack-cache \ + --mount=type=cache,target=/overleaf/services/web/.cache,id=server-ce-webpack-cache \ --mount=type=tmpfs,target=/tmp \ node genScript compile | bash +# Enable Yarn PnP resolution for all Node.js processes +# ----------------------------------------------------- +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + # Copy runit service startup scripts to its location # -------------------------------------------------- ADD server-ce/runit /etc/service diff --git a/server-ce/test/.gitignore b/server-ce/test/.gitignore index 56be476514..7322f339f3 100644 --- a/server-ce/test/.gitignore +++ b/server-ce/test/.gitignore @@ -1,2 +1,3 @@ data/ docker-mailtrap/ +cypress/reporter/ diff --git a/server-ce/test/Dockerfile b/server-ce/test/Dockerfile index 5680b3e677..9be5e2b917 100644 --- a/server-ce/test/Dockerfile +++ b/server-ce/test/Dockerfile @@ -1,7 +1,6 @@ FROM node:24.14.1 # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 diff --git a/server-ce/test/cypress.config.ts b/server-ce/test/cypress.config.ts index e04e8a5384..59f0b84a6c 100644 --- a/server-ce/test/cypress.config.ts +++ b/server-ce/test/cypress.config.ts @@ -33,10 +33,13 @@ if (process.env.CYPRESS_SHARD && !process.env.SPEC_PATTERN) { const specPattern = process.env.SPEC_PATTERN || './**/*.spec.ts' +// Cypress's Electron process uses PackherdModuleLoader which doesn't go through +// PnP hooks. Reporter packages are materialized into /tmp/cypress-reporter by +// scripts/materialize-cypress-reporter.cjs at container startup. let reporterOptions = {} if (process.env.CI) { reporterOptions = { - reporter: `${process.env.MONOREPO}/node_modules/cypress-multi-reporters`, + reporter: '/tmp/cypress-reporter/node_modules/cypress-multi-reporters', reporterOptions: { configFile: 'cypress/cypress-multi-reporters.cjs', }, diff --git a/server-ce/test/docker-compose.yml b/server-ce/test/docker-compose.yml index 26da756b2b..54689d93ad 100644 --- a/server-ce/test/docker-compose.yml +++ b/server-ce/test/docker-compose.yml @@ -79,12 +79,15 @@ services: working_dir: $PWD volumes: - $PWD:$PWD - - $MONOREPO/libraries:$MONOREPO/libraries - - $MONOREPO/node_modules:$MONOREPO/node_modules - - $MONOREPO/.yarn:$MONOREPO/.yarn - - $MONOREPO/.yarnrc.yml:$MONOREPO/.yarnrc.yml - - $MONOREPO/package.json:$MONOREPO/package.json - - $MONOREPO/yarn.lock:$MONOREPO/yarn.lock + - $MONOREPO/libraries:$MONOREPO/libraries:ro + - $MONOREPO/scripts:$MONOREPO/scripts:ro + - $MONOREPO/.yarn:$MONOREPO/.yarn:ro + - $MONOREPO/.yarnrc.yml:$MONOREPO/.yarnrc.yml:ro + - $MONOREPO/.pnp.cjs:$MONOREPO/.pnp.cjs:ro + - $MONOREPO/.pnp.loader.mjs:$MONOREPO/.pnp.loader.mjs:ro + - $MONOREPO/.pnp.register.mjs:$MONOREPO/.pnp.register.mjs:ro + - $MONOREPO/package.json:$MONOREPO/package.json:ro + - $MONOREPO/yarn.lock:$MONOREPO/yarn.lock:ro environment: MONOREPO: CYPRESS_SHARD: @@ -108,15 +111,16 @@ services: host-admin: build: . - entrypoint: ["node", "--watch", "host-admin.js"] + entrypoint: ["yarn", "node", "--watch", "host-admin.js"] # See comment in Makefile regarding matching file paths working_dir: $PWD volumes: - $PWD:$PWD - $MONOREPO/libraries:$MONOREPO/libraries:ro - - $MONOREPO/node_modules:$MONOREPO/node_modules:ro - $MONOREPO/.yarn:$MONOREPO/.yarn:ro - $MONOREPO/.yarnrc.yml:$MONOREPO/.yarnrc.yml:ro + - $MONOREPO/.pnp.cjs:$MONOREPO/.pnp.cjs:ro + - $MONOREPO/.pnp.loader.mjs:$MONOREPO/.pnp.loader.mjs:ro - $MONOREPO/package.json:$MONOREPO/package.json:ro - $MONOREPO/yarn.lock:$MONOREPO/yarn.lock:ro - /var/run/docker.sock:/var/run/docker.sock diff --git a/server-ce/test/package.json b/server-ce/test/package.json index 1e16326d10..b9cc3ac684 100644 --- a/server-ce/test/package.json +++ b/server-ce/test/package.json @@ -4,8 +4,9 @@ "private": true, "type": "module", "scripts": { - "cypress:open": "cypress open --e2e --browser chrome", - "cypress:run": "cypress run --e2e --browser chrome", + "materialize-reporter": "node ../../scripts/materialize-cypress-reporter.cjs /tmp/cypress-reporter", + "cypress:open": "yarn run materialize-reporter && cypress open --e2e --browser chrome", + "cypress:run": "yarn run materialize-reporter && cypress run --e2e --browser chrome", "lint": "eslint --cache --cache-location ../../.cache/eslint/ --max-warnings 0 --format unix --ext .js,.jsx,.mjs,.ts,.tsx .", "lint:fix": "eslint --cache --cache-location ../../.cache/eslint/ --fix --ext .js,.jsx,.mjs,.ts,.tsx ." }, @@ -20,11 +21,15 @@ "body-parser": "1.20.4", "cypress": "15.12.0", "cypress-multi-reporters": "^2.0.5", + "eslint": "^10.4.0", + "eslint-formatter-unix": "^8.40.0", "express": "4.22.1", "isomorphic-git": "^1.33.1", "js-yaml": "^4.1.1", + "mocha": "^11.7.5", "mocha-junit-reporter": "^2.2.1", "pdfjs-dist": "^5.1.91", + "typescript": "^5.0.4", "uuid": "^9.0.1", "zod-validation-error": "^4.0.1" } diff --git a/services/chat/Dockerfile b/services/chat/Dockerfile index ca3c6a25a0..4933cf94e1 100644 --- a/services/chat/Dockerfile +++ b/services/chat/Dockerfile @@ -5,7 +5,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -18,7 +17,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config FROM base AS app -COPY package.json yarn.lock .yarnrc.yml /overleaf/ +COPY package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json COPY libraries/logger/package.json /overleaf/libraries/logger/package.json @@ -44,6 +43,8 @@ COPY libraries/settings/ /overleaf/libraries/settings/ COPY services/chat/ /overleaf/services/chat/ COPY tools/migrations/ /overleaf/tools/migrations/ +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + FROM app USER node diff --git a/services/chat/Makefile b/services/chat/Makefile index 298a93fb50..f261f452ba 100644 --- a/services/chat/Makefile +++ b/services/chat/Makefile @@ -69,9 +69,11 @@ clean: # Eslint and prettier (plus some configs) are on the root. RUN_LINTING = ../../bin/run -w /overleaf/services/$(PROJECT_NAME) monorepo yarn run --silent RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent +RUN_EXEC_MONOREPO = ../../bin/run monorepo yarn exec RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/chat/reports:/overleaf/services/chat/reports --volume $(MONOREPO)/.cache:/overleaf/.cache $(IMAGE_CI) yarn run --silent RUN_LINTING_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/chat/reports:/overleaf/services/chat/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn run --silent +RUN_EXEC_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/chat/reports:/overleaf/services/chat/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn exec SHELLCHECK_OPTS = \ --shell=bash \ @@ -119,14 +121,14 @@ format_fix: $(RUN_LINTING_MONOREPO) format:fix services/chat lint: - $(RUN_LINTING) lint + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format unix services/chat lint_ci: - -$(RUN_LINTING_CI) lint --format json --output-file reports/eslint.json + -$(RUN_EXEC_CI_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format json --output-file services/chat/reports/eslint.json services/chat sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json lint_fix: - $(RUN_LINTING) lint:fix + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --fix services/chat typecheck: $(RUN_LINTING) types:check diff --git a/services/chat/docker-compose.yml b/services/chat/docker-compose.yml index 32c167cd66..8dbb7dd1c4 100644 --- a/services/chat/docker-compose.yml +++ b/services/chat/docker-compose.yml @@ -10,12 +10,14 @@ services: target: base volumes: - .:/overleaf/services/chat - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations working_dir: /overleaf/services/chat @@ -24,7 +26,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_CONNECTION_STRING: mongodb://mongo/test-overleaf NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" entrypoint: /overleaf/bin/shared/wait_for_it mongo:27017 --timeout=60 -- command: yarn run --silent test:unit user: node @@ -39,12 +41,14 @@ services: target: base volumes: - .:/overleaf/services/chat - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations working_dir: /overleaf/services/chat @@ -55,7 +59,7 @@ services: MOCHA_GREP: ${MOCHA_GREP} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" user: node depends_on: mongo: diff --git a/services/chat/package.json b/services/chat/package.json index bfe2516de0..de349c4123 100644 --- a/services/chat/package.json +++ b/services/chat/package.json @@ -29,10 +29,12 @@ }, "devDependencies": { "@overleaf/migrations": "workspace:*", + "@types/node": "^24.5.2", "acorn": "^7.1.1", "ajv": "^6.12.0", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/services/chat/test/acceptance/js/helpers/MongoHelper.js b/services/chat/test/acceptance/js/helpers/MongoHelper.js index cf969c6210..2729bf78d1 100644 --- a/services/chat/test/acceptance/js/helpers/MongoHelper.js +++ b/services/chat/test/acceptance/js/helpers/MongoHelper.js @@ -5,6 +5,6 @@ before('run migrations', async function () { this.timeout(60_000) await promisify(exec)( - `cd ../../tools/migrations && npm run migrations -- migrate -t server-ce` + `cd ../../tools/migrations && yarn run migrations migrate -t server-ce` ) }) diff --git a/services/clsi/Dockerfile b/services/clsi/Dockerfile index 603d6ddf7a..bc2dbdd71e 100644 --- a/services/clsi/Dockerfile +++ b/services/clsi/Dockerfile @@ -5,7 +5,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -22,7 +21,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config FROM base AS app -COPY package.json yarn.lock .yarnrc.yml /overleaf/ +COPY package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json COPY libraries/logger/package.json /overleaf/libraries/logger/package.json @@ -49,20 +48,22 @@ COPY libraries/stream-utils/ /overleaf/libraries/stream-utils/ COPY libraries/validation-tools/ /overleaf/libraries/validation-tools/ COPY services/clsi/ /overleaf/services/clsi/ +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + FROM app AS with-texlive RUN apt-get update \ - && apt-cache depends texlive-full | grep "Depends: " | grep -v -- "-doc" | grep -v -- "-lang-" | sed 's/Depends: //' | xargs apt-get install -y --no-install-recommends \ - && apt-get install -y --no-install-recommends fontconfig inkscape python3-pygments qpdf \ - && rm -rf /var/lib/apt/lists/* + && apt-cache depends texlive-full | grep "Depends: " | grep -v -- "-doc" | grep -v -- "-lang-" | sed 's/Depends: //' | xargs apt-get install -y --no-install-recommends \ + && apt-get install -y --no-install-recommends fontconfig inkscape python3-pygments qpdf \ + && rm -rf /var/lib/apt/lists/* RUN mkdir -p cache compiles output \ -&& chown node:node cache compiles output + && chown node:node cache compiles output CMD ["node", "--expose-gc", "app.js"] FROM app RUN mkdir -p cache compiles output \ -&& chown node:node cache compiles output + && chown node:node cache compiles output CMD ["node", "--expose-gc", "app.js"] diff --git a/services/clsi/Makefile b/services/clsi/Makefile index bf2f86592a..2f6d40e88c 100644 --- a/services/clsi/Makefile +++ b/services/clsi/Makefile @@ -71,9 +71,11 @@ clean: # Eslint and prettier (plus some configs) are on the root. RUN_LINTING = ../../bin/run -w /overleaf/services/$(PROJECT_NAME) monorepo yarn run --silent RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent +RUN_EXEC_MONOREPO = ../../bin/run monorepo yarn exec RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/clsi/reports:/overleaf/services/clsi/reports --volume $(MONOREPO)/.cache:/overleaf/.cache $(IMAGE_CI) yarn run --silent RUN_LINTING_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/clsi/reports:/overleaf/services/clsi/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn run --silent +RUN_EXEC_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/clsi/reports:/overleaf/services/clsi/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn exec SHELLCHECK_OPTS = \ --shell=bash \ @@ -121,14 +123,14 @@ format_fix: $(RUN_LINTING_MONOREPO) format:fix services/clsi lint: - $(RUN_LINTING) lint + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format unix services/clsi lint_ci: - -$(RUN_LINTING_CI) lint --format json --output-file reports/eslint.json + -$(RUN_EXEC_CI_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format json --output-file services/clsi/reports/eslint.json services/clsi sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json lint_fix: - $(RUN_LINTING) lint:fix + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --fix services/clsi typecheck: $(RUN_LINTING) types:check diff --git a/services/clsi/docker-compose.yml b/services/clsi/docker-compose.yml index 1ea4549b20..cf33864e5c 100644 --- a/services/clsi/docker-compose.yml +++ b/services/clsi/docker-compose.yml @@ -10,12 +10,14 @@ services: target: base volumes: - .:/overleaf/services/clsi - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../tsconfig.backend.json:/overleaf/tsconfig.backend.json working_dir: /overleaf/services/clsi environment: @@ -23,7 +25,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_CONNECTION_STRING: mongodb://mongo/test-overleaf NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" command: yarn run --silent test:unit test_acceptance: @@ -33,12 +35,14 @@ services: target: base volumes: - .:/overleaf/services/clsi - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - /var/run/docker.sock:/var/run/docker.sock working_dir: /overleaf/services/clsi environment: @@ -48,7 +52,7 @@ services: MOCHA_GREP: ${MOCHA_GREP} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" DOWNLOAD_HOST: http://clsi-nginx:8080 ALLOWED_COMPILE_GROUPS: clsi-perf simple-latex-file ENABLE_PDF_CACHING: true diff --git a/services/clsi/package.json b/services/clsi/package.json index e2bcc927ed..530c79dc38 100644 --- a/services/clsi/package.json +++ b/services/clsi/package.json @@ -41,8 +41,10 @@ }, "devDependencies": { "@istanbuljs/esm-loader-hook": "^0.3.0", + "@types/node": "^24.5.2", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "form-data": "^4.0.5", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", diff --git a/services/docstore/Dockerfile b/services/docstore/Dockerfile index ae69304db4..1edc62ed38 100644 --- a/services/docstore/Dockerfile +++ b/services/docstore/Dockerfile @@ -5,7 +5,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -18,7 +17,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config FROM base AS app -COPY package.json yarn.lock .yarnrc.yml /overleaf/ +COPY package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json COPY libraries/logger/package.json /overleaf/libraries/logger/package.json @@ -50,6 +49,8 @@ COPY libraries/validation-tools/ /overleaf/libraries/validation-tools/ COPY services/docstore/ /overleaf/services/docstore/ COPY tools/migrations/ /overleaf/tools/migrations/ +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + FROM app USER node diff --git a/services/docstore/Makefile b/services/docstore/Makefile index f199730db2..3659693fe6 100644 --- a/services/docstore/Makefile +++ b/services/docstore/Makefile @@ -72,9 +72,11 @@ clean: # Eslint and prettier (plus some configs) are on the root. RUN_LINTING = ../../bin/run -w /overleaf/services/$(PROJECT_NAME) monorepo yarn run --silent RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent +RUN_EXEC_MONOREPO = ../../bin/run monorepo yarn exec RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/docstore/reports:/overleaf/services/docstore/reports --volume $(MONOREPO)/.cache:/overleaf/.cache $(IMAGE_CI) yarn run --silent RUN_LINTING_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/docstore/reports:/overleaf/services/docstore/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn run --silent +RUN_EXEC_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/docstore/reports:/overleaf/services/docstore/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn exec SHELLCHECK_OPTS = \ --shell=bash \ @@ -122,14 +124,14 @@ format_fix: $(RUN_LINTING_MONOREPO) format:fix services/docstore lint: - $(RUN_LINTING) lint + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format unix services/docstore lint_ci: - -$(RUN_LINTING_CI) lint --format json --output-file reports/eslint.json + -$(RUN_EXEC_CI_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format json --output-file services/docstore/reports/eslint.json services/docstore sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json lint_fix: - $(RUN_LINTING) lint:fix + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --fix services/docstore typecheck: $(RUN_LINTING) types:check diff --git a/services/docstore/docker-compose.yml b/services/docstore/docker-compose.yml index a3789640a1..b6ddf0c934 100644 --- a/services/docstore/docker-compose.yml +++ b/services/docstore/docker-compose.yml @@ -10,12 +10,14 @@ services: target: base volumes: - .:/overleaf/services/docstore - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations - ../../tsconfig.backend.json:/overleaf/tsconfig.backend.json @@ -25,7 +27,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_CONNECTION_STRING: mongodb://mongo/test-overleaf NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" entrypoint: /overleaf/bin/shared/wait_for_it mongo:27017 --timeout=60 -- command: yarn run --silent test:unit user: node @@ -40,12 +42,14 @@ services: target: base volumes: - .:/overleaf/services/docstore - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations working_dir: /overleaf/services/docstore @@ -59,7 +63,7 @@ services: MOCHA_GREP: ${MOCHA_GREP} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" user: node depends_on: mongo: diff --git a/services/docstore/package.json b/services/docstore/package.json index bafbed7762..2380f45656 100644 --- a/services/docstore/package.json +++ b/services/docstore/package.json @@ -31,14 +31,17 @@ "bunyan": "^1.8.15", "express": "4.22.1", "lodash": "^4.18.1", + "mongodb": "6.12.0", "mongodb-legacy": "6.1.3", "p-map": "^4.0.0" }, "devDependencies": { "@google-cloud/storage": "^7.19.0", "@overleaf/migrations": "workspace:*", + "@types/node": "^24.5.2", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/services/docstore/test/acceptance/js/helpers/MongoHelper.js b/services/docstore/test/acceptance/js/helpers/MongoHelper.js index cf969c6210..2729bf78d1 100644 --- a/services/docstore/test/acceptance/js/helpers/MongoHelper.js +++ b/services/docstore/test/acceptance/js/helpers/MongoHelper.js @@ -5,6 +5,6 @@ before('run migrations', async function () { this.timeout(60_000) await promisify(exec)( - `cd ../../tools/migrations && npm run migrations -- migrate -t server-ce` + `cd ../../tools/migrations && yarn run migrations migrate -t server-ce` ) }) diff --git a/services/document-updater/Dockerfile b/services/document-updater/Dockerfile index 07c80ca19e..4dc2335a51 100644 --- a/services/document-updater/Dockerfile +++ b/services/document-updater/Dockerfile @@ -5,7 +5,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -18,7 +17,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config FROM base AS app -COPY package.json yarn.lock .yarnrc.yml /overleaf/ +COPY package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json COPY libraries/logger/package.json /overleaf/libraries/logger/package.json @@ -50,6 +49,8 @@ COPY libraries/settings/ /overleaf/libraries/settings/ COPY services/document-updater/ /overleaf/services/document-updater/ COPY tools/migrations/ /overleaf/tools/migrations/ +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + FROM app USER node diff --git a/services/document-updater/Makefile b/services/document-updater/Makefile index 423bb66349..4a5b00a518 100644 --- a/services/document-updater/Makefile +++ b/services/document-updater/Makefile @@ -72,9 +72,11 @@ clean: # Eslint and prettier (plus some configs) are on the root. RUN_LINTING = ../../bin/run -w /overleaf/services/$(PROJECT_NAME) monorepo yarn run --silent RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent +RUN_EXEC_MONOREPO = ../../bin/run monorepo yarn exec RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/document-updater/reports:/overleaf/services/document-updater/reports --volume $(MONOREPO)/.cache:/overleaf/.cache $(IMAGE_CI) yarn run --silent RUN_LINTING_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/document-updater/reports:/overleaf/services/document-updater/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn run --silent +RUN_EXEC_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/document-updater/reports:/overleaf/services/document-updater/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn exec SHELLCHECK_OPTS = \ --shell=bash \ @@ -122,14 +124,14 @@ format_fix: $(RUN_LINTING_MONOREPO) format:fix services/document-updater lint: - $(RUN_LINTING) lint + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format unix services/document-updater lint_ci: - -$(RUN_LINTING_CI) lint --format json --output-file reports/eslint.json + -$(RUN_EXEC_CI_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format json --output-file services/document-updater/reports/eslint.json services/document-updater sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json lint_fix: - $(RUN_LINTING) lint:fix + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --fix services/document-updater typecheck: $(RUN_LINTING) types:check diff --git a/services/document-updater/docker-compose.yml b/services/document-updater/docker-compose.yml index 7c577603c0..72b1b2a601 100644 --- a/services/document-updater/docker-compose.yml +++ b/services/document-updater/docker-compose.yml @@ -10,12 +10,14 @@ services: target: base volumes: - .:/overleaf/services/document-updater - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations working_dir: /overleaf/services/document-updater @@ -24,7 +26,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_CONNECTION_STRING: mongodb://mongo/test-overleaf NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" REDIS_HOST: redis_test HISTORY_REDIS_HOST: redis_test QUEUES_REDIS_HOST: redis_test @@ -46,12 +48,14 @@ services: target: base volumes: - .:/overleaf/services/document-updater - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations working_dir: /overleaf/services/document-updater @@ -67,7 +71,7 @@ services: MOCHA_GREP: ${MOCHA_GREP} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" user: node depends_on: mongo: diff --git a/services/document-updater/package.json b/services/document-updater/package.json index 15627e738c..dd30fbb710 100644 --- a/services/document-updater/package.json +++ b/services/document-updater/package.json @@ -34,15 +34,20 @@ "express": "4.22.1", "lodash": "^4.18.1", "minimist": "^1.2.8", + "mongodb": "6.12.0", "mongodb-legacy": "6.1.3", "overleaf-editor-core": "workspace:*" }, "devDependencies": { "@overleaf/migrations": "workspace:*", + "@types/ioredis": "^4.28.10", + "@types/mocha": "^10.0.6", + "@types/node": "^24.5.2", "basic-auth": "^2.0.1", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", "cluster-key-slot": "^1.0.5", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/services/document-updater/scripts/flush_projects_with_no_history_id.js b/services/document-updater/scripts/flush_projects_with_no_history_id.js index 80b6ddb042..e94a8a8149 100644 --- a/services/document-updater/scripts/flush_projects_with_no_history_id.js +++ b/services/document-updater/scripts/flush_projects_with_no_history_id.js @@ -204,7 +204,10 @@ async function scanNodes(nodes, batchSize = 1000) { } } - logger.info({ scanned, server: node.serverInfo.role }, 'Scanned node') + logger.info( + { scanned, server: /** @type {any} */ (node).serverInfo.role }, + 'Scanned node' + ) } } diff --git a/services/document-updater/test/acceptance/js/helpers/MongoHelper.js b/services/document-updater/test/acceptance/js/helpers/MongoHelper.js index 2dc6bcaedc..eba0dd20d3 100644 --- a/services/document-updater/test/acceptance/js/helpers/MongoHelper.js +++ b/services/document-updater/test/acceptance/js/helpers/MongoHelper.js @@ -5,6 +5,6 @@ before('run migrations', async function () { this.timeout(60_000) await promisify(exec)( - `cd ../../tools/migrations && npm run migrations -- migrate -t server-ce` + `cd ../../tools/migrations && yarn run migrations migrate -t server-ce` ) }) diff --git a/services/filestore/Dockerfile b/services/filestore/Dockerfile index c3445ae8a1..a754192555 100644 --- a/services/filestore/Dockerfile +++ b/services/filestore/Dockerfile @@ -5,7 +5,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -20,7 +19,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config FROM base AS app -COPY package.json yarn.lock .yarnrc.yml /overleaf/ +COPY package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json COPY libraries/logger/package.json /overleaf/libraries/logger/package.json @@ -43,9 +42,11 @@ COPY libraries/settings/ /overleaf/libraries/settings/ COPY libraries/stream-utils/ /overleaf/libraries/stream-utils/ COPY services/filestore/ /overleaf/services/filestore/ +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + FROM app RUN mkdir -p uploads template_files \ -&& chown node:node uploads template_files + && chown node:node uploads template_files USER node CMD ["node", "--expose-gc", "app.js"] diff --git a/services/filestore/Makefile b/services/filestore/Makefile index 171633c975..7fa1c9a9c5 100644 --- a/services/filestore/Makefile +++ b/services/filestore/Makefile @@ -69,9 +69,11 @@ clean: # Eslint and prettier (plus some configs) are on the root. RUN_LINTING = ../../bin/run -w /overleaf/services/$(PROJECT_NAME) monorepo yarn run --silent RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent +RUN_EXEC_MONOREPO = ../../bin/run monorepo yarn exec RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/filestore/reports:/overleaf/services/filestore/reports --volume $(MONOREPO)/.cache:/overleaf/.cache $(IMAGE_CI) yarn run --silent RUN_LINTING_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/filestore/reports:/overleaf/services/filestore/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn run --silent +RUN_EXEC_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/filestore/reports:/overleaf/services/filestore/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn exec SHELLCHECK_OPTS = \ --shell=bash \ @@ -119,14 +121,14 @@ format_fix: $(RUN_LINTING_MONOREPO) format:fix services/filestore lint: - $(RUN_LINTING) lint + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format unix services/filestore lint_ci: - -$(RUN_LINTING_CI) lint --format json --output-file reports/eslint.json + -$(RUN_EXEC_CI_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format json --output-file services/filestore/reports/eslint.json services/filestore sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json lint_fix: - $(RUN_LINTING) lint:fix + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --fix services/filestore typecheck: $(RUN_LINTING) types:check diff --git a/services/filestore/docker-compose.yml b/services/filestore/docker-compose.yml index 4629a5a0cf..0e0d279582 100644 --- a/services/filestore/docker-compose.yml +++ b/services/filestore/docker-compose.yml @@ -13,12 +13,14 @@ services: target: base volumes: - .:/overleaf/services/filestore - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../tsconfig.backend.json:/overleaf/tsconfig.backend.json working_dir: /overleaf/services/filestore environment: @@ -26,7 +28,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_CONNECTION_STRING: mongodb://mongo/test-overleaf NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" command: yarn run --silent test:unit user: node @@ -37,12 +39,14 @@ services: target: base volumes: - .:/overleaf/services/filestore - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - minio-certs:/certs working_dir: /overleaf/services/filestore environment: @@ -62,7 +66,7 @@ services: MOCHA_GREP: ${MOCHA_GREP} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" ENABLE_CONVERSIONS: true USE_PROM_METRICS: true AWS_S3_USER_FILES_STORAGE_CLASS: REDUCED_REDUNDANCY diff --git a/services/filestore/package.json b/services/filestore/package.json index 13ef2fdacc..25a41710ab 100644 --- a/services/filestore/package.json +++ b/services/filestore/package.json @@ -36,8 +36,10 @@ }, "devDependencies": { "@google-cloud/storage": "^7.19.0", + "@types/node": "^24.5.2", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/services/history-v1/Dockerfile b/services/history-v1/Dockerfile index dee30c5f19..2178fa5e1f 100644 --- a/services/history-v1/Dockerfile +++ b/services/history-v1/Dockerfile @@ -5,7 +5,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -23,7 +22,7 @@ RUN mkdir /buckets && chown node:node /buckets FROM base AS app -COPY package.json yarn.lock .yarnrc.yml /overleaf/ +COPY package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json COPY libraries/logger/package.json /overleaf/libraries/logger/package.json @@ -59,6 +58,8 @@ COPY libraries/validation-tools/ /overleaf/libraries/validation-tools/ COPY services/history-v1/ /overleaf/services/history-v1/ COPY tools/migrations/ /overleaf/tools/migrations/ +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + FROM app USER node diff --git a/services/history-v1/Makefile b/services/history-v1/Makefile index eb3e7556f8..82556795ff 100644 --- a/services/history-v1/Makefile +++ b/services/history-v1/Makefile @@ -74,9 +74,11 @@ clean: # Eslint and prettier (plus some configs) are on the root. RUN_LINTING = ../../bin/run -w /overleaf/services/$(PROJECT_NAME) monorepo yarn run --silent RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent +RUN_EXEC_MONOREPO = ../../bin/run monorepo yarn exec RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/history-v1/reports:/overleaf/services/history-v1/reports --volume $(MONOREPO)/.cache:/overleaf/.cache $(IMAGE_CI) yarn run --silent RUN_LINTING_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/history-v1/reports:/overleaf/services/history-v1/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn run --silent +RUN_EXEC_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/history-v1/reports:/overleaf/services/history-v1/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn exec SHELLCHECK_OPTS = \ --shell=bash \ @@ -124,14 +126,14 @@ format_fix: $(RUN_LINTING_MONOREPO) format:fix services/history-v1 lint: - $(RUN_LINTING) lint + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format unix services/history-v1 lint_ci: - -$(RUN_LINTING_CI) lint --format json --output-file reports/eslint.json + -$(RUN_EXEC_CI_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format json --output-file services/history-v1/reports/eslint.json services/history-v1 sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json lint_fix: - $(RUN_LINTING) lint:fix + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --fix services/history-v1 typecheck: $(RUN_LINTING) types:check diff --git a/services/history-v1/docker-compose.yml b/services/history-v1/docker-compose.yml index a92ff491ba..679ba02987 100644 --- a/services/history-v1/docker-compose.yml +++ b/services/history-v1/docker-compose.yml @@ -13,12 +13,14 @@ services: target: base volumes: - .:/overleaf/services/history-v1 - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations working_dir: /overleaf/services/history-v1 @@ -27,7 +29,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_CONNECTION_STRING: mongodb://mongo/test-overleaf NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" REDIS_HOST: redis_test HISTORY_REDIS_HOST: redis_test QUEUES_REDIS_HOST: redis_test @@ -49,12 +51,14 @@ services: target: base volumes: - .:/overleaf/services/history-v1 - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - minio-certs:/certs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations @@ -81,7 +85,7 @@ services: MOCHA_GREP: ${MOCHA_GREP} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" user: node depends_on: mongo: diff --git a/services/history-v1/package.json b/services/history-v1/package.json index 8dd6cdafc8..a31854d519 100644 --- a/services/history-v1/package.json +++ b/services/history-v1/package.json @@ -7,6 +7,7 @@ "private": true, "dependencies": { "@google-cloud/secret-manager": "^5.6.0", + "@google-cloud/storage": "^7.19.0", "@overleaf/fetch-utils": "workspace:*", "@overleaf/logger": "workspace:*", "@overleaf/metrics": "workspace:*", @@ -48,11 +49,16 @@ "zip-stream": "^7.0.2" }, "devDependencies": { + "@aws-sdk/client-s3": "^3.994.0", "@overleaf/migrations": "workspace:*", + "@types/chai-as-promised": "^7.1.8", + "@types/mocha": "^10.0.6", + "@types/node": "^24.5.2", "benny": "^3.7.1", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", "chai-exclude": "^2.1.1", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/services/history-v1/storage/scripts/back_fill_file_hash.mjs b/services/history-v1/storage/scripts/back_fill_file_hash.mjs index 8b25fb8bd6..7c2f031cfe 100644 --- a/services/history-v1/storage/scripts/back_fill_file_hash.mjs +++ b/services/history-v1/storage/scripts/back_fill_file_hash.mjs @@ -316,8 +316,9 @@ if (OUTPUT_FILE !== '-') { logger.initialize('file-migration', { streams: [ { - stream: - OUTPUT_FILE === '-' + stream: DISPLAY_REPORT + ? process.stderr + : OUTPUT_FILE === '-' ? process.stdout : fs.createWriteStream(OUTPUT_FILE, { flags: 'a' }), }, diff --git a/services/history-v1/storage/scripts/fix_string_backedUpBlobs_ids.mjs b/services/history-v1/storage/scripts/fix_string_backedUpBlobs_ids.mjs index 007eebea77..54a9d9c490 100644 --- a/services/history-v1/storage/scripts/fix_string_backedUpBlobs_ids.mjs +++ b/services/history-v1/storage/scripts/fix_string_backedUpBlobs_ids.mjs @@ -1,9 +1,11 @@ // @ts-check import { backedUpBlobs } from '../lib/mongodb.js' -import { mongoId } from '../lib/assert.js' +import assert from '../lib/assert.js' import { ObjectId } from 'mongodb' import commandLineArgs from 'command-line-args' +const { mongoId } = assert + const STATS = { total: 0, replaced: 0, diff --git a/services/history-v1/test/acceptance/js/storage/back_fill_file_hash.test.mjs b/services/history-v1/test/acceptance/js/storage/back_fill_file_hash.test.mjs index 14a1c811d6..5757fc511e 100644 --- a/services/history-v1/test/acceptance/js/storage/back_fill_file_hash.test.mjs +++ b/services/history-v1/test/acceptance/js/storage/back_fill_file_hash.test.mjs @@ -485,7 +485,7 @@ describe('back_fill_file_hash script', function () { * @param {Array} args * @return {Promise<{result: { stdout: string, stderr: string, status: number }, stats: any}>} */ - async function rawRunScript(args = []) { + async function rawRunScript(args = [], env = {}) { let result try { result = await promisify(execFile)( @@ -502,6 +502,7 @@ describe('back_fill_file_hash script', function () { ...process.env, AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE: '1', LOG_LEVEL: 'warn', // Override LOG_LEVEL of acceptance tests + ...env, }, } ) @@ -1120,7 +1121,7 @@ describe('back_fill_file_hash script', function () { let output before('prepare environment', prepareEnvironment) before('run script', async function () { - output = await rawRunScript(['--report']) + output = await rawRunScript(['--report'], { LOG_LEVEL: 'error' }) }) it('should print the report', () => { expect(output.status).to.equal(0) diff --git a/services/history-v1/test/acceptance/js/storage/recover_zip.test.mjs b/services/history-v1/test/acceptance/js/storage/recover_zip.test.mjs index e0f8a99498..94b9723b6b 100644 --- a/services/history-v1/test/acceptance/js/storage/recover_zip.test.mjs +++ b/services/history-v1/test/acceptance/js/storage/recover_zip.test.mjs @@ -140,7 +140,7 @@ async function runRecoverZipScript(args) { try { result = await promisify(execFile)( 'node', - ['storage/scripts/recover_zip.js', ...args], + ['--no-deprecation', 'storage/scripts/recover_zip.js', ...args], { encoding: 'utf-8', timeout: TIMEOUT, diff --git a/services/history-v1/test/setup.js b/services/history-v1/test/setup.js index 7f0e411cd1..42a5dfe450 100644 --- a/services/history-v1/test/setup.js +++ b/services/history-v1/test/setup.js @@ -22,7 +22,7 @@ async function setupMongoDatabase() { this.timeout(60_000) await promisify(exec)( // Run saas migrations for backup indexes - `cd ../../tools/migrations && npm run migrations -- migrate -t saas` + `cd ../../tools/migrations && yarn run migrations migrate -t saas` ) } diff --git a/services/notifications/Dockerfile b/services/notifications/Dockerfile index 0732cf7cc9..fb7d837fba 100644 --- a/services/notifications/Dockerfile +++ b/services/notifications/Dockerfile @@ -5,7 +5,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -18,7 +17,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config FROM base AS app -COPY package.json yarn.lock .yarnrc.yml /overleaf/ +COPY package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json COPY libraries/logger/package.json /overleaf/libraries/logger/package.json @@ -46,6 +45,8 @@ COPY libraries/validation-tools/ /overleaf/libraries/validation-tools/ COPY services/notifications/ /overleaf/services/notifications/ COPY tools/migrations/ /overleaf/tools/migrations/ +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + FROM app USER node diff --git a/services/notifications/Makefile b/services/notifications/Makefile index e161b7651a..b3fc03c02f 100644 --- a/services/notifications/Makefile +++ b/services/notifications/Makefile @@ -70,9 +70,11 @@ clean: # Eslint and prettier (plus some configs) are on the root. RUN_LINTING = ../../bin/run -w /overleaf/services/$(PROJECT_NAME) monorepo yarn run --silent RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent +RUN_EXEC_MONOREPO = ../../bin/run monorepo yarn exec RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/notifications/reports:/overleaf/services/notifications/reports --volume $(MONOREPO)/.cache:/overleaf/.cache $(IMAGE_CI) yarn run --silent RUN_LINTING_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/notifications/reports:/overleaf/services/notifications/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn run --silent +RUN_EXEC_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/notifications/reports:/overleaf/services/notifications/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn exec SHELLCHECK_OPTS = \ --shell=bash \ @@ -120,14 +122,14 @@ format_fix: $(RUN_LINTING_MONOREPO) format:fix services/notifications lint: - $(RUN_LINTING) lint + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format unix services/notifications lint_ci: - -$(RUN_LINTING_CI) lint --format json --output-file reports/eslint.json + -$(RUN_EXEC_CI_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format json --output-file services/notifications/reports/eslint.json services/notifications sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json lint_fix: - $(RUN_LINTING) lint:fix + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --fix services/notifications typecheck: $(RUN_LINTING) types:check diff --git a/services/notifications/docker-compose.yml b/services/notifications/docker-compose.yml index 0361fea5fc..c68ffc28d9 100644 --- a/services/notifications/docker-compose.yml +++ b/services/notifications/docker-compose.yml @@ -10,12 +10,14 @@ services: target: base volumes: - .:/overleaf/services/notifications - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations - ../../tsconfig.backend.json:/overleaf/tsconfig.backend.json @@ -25,7 +27,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_CONNECTION_STRING: mongodb://mongo/test-overleaf NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" entrypoint: /overleaf/bin/shared/wait_for_it mongo:27017 --timeout=60 -- command: yarn run --silent test:unit user: node @@ -40,12 +42,14 @@ services: target: base volumes: - .:/overleaf/services/notifications - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations - ../../tsconfig.backend.json:/overleaf/tsconfig.backend.json @@ -57,7 +61,7 @@ services: MOCHA_GREP: ${MOCHA_GREP} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" user: node depends_on: mongo: diff --git a/services/notifications/package.json b/services/notifications/package.json index d144b7ab09..eab5c2053d 100644 --- a/services/notifications/package.json +++ b/services/notifications/package.json @@ -30,14 +30,17 @@ "body-parser": "1.20.4", "bunyan": "^1.8.15", "express": "4.22.1", + "mongodb": "6.12.0", "mongodb-legacy": "6.1.3", "zod": "^4.1.7", "zod-validation-error": "^4.0.1" }, "devDependencies": { "@overleaf/migrations": "workspace:*", + "@types/node": "^24.5.2", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", + "eslint": "^10.4.0", "mocha": "^11.1.0", "typescript": "^5.0.4", "vitest": "4.1.5" diff --git a/services/notifications/test/acceptance/js/MongoHelper.ts b/services/notifications/test/acceptance/js/MongoHelper.ts index f0ee6ce5c6..509936f346 100644 --- a/services/notifications/test/acceptance/js/MongoHelper.ts +++ b/services/notifications/test/acceptance/js/MongoHelper.ts @@ -4,6 +4,6 @@ import { promisify } from 'node:util' beforeAll(async function () { await promisify(exec)( - `cd ../../tools/migrations && npm run migrations -- migrate -t server-ce` + `cd ../../tools/migrations && yarn run migrations migrate -t server-ce` ) }, 60_000) diff --git a/services/project-history/Dockerfile b/services/project-history/Dockerfile index 2bab7e0eb9..6a11313a48 100644 --- a/services/project-history/Dockerfile +++ b/services/project-history/Dockerfile @@ -5,7 +5,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -18,7 +17,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config FROM base AS app -COPY package.json yarn.lock .yarnrc.yml /overleaf/ +COPY package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json COPY libraries/logger/package.json /overleaf/libraries/logger/package.json @@ -27,16 +26,18 @@ COPY libraries/mongo-utils/package.json /overleaf/libraries/mongo-utils/package. COPY libraries/o-error/package.json /overleaf/libraries/o-error/package.json COPY libraries/overleaf-editor-core/package.json /overleaf/libraries/overleaf-editor-core/package.json COPY libraries/promise-utils/package.json /overleaf/libraries/promise-utils/package.json +COPY libraries/ranges-tracker/package.json /overleaf/libraries/ranges-tracker/package.json COPY libraries/redis-wrapper/package.json /overleaf/libraries/redis-wrapper/package.json COPY libraries/settings/package.json /overleaf/libraries/settings/package.json COPY libraries/stream-utils/package.json /overleaf/libraries/stream-utils/package.json COPY libraries/validation-tools/package.json /overleaf/libraries/validation-tools/package.json +COPY services/document-updater/package.json /overleaf/services/document-updater/package.json COPY services/project-history/package.json /overleaf/services/project-history/package.json COPY tools/migrations/package.json /overleaf/tools/migrations/package.json COPY .yarn/patches/ /overleaf/.yarn/patches/ COPY tools/migrations/ /overleaf/tools/migrations/ -RUN cd /overleaf && yarn workspaces focus @overleaf/project-history overleaf +RUN cd /overleaf && yarn workspaces focus @overleaf/project-history @overleaf/document-updater overleaf COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/ COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/ COPY libraries/logger/ /overleaf/libraries/logger/ @@ -45,13 +46,17 @@ COPY libraries/mongo-utils/ /overleaf/libraries/mongo-utils/ COPY libraries/o-error/ /overleaf/libraries/o-error/ COPY libraries/overleaf-editor-core/ /overleaf/libraries/overleaf-editor-core/ COPY libraries/promise-utils/ /overleaf/libraries/promise-utils/ +COPY libraries/ranges-tracker/ /overleaf/libraries/ranges-tracker/ COPY libraries/redis-wrapper/ /overleaf/libraries/redis-wrapper/ COPY libraries/settings/ /overleaf/libraries/settings/ COPY libraries/stream-utils/ /overleaf/libraries/stream-utils/ COPY libraries/validation-tools/ /overleaf/libraries/validation-tools/ +COPY services/document-updater/ /overleaf/services/document-updater/ COPY services/project-history/ /overleaf/services/project-history/ COPY tools/migrations/ /overleaf/tools/migrations/ +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + FROM app USER node diff --git a/services/project-history/Makefile b/services/project-history/Makefile index 29a1d82601..30a942a245 100644 --- a/services/project-history/Makefile +++ b/services/project-history/Makefile @@ -24,10 +24,12 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \ $(MONOREPO)/libraries/o-error/package.json \ $(MONOREPO)/libraries/overleaf-editor-core/package.json \ $(MONOREPO)/libraries/promise-utils/package.json \ + $(MONOREPO)/libraries/ranges-tracker/package.json \ $(MONOREPO)/libraries/redis-wrapper/package.json \ $(MONOREPO)/libraries/settings/package.json \ $(MONOREPO)/libraries/stream-utils/package.json \ $(MONOREPO)/libraries/validation-tools/package.json \ + $(MONOREPO)/services/document-updater/package.json \ $(MONOREPO)/services/project-history/package.json \ $(MONOREPO)/tools/migrations/package.json \ $(MONOREPO)/.yarn/patches/* \ @@ -73,9 +75,11 @@ clean: # Eslint and prettier (plus some configs) are on the root. RUN_LINTING = ../../bin/run -w /overleaf/services/$(PROJECT_NAME) monorepo yarn run --silent RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent +RUN_EXEC_MONOREPO = ../../bin/run monorepo yarn exec RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/document-updater/app/js/types.ts:/overleaf/services/document-updater/app/js/types.ts --volume $(MONOREPO)/services/project-history/reports:/overleaf/services/project-history/reports --volume $(MONOREPO)/.cache:/overleaf/.cache $(IMAGE_CI) yarn run --silent RUN_LINTING_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/document-updater/app/js/types.ts:/overleaf/services/document-updater/app/js/types.ts --volume $(MONOREPO)/services/project-history/reports:/overleaf/services/project-history/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn run --silent +RUN_EXEC_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/document-updater/app/js/types.ts:/overleaf/services/document-updater/app/js/types.ts --volume $(MONOREPO)/services/project-history/reports:/overleaf/services/project-history/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn exec SHELLCHECK_OPTS = \ --shell=bash \ @@ -123,14 +127,14 @@ format_fix: $(RUN_LINTING_MONOREPO) format:fix services/project-history lint: - $(RUN_LINTING) lint + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format unix services/project-history lint_ci: - -$(RUN_LINTING_CI) lint --format json --output-file reports/eslint.json + -$(RUN_EXEC_CI_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format json --output-file services/project-history/reports/eslint.json services/project-history sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json lint_fix: - $(RUN_LINTING) lint:fix + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --fix services/project-history typecheck: $(RUN_LINTING) types:check diff --git a/services/project-history/buildscript.txt b/services/project-history/buildscript.txt index bcc89ae526..1b34ae0fcc 100644 --- a/services/project-history/buildscript.txt +++ b/services/project-history/buildscript.txt @@ -4,6 +4,7 @@ project-history --env-add= --env-pass-through= --esmock-loader=True +--extra-focus-packages=@overleaf/document-updater --node-version=24.14.1 --package-name=@overleaf/project-history --pipeline-owner=44 diff --git a/services/project-history/docker-compose.yml b/services/project-history/docker-compose.yml index 38f0a353d5..2126093b5c 100644 --- a/services/project-history/docker-compose.yml +++ b/services/project-history/docker-compose.yml @@ -10,12 +10,14 @@ services: target: base volumes: - .:/overleaf/services/project-history - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations working_dir: /overleaf/services/project-history @@ -24,7 +26,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_CONNECTION_STRING: mongodb://mongo/test-overleaf NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" REDIS_HOST: redis_test HISTORY_REDIS_HOST: redis_test QUEUES_REDIS_HOST: redis_test @@ -46,12 +48,14 @@ services: target: base volumes: - .:/overleaf/services/project-history - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations working_dir: /overleaf/services/project-history @@ -67,7 +71,7 @@ services: MOCHA_GREP: ${MOCHA_GREP} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" user: node depends_on: mongo: diff --git a/services/project-history/package.json b/services/project-history/package.json index 4b62bf714a..2788a9f99d 100644 --- a/services/project-history/package.json +++ b/services/project-history/package.json @@ -33,18 +33,22 @@ "express": "4.22.1", "lodash": "^4.18.1", "minimist": "^1.2.8", + "mongodb": "6.12.0", "mongodb-legacy": "6.1.3", "overleaf-editor-core": "workspace:*", "p-queue": "^8.1.0" }, "devDependencies": { "@overleaf/migrations": "workspace:*", + "@types/node": "^24.5.2", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", - "esmock": "^2.7.3", + "eslint": "^10.4.0", + "esmock": "patch:esmock@npm%3A2.7.3#~/.yarn/patches/esmock-npm-2.7.3-83624b28f6.patch", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", + "mongodb": "6.12.0", "nock": "^13.5.3", "sinon": "~9.0.1", "sinon-chai": "^3.7.0", diff --git a/services/project-history/test/acceptance/js/helpers/MongoHelper.js b/services/project-history/test/acceptance/js/helpers/MongoHelper.js index cf969c6210..2729bf78d1 100644 --- a/services/project-history/test/acceptance/js/helpers/MongoHelper.js +++ b/services/project-history/test/acceptance/js/helpers/MongoHelper.js @@ -5,6 +5,6 @@ before('run migrations', async function () { this.timeout(60_000) await promisify(exec)( - `cd ../../tools/migrations && npm run migrations -- migrate -t server-ce` + `cd ../../tools/migrations && yarn run migrations migrate -t server-ce` ) }) diff --git a/services/real-time/Dockerfile b/services/real-time/Dockerfile index 56103a946b..ae2ef02533 100644 --- a/services/real-time/Dockerfile +++ b/services/real-time/Dockerfile @@ -5,7 +5,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 @@ -18,7 +17,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config FROM base AS app -COPY package.json yarn.lock .yarnrc.yml /overleaf/ +COPY package.json yarn.lock .yarnrc.yml .pnp.register.mjs /overleaf/ COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json COPY libraries/logger/package.json /overleaf/libraries/logger/package.json @@ -43,6 +42,8 @@ COPY libraries/settings/ /overleaf/libraries/settings/ COPY libraries/validation-tools/ /overleaf/libraries/validation-tools/ COPY services/real-time/ /overleaf/services/real-time/ +ENV NODE_OPTIONS="--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + FROM app USER node diff --git a/services/real-time/Makefile b/services/real-time/Makefile index 452f140e4a..65135b92d2 100644 --- a/services/real-time/Makefile +++ b/services/real-time/Makefile @@ -69,9 +69,11 @@ clean: # Eslint and prettier (plus some configs) are on the root. RUN_LINTING = ../../bin/run -w /overleaf/services/$(PROJECT_NAME) monorepo yarn run --silent RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent +RUN_EXEC_MONOREPO = ../../bin/run monorepo yarn exec RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/real-time/reports:/overleaf/services/real-time/reports --volume $(MONOREPO)/.cache:/overleaf/.cache $(IMAGE_CI) yarn run --silent RUN_LINTING_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/real-time/reports:/overleaf/services/real-time/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn run --silent +RUN_EXEC_CI_MONOREPO = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/eslint.config.mjs:/overleaf/eslint.config.mjs --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json --volume $(MONOREPO)/services/real-time/reports:/overleaf/services/real-time/reports --volume $(MONOREPO)/.cache:/overleaf/.cache -w /overleaf $(IMAGE_CI) yarn exec SHELLCHECK_OPTS = \ --shell=bash \ @@ -119,14 +121,14 @@ format_fix: $(RUN_LINTING_MONOREPO) format:fix services/real-time lint: - $(RUN_LINTING) lint + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format unix services/real-time lint_ci: - -$(RUN_LINTING_CI) lint --format json --output-file reports/eslint.json + -$(RUN_EXEC_CI_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --max-warnings 0 --format json --output-file services/real-time/reports/eslint.json services/real-time sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json lint_fix: - $(RUN_LINTING) lint:fix + $(RUN_EXEC_MONOREPO) eslint --cache --cache-location ./.cache/eslint/ --fix services/real-time typecheck: $(RUN_LINTING) types:check diff --git a/services/real-time/docker-compose.yml b/services/real-time/docker-compose.yml index 678d96e22d..9e973356f0 100644 --- a/services/real-time/docker-compose.yml +++ b/services/real-time/docker-compose.yml @@ -10,12 +10,14 @@ services: target: base volumes: - .:/overleaf/services/real-time - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../tsconfig.backend.json:/overleaf/tsconfig.backend.json working_dir: /overleaf/services/real-time environment: @@ -23,7 +25,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_CONNECTION_STRING: mongodb://mongo/test-overleaf NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" REDIS_HOST: redis_test HISTORY_REDIS_HOST: redis_test QUEUES_REDIS_HOST: redis_test @@ -42,12 +44,14 @@ services: target: base volumes: - .:/overleaf/services/real-time - - ../../node_modules:/overleaf/node_modules - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml - ../../yarn.lock:/overleaf/yarn.lock - ../../.yarn:/overleaf/.yarn + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs working_dir: /overleaf/services/real-time environment: RETRIES: @@ -61,7 +65,7 @@ services: MOCHA_GREP: ${MOCHA_GREP} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" user: node depends_on: redis_test: diff --git a/services/real-time/package.json b/services/real-time/package.json index 9bc153f21d..20a9d65cd4 100644 --- a/services/real-time/package.json +++ b/services/real-time/package.json @@ -36,12 +36,15 @@ "proxy-addr": "^2.0.7", "socket.io": "github:overleaf/socket.io#0.9.19-overleaf-12", "socket.io-client": "github:overleaf/socket.io-client#0.9.17-overleaf-5", + "zod": "^3.24.0", "zod-validation-error": "^4.0.1" }, "devDependencies": { + "@types/node": "^24.5.2", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", "cookie-signature": "^1.1.0", + "eslint": "^10.4.0", "mocha": "^11.1.0", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/services/web/.gitignore b/services/web/.gitignore index 5475a79063..95f52a993a 100644 --- a/services/web/.gitignore +++ b/services/web/.gitignore @@ -22,6 +22,7 @@ cypress/screenshots/ cypress/videos/ cypress/downloads/ cypress/results/ +cypress/reporter/ # Ace themes for conversion frontend/js/features/source-editor/themes/ace/ diff --git a/services/web/.storybook/main.ts b/services/web/.storybook/main.ts index fc0672e6e0..eb62c3962a 100644 --- a/services/web/.storybook/main.ts +++ b/services/web/.storybook/main.ts @@ -127,6 +127,9 @@ export default defineMain({ rootDir, 'modules/writefull/frontend/js/integration/src/' ), + // Allow all packages to resolve core-js (injected by Babel's + // useBuiltIns: 'usage') even under Yarn PnP strict resolution. + 'core-js': path.dirname(require.resolve('core-js/package.json')), }, }, module: { diff --git a/services/web/Dockerfile b/services/web/Dockerfile index 47ed96ed0b..b9a52b7c53 100644 --- a/services/web/Dockerfile +++ b/services/web/Dockerfile @@ -4,7 +4,6 @@ FROM node:24.14.1 AS base # Corepack setup, shared between all the images. -ENV PATH="/overleaf/node_modules/.bin:$PATH" ENV COREPACK_HOME=/opt/corepack RUN corepack enable && corepack install -g yarn@4.14.1 ENV COREPACK_ENABLE_NETWORK=0 diff --git a/services/web/Makefile b/services/web/Makefile index cc6d18c9e4..bde9ee79a4 100644 --- a/services/web/Makefile +++ b/services/web/Makefile @@ -499,9 +499,9 @@ RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent ORG_PATH = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin RUN_LINT_FORMAT ?= \ - docker run --rm --env BRANCH_NAME --env CI --env COMMIT_SHA --env MONOREPO --env PATH=/overleaf/node_modules/.bin:$(ORG_PATH) --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume ${PWD}/data/reports:/overleaf/services/web/data/reports --volume $(MONOREPO)/.cache/:/overleaf/.cache/ ${IMAGE_CI} + docker run --rm --env BRANCH_NAME --env CI --env COMMIT_SHA --env MONOREPO --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc.cjs:/overleaf/.prettierrc.cjs --volume ${PWD}/data/reports:/overleaf/services/web/data/reports --volume $(MONOREPO)/.cache/:/overleaf/.cache/ ${IMAGE_CI} -NODE_MODULES_PATH := ${PATH}:${PWD}/node_modules/.bin:/overleaf/services/web/node_modules/.bin +NODE_MODULES_PATH := ${PATH} WITH_NODE_MODULES_PATH = \ format_backend \ format_frontend \ @@ -583,7 +583,7 @@ lint_flag_res_send_usage: lint: lint_overleafModuleImports lint_overleafModuleImports: - node scripts/check_overleafModuleImports.mjs + yarn node scripts/check_overleafModuleImports.mjs lint: typecheck_frontend typecheck_frontend: @@ -668,6 +668,7 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \ $(MONOREPO)/package.json \ $(MONOREPO)/yarn.lock \ $(MONOREPO)/libraries/access-token-encryptor/package.json \ + $(MONOREPO)/libraries/eslint-config/package.json \ $(MONOREPO)/libraries/eslint-plugin/package.json \ $(MONOREPO)/libraries/fetch-utils/package.json \ $(MONOREPO)/libraries/logger/package.json \ diff --git a/services/web/bin/check_extracted_translations b/services/web/bin/check_extracted_translations index 569af5ccf0..d4e7cba5e2 100755 --- a/services/web/bin/check_extracted_translations +++ b/services/web/bin/check_extracted_translations @@ -5,7 +5,7 @@ set -e # Ensure all locales used in the frontend are tracked OUTPUT=data/dumpFolder/i18next-scanner trap 'rm -rf "$OUTPUT"' EXIT -npx i18next-scanner --output "$OUTPUT" +yarn exec i18next-scanner --output "$OUTPUT" ACTUAL=frontend/extracted-translations.json EXPECTED="$OUTPUT/frontend/extracted-translations.json" if ! diff "$ACTUAL" "$EXPECTED"; then diff --git a/services/web/cypress.config.ts b/services/web/cypress.config.ts index 2f24ab8091..c27c7d0925 100644 --- a/services/web/cypress.config.ts +++ b/services/web/cypress.config.ts @@ -1,10 +1,13 @@ import { defineConfig } from 'cypress' import { webpackConfig } from './cypress/support/webpack.cypress' +// Cypress's Electron process uses PackherdModuleLoader which doesn't go through +// PnP hooks. Reporter packages are materialized into /tmp/cypress-reporter by +// scripts/materialize-cypress-reporter.js at container startup. let reporterOptions = {} if (process.env.CI) { reporterOptions = { - reporter: 'cypress-multi-reporters', + reporter: '/tmp/cypress-reporter/node_modules/cypress-multi-reporters', reporterOptions: { configFile: 'cypress/cypress-multi-reporters.json', }, diff --git a/services/web/docker-compose.yml b/services/web/docker-compose.yml index be82f0432e..7107c3e4ff 100644 --- a/services/web/docker-compose.yml +++ b/services/web/docker-compose.yml @@ -9,7 +9,9 @@ services: target: base volumes: - .:/overleaf/services/web - - ../../node_modules:/overleaf/node_modules + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../libraries:/overleaf/libraries - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations @@ -30,7 +32,7 @@ services: MOCHA_GREP: ${MOCHA_GREP:-} LOG_LEVEL: ${LOG_LEVEL:-} NODE_ENV: test - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" REDIS_HOST: redis_test MONOREPO: entrypoint: /overleaf/bin/shared/wait_for_it mongo:27017 --timeout=60 -- @@ -47,7 +49,9 @@ services: target: base volumes: - .:/overleaf/services/web - - ../../node_modules:/overleaf/node_modules + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../libraries:/overleaf/libraries - ../../bin/shared/wait_for_it:/overleaf/bin/shared/wait_for_it - ../../tools/migrations:/overleaf/tools/migrations @@ -69,6 +73,7 @@ services: LOG_LEVEL: ${LOG_LEVEL:-} MONGO_SERVER_SELECTION_TIMEOUT: 600000 MONGO_SOCKET_TIMEOUT: 300000 + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" REDIS_HOST: redis_test MONOREPO: RETRIES: @@ -91,7 +96,9 @@ services: target: base volumes: - .:/overleaf/services/web - - ../../node_modules:/overleaf/node_modules + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml @@ -102,7 +109,7 @@ services: CI: JUNIT_ROOT_SUITE_NAME: MOCHA_GREP: ${MOCHA_GREP} - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" VERBOSE_LOGGING: command: yarn run --silent test:frontend user: node @@ -115,7 +122,10 @@ services: - USER_GID volumes: - .:/overleaf/services/web - - ../../node_modules:/overleaf/node_modules + - ../../scripts:/overleaf/scripts:ro + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml @@ -128,7 +138,8 @@ services: JUNIT_ROOT_SUITE_NAME: CYPRESS_SPEC_PATTERN: ${CYPRESS_SPEC_PATTERN:-} CYPRESS_EXCLUDE_SPEC_PATTERN: ${CYPRESS_EXCLUDE_SPEC_PATTERN:-} - entrypoint: npm + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs" + entrypoint: yarn command: - "run" - "cypress:run-ct" @@ -140,7 +151,9 @@ services: target: base volumes: - .:/overleaf/services/web - - ../../node_modules:/overleaf/node_modules + - ../../.pnp.cjs:/overleaf/.pnp.cjs + - ../../.pnp.loader.mjs:/overleaf/.pnp.loader.mjs + - ../../.pnp.register.mjs:/overleaf/.pnp.register.mjs - ../../libraries:/overleaf/libraries - ../../package.json:/overleaf/package.json - ../../.yarnrc.yml:/overleaf/.yarnrc.yml @@ -150,7 +163,7 @@ services: environment: CI: JUNIT_ROOT_SUITE_NAME: - NODE_OPTIONS: "--unhandled-rejections=strict" + NODE_OPTIONS: "--require /overleaf/.pnp.cjs --import /overleaf/.pnp.register.mjs --unhandled-rejections=strict" VERBOSE_LOGGING: command: yarn run --silent test:writefull user: node diff --git a/services/web/package.json b/services/web/package.json index 1e3dd2acc4..14289f3b73 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -3,6 +3,10 @@ "description": "The HTTP front end for Overleaf", "private": true, "main": "app.mjs", + "exports": { + ".": "./app.mjs", + "./*": "./*" + }, "directories": { "public": "./public" }, @@ -36,8 +40,9 @@ "type-check:backend": "tsc -p tsconfig.backend.json --noEmit", "extract-translations": "i18next-scanner", "convert-themes": "node frontend/js/features/source-editor/themes/scripts/convert.js", - "cypress:open-ct": "OVERLEAF_CONFIG=$(pwd)/config/settings.webpack.js cypress open --component", - "cypress:run-ct": "OVERLEAF_CONFIG=$(pwd)/config/settings.webpack.js cypress run --component --browser chrome", + "materialize-reporter": "node scripts/materialize-cypress-reporter.js /tmp/cypress-reporter", + "cypress:open-ct": "yarn run materialize-reporter && OVERLEAF_CONFIG=$(pwd)/config/settings.webpack.js cypress open --component", + "cypress:run-ct": "yarn run materialize-reporter && OVERLEAF_CONFIG=$(pwd)/config/settings.webpack.js cypress run --component --browser chrome", "cypress:docker:open-ct": "USER_UID=$(id -u) USER_GID=$(id -g) docker compose -f docker-compose.cypress.yml run --rm cypress yarn run cypress:open-ct", "cypress:docker:run-ct": "USER_UID=$(id -u) USER_GID=$(id -g) docker compose -f docker-compose.cypress.yml run --rm cypress yarn run cypress:run-ct --browser chrome", "lezer-latex:generate": "node scripts/lezer-latex/generate.mjs", @@ -152,6 +157,7 @@ "minimist": "^1.2.7", "mmmagic": "^0.5.3", "moment": "^2.29.4", + "mongodb": "6.12.0", "mongodb-legacy": "6.1.3", "mongoose": "8.22.1", "multer": "2.1.1", @@ -198,6 +204,7 @@ "@ai-sdk/react": "^3.0.172", "@babel/core": "^7.28.5", "@babel/plugin-proposal-decorators": "^7.28.0", + "@babel/plugin-transform-typescript": "^7.28.0", "@babel/preset-env": "^7.28.5", "@babel/preset-react": "^7.28.5", "@babel/preset-typescript": "^7.28.5", @@ -235,6 +242,7 @@ "@replit/codemirror-indentation-markers": "overleaf/codemirror-indentation-markers#371ce3b56f453a392eb0d3b85ab019c185c68e1f", "@replit/codemirror-vim": "overleaf/codemirror-vim#1bef138382d948018f3f9b8a4d7a70ab61774e4b", "@sentry/browser": "7.46.0", + "@sentry/types": "7.46.0", "@storybook/addon-a11y": "10.3.5", "@storybook/addon-designs": "^11.1.3", "@storybook/addon-docs": "10.3.5", @@ -256,15 +264,19 @@ "@types/async": "^3.2.25", "@types/bootstrap": "^5.2.10", "@types/chai": "^4.3.0", + "@types/chai-as-promised": "^8.0.2", "@types/dateformat": "^5.0.3", "@types/diff": "^5.2.3", "@types/dom-speech-recognition": "^0.0.7", "@types/events": "^3.0.3", "@types/express": "^4.17.23", + "@types/lodash": "^4.17.24", + "@types/mdast": "^4.0.4", "@types/minimist": "^1.2.5", "@types/mocha": "^9.1.0", "@types/mocha-each": "^2.0.4", "@types/node": "^24.5.2", + "@types/path-browserify": "^1.0.3", "@types/react": "^18.3.20", "@types/react-color": "^3.0.13", "@types/react-dom": "^18.3.6", @@ -273,15 +285,19 @@ "@types/react-syntax-highlighter": "^15.5.11", "@types/recurly__recurly-js": "^4.38.0", "@types/sanitize-html": "^2.14.0", + "@types/sinon": "^21.0.1", "@types/sinon-chai": "^3.2.12", "@types/utf-8-validate": "^5.0.2", "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^8.59.4", + "@typescript-eslint/parser": "^8.59.4", "@uppy/core": "^3.8.0", "@uppy/dashboard": "3.7.1", "@uppy/drag-drop": "3.0.3", "@uppy/file-input": "3.0.4", "@uppy/progress-bar": "3.0.4", "@uppy/react": "3.2.1", + "@uppy/status-bar": "^3.2.5", "@uppy/utils": "^5.7.0", "@uppy/xhr-upload": "3.6.0", "@vitest/coverage-istanbul": "^4.0.17", @@ -316,6 +332,8 @@ "core-js": "~3.46.0", "css-loader": "^7.1.4", "css-minimizer-webpack-plugin": "^8.0.0", + "csv-parse": "^6.2.1", + "csv-stringify": "^6.7.0", "cypress": "15.12.0", "cypress-multi-reporters": "^2.0.5", "cypress-plugin-tab": "^1.0.5", @@ -326,9 +344,12 @@ "downshift": "^9.0.9", "es6-promise": "^4.2.8", "escodegen": "^2.0.0", + "eslint": "^10.4.0", "eslint-config-prettier": "^10.1.8", + "eslint-formatter-unix": "^8.40.0", "eslint-plugin-chai-expect": "^4.1.0", "eslint-plugin-chai-friendly": "^1.2.0", + "eslint-plugin-cypress": "^4.1.0", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-mocha": "^11.3.0", @@ -344,6 +365,7 @@ "fake-indexeddb": "^6.0.0", "fast-fuzzy": "^1.12.0", "fetch-mock": "^12.6.0", + "focus-trap": "^8.2.1", "formik": "^2.2.9", "glob": "^12.0.0", "globals": "^17.6.0", @@ -419,8 +441,9 @@ "timekeeper": "^2.2.0", "to-string-loader": "^1.2.0", "ts-loader": "^9.5.7", + "tslib": "^2.8.1", "tty-browserify": "^0.0.1", - "typescript": "^5.9.3", + "typescript": "^5.0.4", "unified": "^11.0.5", "unist-util-visit": "^5.0.0", "use-stick-to-bottom": "^1.1.1", diff --git a/services/web/scripts/learn/checkSanitize/checkSanitizeOptions.mjs b/services/web/scripts/learn/checkSanitize/checkSanitizeOptions.mjs index a702a4846e..9471b3428e 100644 --- a/services/web/scripts/learn/checkSanitize/checkSanitizeOptions.mjs +++ b/services/web/scripts/learn/checkSanitize/checkSanitizeOptions.mjs @@ -3,7 +3,7 @@ import fs from 'node:fs' import Path from 'node:path' import cheerio from 'cheerio' // checkSanitizeOptions is only used in dev env -// eslint-disable-next-line import/no-extraneous-dependencies +// eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved import * as prettier from 'prettier' import sanitizeHtml from 'sanitize-html' import { sanitizeOptions } from '../../../modules/learn/app/src/sanitizeOptions.mjs' diff --git a/services/web/scripts/materialize-cypress-reporter.js b/services/web/scripts/materialize-cypress-reporter.js new file mode 100644 index 0000000000..dc2b444e54 --- /dev/null +++ b/services/web/scripts/materialize-cypress-reporter.js @@ -0,0 +1,113 @@ +#!/usr/bin/env node +'use strict' +/** + * Materialize Cypress reporter packages (and their transitive dependencies) + * into a real node_modules tree so that Cypress's Electron process (which uses + * PackherdModuleLoader, NOT Yarn PnP hooks) can load them. + * + * Builds a NESTED node_modules structure (each package gets its own + * node_modules/ for its deps) to avoid version conflicts from flat dedup. + * + * The target-dir must be OUTSIDE the PnP workspace root — otherwise PnP + * intercepts requires from the materialized packages and blocks undeclared deps. + * + * Usage: yarn node scripts/materialize-cypress-reporter.js + */ + +const path = require('path') +const fs = require('fs') + +const targetDir = process.argv[2] +if (!targetDir) { + console.error( + 'Usage: yarn node scripts/materialize-cypress-reporter.js ' + ) + process.exit(1) +} + +const pnp = require('module').findPnpApi(__filename) +if (!pnp) { + console.log('Not running under PnP — nothing to do.') + process.exit(0) +} + +let totalCopied = 0 + +// PnP patches readFileSync/readdirSync/statSync but NOT cpSync. +// Manual recursive copy to read from virtual/zip paths. +function copyRecursive(src, dest) { + const stat = fs.statSync(src) + if (stat.isDirectory()) { + fs.mkdirSync(dest, { recursive: true }) + for (const entry of fs.readdirSync(src)) { + copyRecursive(path.join(src, entry), path.join(dest, entry)) + } + } else { + fs.mkdirSync(path.dirname(dest), { recursive: true }) + fs.writeFileSync(dest, fs.readFileSync(src)) + } +} + +function resolvePkgDir(pkgName, issuer) { + // Use resolveToUnqualified to get the package directory without going + // through the package's exports map (which may not expose package.json). + let pkgDir = pnp.resolveToUnqualified(pkgName, issuer + '/') + if (pkgDir.endsWith('/')) pkgDir = pkgDir.slice(0, -1) + return pkgDir +} + +/** + * Materialize a package and its deps into destDir/node_modules/pkgName. + * Each package's own deps get nested under its own node_modules/. + */ +function materializeRecursive(pkgName, issuer, destNodeModules, seen) { + // Dedupe by destination path to avoid infinite loops, but allow the same + // package to appear in multiple locations (nested node_modules). + const key = `${destNodeModules}/${pkgName}` + if (seen.has(key)) return + seen.add(key) + + let pkgDir + try { + pkgDir = resolvePkgDir(pkgName, issuer) + } catch { + return // optional/missing dep + } + + const dest = path.join(destNodeModules, pkgName) + copyRecursive(pkgDir, dest) + totalCopied++ + + const pkg = JSON.parse( + fs.readFileSync(path.join(pkgDir, 'package.json'), 'utf8') + ) + const deps = [ + ...Object.keys(pkg.dependencies || {}), + ...Object.keys(pkg.peerDependencies || {}), + ] + + if (deps.length > 0) { + const nestedNodeModules = path.join(dest, 'node_modules') + for (const dep of deps) { + materializeRecursive(dep, pkgDir, nestedNodeModules, seen) + } + } +} + +const rootNodeModules = path.resolve(targetDir, 'node_modules') +const seen = new Set() +const topLevel = [ + 'cypress-multi-reporters', + 'mocha-junit-reporter', + 'typescript', +] + +for (const pkg of topLevel) { + try { + materializeRecursive(pkg, process.cwd(), rootNodeModules, seen) + } catch (e) { + console.warn(`Warning: could not materialize ${pkg}: ${e.message}`) + } +} + +console.log(`Materialized ${totalCopied} packages into ${rootNodeModules}`) diff --git a/services/web/test/acceptance/bootstrap.js b/services/web/test/acceptance/bootstrap.js index 03d956ef24..2166a43e62 100644 --- a/services/web/test/acceptance/bootstrap.js +++ b/services/web/test/acceptance/bootstrap.js @@ -1,3 +1,15 @@ +// Register PnP ESM loader via module.register() for synchronous ESM resolution +// (--experimental-loader from yarn only works for async resolution) +const { register } = require('node:module') +const { pathToFileURL } = require('node:url') +const path = require('node:path') +const pnpRegister = path.resolve(__dirname, '../../.pnp.register.mjs') +try { + register(pathToFileURL(pnpRegister), pathToFileURL(__filename)) +} catch { + // .pnp.register.mjs may not exist in non-PnP environments +} + const chai = require('chai') chai.should() chai.use(require('chai-as-promised')) diff --git a/services/web/test/acceptance/src/DeleteOrphanedDocsOnlineCheckTests.mjs b/services/web/test/acceptance/src/DeleteOrphanedDocsOnlineCheckTests.mjs index 8e951c5554..21e029e81a 100644 --- a/services/web/test/acceptance/src/DeleteOrphanedDocsOnlineCheckTests.mjs +++ b/services/web/test/acceptance/src/DeleteOrphanedDocsOnlineCheckTests.mjs @@ -119,7 +119,8 @@ describe('DeleteOrphanedDocsOnlineCheck', function () { // Hide verbose log messages `calling destroy for project in docstore` 'LOG_LEVEL=error', // Hide deprecation warnings for calling `db.collection.count` - 'NODE_OPTIONS=--no-deprecation', + // Preserve existing NODE_OPTIONS (e.g. PnP hooks) while adding --no-deprecation + `NODE_OPTIONS='${process.env.NODE_OPTIONS || ''} --no-deprecation'`, ]) .concat(['node', 'scripts/delete_orphaned_docs_online_check.mjs']) .join(' ') diff --git a/services/web/test/acceptance/src/helpers/MongoHelper.mjs b/services/web/test/acceptance/src/helpers/MongoHelper.mjs index 35ce209ea1..5ba4ad9667 100644 --- a/services/web/test/acceptance/src/helpers/MongoHelper.mjs +++ b/services/web/test/acceptance/src/helpers/MongoHelper.mjs @@ -22,7 +22,7 @@ export default { this.timeout(60_000) await promisify(exec)( - `cd ../../tools/migrations && npm run migrations -- migrate -t ${Settings.env || DEFAULT_ENV}` + `cd ../../tools/migrations && yarn run migrations migrate -t ${Settings.env || DEFAULT_ENV}` ) }) diff --git a/services/web/test/unit/src/Settings/Settings.test.mjs b/services/web/test/unit/src/Settings/Settings.test.mjs index 21e53061ad..a8b57b1be9 100644 --- a/services/web/test/unit/src/Settings/Settings.test.mjs +++ b/services/web/test/unit/src/Settings/Settings.test.mjs @@ -10,7 +10,9 @@ function clearSettingsCache() { const settingsDeps = Object.keys(require.cache).filter( x => x.includes('/@overleaf/settings') || + x.includes('/@overleaf-settings-virtual') || x.includes(`${monorepoPath}/libraries/settings`) || + x.includes('/libraries/settings/') || x.includes(`${monorepoPath}/services/web/config`) ) settingsDeps.forEach(dep => delete require.cache[dep]) diff --git a/services/web/tsconfig.json b/services/web/tsconfig.json index 2e5fc9ad56..1355045875 100644 --- a/services/web/tsconfig.json +++ b/services/web/tsconfig.json @@ -20,6 +20,9 @@ "@modules/*": ["./modules/*"], "@overleaf/o-error": ["../../libraries/o-error"], "@overleaf/ranges-tracker": ["../../libraries/ranges-tracker"], + "@overleaf/validation-tools": ["../../libraries/validation-tools"], + "overleaf-editor-core": ["../../libraries/overleaf-editor-core"], + "overleaf-editor-core/*": ["../../libraries/overleaf-editor-core/*"], "@ol-types/*": ["./types/*"], "@ol-storybook/*": ["./.storybook/*"], diff --git a/services/web/types/uppy-utils.d.ts b/services/web/types/uppy-utils.d.ts new file mode 100644 index 0000000000..1c72e0f426 --- /dev/null +++ b/services/web/types/uppy-utils.d.ts @@ -0,0 +1,11 @@ +// Ambient module declaration for @uppy/utils subpath imports. +// Under Yarn PnP, TypeScript cannot find the ambient declarations in +// @uppy/utils/types/index.d.ts for deep imports like +// @uppy/utils/lib/getDroppedFiles. Re-declare the subset we use here. +declare module '@uppy/utils/lib/getDroppedFiles' { + function getDroppedFiles( + dataTransfer: DataTransfer, + options?: Record + ): Promise + export default getDroppedFiles +} diff --git a/services/web/webpack.config.js b/services/web/webpack.config.js index 35b4e96cd3..e7edc05502 100644 --- a/services/web/webpack.config.js +++ b/services/web/webpack.config.js @@ -50,13 +50,11 @@ globSync( }) function getModuleDirectory(moduleName) { - const entrypointPath = require.resolve(moduleName) - const suffix = `node_modules/${moduleName}` - const idx = entrypointPath.indexOf(suffix) - if (idx === -1) { - throw new Error(`could not find Node module: ${moduleName}`) + try { + return path.dirname(require.resolve(`${moduleName}/package.json`)) + } catch (err) { + throw new Error(`could not find Node module: ${moduleName}`, { cause: err }) } - return entrypointPath.slice(0, idx + suffix.length) } const mathjaxDir = getModuleDirectory('mathjax') @@ -312,6 +310,21 @@ module.exports = { // Ensure all packages use the same jQuery instance (prevents duplicate // copies from Yarn hoisting breaking jQuery plugins like daterangepicker) jquery: require.resolve('jquery'), + // Under Yarn PnP, babel-injected core-js polyfill imports cannot be + // resolved from third-party packages (e.g. @uppy, pdfjs-dist) because + // they don't declare core-js as a dependency. Alias to the web + // workspace's copy so all packages can resolve it. + 'core-js': path.dirname(require.resolve('core-js/package.json')), + // writefull's tsconfig uses importHelpers: true, which emits tslib + // imports that must be resolvable from the web workspace. + tslib: path.dirname(require.resolve('tslib/package.json')), + // Under PnP, packages like cypress/react that import react/react-dom + // can't resolve them from their own scope. Alias to web's copies. + react: path.dirname(require.resolve('react/package.json')), + 'react-dom': path.dirname(require.resolve('react-dom/package.json')), + // ai-sdk packages declare zod as a peer dep but PnP can't resolve it + // from their scope in the Docker build. + zod: path.dirname(require.resolve('zod/package.json')), }, // symlinks: false, // enable this while using `npm link` extensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', '.json'], diff --git a/tools/migrations/package.json b/tools/migrations/package.json index 2f938ef412..e4f0286804 100644 --- a/tools/migrations/package.json +++ b/tools/migrations/package.json @@ -5,6 +5,9 @@ "lint": "eslint --cache --cache-location ../../.cache/eslint/ --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .", "lint:fix": "eslint --cache --cache-location ../../.cache/eslint/ --fix --ext .cjs,.js,.jsx,.mjs,.ts ." }, + "devDependencies": { + "eslint": "^10.4.0" + }, "dependencies": { "@overleaf/logger": "workspace:*", "@overleaf/mongo-utils": "workspace:*", diff --git a/tsconfig.backend.json b/tsconfig.backend.json index 31a45a1b15..8e4c4b392b 100644 --- a/tsconfig.backend.json +++ b/tsconfig.backend.json @@ -15,6 +15,7 @@ "@overleaf/logger": ["./libraries/logger"], "@overleaf/metrics": ["./libraries/metrics"], "@overleaf/mongo-utils": ["./libraries/mongo-utils"], + "@overleaf/mongo-utils/*": ["./libraries/mongo-utils/*"], "@overleaf/object-persistor": ["./libraries/object-persistor"], "@overleaf/o-error": ["./libraries/o-error"], "overleaf-editor-core": ["./libraries/overleaf-editor-core"], diff --git a/yarn.lock b/yarn.lock index c8337b9960..9c15a30277 100644 --- a/yarn.lock +++ b/yarn.lock @@ -158,6 +158,157 @@ __metadata: languageName: node linkType: hard +"@algolia/cache-browser-local-storage@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/cache-browser-local-storage@npm:4.27.0" + dependencies: + "@algolia/cache-common": "npm:4.27.0" + checksum: 10c0/e66b37d6122c14cc70b1cbb6f8ad7ae9f33e1c14842de25527d99eae13ab9a55c77e5a8acd62b11ff1bfd8327e7c25d7418558a08e5846764f721157d9a781ee + languageName: node + linkType: hard + +"@algolia/cache-common@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/cache-common@npm:4.27.0" + checksum: 10c0/a2c122d5aac08a945e0973d93100dc29c82da81fca979492986eaf5906364cb1c5d8c66ebb2a173fd6f267224ae47ea0e191bb45b6fab331eaccde3dfd6043b9 + languageName: node + linkType: hard + +"@algolia/cache-in-memory@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/cache-in-memory@npm:4.27.0" + dependencies: + "@algolia/cache-common": "npm:4.27.0" + checksum: 10c0/87f92760f2aa5a10aca43193799010c00e4b3f9847851427ee5579cc0356c36b2b71e0c6a5fcab6c4ba0f7d719bc3a91a1940c9abc00855beb558840479b9c24 + languageName: node + linkType: hard + +"@algolia/client-account@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/client-account@npm:4.27.0" + dependencies: + "@algolia/client-common": "npm:4.27.0" + "@algolia/client-search": "npm:4.27.0" + "@algolia/transporter": "npm:4.27.0" + checksum: 10c0/e92edbc1097a6f56d3f2618862d4ec533c97584cfef8725a50efe06c45159dfb0fc9216da9be2809152a8900f888ed19ed312afbee14b0f08896cab084667651 + languageName: node + linkType: hard + +"@algolia/client-analytics@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/client-analytics@npm:4.27.0" + dependencies: + "@algolia/client-common": "npm:4.27.0" + "@algolia/client-search": "npm:4.27.0" + "@algolia/requester-common": "npm:4.27.0" + "@algolia/transporter": "npm:4.27.0" + checksum: 10c0/345f94045c8878df543d87852a632be05b0f6b889d012b8b1d18d78e8c74648785e019f49f4d1ef7aa5e9619323ecc9ce793f54871ac1574c91d9bd7956dc1f4 + languageName: node + linkType: hard + +"@algolia/client-common@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/client-common@npm:4.27.0" + dependencies: + "@algolia/requester-common": "npm:4.27.0" + "@algolia/transporter": "npm:4.27.0" + checksum: 10c0/2ea73593194154cfb2b1b14bb1356e423b6ac85c564c7ecaa9e4db6ff9a9974353aea48a337ea2c0e82376cbca5d41bd0bd42ace26edd9d1ab2bb1b8fee95eca + languageName: node + linkType: hard + +"@algolia/client-personalization@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/client-personalization@npm:4.27.0" + dependencies: + "@algolia/client-common": "npm:4.27.0" + "@algolia/requester-common": "npm:4.27.0" + "@algolia/transporter": "npm:4.27.0" + checksum: 10c0/bdbfb4ae77017db7e28c5bf20a85ab99078e8cea4a3f8fcde4ca735bbf5ae3f0fa0eab4c0f0b1fc4fbfd2ae318eef0da8bc1d647af72ce8dbb1fa4a25d244ede + languageName: node + linkType: hard + +"@algolia/client-search@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/client-search@npm:4.27.0" + dependencies: + "@algolia/client-common": "npm:4.27.0" + "@algolia/requester-common": "npm:4.27.0" + "@algolia/transporter": "npm:4.27.0" + checksum: 10c0/8892b42b9efd4679d9e432ed766f16b74eb2928919fd863d75630cc4d2e3eafb0a41d59f87225a64989e20006b96933d0b2716ef78bc216b8248cd49934effea + languageName: node + linkType: hard + +"@algolia/logger-common@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/logger-common@npm:4.27.0" + checksum: 10c0/5546ddc8e7f1466dbd8522f6ddf565b26f340407ba61d39a862686d30c8a1ba51ce0be9078d91c9eda34b901c3b5abc1244961020c33938fda88cc7488284156 + languageName: node + linkType: hard + +"@algolia/logger-console@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/logger-console@npm:4.27.0" + dependencies: + "@algolia/logger-common": "npm:4.27.0" + checksum: 10c0/3e82c31b7b564eb81e8a66ef0e9554f6b018694c6ffd844cf1d98b5b81551dcc44f572ed84ba638b4316538f0ada7db985db652f40ec12420b7b74d346c66362 + languageName: node + linkType: hard + +"@algolia/recommend@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/recommend@npm:4.27.0" + dependencies: + "@algolia/cache-browser-local-storage": "npm:4.27.0" + "@algolia/cache-common": "npm:4.27.0" + "@algolia/cache-in-memory": "npm:4.27.0" + "@algolia/client-common": "npm:4.27.0" + "@algolia/client-search": "npm:4.27.0" + "@algolia/logger-common": "npm:4.27.0" + "@algolia/logger-console": "npm:4.27.0" + "@algolia/requester-browser-xhr": "npm:4.27.0" + "@algolia/requester-common": "npm:4.27.0" + "@algolia/requester-node-http": "npm:4.27.0" + "@algolia/transporter": "npm:4.27.0" + checksum: 10c0/13c496033389774aa8f0a5709bbd1eff92e52b32b239e7dacfb3e120bfb13bb5b9b4e281a2a1d10be991d127060599b37ae066ed46845ea31ff6e3c1246b1140 + languageName: node + linkType: hard + +"@algolia/requester-browser-xhr@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/requester-browser-xhr@npm:4.27.0" + dependencies: + "@algolia/requester-common": "npm:4.27.0" + checksum: 10c0/dc66b0010787fb6f29ff3b26e4571627f6c10622c1482da3af71a14cfe995a0ac402d141d1ed6fc9c734076c3a8ed6c633459dd81e6837ea17237bb30baca348 + languageName: node + linkType: hard + +"@algolia/requester-common@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/requester-common@npm:4.27.0" + checksum: 10c0/619cc397186360b33ae283f6f72caddecfc41078073eba9ff03741466b550f73a95553dbd7f81be002856620fbb27a2f2c2af32ad263f64179175c037a490705 + languageName: node + linkType: hard + +"@algolia/requester-node-http@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/requester-node-http@npm:4.27.0" + dependencies: + "@algolia/requester-common": "npm:4.27.0" + checksum: 10c0/9e89677bc3746bd118d1e74af99c39d187c19f1f0e95d69da23a01eb68415af4a917a0a16e197aaa2438c1e3c6bab545872999432425409581c70c31ed4d53a4 + languageName: node + linkType: hard + +"@algolia/transporter@npm:4.27.0": + version: 4.27.0 + resolution: "@algolia/transporter@npm:4.27.0" + dependencies: + "@algolia/cache-common": "npm:4.27.0" + "@algolia/logger-common": "npm:4.27.0" + "@algolia/requester-common": "npm:4.27.0" + checksum: 10c0/0229bad948a9d28ff6abc4dcc440ac756663a8e7c6a753a943a0387dd1fd899ef8f84f106bc64b31779690860371e9eac94e59fcf3c06ee518c30974aaeae839 + languageName: node + linkType: hard + "@alloc/quick-lru@npm:^5.2.0": version: 5.2.0 resolution: "@alloc/quick-lru@npm:5.2.0" @@ -1050,6 +1201,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/code-frame@npm:7.29.7" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.29.7" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10c0/169fc2080169a40c1760155eaaaf739bcb882df0bec76a83adbda5493645bc17270a3434b8848c494b1933e96fe1d147370001e3cda09a39f43ae30f08ef2069 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.28.5, @babel/compat-data@npm:^7.28.6": version: 7.29.0 resolution: "@babel/compat-data@npm:7.29.0" @@ -1093,6 +1255,19 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/generator@npm:7.29.7" + dependencies: + "@babel/parser": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + jsesc: "npm:^3.0.2" + checksum: 10c0/9bf72b01b5bd0ea5b1288a0e37dbd360bff2f2b1ce73342c0d40fb3db2ec3dc004ada5ffa925c5e12939a416eed59e600d562b8ecd938ce0d27dfd0eb6c6c2b7 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.27.1, @babel/helper-annotate-as-pure@npm:^7.27.3": version: 7.27.3 resolution: "@babel/helper-annotate-as-pure@npm:7.27.3" @@ -1102,6 +1277,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-annotate-as-pure@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-annotate-as-pure@npm:7.29.7" + dependencies: + "@babel/types": "npm:^7.29.7" + checksum: 10c0/c56536b52d17632d89d49db2063ed6102f0e3bbadf6a0ccb74e6599d6a77173b644c7fe8c3ef17c7a162709d55b75ee5145ef6db917d16ba7f375fbffcf2e942 + languageName: node + linkType: hard + "@babel/helper-builder-react-jsx@npm:^7.27.1": version: 7.28.6 resolution: "@babel/helper-builder-react-jsx@npm:7.28.6" @@ -1142,6 +1326,23 @@ __metadata: languageName: node linkType: hard +"@babel/helper-create-class-features-plugin@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-create-class-features-plugin@npm:7.29.7" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.29.7" + "@babel/helper-member-expression-to-functions": "npm:^7.29.7" + "@babel/helper-optimise-call-expression": "npm:^7.29.7" + "@babel/helper-replace-supers": "npm:^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.29.7" + "@babel/traverse": "npm:^7.29.7" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/75f34905b5e708b473f1e9b33e07b2fcc8f4c60676df8bc74541bb91c77f387c32a948dd04d5071e469ba454d72d0a872e3ace40fbb1d1e7aaa8569efcf09ed4 + languageName: node + linkType: hard + "@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.27.1, @babel/helper-create-regexp-features-plugin@npm:^7.28.5": version: 7.28.5 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.28.5" @@ -1177,6 +1378,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-globals@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-globals@npm:7.29.7" + checksum: 10c0/f38417c40b1129a1b2b519ca961b9040c8827d1444fd74068702286b91b77089431dc76b6b9d5c1496e5da2a4f3ad329c6946e688ba3fa0d1d0b3d2b4f34f36a + languageName: node + linkType: hard + "@babel/helper-member-expression-to-functions@npm:^7.28.5": version: 7.28.5 resolution: "@babel/helper-member-expression-to-functions@npm:7.28.5" @@ -1187,6 +1395,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-member-expression-to-functions@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-member-expression-to-functions@npm:7.29.7" + dependencies: + "@babel/traverse": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10c0/eef7940ce0797208854a5af1049a98fee9abbffb5c619640c69ff5a555f8e3552295bb18756490b02bc6af7df8c1babcb83f12203aac2deb9dfecfc78846e12d + languageName: node + linkType: hard + "@babel/helper-module-imports@npm:^7.28.6": version: 7.28.6 resolution: "@babel/helper-module-imports@npm:7.28.6" @@ -1219,6 +1437,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-optimise-call-expression@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-optimise-call-expression@npm:7.29.7" + dependencies: + "@babel/types": "npm:^7.29.7" + checksum: 10c0/fd0244b9bfbb487db02d59aa2703c6991d654ea5f3f39d912682842bdca2e87b5ae8643b0ce8069bf5fbee39d1aa9db7abefeb5e6ba1aa650dca12777cf5b7e2 + languageName: node + linkType: hard + "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.27.1, @babel/helper-plugin-utils@npm:^7.28.6": version: 7.28.6 resolution: "@babel/helper-plugin-utils@npm:7.28.6" @@ -1226,6 +1453,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-plugin-utils@npm:7.29.7" + checksum: 10c0/380477a06133274a2759f9355929cb60a95e8b8fee624a1ae1fa349e1d1645b89daca456f72833f6d1062bffa12ee4271c5bf0cc5a61c0166cdc24c7591e2408 + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-remap-async-to-generator@npm:7.27.1" @@ -1252,6 +1486,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-replace-supers@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-replace-supers@npm:7.29.7" + dependencies: + "@babel/helper-member-expression-to-functions": "npm:^7.29.7" + "@babel/helper-optimise-call-expression": "npm:^7.29.7" + "@babel/traverse": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/1c7ae37797f226e965ab85f6affa53d25a10c169c604a4daeb36f9df09e673471e6522f631c13761cf9fbafeca2ea14c241dea8d723a51039d561beb01d86ac4 + languageName: node + linkType: hard + "@babel/helper-skip-transparent-expression-wrappers@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.27.1" @@ -1262,6 +1509,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.29.7" + dependencies: + "@babel/traverse": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10c0/8c59493621487fc491f27adfc200af82a6aca3b9a5511e4e6050f8716593b4b243472cb56c8d2016e828b7ae12d605a819205aa8600ca08ee291dcd58d65c832 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-string-parser@npm:7.27.1" @@ -1269,6 +1526,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-string-parser@npm:7.29.7" + checksum: 10c0/194bc0f1716e396d5ffde56ad6119745fb9557662c98611590e5e454906783a4ccb21ce93056b8eb69a4909044834e45d96e50ac695bbe9e3221648fe033c06c + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.24.7, @babel/helper-validator-identifier@npm:^7.28.5": version: 7.28.5 resolution: "@babel/helper-validator-identifier@npm:7.28.5" @@ -1276,6 +1540,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-validator-identifier@npm:7.29.7" + checksum: 10c0/4795354e7ae0dcafa72de1cd04ec51252dc1498517170beaf019e03effc5b7bf13c6b21a3949a77e07b8125be7f106ed1131350d8ebd4566ae874094a726d62b + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-validator-option@npm:7.27.1" @@ -1326,6 +1597,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/parser@npm:7.29.7" + dependencies: + "@babel/types": "npm:^7.29.7" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/65133038f80b54a714d6027cb77cee3f9a6b5c4c6842ce674301e13947cbcbfa8055e63acaf1b84c085d34226a14425b2c2b97b829e0e226d2e8f1299942a51d + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.28.5": version: 7.28.5 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.28.5" @@ -1484,6 +1766,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-typescript@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/plugin-syntax-typescript@npm:7.29.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/c49883b0327e8683b770dc823205af5c697da216e590dcf5bf53f3f031e7e381de450b164f8f99853f0837a3de5cb793298e2be6697a0f6e452bb9dd34b5165e + languageName: node + linkType: hard + "@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" @@ -2167,6 +2460,21 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-typescript@npm:^7.28.0": + version: 7.29.7 + resolution: "@babel/plugin-transform-typescript@npm:7.29.7" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.29.7" + "@babel/helper-create-class-features-plugin": "npm:^7.29.7" + "@babel/helper-plugin-utils": "npm:^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.29.7" + "@babel/plugin-syntax-typescript": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/8bf6a89c6827af6f11d4b189f1f97a64b8d754cc4caa5cbae16a6a8b113294d7f310dd40efd82e87ebcff2a1c683584b872d6d8960abe88d48f441d42f94c4d1 + languageName: node + linkType: hard + "@babel/plugin-transform-typescript@npm:^7.28.5": version: 7.28.6 resolution: "@babel/plugin-transform-typescript@npm:7.28.6" @@ -2418,6 +2726,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/template@npm:7.29.7" + dependencies: + "@babel/code-frame": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10c0/8bb7f900dcab0e9e1c5ffbc33ca10e0d26b7b2e2ca804becb73ee771b9c4ed6e2908a4ae4a14c08560febb45d2b6b9a173955e42ad404d05f8b04840a14d9c58 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.0, @babel/traverse@npm:^7.28.5, @babel/traverse@npm:^7.28.6, @babel/traverse@npm:^7.29.0": version: 7.29.0 resolution: "@babel/traverse@npm:7.29.0" @@ -2433,6 +2752,21 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/traverse@npm:7.29.7" + dependencies: + "@babel/code-frame": "npm:^7.29.7" + "@babel/generator": "npm:^7.29.7" + "@babel/helper-globals": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/template": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + debug: "npm:^4.3.1" + checksum: 10c0/e256a1fbdb956555b76f3c285b1e453f6bedec8b3afb61751d99d933efd11c7d79caf5ddf2493570058a9f7deaa1b48324380d7c1aa1443fd9508becbf56331a + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.9.6": version: 7.29.0 resolution: "@babel/types@npm:7.29.0" @@ -2443,6 +2777,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/types@npm:7.29.7" + dependencies: + "@babel/helper-string-parser": "npm:^7.29.7" + "@babel/helper-validator-identifier": "npm:^7.29.7" + checksum: 10c0/b6623994c69717fa27294f5fa46d59140338e2d86c6c1c13085c84ef7d53086ee357fbf4fe9abe3dd3da75734dc77c4c0df2f90fb29e667558bb3b3fb705e88f + languageName: node + linkType: hard + "@balena/dockerignore@npm:^1.0.2": version: 1.0.2 resolution: "@balena/dockerignore@npm:1.0.2" @@ -4076,13 +4420,13 @@ __metadata: linkType: hard "@hapi/wreck@npm:^18.0.0": - version: 18.1.2 - resolution: "@hapi/wreck@npm:18.1.2" + version: 18.1.0 + resolution: "@hapi/wreck@npm:18.1.0" dependencies: "@hapi/boom": "npm:^10.0.1" "@hapi/bourne": "npm:^3.0.0" "@hapi/hoek": "npm:^11.0.2" - checksum: 10c0/6e2bbfb7f424f16c1182a29ac771d4428409c6e6370deb0a6505ba7897b3ba104c9772a1cde669894c3c4508ede9d7cbb2be4cd66e955440ba102109d89a5ea5 + checksum: 10c0/eab85afdf24d0c514abada83ef09e5f3b096348bfba36bb6c7a6f7eebd47ab583e07aa1005be7d638b405e4c55ec82a3697ad0cbe1b2db6bb73fa0e66baffde4 languageName: node linkType: hard @@ -6350,8 +6694,10 @@ __metadata: version: 0.0.0-use.local resolution: "@overleaf/access-token-encryptor@workspace:libraries/access-token-encryptor" dependencies: + "@types/node": "npm:^24.5.2" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" lodash: "npm:^4.18.1" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" @@ -6381,6 +6727,7 @@ __metadata: "@pollyjs/adapter-node-http": "npm:^6.0.6" "@pollyjs/core": "npm:^6.0.6" "@pollyjs/persister-fs": "npm:^6.0.6" + "@types/node": "npm:^24.5.2" bluebird: "npm:^3.7.2" body-parser: "npm:1.20.4" bull: "npm:^3.18.0" @@ -6389,6 +6736,7 @@ __metadata: chai-as-promised: "npm:^7.1.1" csv: "npm:^5.4.0" east: "npm:^2.0.3" + eslint: "npm:^10.4.0" express: "npm:4.22.1" json2csv: "npm:^4.5.4" lodash: "npm:^4.18.1" @@ -6424,12 +6772,14 @@ __metadata: "@overleaf/mongo-utils": "npm:*" "@overleaf/promise-utils": "npm:*" "@overleaf/settings": "npm:*" + "@types/node": "npm:^24.5.2" acorn: "npm:^7.1.1" ajv: "npm:^6.12.0" async: "npm:^3.2.5" body-parser: "npm:1.20.4" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" exegesis-express: "npm:4.0.0" express: "npm:4.22.1" mocha: "npm:^11.1.0" @@ -6456,16 +6806,19 @@ __metadata: "@overleaf/settings": "workspace:*" "@overleaf/stream-utils": "workspace:*" "@overleaf/validation-tools": "workspace:*" + "@types/node": "npm:^24.5.2" body-parser: "npm:1.20.4" bunyan: "npm:^1.8.15" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" express: "npm:^4.22.1" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" p-limit: "npm:^3.1.0" tar-fs: "npm:^3.1.1" + typescript: "npm:^5.0.4" languageName: unknown linkType: soft @@ -6477,6 +6830,7 @@ __metadata: "@overleaf/o-error": "workspace:*" "@overleaf/settings": "workspace:*" "@overleaf/stream-utils": "workspace:*" + "@types/node": "npm:^24.5.2" chai-as-promised: "npm:^7.1.1" gcp-metadata: "npm:^6.1.0" googleapis: "npm:^144.0.0" @@ -6494,10 +6848,12 @@ __metadata: "@overleaf/logger": "workspace:*" "@overleaf/o-error": "workspace:*" "@overleaf/settings": "workspace:*" + "@types/node": "npm:^24.5.2" bunyan: "npm:^1.8.15" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" cookie: "npm:^0.4.1" + eslint: "npm:^10.4.0" express: "npm:4.22.1" glob: "npm:^12.0.0" mocha: "npm:^11.1.0" @@ -6521,6 +6877,7 @@ __metadata: "@overleaf/settings": "workspace:*" "@overleaf/stream-utils": "workspace:*" "@overleaf/validation-tools": "workspace:*" + "@types/node": "npm:^24.5.2" archiver: "npm:5.3.2" async: "npm:^3.2.5" body-parser: "npm:1.20.4" @@ -6528,6 +6885,7 @@ __metadata: chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" dockerode: "npm:^4.0.9" + eslint: "npm:^10.4.0" express: "npm:4.22.1" form-data: "npm:^4.0.5" lodash: "npm:^4.18.1" @@ -6586,16 +6944,19 @@ __metadata: "@overleaf/settings": "workspace:*" "@overleaf/stream-utils": "npm:^0.1.0" "@overleaf/validation-tools": "workspace:*" + "@types/node": "npm:^24.5.2" async: "npm:^3.2.5" body-parser: "npm:1.20.4" bunyan: "npm:^1.8.15" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" express: "npm:4.22.1" lodash: "npm:^4.18.1" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" + mongodb: "npm:6.12.0" mongodb-legacy: "npm:6.1.3" p-map: "npm:^4.0.0" sinon: "npm:~9.0.2" @@ -6620,6 +6981,9 @@ __metadata: "@overleaf/redis-wrapper": "workspace:*" "@overleaf/settings": "workspace:*" "@types/chai-as-promised": "npm:^7.1.8" + "@types/ioredis": "npm:^4.28.10" + "@types/mocha": "npm:^10.0.6" + "@types/node": "npm:^24.5.2" async: "npm:^3.2.5" basic-auth: "npm:^2.0.1" body-parser: "npm:1.20.4" @@ -6629,12 +6993,14 @@ __metadata: chai-as-promised: "npm:^7.1.1" cluster-key-slot: "npm:^1.0.5" diff-match-patch: "overleaf/diff-match-patch#89805f9c671a77a263fc53461acd62aa7498f688" + eslint: "npm:^10.4.0" express: "npm:4.22.1" lodash: "npm:^4.18.1" minimist: "npm:^1.2.8" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" + mongodb: "npm:6.12.0" mongodb-legacy: "npm:6.1.3" overleaf-editor-core: "workspace:*" sandboxed-module: "npm:^2.0.4" @@ -6663,10 +7029,12 @@ __metadata: resolution: "@overleaf/fetch-utils@workspace:libraries/fetch-utils" dependencies: "@overleaf/o-error": "workspace:*" + "@types/node": "npm:^24.5.2" "@types/node-fetch": "npm:^2.6.13" body-parser: "npm:1.20.4" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" express: "npm:4.22.1" lodash: "npm:^4.18.1" mocha: "npm:^11.1.0" @@ -6690,10 +7058,12 @@ __metadata: "@overleaf/object-persistor": "workspace:*" "@overleaf/settings": "workspace:*" "@overleaf/stream-utils": "npm:^0.1.0" + "@types/node": "npm:^24.5.2" body-parser: "npm:1.20.4" bunyan: "npm:^1.8.15" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" express: "npm:4.22.1" glob: "npm:^12.0.0" lodash.once: "npm:^4.1.1" @@ -6730,17 +7100,20 @@ __metadata: "@pollyjs/adapter-node-http": "npm:^6.0.6" "@pollyjs/core": "npm:^6.0.6" "@pollyjs/persister-fs": "npm:^6.0.6" + "@types/node": "npm:^24.5.2" async: "npm:^3.2.5" base64-stream: "npm:^0.1.2" body-parser: "npm:1.20.4" bunyan: "npm:^1.8.15" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" express: "npm:4.22.1" lodash: "npm:^4.18.1" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" + mongodb: "npm:6.12.0" mongodb-legacy: "npm:6.1.3" nock: "npm:^13.5.6" octonode: "npm:0.9.5" @@ -6760,9 +7133,11 @@ __metadata: version: 0.0.0-use.local resolution: "@overleaf/idp@workspace:services/idp" dependencies: + "@types/node": "npm:^24.5.2" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" ejs: "npm:^3.1.10" + eslint: "npm:^10.4.0" express: "npm:4.22.1" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" @@ -6772,6 +7147,24 @@ __metadata: languageName: unknown linkType: soft +"@overleaf/linked-url-proxy@workspace:services/linked-url-proxy": + version: 0.0.0-use.local + resolution: "@overleaf/linked-url-proxy@workspace:services/linked-url-proxy" + dependencies: + "@types/node": "npm:^24.5.2" + chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" + express: "npm:^4.22.2" + ipaddr.js: "npm:^2.2.0" + node-fetch: "npm:^2.7.0" + sinon: "npm:^14.0.0" + sinon-chai: "npm:^3.7.0" + tsscmp: "npm:^1.0.6" + typescript: "npm:^5.0.4" + vitest: "npm:4.1.5" + languageName: unknown + linkType: soft + "@overleaf/logger@npm:*, @overleaf/logger@workspace:*, @overleaf/logger@workspace:libraries/logger": version: 0.0.0-use.local resolution: "@overleaf/logger@workspace:libraries/logger" @@ -6779,8 +7172,10 @@ __metadata: "@google-cloud/logging-bunyan": "npm:^5.1.0" "@overleaf/fetch-utils": "workspace:*" "@overleaf/o-error": "workspace:*" + "@types/node": "npm:^24.5.2" bunyan: "npm:^1.8.14" chai: "npm:^4.3.6" + eslint: "npm:^10.4.0" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" @@ -6805,9 +7200,12 @@ __metadata: "@opentelemetry/resources": "npm:^2.7.1" "@opentelemetry/sdk-node": "npm:^0.218.0" "@opentelemetry/semantic-conventions": "npm:^1.41.1" + "@overleaf/logger": "workspace:*" + "@types/node": "npm:^24.5.2" bunyan: "npm:^1.0.0" chai: "npm:^4.3.6" compression: "npm:^1.7.4" + eslint: "npm:^10.4.0" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" @@ -6832,6 +7230,7 @@ __metadata: "@overleaf/settings": "workspace:*" bcrypt: "npm:^6.0.0" east: "npm:2.0.3" + eslint: "npm:^10.4.0" mongodb: "npm:6.12.0" languageName: unknown linkType: soft @@ -6840,7 +7239,9 @@ __metadata: version: 0.0.0-use.local resolution: "@overleaf/mongo-utils@workspace:libraries/mongo-utils" dependencies: + "@types/node": "npm:^24.5.2" chai: "npm:^4.3.6" + eslint: "npm:^10.4.0" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" @@ -6866,13 +7267,16 @@ __metadata: "@overleaf/promise-utils": "workspace:*" "@overleaf/settings": "workspace:*" "@overleaf/validation-tools": "workspace:*" + "@types/node": "npm:^24.5.2" async: "npm:^3.2.5" body-parser: "npm:1.20.4" bunyan: "npm:^1.8.15" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" express: "npm:4.22.1" mocha: "npm:^11.1.0" + mongodb: "npm:6.12.0" mongodb-legacy: "npm:6.1.3" typescript: "npm:^5.0.4" vitest: "npm:4.1.5" @@ -6888,6 +7292,7 @@ __metadata: "@types/chai": "npm:^4.3.0" "@types/node": "npm:^24.5.2" chai: "npm:^4.3.6" + eslint: "npm:^10.4.0" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" @@ -6908,8 +7313,10 @@ __metadata: "@overleaf/metrics": "workspace:*" "@overleaf/o-error": "workspace:*" "@overleaf/stream-utils": "workspace:*" + "@types/node": "npm:^24.5.2" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" fast-crc32c: "overleaf/node-fast-crc32c#aae6b2a4c7a7a159395df9cc6c38dfde702d6f51" glob: "npm:^12.0.0" mocha: "npm:^11.1.0" @@ -6930,7 +7337,9 @@ __metadata: resolution: "@overleaf/piece-table@workspace:libraries/piece-table" dependencies: "@overleaf/o-error": "workspace:*" + "@types/node": "npm:^24.5.2" chai: "npm:^4.3.6" + eslint: "npm:^10.4.0" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" @@ -6953,19 +7362,22 @@ __metadata: "@overleaf/settings": "workspace:*" "@overleaf/stream-utils": "workspace:*" "@overleaf/validation-tools": "workspace:*" + "@types/node": "npm:^24.5.2" async: "npm:^3.2.5" body-parser: "npm:1.20.4" bunyan: "npm:^1.8.15" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" diff-match-patch: "overleaf/diff-match-patch#89805f9c671a77a263fc53461acd62aa7498f688" - esmock: "npm:^2.7.3" + eslint: "npm:^10.4.0" + esmock: "patch:esmock@npm%3A2.7.3#~/.yarn/patches/esmock-npm-2.7.3-83624b28f6.patch" express: "npm:4.22.1" lodash: "npm:^4.18.1" minimist: "npm:^1.2.8" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" + mongodb: "npm:6.12.0" mongodb-legacy: "npm:6.1.3" nock: "npm:^13.5.3" overleaf-editor-core: "workspace:*" @@ -6981,8 +7393,10 @@ __metadata: version: 0.0.0-use.local resolution: "@overleaf/promise-utils@workspace:libraries/promise-utils" dependencies: + "@types/node": "npm:^24.5.2" chai: "npm:^4.3.10" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" @@ -6995,7 +7409,10 @@ __metadata: version: 0.0.0-use.local resolution: "@overleaf/ranges-tracker@workspace:libraries/ranges-tracker" dependencies: + "@types/node": "npm:^24.5.2" chai: "npm:^4.3.6" + core-js: "npm:~3.46.0" + eslint: "npm:^10.4.0" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" @@ -7015,6 +7432,7 @@ __metadata: "@overleaf/redis-wrapper": "workspace:*" "@overleaf/settings": "workspace:*" "@overleaf/validation-tools": "workspace:*" + "@types/node": "npm:^24.5.2" async: "npm:^3.2.5" base64id: "npm:0.1.0" body-parser: "npm:1.20.4" @@ -7024,6 +7442,7 @@ __metadata: connect-redis: "npm:^6.1.3" cookie-parser: "npm:^1.4.6" cookie-signature: "npm:^1.1.0" + eslint: "npm:^10.4.0" express: "npm:4.22.1" express-session: "npm:^1.17.1" lodash: "npm:^4.18.1" @@ -7039,6 +7458,7 @@ __metadata: typescript: "npm:^5.0.4" uid-safe: "npm:^2.1.5" vitest: "npm:4.1.5" + zod: "npm:^3.24.0" zod-validation-error: "npm:^4.0.1" languageName: unknown linkType: soft @@ -7049,8 +7469,10 @@ __metadata: dependencies: "@overleaf/logger": "workspace:*" "@overleaf/o-error": "workspace:*" + "@types/node": "npm:^24.5.2" async: "npm:^3.2.5" chai: "npm:^4.3.6" + eslint: "npm:^10.4.0" ioredis: "npm:~4.27.1" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" @@ -7077,6 +7499,8 @@ __metadata: adm-zip: "npm:^0.5.12" cypress: "npm:15.12.0" cypress-multi-reporters: "npm:^2.0.5" + eslint: "npm:^10.4.0" + eslint-formatter-unix: "npm:^8.40.0" isomorphic-git: "npm:^1.33.1" mailtrap: "npm:^4.3.0" mocha: "npm:^11.7.5" @@ -7101,11 +7525,15 @@ __metadata: body-parser: "npm:1.20.4" cypress: "npm:15.12.0" cypress-multi-reporters: "npm:^2.0.5" + eslint: "npm:^10.4.0" + eslint-formatter-unix: "npm:^8.40.0" express: "npm:4.22.1" isomorphic-git: "npm:^1.33.1" js-yaml: "npm:^4.1.1" + mocha: "npm:^11.7.5" mocha-junit-reporter: "npm:^2.2.1" pdfjs-dist: "npm:^5.1.91" + typescript: "npm:^5.0.4" uuid: "npm:^9.0.1" zod-validation-error: "npm:^4.0.1" languageName: unknown @@ -7115,6 +7543,8 @@ __metadata: version: 0.0.0-use.local resolution: "@overleaf/settings@workspace:libraries/settings" dependencies: + "@types/node": "npm:^24.5.2" + eslint: "npm:^10.4.0" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" @@ -7126,8 +7556,10 @@ __metadata: version: 0.0.0-use.local resolution: "@overleaf/stream-utils@workspace:libraries/stream-utils" dependencies: + "@types/node": "npm:^24.5.2" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" @@ -7145,12 +7577,14 @@ __metadata: "@overleaf/migrations": "workspace:*" "@overleaf/promise-utils": "workspace:*" "@overleaf/settings": "workspace:*" + "@types/node": "npm:^24.5.2" args-js: "npm:0.10.12" async: "npm:^3.2.5" body-parser: "npm:1.20.4" bunyan: "npm:^1.8.15" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" express: "npm:4.22.1" install: "npm:^0.13.0" lodash: "npm:^4.18.1" @@ -7179,6 +7613,7 @@ __metadata: "@overleaf/o-error": "workspace:*" "@overleaf/promise-utils": "workspace:*" "@overleaf/settings": "workspace:*" + "@types/node": "npm:^24.5.2" async: "npm:^3.2.5" body-parser: "npm:1.20.4" bunyan: "npm:^1.8.15" @@ -7186,6 +7621,7 @@ __metadata: chai-as-promised: "npm:^7.1.1" chai-http: "npm:4.4.0" dropbox: "npm:^10.34.0" + eslint: "npm:^10.4.0" express: "npm:4.22.1" express-basic-auth: "npm:^1.2.0" ioredis: "npm:^4.16.0" @@ -7196,6 +7632,7 @@ __metadata: mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" + mongodb: "npm:6.12.0" mongodb-legacy: "npm:6.1.3" node-fetch: "npm:^2.7.0" p-limit: "npm:^2.3.0" @@ -7220,19 +7657,23 @@ __metadata: "@overleaf/o-error": "workspace:*" "@overleaf/promise-utils": "workspace:*" "@overleaf/settings": "workspace:*" + "@types/mocha": "npm:^10.0.6" + "@types/node": "npm:^24.5.2" "@types/simple-oauth2": "npm:^5.0.7" async: "npm:^3.2.5" body-parser: "npm:1.20.4" bunyan: "npm:^1.8.15" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" - esmock: "npm:^2.7.3" + eslint: "npm:^10.4.0" + esmock: "patch:esmock@npm%3A2.7.3#~/.yarn/patches/esmock-npm-2.7.3-83624b28f6.patch" express: "npm:4.22.1" lodash: "npm:^4.18.1" lru-cache: "npm:^5.1.1" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" + mongodb: "npm:6.12.0" mongodb-legacy: "npm:6.1.3" oauth: "npm:0.9.15" request: "npm:2.88.2" @@ -7248,6 +7689,9 @@ __metadata: resolution: "@overleaf/validation-tools@workspace:libraries/validation-tools" dependencies: "@overleaf/o-error": "workspace:*" + "@types/express": "npm:4.17.23" + "@types/node": "npm:^24.5.2" + eslint: "npm:^10.4.0" mongodb: "npm:^6.12.0" typescript: "npm:^5.0.4" vitest: "npm:4.1.5" @@ -7267,6 +7711,7 @@ __metadata: "@aws-sdk/client-ses": "npm:^3.994.0" "@babel/core": "npm:^7.28.5" "@babel/plugin-proposal-decorators": "npm:^7.28.0" + "@babel/plugin-transform-typescript": "npm:^7.28.0" "@babel/preset-env": "npm:^7.28.5" "@babel/preset-react": "npm:^7.28.5" "@babel/preset-typescript": "npm:^7.28.5" @@ -7325,6 +7770,7 @@ __metadata: "@replit/codemirror-indentation-markers": "overleaf/codemirror-indentation-markers#371ce3b56f453a392eb0d3b85ab019c185c68e1f" "@replit/codemirror-vim": "overleaf/codemirror-vim#1bef138382d948018f3f9b8a4d7a70ab61774e4b" "@sentry/browser": "npm:7.46.0" + "@sentry/types": "npm:7.46.0" "@slack/webhook": "npm:^7.0.2" "@storybook/addon-a11y": "npm:10.3.5" "@storybook/addon-designs": "npm:^11.1.3" @@ -7350,15 +7796,19 @@ __metadata: "@types/async": "npm:^3.2.25" "@types/bootstrap": "npm:^5.2.10" "@types/chai": "npm:^4.3.0" + "@types/chai-as-promised": "npm:^8.0.2" "@types/dateformat": "npm:^5.0.3" "@types/diff": "npm:^5.2.3" "@types/dom-speech-recognition": "npm:^0.0.7" "@types/events": "npm:^3.0.3" "@types/express": "npm:^4.17.23" + "@types/lodash": "npm:^4.17.24" + "@types/mdast": "npm:^4.0.4" "@types/minimist": "npm:^1.2.5" "@types/mocha": "npm:^9.1.0" "@types/mocha-each": "npm:^2.0.4" "@types/node": "npm:^24.5.2" + "@types/path-browserify": "npm:^1.0.3" "@types/react": "npm:^18.3.20" "@types/react-color": "npm:^3.0.13" "@types/react-dom": "npm:^18.3.6" @@ -7367,15 +7817,19 @@ __metadata: "@types/react-syntax-highlighter": "npm:^15.5.11" "@types/recurly__recurly-js": "npm:^4.38.0" "@types/sanitize-html": "npm:^2.14.0" + "@types/sinon": "npm:^21.0.1" "@types/sinon-chai": "npm:^3.2.12" "@types/utf-8-validate": "npm:^5.0.2" "@types/uuid": "npm:^10.0.0" + "@typescript-eslint/eslint-plugin": "npm:^8.59.4" + "@typescript-eslint/parser": "npm:^8.59.4" "@uppy/core": "npm:^3.8.0" "@uppy/dashboard": "npm:3.7.1" "@uppy/drag-drop": "npm:3.0.3" "@uppy/file-input": "npm:3.0.4" "@uppy/progress-bar": "npm:3.0.4" "@uppy/react": "npm:3.2.1" + "@uppy/status-bar": "npm:^3.2.5" "@uppy/utils": "npm:^5.7.0" "@uppy/xhr-upload": "npm:3.6.0" "@vitest/coverage-istanbul": "npm:^4.0.17" @@ -7432,6 +7886,8 @@ __metadata: css-minimizer-webpack-plugin: "npm:^8.0.0" csurf: "npm:^1.11.0" csv: "npm:^6.2.5" + csv-parse: "npm:^6.2.1" + csv-stringify: "npm:^6.7.0" cypress: "npm:15.12.0" cypress-multi-reporters: "npm:^2.0.5" cypress-plugin-tab: "npm:^1.0.5" @@ -7445,9 +7901,12 @@ __metadata: email-addresses: "npm:^5.0.0" es6-promise: "npm:^4.2.8" escodegen: "npm:^2.0.0" + eslint: "npm:^10.4.0" eslint-config-prettier: "npm:^10.1.8" + eslint-formatter-unix: "npm:^8.40.0" eslint-plugin-chai-expect: "npm:^4.1.0" eslint-plugin-chai-friendly: "npm:^1.2.0" + eslint-plugin-cypress: "npm:^4.1.0" eslint-plugin-import: "npm:^2.32.0" eslint-plugin-jsx-a11y: "npm:^6.10.2" eslint-plugin-mocha: "npm:^11.3.0" @@ -7469,6 +7928,7 @@ __metadata: fast-fuzzy: "npm:^1.12.0" fetch-mock: "npm:^12.6.0" file-type: "npm:^21.3.4" + focus-trap: "npm:^8.2.1" focus-trap-react: "npm:^11.0.4" form-data: "npm:^4.0.5" formik: "npm:^2.2.9" @@ -7512,6 +7972,7 @@ __metadata: mocha-junit-reporter: "npm:^2.2.1" mocha-multi-reporters: "npm:^1.5.1" moment: "npm:^2.29.4" + mongodb: "npm:6.12.0" mongodb-legacy: "npm:6.1.3" mongoose: "npm:8.22.1" multer: "npm:2.1.1" @@ -7590,9 +8051,10 @@ __metadata: to-string-loader: "npm:^1.2.0" tough-cookie: "npm:^4.0.0" ts-loader: "npm:^9.5.7" + tslib: "npm:^2.8.1" tsscmp: "npm:^1.0.6" tty-browserify: "npm:^0.0.1" - typescript: "npm:^5.9.3" + typescript: "npm:^5.0.4" uid-safe: "npm:^2.1.5" unified: "npm:^11.0.5" unist-util-visit: "npm:^5.0.0" @@ -8066,7 +8528,7 @@ __metadata: languageName: node linkType: hard -"@popperjs/core@npm:^2.11.8, @popperjs/core@npm:^2.9.2": +"@popperjs/core@npm:*, @popperjs/core@npm:^2.11.8, @popperjs/core@npm:^2.9.2": version: 2.11.8 resolution: "@popperjs/core@npm:2.11.8" checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 @@ -8200,10 +8662,10 @@ __metadata: languageName: node linkType: hard -"@remix-run/router@npm:1.23.3": - version: 1.23.3 - resolution: "@remix-run/router@npm:1.23.3" - checksum: 10c0/73622465dd9e9a2c5a7ced7d1151ea6e9195a8a979c99b4f70a67093eeff7f339daf03a7c6304709a9c27deb2081a8fff6737663aacb33529c1a12a0a0827a17 +"@remix-run/router@npm:1.23.2": + version: 1.23.2 + resolution: "@remix-run/router@npm:1.23.2" + checksum: 10c0/7096b7f2086b2cd80c9e06873b71a8317e04858c01edc06a6fed187b660408a90f47c8e120e8af4c369cf1fa6b6a316a66b0917f42b6eb8a566e98b277c50449 languageName: node linkType: hard @@ -8586,7 +9048,16 @@ __metadata: languageName: node linkType: hard -"@sinonjs/commons@npm:^3.0.1": +"@sinonjs/commons@npm:^2.0.0": + version: 2.0.0 + resolution: "@sinonjs/commons@npm:2.0.0" + dependencies: + type-detect: "npm:4.0.8" + checksum: 10c0/babe3fdfc7dfb810f6918f2ae055032a1c7c18910595f1c6bfda87bb1737c1a57268d4ca78c3d8ad2fa4aae99ff79796fad76be735a5a38ab763c0b3cfad1ae7 + languageName: node + linkType: hard + +"@sinonjs/commons@npm:^3.0.0, @sinonjs/commons@npm:^3.0.1": version: 3.0.1 resolution: "@sinonjs/commons@npm:3.0.1" dependencies: @@ -8595,6 +9066,15 @@ __metadata: languageName: node linkType: hard +"@sinonjs/fake-timers@npm:^11.2.2": + version: 11.3.1 + resolution: "@sinonjs/fake-timers@npm:11.3.1" + dependencies: + "@sinonjs/commons": "npm:^3.0.1" + checksum: 10c0/c4f96ea7c3ab0e1a5fc1e2e1201e984a9302841a9fb10059120ce3b6789dae0f851c8827cf16b052a6f87db9a098cdd36f7067246e7a9b71da1d5a2c3d3a9f3d + languageName: node + linkType: hard + "@sinonjs/fake-timers@npm:^15.3.2": version: 15.4.0 resolution: "@sinonjs/fake-timers@npm:15.4.0" @@ -8613,6 +9093,15 @@ __metadata: languageName: node linkType: hard +"@sinonjs/fake-timers@npm:^9.1.2": + version: 9.1.2 + resolution: "@sinonjs/fake-timers@npm:9.1.2" + dependencies: + "@sinonjs/commons": "npm:^1.7.0" + checksum: 10c0/d9187f9130f03272562ff9845867299c6f7cf15157bbb3e6aca4a1f06d885b0eef54259d0ad41e2f8043dc530b4db730b6c9415b169033e7ba8fed0ad449ceec + languageName: node + linkType: hard + "@sinonjs/formatio@npm:^3.2.1": version: 3.2.2 resolution: "@sinonjs/formatio@npm:3.2.2" @@ -8665,7 +9154,18 @@ __metadata: languageName: node linkType: hard -"@sinonjs/text-encoding@npm:^0.7.1": +"@sinonjs/samsam@npm:^7.0.1": + version: 7.0.1 + resolution: "@sinonjs/samsam@npm:7.0.1" + dependencies: + "@sinonjs/commons": "npm:^2.0.0" + lodash.get: "npm:^4.4.2" + type-detect: "npm:^4.0.8" + checksum: 10c0/cc5e61e102dfa837ea3dd0102c924636de8a43e39d3e5ea009b57095be15fad807535feb8b2a3e90686f022451ab2dfa49c99167d68c661e7fab19a07227d467 + languageName: node + linkType: hard + +"@sinonjs/text-encoding@npm:^0.7.1, @sinonjs/text-encoding@npm:^0.7.2": version: 0.7.3 resolution: "@sinonjs/text-encoding@npm:0.7.3" checksum: 10c0/b112d1e97af7f99fbdc63c7dbcd35d6a60764dfec85cfcfff532e55cce8ecd8453f9fa2139e70aea47142c940fd90cd201d19f370b9a0141700d8a6de3116815 @@ -10671,6 +11171,15 @@ __metadata: languageName: node linkType: hard +"@types/chai-as-promised@npm:^8.0.2": + version: 8.0.2 + resolution: "@types/chai-as-promised@npm:8.0.2" + dependencies: + "@types/chai": "npm:*" + checksum: 10c0/94492694121ba3c8b16e61be5f3d91bf1996c37e7b5f85363f30e160344b32d42b7ad9606198e57a3b3c06eb3b36e345ac0494e7556fc406433d8e13f1b83a77 + languageName: node + linkType: hard + "@types/chai@npm:*, @types/chai@npm:^5.2.2": version: 5.2.3 resolution: "@types/chai@npm:5.2.3" @@ -10947,6 +11456,15 @@ __metadata: languageName: node linkType: hard +"@types/ioredis@npm:^4.28.10": + version: 4.28.10 + resolution: "@types/ioredis@npm:4.28.10" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/ff680fef6750721c465ee9d6060d3229e49e5b217d68503c4972c4b869b8f84b91cbd9b7d5195a40fb0bff6ab9a4f5e24a2cc17a368ddb0bfe2dfd4eb5fc1872 + languageName: node + linkType: hard + "@types/is-core-module@npm:^2.2.2": version: 2.2.2 resolution: "@types/is-core-module@npm:2.2.2" @@ -11009,7 +11527,7 @@ __metadata: languageName: node linkType: hard -"@types/lodash@npm:^4.14.175": +"@types/lodash@npm:^4.14.175, @types/lodash@npm:^4.17.24": version: 4.17.24 resolution: "@types/lodash@npm:4.17.24" checksum: 10c0/b72f60d4daacdad1fa643edb3faba204c02a01eb1ac00a83ff73496a6d236fc55e459c06106e8ced42277dba932d087d8fc090f8de4ef590d3f91e6d6f7ce85a @@ -11023,7 +11541,7 @@ __metadata: languageName: node linkType: hard -"@types/mdast@npm:^4.0.0": +"@types/mdast@npm:^4.0.0, @types/mdast@npm:^4.0.4": version: 4.0.4 resolution: "@types/mdast@npm:4.0.4" dependencies: @@ -11459,7 +11977,7 @@ __metadata: languageName: node linkType: hard -"@types/sinon@npm:*": +"@types/sinon@npm:*, @types/sinon@npm:^21.0.1": version: 21.0.1 resolution: "@types/sinon@npm:21.0.1" dependencies: @@ -12289,6 +12807,15 @@ __metadata: languageName: node linkType: hard +"@vitest/pretty-format@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/pretty-format@npm:4.1.8" + dependencies: + tinyrainbow: "npm:^3.1.0" + checksum: 10c0/553c456692a4b9ae13cd116c234c74b4495e0f1a0d5c51ffc3fab8ea085e3550769967e29db79bdac0cf127b1bf88b7f70bfba3dcc72be6bddf834433e30cc91 + languageName: node + linkType: hard + "@vitest/runner@npm:4.1.5": version: 4.1.5 resolution: "@vitest/runner@npm:4.1.5" @@ -12299,6 +12826,16 @@ __metadata: languageName: node linkType: hard +"@vitest/runner@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/runner@npm:4.1.8" + dependencies: + "@vitest/utils": "npm:4.1.8" + pathe: "npm:^2.0.3" + checksum: 10c0/706808a4b7b95ea9a9268fc152dd39e15a9a754f37c7990aea167486a9094caa913dae454771ae02c18dccfabd667f8cc38eed33a1307a79d32a89878b5bcce1 + languageName: node + linkType: hard + "@vitest/snapshot@npm:4.1.5": version: 4.1.5 resolution: "@vitest/snapshot@npm:4.1.5" @@ -12311,6 +12848,18 @@ __metadata: languageName: node linkType: hard +"@vitest/snapshot@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/snapshot@npm:4.1.8" + dependencies: + "@vitest/pretty-format": "npm:4.1.8" + "@vitest/utils": "npm:4.1.8" + magic-string: "npm:^0.30.21" + pathe: "npm:^2.0.3" + checksum: 10c0/ba4c32112491d42d24986f921c50ede5edbdb4b7eafa16c72cf8d2c9ecc44121fdb3d9365236747a9841f0d6776affc6457470fcbb082df9dbc28c24792a0c6d + languageName: node + linkType: hard + "@vitest/spy@npm:4.1.5": version: 4.1.5 resolution: "@vitest/spy@npm:4.1.5" @@ -12329,6 +12878,17 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/utils@npm:4.1.8" + dependencies: + "@vitest/pretty-format": "npm:4.1.8" + convert-source-map: "npm:^2.0.0" + tinyrainbow: "npm:^3.1.0" + checksum: 10c0/acda9d3d640c1ebc81afb358ac30589d7d7d583af81e2d09419f0af9cbe41f3ce0b90527326943bf0da51614be5fc31afcd32259f6beb32b3417999d6ef380f3 + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.14.1, @webassemblyjs/ast@npm:^1.14.1": version: 1.14.1 resolution: "@webassemblyjs/ast@npm:1.14.1" @@ -12868,6 +13428,29 @@ __metadata: languageName: node linkType: hard +"algoliasearch@npm:^4.19.1": + version: 4.27.0 + resolution: "algoliasearch@npm:4.27.0" + dependencies: + "@algolia/cache-browser-local-storage": "npm:4.27.0" + "@algolia/cache-common": "npm:4.27.0" + "@algolia/cache-in-memory": "npm:4.27.0" + "@algolia/client-account": "npm:4.27.0" + "@algolia/client-analytics": "npm:4.27.0" + "@algolia/client-common": "npm:4.27.0" + "@algolia/client-personalization": "npm:4.27.0" + "@algolia/client-search": "npm:4.27.0" + "@algolia/logger-common": "npm:4.27.0" + "@algolia/logger-console": "npm:4.27.0" + "@algolia/recommend": "npm:4.27.0" + "@algolia/requester-browser-xhr": "npm:4.27.0" + "@algolia/requester-common": "npm:4.27.0" + "@algolia/requester-node-http": "npm:4.27.0" + "@algolia/transporter": "npm:4.27.0" + checksum: 10c0/0c6860c58342fe5804399c15fd86bcd04356fa23e8e57ca3070de02bcd1f7f15efccae7fa637510aed7444c149f0ddb120be523bbe952c6d8b357fb3f892961b + languageName: node + linkType: hard + "ally.js@npm:^1.4.1": version: 1.4.1 resolution: "ally.js@npm:1.4.1" @@ -13076,15 +13659,6 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^1.0.7": - version: 1.0.10 - resolution: "argparse@npm:1.0.10" - dependencies: - sprintf-js: "npm:~1.0.2" - checksum: 10c0/b2972c5c23c63df66bca144dbc65d180efa74f25f8fd9b7d9a0a6c88ae839db32df3d54770dcb6460cf840d232b60695d1a6b1053f599d84e73f7437087712de - languageName: node - linkType: hard - "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -14042,6 +14616,26 @@ __metadata: languageName: node linkType: hard +"body-parser@npm:~1.20.5": + version: 1.20.5 + resolution: "body-parser@npm:1.20.5" + dependencies: + bytes: "npm:~3.1.2" + content-type: "npm:~1.0.5" + debug: "npm:2.6.9" + depd: "npm:2.0.0" + destroy: "npm:~1.2.0" + http-errors: "npm:~2.0.1" + iconv-lite: "npm:~0.4.24" + on-finished: "npm:~2.4.1" + qs: "npm:~6.15.1" + raw-body: "npm:~2.5.3" + type-is: "npm:~1.6.18" + unpipe: "npm:~1.0.0" + checksum: 10c0/ad777ca5e4711eae253c93f50fdc4608c60b76a9710d79e5e5b84581c76691e6ad21ecc9158986d9ea2b365df73e403ca33c27a8bccc1a7cfc2ccc248548118d + languageName: node + linkType: hard + "body-parser@patch:body-parser@npm%3A1.20.4#~/.yarn/patches/body-parser-npm-1.20.4.patch": version: 1.20.4 resolution: "body-parser@patch:body-parser@npm%3A1.20.4#~/.yarn/patches/body-parser-npm-1.20.4.patch::version=1.20.4&hash=83d8bd" @@ -14589,6 +15183,17 @@ __metadata: languageName: node linkType: hard +"chai-as-promised@npm:^8.0.2": + version: 8.0.2 + resolution: "chai-as-promised@npm:8.0.2" + dependencies: + check-error: "npm:^2.1.1" + peerDependencies: + chai: ">= 2.1.2 < 7" + checksum: 10c0/829bcd98c04f0b108b2f7379efd33c668e53fbf0bda8d460dc63c96a709fd5de79909392aa78b4256de16a4d57640641d7affc516111e371d6e9f6aec1cc6c8a + languageName: node + linkType: hard + "chai-exclude@npm:^2.0.3, chai-exclude@npm:^2.1.1": version: 2.1.1 resolution: "chai-exclude@npm:2.1.1" @@ -14766,6 +15371,13 @@ __metadata: languageName: node linkType: hard +"check-error@npm:^2.1.1": + version: 2.1.3 + resolution: "check-error@npm:2.1.3" + checksum: 10c0/878e99038fb6476316b74668cd6a498c7e66df3efe48158fa40db80a06ba4258742ac3ee2229c4a2a98c5e73f5dff84eb3e50ceb6b65bbd8f831eafc8338607d + languageName: node + linkType: hard + "check-types@npm:^11.1.2": version: 11.2.3 resolution: "check-types@npm:11.2.3" @@ -16701,7 +17313,7 @@ __metadata: languageName: node linkType: hard -"diff@npm:^5.1.0": +"diff@npm:^5.0.0, diff@npm:^5.1.0": version: 5.2.2 resolution: "diff@npm:5.2.2" checksum: 10c0/52da594c54e9033423da26984b1449ae6accd782d5afc4431c9a192a8507ddc83120fe8f925d7220b9da5b5963c7b6f5e46add3660a00cb36df7a13420a09d4b @@ -18070,13 +18682,20 @@ __metadata: languageName: node linkType: hard -"esmock@npm:^2.7.3": +"esmock@npm:2.7.3": version: 2.7.3 resolution: "esmock@npm:2.7.3" checksum: 10c0/71aebd7b82ad11bab56b9ff3897e105c0fc51eef9e9268c9406c3ca14401eddc8a69f2f381ae82e24d039452de5fc7f32ec694fdf3b1c6d724af22cf69e5f9dd languageName: node linkType: hard +"esmock@patch:esmock@npm%3A2.7.3#~/.yarn/patches/esmock-npm-2.7.3-83624b28f6.patch": + version: 2.7.3 + resolution: "esmock@patch:esmock@npm%3A2.7.3#~/.yarn/patches/esmock-npm-2.7.3-83624b28f6.patch::version=2.7.3&hash=acc414" + checksum: 10c0/67532f6510599549060545aabd4b64e080a30d98f1ec91f697058e343a14bd1845a4cdf452a38335f44aad827a5dee0e86d6e0e16853aad0b65235dcd0c55e18 + languageName: node + linkType: hard + "esniff@npm:^2.0.1": version: 2.0.1 resolution: "esniff@npm:2.0.1" @@ -18472,6 +19091,45 @@ __metadata: languageName: node linkType: hard +"express@npm:^4.22.2": + version: 4.22.2 + resolution: "express@npm:4.22.2" + dependencies: + accepts: "npm:~1.3.8" + array-flatten: "npm:1.1.1" + body-parser: "npm:~1.20.5" + content-disposition: "npm:~0.5.4" + content-type: "npm:~1.0.4" + cookie: "npm:~0.7.1" + cookie-signature: "npm:~1.0.6" + debug: "npm:2.6.9" + depd: "npm:2.0.0" + encodeurl: "npm:~2.0.0" + escape-html: "npm:~1.0.3" + etag: "npm:~1.8.1" + finalhandler: "npm:~1.3.1" + fresh: "npm:~0.5.2" + http-errors: "npm:~2.0.0" + merge-descriptors: "npm:1.0.3" + methods: "npm:~1.1.2" + on-finished: "npm:~2.4.1" + parseurl: "npm:~1.3.3" + path-to-regexp: "npm:~0.1.12" + proxy-addr: "npm:~2.0.7" + qs: "npm:~6.15.1" + range-parser: "npm:~1.2.1" + safe-buffer: "npm:5.2.1" + send: "npm:~0.19.0" + serve-static: "npm:~1.16.2" + setprototypeof: "npm:1.2.0" + statuses: "npm:~2.0.1" + type-is: "npm:~1.6.18" + utils-merge: "npm:1.0.1" + vary: "npm:~1.1.2" + checksum: 10c0/d06dd4379fd217440b30f8abbe45f0e74931114c1395034f03e7d635196ecdab530d4835a1962a6aa34838d61967dc6f1f77846999bba3032373e9e714222c44 + languageName: node + linkType: hard + "expressionify@npm:0.9.3": version: 0.9.3 resolution: "expressionify@npm:0.9.3" @@ -19054,6 +19712,15 @@ __metadata: languageName: node linkType: hard +"focus-trap@npm:^8.2.1": + version: 8.2.1 + resolution: "focus-trap@npm:8.2.1" + dependencies: + tabbable: "npm:^6.4.0" + checksum: 10c0/afcb1639d1c0958ff6a1350a4b7eaac4c956487b13ebaf91e7a2ccab39158dce74cb930d60715d13a723cb0ae55ff197671fd41a58a74ac54c8b8c49c5966225 + languageName: node + linkType: hard + "follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.16.0": version: 1.16.0 resolution: "follow-redirects@npm:1.16.0" @@ -19240,8 +19907,10 @@ __metadata: "@overleaf/fetch-utils": "workspace:*" "@overleaf/logger": "workspace:*" "@overleaf/metrics": "workspace:*" + "@types/node": "npm:^24.5.2" chai: "npm:^4.3.6" chai-as-promised: "npm:^7.1.1" + eslint: "npm:^10.4.0" express: "npm:4.22.1" is-valid-hostname: "npm:^1.0.2" mocha: "npm:^11.1.0" @@ -21172,6 +21841,13 @@ __metadata: languageName: node linkType: hard +"ipaddr.js@npm:^2.2.0": + version: 2.4.0 + resolution: "ipaddr.js@npm:2.4.0" + checksum: 10c0/47c2f17677b40054ca50a09e1228cf818c0d02d4474c2e0e29232c6668b3c4d51a3cfc19d1e17897d7baf4d933b3111d6bdf5cfbe55ab184165469a75f2bf177 + languageName: node + linkType: hard + "is-absolute-url@npm:^3.0.3": version: 3.0.3 resolution: "is-absolute-url@npm:3.0.3" @@ -22037,7 +22713,7 @@ __metadata: languageName: node linkType: hard -"jquery@npm:>=1.10": +"jquery@npm:*, jquery@npm:>=1.10": version: 4.0.0 resolution: "jquery@npm:4.0.0" checksum: 10c0/06d8d0f51121af5a691f8b59c74823157bb5b60eea915b30eaa920d6c0ffd91e60ba81e9b97bd8203f331f9dd8d0ec9a4b010935ea314bdd2f15453c29bc780b @@ -22096,19 +22772,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^3.13.1": - version: 3.14.2 - resolution: "js-yaml@npm:3.14.2" - dependencies: - argparse: "npm:^1.0.7" - esprima: "npm:^4.0.0" - bin: - js-yaml: bin/js-yaml.js - checksum: 10c0/3261f25912f5dd76605e5993d0a126c2b6c346311885d3c483706cd722efe34f697ea0331f654ce27c00a42b426e524518ec89d65ed02ea47df8ad26dcc8ce69 - languageName: node - linkType: hard - -"js-yaml@npm:^4.1.0, js-yaml@npm:^4.1.1": +"js-yaml@npm:^4.1.1": version: 4.1.1 resolution: "js-yaml@npm:4.1.1" dependencies: @@ -22504,6 +23168,13 @@ __metadata: languageName: node linkType: hard +"just-extend@npm:^6.2.0": + version: 6.2.0 + resolution: "just-extend@npm:6.2.0" + checksum: 10c0/d41cbdb6d85b986d4deaf2144d81d4f7266cd408fc95189d046d63f610c2dc486b141aeb6ef319c2d76fe904d45a6bb31f19b098ff0427c35688e0c383fc0511 + languageName: node + linkType: hard + "just-once@npm:1.1.0": version: 1.1.0 resolution: "just-once@npm:1.1.0" @@ -22691,7 +23362,9 @@ __metadata: "@overleaf/fetch-utils": "workspace:*" "@overleaf/o-error": "workspace:*" "@popperjs/core": "npm:^2.11.8" + "@testing-library/dom": "npm:^10.4.0" "@testing-library/react": "npm:^16.3.2" + "@types/react": "npm:^18.3.1" "@vitejs/plugin-react": "npm:^4.3.4" babel-loader: "npm:^10.1.1" babel-plugin-react-transform: "npm:^3.0.0" @@ -22744,6 +23417,7 @@ __metadata: style-loader: "npm:^4.0.0" throng: "npm:^4.0.0" url-loader: "npm:^4.1.1" + vite: "npm:^6.0.0" vitest: "npm:4.1.5" webpack: "npm:^5.106.2" webpack-cli: "npm:^7.0.2" @@ -25216,6 +25890,19 @@ __metadata: languageName: node linkType: hard +"nise@npm:^5.1.2": + version: 5.1.9 + resolution: "nise@npm:5.1.9" + dependencies: + "@sinonjs/commons": "npm:^3.0.0" + "@sinonjs/fake-timers": "npm:^11.2.2" + "@sinonjs/text-encoding": "npm:^0.7.2" + just-extend: "npm:^6.2.0" + path-to-regexp: "npm:^6.2.1" + checksum: 10c0/a44318e6de738b34a1f51b4b478f97f5b40a5a27175be4bf13f6e5b8e67aa70d0b3f51c77a966d6617fccdc3b436c675a89be57424833e6d8a290367faa66b28 + languageName: node + linkType: hard + "no-case@npm:^3.0.4": version: 3.0.4 resolution: "no-case@npm:3.0.4" @@ -25508,6 +26195,8 @@ __metadata: "npm-overrides-helper@workspace:tools/npm-overrides-helper": version: 0.0.0-use.local resolution: "npm-overrides-helper@workspace:tools/npm-overrides-helper" + dependencies: + eslint: "npm:^10.4.0" languageName: unknown linkType: soft @@ -25910,6 +26599,7 @@ __metadata: "@types/is-core-module": "npm:^2.2.2" "@types/minimist": "npm:^1.2.5" "@types/node": "npm:^24.5.2" + eslint: "npm:^10.4.0" is-core-module: "npm:^2.16.1" minimist: "npm:^1.2.8" npm-check-updates: "npm:^18.1.1" @@ -25923,9 +26613,13 @@ __metadata: dependencies: "@overleaf/o-error": "workspace:*" "@types/check-types": "npm:^7.3.7" + "@types/lodash": "npm:^4.17.24" + "@types/mocha": "npm:^10.0.6" + "@types/node": "npm:^24.5.2" "@types/path-browserify": "npm:^1.0.3" chai: "npm:^3.3.0" check-types: "npm:^5.1.0" + eslint: "npm:^10.4.0" lodash: "npm:^4.18.1" mocha: "npm:^11.1.0" mocha-junit-reporter: "npm:^2.2.1" @@ -25941,7 +26635,9 @@ __metadata: version: 0.0.0-use.local resolution: "overleaf-editor@workspace:services/history-v1" dependencies: + "@aws-sdk/client-s3": "npm:^3.994.0" "@google-cloud/secret-manager": "npm:^5.6.0" + "@google-cloud/storage": "npm:^7.19.0" "@overleaf/fetch-utils": "workspace:*" "@overleaf/logger": "workspace:*" "@overleaf/metrics": "workspace:*" @@ -25954,6 +26650,9 @@ __metadata: "@overleaf/settings": "workspace:*" "@overleaf/stream-utils": "npm:^0.1.0" "@overleaf/validation-tools": "workspace:*" + "@types/chai-as-promised": "npm:^7.1.8" + "@types/mocha": "npm:^10.0.6" + "@types/node": "npm:^24.5.2" archiver: "npm:^5.3.0" basic-auth: "npm:^2.0.1" benny: "npm:^3.7.1" @@ -25967,6 +26666,7 @@ __metadata: check-types: "npm:^11.1.2" command-line-args: "npm:^3.0.3" config: "npm:^3.3.12" + eslint: "npm:^10.4.0" express: "npm:4.22.1" fs-extra: "npm:^9.0.1" generic-pool: "npm:^2.1.1" @@ -26023,9 +26723,15 @@ __metadata: eslint-plugin-promise: "npm:^7.2.1" eslint-plugin-unicorn: "npm:^56.0.0" globals: "npm:^17.6.0" + js-yaml: "npm:^4.1.1" prettier: "npm:3.7.4" prettier-plugin-groovy: "npm:0.2.1" typescript: "npm:^5.9.3" + dependenciesMeta: + cypress-multi-reporters@2.0.5: + unplugged: true + esmock@2.7.3: + unplugged: true languageName: unknown linkType: soft @@ -26632,6 +27338,13 @@ __metadata: languageName: node linkType: hard +"path-to-regexp@npm:^6.2.1": + version: 6.3.0 + resolution: "path-to-regexp@npm:6.3.0" + checksum: 10c0/73b67f4638b41cde56254e6354e46ae3a2ebc08279583f6af3d96fe4664fc75788f74ed0d18ca44fa4a98491b69434f9eee73b97bb5314bd1b5adb700f5c18d6 + languageName: node + linkType: hard + "path-to-regexp@npm:~0.1.12": version: 0.1.13 resolution: "path-to-regexp@npm:0.1.13" @@ -28418,6 +29131,15 @@ __metadata: languageName: node linkType: hard +"qs@npm:~6.15.1": + version: 6.15.2 + resolution: "qs@npm:6.15.2" + dependencies: + side-channel: "npm:^1.1.0" + checksum: 10c0/e6fd5f6f0aab06d480fe9ab15cebfc4ce4235303e2f91dc69a8f7f4df1e668a61c11d1cfbabacf4295cbbeb7b670ed23db45307480726259761f98e5695e93a7 + languageName: node + linkType: hard + "querystring-es3@npm:^0.2.1": version: 0.2.1 resolution: "querystring-es3@npm:0.2.1" @@ -28904,26 +29626,26 @@ __metadata: linkType: hard "react-router-dom@npm:^6.26.1": - version: 6.30.4 - resolution: "react-router-dom@npm:6.30.4" + version: 6.30.3 + resolution: "react-router-dom@npm:6.30.3" dependencies: - "@remix-run/router": "npm:1.23.3" - react-router: "npm:6.30.4" + "@remix-run/router": "npm:1.23.2" + react-router: "npm:6.30.3" peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: 10c0/1b25ab26a288da852f7b58eec5c14b3f37919e6773a557cd846d3a05d7a7d890c8d49bda93c0a7f497f240df1df8b0ad50635f990aafb55f2fc545ad8269a822 + checksum: 10c0/e8a1e13c662ed6ee71a785bd3418ba04b700bcd8aff6ea7b32524371e8abb1c85568cd4fe9b9e9d555b8101fd415f6f1796531f593da60be179ce75b37038657 languageName: node linkType: hard -"react-router@npm:6.30.4": - version: 6.30.4 - resolution: "react-router@npm:6.30.4" +"react-router@npm:6.30.3": + version: 6.30.3 + resolution: "react-router@npm:6.30.3" dependencies: - "@remix-run/router": "npm:1.23.3" + "@remix-run/router": "npm:1.23.2" peerDependencies: react: ">=16.8" - checksum: 10c0/fb6de7d1002bcab9ea12c4072d93792eca494f1e4f30cfec334ccb6523756d23ce3e093c7c1241399296cebed94789a3fb89f96ee76004e0e746458a8f6bab33 + checksum: 10c0/a0a74bf5a933cf0abd47e0eac1d3a505cd66b866e3ee8f20d8016885d3b4361ba3ba72dee026248c6125e631b191ba6ad109184c892281cea6cb747c71bf5940 languageName: node linkType: hard @@ -29264,7 +29986,7 @@ __metadata: languageName: node linkType: hard -"reflect-metadata@npm:^0.2.2": +"reflect-metadata@npm:*, reflect-metadata@npm:^0.2.2": version: 0.2.2 resolution: "reflect-metadata@npm:0.2.2" checksum: 10c0/1cd93a15ea291e420204955544637c264c216e7aac527470e393d54b4bb075f10a17e60d8168ec96600c7e0b9fcc0cb0bb6e91c3fbf5b0d8c9056f04e6ac1ec2 @@ -30760,6 +31482,20 @@ __metadata: languageName: node linkType: hard +"sinon@npm:^14.0.0": + version: 14.0.2 + resolution: "sinon@npm:14.0.2" + dependencies: + "@sinonjs/commons": "npm:^2.0.0" + "@sinonjs/fake-timers": "npm:^9.1.2" + "@sinonjs/samsam": "npm:^7.0.1" + diff: "npm:^5.0.0" + nise: "npm:^5.1.2" + supports-color: "npm:^7.2.0" + checksum: 10c0/cef92d9a018e08c22812f04038eb33972e5386253f897c3efc4ff26d80e354d17a1d8123aed443c03ba94d85c4c3eb0660c6d3f6f8460d7d0af4d6bd3e058ae0 + languageName: node + linkType: hard + "sinon@npm:^21.1.0": version: 21.1.2 resolution: "sinon@npm:21.1.2" @@ -31119,13 +31855,6 @@ __metadata: languageName: node linkType: hard -"sprintf-js@npm:~1.0.2": - version: 1.0.3 - resolution: "sprintf-js@npm:1.0.3" - checksum: 10c0/ecadcfe4c771890140da5023d43e190b7566d9cf8b2d238600f31bec0fc653f328da4450eb04bd59a431771a8e9cc0e118f0aa3974b683a4981b4e07abc2a5bb - languageName: node - linkType: hard - "sprintf-kit@npm:^2.0.2": version: 2.0.2 resolution: "sprintf-kit@npm:2.0.2" @@ -31833,7 +32562,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^7.0.0, supports-color@npm:^7.1.0": +"supports-color@npm:^7.0.0, supports-color@npm:^7.1.0, supports-color@npm:^7.2.0": version: 7.2.0 resolution: "supports-color@npm:7.2.0" dependencies: @@ -33934,6 +34663,74 @@ __metadata: languageName: node linkType: hard +"vitest@npm:^4.0.0": + version: 4.1.8 + resolution: "vitest@npm:4.1.8" + dependencies: + "@vitest/expect": "npm:4.1.8" + "@vitest/mocker": "npm:4.1.8" + "@vitest/pretty-format": "npm:4.1.8" + "@vitest/runner": "npm:4.1.8" + "@vitest/snapshot": "npm:4.1.8" + "@vitest/spy": "npm:4.1.8" + "@vitest/utils": "npm:4.1.8" + es-module-lexer: "npm:^2.0.0" + expect-type: "npm:^1.3.0" + magic-string: "npm:^0.30.21" + obug: "npm:^2.1.1" + pathe: "npm:^2.0.3" + picomatch: "npm:^4.0.3" + std-env: "npm:^4.0.0-rc.1" + tinybench: "npm:^2.9.0" + tinyexec: "npm:^1.0.2" + tinyglobby: "npm:^0.2.15" + tinyrainbow: "npm:^3.1.0" + vite: "npm:^6.0.0 || ^7.0.0 || ^8.0.0" + why-is-node-running: "npm:^2.3.0" + peerDependencies: + "@edge-runtime/vm": "*" + "@opentelemetry/api": ^1.9.0 + "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0 + "@vitest/browser-playwright": 4.1.8 + "@vitest/browser-preview": 4.1.8 + "@vitest/browser-webdriverio": 4.1.8 + "@vitest/coverage-istanbul": 4.1.8 + "@vitest/coverage-v8": 4.1.8 + "@vitest/ui": 4.1.8 + happy-dom: "*" + jsdom: "*" + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@opentelemetry/api": + optional: true + "@types/node": + optional: true + "@vitest/browser-playwright": + optional: true + "@vitest/browser-preview": + optional: true + "@vitest/browser-webdriverio": + optional: true + "@vitest/coverage-istanbul": + optional: true + "@vitest/coverage-v8": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vite: + optional: false + bin: + vitest: vitest.mjs + checksum: 10c0/f459c500f8818c7a2318cd23228b4e5c0b5efb25bf8e5cb7f116c6d26e51482b2f800a8bb19837c0b5f0d05c51519edbf502bc8ceb5bd86868e8facf1d2c498e + languageName: node + linkType: hard + "void-elements@npm:3.1.0, void-elements@npm:^3.1.0": version: 3.1.0 resolution: "void-elements@npm:3.1.0" @@ -34466,6 +35263,19 @@ __metadata: languageName: node linkType: hard +"wiki-algolia@workspace:jobs/wiki-algolia": + version: 0.0.0-use.local + resolution: "wiki-algolia@workspace:jobs/wiki-algolia" + dependencies: + algoliasearch: "npm:^4.19.1" + chai-as-promised: "npm:^8.0.2" + lodash: "npm:^4.18.1" + sanitize-html: "npm:^2.17.4" + typescript: "npm:^5.0.4" + vitest: "npm:^4.0.0" + languageName: unknown + linkType: soft + "wildcard@npm:^1.1.0": version: 1.1.2 resolution: "wildcard@npm:1.1.2"