Просмотр исходного кода

Convert to ESM

GitOrigin-RevId: b58b02f9e9c8d47909e95c3ade8e1bf33ed46c80
Andrew Rumble 9 месяцев назад
Родитель
Сommit
912324f560
78 измененных файлов с 515 добавлено и 484 удалено
  1. 1 1
      services/web/app/src/Features/Analytics/AccountMappingHelper.mjs
  2. 10 11
      services/web/app/src/Features/Analytics/AnalyticsManager.mjs
  3. 3 3
      services/web/app/src/Features/Analytics/AnalyticsRegistrationSourceHelper.mjs
  4. 6 3
      services/web/app/src/Features/Analytics/EmailChangeHelper.mjs
  5. 3 3
      services/web/app/src/Features/Analytics/RequestHelper.mjs
  6. 4 4
      services/web/app/src/Features/Analytics/UserAnalyticsIdCache.mjs
  7. 16 17
      services/web/app/src/Features/Authentication/AuthenticationManager.mjs
  8. 8 7
      services/web/app/src/Features/Authentication/HaveIBeenPwned.mjs
  9. 2 2
      services/web/app/src/Features/Authentication/SessionManager.mjs
  10. 1 1
      services/web/app/src/Features/Authorization/PublicAccessLevels.mjs
  11. 1 1
      services/web/app/src/Features/Authorization/Sources.mjs
  12. 5 4
      services/web/app/src/Features/Chat/ChatApiHandler.mjs
  13. 5 5
      services/web/app/src/Features/Collaborators/CollaboratorsInviteGetter.mjs
  14. 2 2
      services/web/app/src/Features/Collaborators/CollaboratorsInviteHelper.mjs
  15. 9 9
      services/web/app/src/Features/Compile/ClsiCacheHandler.mjs
  16. 5 5
      services/web/app/src/Features/Contacts/ContactManager.mjs
  17. 10 9
      services/web/app/src/Features/Docstore/DocstoreManager.mjs
  18. 2 1
      services/web/app/src/Features/Documents/DocumentHelper.mjs
  19. 6 6
      services/web/app/src/Features/Editor/EditorRealTimeController.mjs
  20. 10 10
      services/web/app/src/Features/Email/EmailBuilder.mjs
  21. 7 7
      services/web/app/src/Features/Email/EmailHandler.mjs
  22. 1 1
      services/web/app/src/Features/Email/EmailOptionsHelper.mjs
  23. 10 10
      services/web/app/src/Features/Email/EmailSender.mjs
  24. 2 2
      services/web/app/src/Features/Email/SpamSafe.mjs
  25. 5 4
      services/web/app/src/Features/Errors/HttpErrorHandler.mjs
  26. 5 5
      services/web/app/src/Features/FileStore/FileHashManager.mjs
  27. 2 4
      services/web/app/src/Features/Helpers/AsyncFormHelper.mjs
  28. 2 2
      services/web/app/src/Features/Helpers/SafeHTMLSubstitution.mjs
  29. 1 1
      services/web/app/src/Features/Helpers/StringHelper.mjs
  30. 3 3
      services/web/app/src/Features/Helpers/UrlHelper.mjs
  31. 3 3
      services/web/app/src/Features/History/HistoryBackupDeletionHandler.mjs
  32. 12 13
      services/web/app/src/Features/Institutions/InstitutionsAPI.mjs
  33. 6 5
      services/web/app/src/Features/Institutions/InstitutionsFeatures.mjs
  34. 1 1
      services/web/app/src/Features/Institutions/InstitutionsHelper.mjs
  35. 2 2
      services/web/app/src/Features/Newsletter/MailChimpClient.mjs
  36. 7 7
      services/web/app/src/Features/Newsletter/MailChimpProvider.mjs
  37. 3 3
      services/web/app/src/Features/Newsletter/NewsletterManager.mjs
  38. 9 7
      services/web/app/src/Features/Notifications/NotificationsBuilder.mjs
  39. 6 6
      services/web/app/src/Features/Notifications/NotificationsHandler.mjs
  40. 6 6
      services/web/app/src/Features/OnboardingDataCollection/OnboardingDataCollectionManager.mjs
  41. 6 4
      services/web/app/src/Features/Project/FolderStructureBuilder.mjs
  42. 3 3
      services/web/app/src/Features/Project/ProjectEditorHandler.mjs
  43. 7 5
      services/web/app/src/Features/Project/ProjectHelper.mjs
  44. 9 7
      services/web/app/src/Features/Project/ProjectOptionsHandler.mjs
  45. 3 3
      services/web/app/src/Features/Project/ProjectUpdateHandler.mjs
  46. 1 1
      services/web/app/src/Features/Project/SafePath.mjs
  47. 7 7
      services/web/app/src/Features/Publishers/PublishersGetter.mjs
  48. 5 5
      services/web/app/src/Features/Referal/ReferalFeatures.mjs
  49. 1 1
      services/web/app/src/Features/SplitTests/LocalsHelper.mjs
  50. 4 4
      services/web/app/src/Features/SplitTests/SplitTestCache.mjs
  51. 19 19
      services/web/app/src/Features/SplitTests/SplitTestHandler.mjs
  52. 6 6
      services/web/app/src/Features/SplitTests/SplitTestManager.mjs
  53. 12 10
      services/web/app/src/Features/SplitTests/SplitTestSessionHandler.mjs
  54. 4 4
      services/web/app/src/Features/SplitTests/SplitTestUserGetter.mjs
  55. 2 2
      services/web/app/src/Features/SplitTests/SplitTestUtils.mjs
  56. 3 3
      services/web/app/src/Features/Subscription/FeaturesHelper.mjs
  57. 19 19
      services/web/app/src/Features/Subscription/FeaturesUpdater.mjs
  58. 9 8
      services/web/app/src/Features/Subscription/PaymentProviderEntities.mjs
  59. 4 3
      services/web/app/src/Features/Subscription/PlansLocator.mjs
  60. 17 14
      services/web/app/src/Features/Subscription/RecurlyClient.mjs
  61. 2 2
      services/web/app/src/Features/Subscription/RecurlyMetrics.mjs
  62. 11 11
      services/web/app/src/Features/Subscription/RecurlyWrapper.mjs
  63. 9 8
      services/web/app/src/Features/Subscription/SubscriptionLocator.mjs
  64. 18 18
      services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs
  65. 4 4
      services/web/app/src/Features/Subscription/UserFeaturesUpdater.mjs
  66. 9 8
      services/web/app/src/Features/Subscription/V1SubscriptionManager.mjs
  67. 3 3
      services/web/app/src/Features/Tags/TagsHandler.mjs
  68. 16 13
      services/web/app/src/Features/TokenAccess/TokenAccessHandler.mjs
  69. 13 12
      services/web/app/src/Features/Uploads/ArchiveManager.mjs
  70. 8 7
      services/web/app/src/Features/Uploads/FileTypeManager.mjs
  71. 11 11
      services/web/app/src/Features/User/ThirdPartyIdentityManager.mjs
  72. 6 6
      services/web/app/src/Features/User/UserAuditLogHandler.mjs
  73. 16 16
      services/web/app/src/Features/User/UserGetter.mjs
  74. 7 7
      services/web/app/src/Features/User/UserSessionsManager.mjs
  75. 2 2
      services/web/app/src/Features/User/UserSessionsRedis.mjs
  76. 24 24
      services/web/app/src/Features/User/UserUpdater.mjs
  77. 1 1
      services/web/app/src/Features/UserMembership/UserMembershipEntityConfigs.mjs
  78. 12 7
      services/web/app/src/Features/UserMembership/UserMembershipsHandler.mjs

+ 1 - 1
services/web/app/src/Features/Analytics/AccountMappingHelper.mjs

@@ -116,7 +116,7 @@ function generateSubscriptionToStripeMapping(
   }
 }
 
-module.exports = {
+export default {
   extractAccountMappingsFromSubscription,
   generateV1Mapping,
   generateSubscriptionToRecurlyMapping,

+ 10 - 11
services/web/app/src/Features/Analytics/AnalyticsManager.mjs

@@ -1,13 +1,12 @@
-const SessionManager = require('../Authentication/SessionManager')
-const UserAnalyticsIdCache = require('./UserAnalyticsIdCache')
-const Settings = require('@overleaf/settings')
-const Metrics = require('../../infrastructure/Metrics')
-const Queues = require('../../infrastructure/Queues')
-const crypto = require('crypto')
-const _ = require('lodash')
-const { expressify } = require('@overleaf/promise-utils')
-const logger = require('@overleaf/logger')
-const { createHash } = require('crypto')
+import SessionManager from '../Authentication/SessionManager.mjs'
+import UserAnalyticsIdCache from './UserAnalyticsIdCache.mjs'
+import Settings from '@overleaf/settings'
+import Metrics from '../../infrastructure/Metrics.js'
+import Queues from '../../infrastructure/Queues.js'
+import crypto, { createHash } from 'node:crypto'
+import _ from 'lodash'
+import { expressify } from '@overleaf/promise-utils'
+import logger from '@overleaf/logger'
 
 if (
   Settings.analytics?.enabled &&
@@ -450,7 +449,7 @@ async function analyticsIdMiddleware(req, res, next) {
   next()
 }
 
-module.exports = {
+export default {
   identifyUser,
   recordEventForSession,
   recordEventForUser,

+ 3 - 3
services/web/app/src/Features/Analytics/AnalyticsRegistrationSourceHelper.mjs

@@ -1,5 +1,5 @@
-const AnalyticsManager = require('./AnalyticsManager')
-const RequestHelper = require('./RequestHelper')
+import AnalyticsManager from './AnalyticsManager.mjs'
+import RequestHelper from './RequestHelper.mjs'
 
 function clearSource(session) {
   if (session) {
@@ -88,7 +88,7 @@ function addUserProperties(userId, session) {
   }
 }
 
-module.exports = {
+export default {
   clearSource,
   setInbound,
   clearInbound,

+ 6 - 3
services/web/app/src/Features/Analytics/EmailChangeHelper.mjs

@@ -1,6 +1,9 @@
 // @ts-check
-const UserGetter = require('../User/UserGetter')
-const { registerEmailChange } = require('./AnalyticsManager')
+import UserGetter from '../User/UserGetter.mjs'
+
+import AnalyticsManager from './AnalyticsManager.mjs'
+
+const { registerEmailChange } = AnalyticsManager
 
 /**
  * @typedef {object} EmailData
@@ -115,7 +118,7 @@ function fillMissingEventData(eventData, emailData) {
   return eventData
 }
 
-module.exports = {
+export default {
   registerEmailUpdate,
   registerEmailCreation,
   registerEmailDeletion,

+ 3 - 3
services/web/app/src/Features/Analytics/RequestHelper.mjs

@@ -1,5 +1,5 @@
-const RefererParser = require('referer-parser')
-const { URL } = require('url')
+import RefererParser from 'referer-parser'
+import { URL } from 'node:url'
 
 const UTM_KEYS = [
   'utm_campaign',
@@ -49,7 +49,7 @@ function parseReferrer(referrer, url) {
   return referrerValues
 }
 
-module.exports = {
+export default {
   UTM_KEYS,
   parseUtm,
   parseReferrer,

+ 4 - 4
services/web/app/src/Features/Analytics/UserAnalyticsIdCache.mjs

@@ -1,6 +1,6 @@
-const UserGetter = require('../User/UserGetter')
-const { CacheLoader } = require('cache-flow')
-const { callbackify } = require('util')
+import UserGetter from '../User/UserGetter.mjs'
+import { CacheLoader } from 'cache-flow'
+import { callbackify } from 'node:util'
 
 class UserAnalyticsIdCache extends CacheLoader {
   constructor() {
@@ -28,4 +28,4 @@ const userAnalyticsIdCache = new UserAnalyticsIdCache()
 userAnalyticsIdCache.callbacks = {
   get: callbackify(userAnalyticsIdCache.get).bind(userAnalyticsIdCache),
 }
-module.exports = userAnalyticsIdCache
+export default userAnalyticsIdCache

+ 16 - 17
services/web/app/src/Features/Authentication/AuthenticationManager.mjs

@@ -1,24 +1,23 @@
-const Settings = require('@overleaf/settings')
-const { User } = require('../../models/User')
-const { db, ObjectId } = require('../../infrastructure/mongodb')
-const bcrypt = require('bcrypt')
-const EmailHelper = require('../Helpers/EmailHelper')
-const {
+import Settings from '@overleaf/settings'
+import { User } from '../../models/User.js'
+import { db, ObjectId } from '../../infrastructure/mongodb.js'
+import bcrypt from 'bcrypt'
+import EmailHelper from '../Helpers/EmailHelper.js'
+
+import {
   InvalidEmailError,
   InvalidPasswordError,
   ParallelLoginError,
   PasswordMustBeDifferentError,
   PasswordReusedError,
-} = require('./AuthenticationErrors')
-const {
-  callbackify,
-  callbackifyMultiResult,
-} = require('@overleaf/promise-utils')
-const HaveIBeenPwned = require('./HaveIBeenPwned')
-const UserAuditLogHandler = require('../User/UserAuditLogHandler')
-const logger = require('@overleaf/logger')
-const DiffHelper = require('../Helpers/DiffHelper')
-const Metrics = require('@overleaf/metrics')
+} from './AuthenticationErrors.js'
+
+import { callbackify, callbackifyMultiResult } from '@overleaf/promise-utils'
+import HaveIBeenPwned from './HaveIBeenPwned.mjs'
+import UserAuditLogHandler from '../User/UserAuditLogHandler.mjs'
+import logger from '@overleaf/logger'
+import DiffHelper from '../Helpers/DiffHelper.js'
+import Metrics from '@overleaf/metrics'
 
 const BCRYPT_ROUNDS = Settings.security.bcryptRounds || 12
 const BCRYPT_MINOR_VERSION = Settings.security.bcryptMinorVersion || 'a'
@@ -458,7 +457,7 @@ const AuthenticationManager = {
   },
 }
 
-module.exports = {
+export default {
   _validatePasswordNotTooSimilar:
     AuthenticationManager._validatePasswordNotTooSimilar, // Private function exported for tests
   validateEmail: AuthenticationManager.validateEmail,

+ 8 - 7
services/web/app/src/Features/Authentication/HaveIBeenPwned.mjs

@@ -5,12 +5,13 @@
    happy path or via an error (message or attributes).
  */
 
-const { callbackify } = require('util')
-const { fetchString } = require('@overleaf/fetch-utils')
-const crypto = require('crypto')
-const Settings = require('@overleaf/settings')
-const Metrics = require('@overleaf/metrics')
-const logger = require('@overleaf/logger')
+import { callbackify } from 'node:util'
+
+import { fetchString } from '@overleaf/fetch-utils'
+import crypto from 'node:crypto'
+import Settings from '@overleaf/settings'
+import Metrics from '@overleaf/metrics'
+import logger from '@overleaf/logger'
 
 const HEX_CHARS_UPPER = '1234567890ABCDEF'
 const API_ERROR = new Error('cannot contact HaveIBeenPwned api')
@@ -118,7 +119,7 @@ function checkPasswordForReuseInBackground(password) {
   })
 }
 
-module.exports = {
+export default {
   checkPasswordForReuse: callbackify(checkPasswordForReuse),
   checkPasswordForReuseInBackground,
   promises: {

+ 2 - 2
services/web/app/src/Features/Authentication/SessionManager.mjs

@@ -1,4 +1,4 @@
-const _ = require('lodash')
+import _ from 'lodash'
 
 const SessionManager = {
   getSessionUser(session) {
@@ -43,4 +43,4 @@ const SessionManager = {
   },
 }
 
-module.exports = SessionManager
+export default SessionManager

+ 1 - 1
services/web/app/src/Features/Authorization/PublicAccessLevels.mjs

@@ -13,7 +13,7 @@
  */
 
 /** @type {import('./types').PublicAccessLevelsType} */
-module.exports = {
+export default {
   READ_ONLY: 'readOnly', // LEGACY
   READ_AND_WRITE: 'readAndWrite', // LEGACY
   PRIVATE: 'private',

+ 1 - 1
services/web/app/src/Features/Authorization/Sources.mjs

@@ -1,7 +1,7 @@
 // @ts-check
 
 /** @type {import('./types').SourcesType} */
-module.exports = {
+export default {
   INVITE: 'invite',
   TOKEN: 'token',
   OWNER: 'owner',

+ 5 - 4
services/web/app/src/Features/Chat/ChatApiHandler.mjs

@@ -1,8 +1,9 @@
 // @ts-check
 
-const { fetchJson, fetchNothing } = require('@overleaf/fetch-utils')
-const settings = require('@overleaf/settings')
-const { callbackify } = require('util')
+import { fetchJson, fetchNothing } from '@overleaf/fetch-utils'
+
+import settings from '@overleaf/settings'
+import { callbackify } from 'node:util'
 
 async function getThread(projectId, threadId) {
   return await fetchJson(chatApiUrl(`/project/${projectId}/thread/${threadId}`))
@@ -165,7 +166,7 @@ function chatApiUrl(path) {
   return new URL(path, settings.apis.chat.internal_url)
 }
 
-module.exports = {
+export default {
   getThread: callbackify(getThread),
   getThreadMessage: callbackify(getThreadMessage),
   getThreads: callbackify(getThreads),

+ 5 - 5
services/web/app/src/Features/Collaborators/CollaboratorsInviteGetter.mjs

@@ -1,7 +1,7 @@
-const logger = require('@overleaf/logger')
-const { ProjectInvite } = require('../../models/ProjectInvite')
-const PrivilegeLevels = require('../Authorization/PrivilegeLevels')
-const CollaboratorsInviteHelper = require('./CollaboratorsInviteHelper')
+import logger from '@overleaf/logger'
+import { ProjectInvite } from '../../models/ProjectInvite.js'
+import PrivilegeLevels from '../Authorization/PrivilegeLevels.js'
+import CollaboratorsInviteHelper from './CollaboratorsInviteHelper.mjs'
 
 async function getAllInvites(projectId) {
   logger.debug({ projectId }, 'fetching invites for project')
@@ -39,7 +39,7 @@ async function getInviteByToken(projectId, tokenString) {
   return invite
 }
 
-module.exports = {
+export default {
   promises: {
     getAllInvites,
     getEditInviteCount,

+ 2 - 2
services/web/app/src/Features/Collaborators/CollaboratorsInviteHelper.mjs

@@ -1,4 +1,4 @@
-const Crypto = require('crypto')
+import Crypto from 'node:crypto'
 
 function generateToken() {
   const buffer = Crypto.randomBytes(24)
@@ -11,7 +11,7 @@ function hashInviteToken(token) {
     .digest('hex')
 }
 
-module.exports = {
+export default {
   generateToken,
   hashInviteToken,
 }

+ 9 - 9
services/web/app/src/Features/Compile/ClsiCacheHandler.mjs

@@ -1,14 +1,14 @@
-const _ = require('lodash')
-const {
+import _ from 'lodash'
+import {
   fetchNothing,
   fetchRedirectWithResponse,
   RequestFailedError,
-} = require('@overleaf/fetch-utils')
-const logger = require('@overleaf/logger')
-const Settings = require('@overleaf/settings')
-const OError = require('@overleaf/o-error')
-const { NotFoundError, InvalidNameError } = require('../Errors/Errors')
-const Features = require('../../infrastructure/Features')
+} from '@overleaf/fetch-utils'
+import logger from '@overleaf/logger'
+import Settings from '@overleaf/settings'
+import OError from '@overleaf/o-error'
+import { NotFoundError, InvalidNameError } from '../Errors/Errors.js'
+import Features from '../../infrastructure/Features.js'
 
 const TIMEOUT = 4_000
 
@@ -263,7 +263,7 @@ async function prepareCacheSource(
   }
 }
 
-module.exports = {
+export default {
   TIMEOUT,
   getEgressLabel,
   clearCache,

+ 5 - 5
services/web/app/src/Features/Contacts/ContactManager.mjs

@@ -1,7 +1,7 @@
-const { callbackify } = require('util')
-const OError = require('@overleaf/o-error')
-const { fetchJson } = require('@overleaf/fetch-utils')
-const settings = require('@overleaf/settings')
+import { callbackify } from 'node:util'
+import OError from '@overleaf/o-error'
+import { fetchJson } from '@overleaf/fetch-utils'
+import settings from '@overleaf/settings'
 
 async function getContactIds(userId, options) {
   options = options ?? { limit: 50 }
@@ -41,7 +41,7 @@ async function addContact(userId, contactId) {
   return body?.contact_ids || []
 }
 
-module.exports = {
+export default {
   getContactIds: callbackify(getContactIds),
   addContact: callbackify(addContact),
   promises: {

+ 10 - 9
services/web/app/src/Features/Docstore/DocstoreManager.mjs

@@ -1,11 +1,12 @@
-const { promisify } = require('util')
-const { promisifyMultiResult, callbackify } = require('@overleaf/promise-utils')
-const request = require('request').defaults({ jar: false })
-const OError = require('@overleaf/o-error')
-const logger = require('@overleaf/logger')
-const settings = require('@overleaf/settings')
-const Errors = require('../Errors/Errors')
-const { fetchJson } = require('@overleaf/fetch-utils')
+import { promisify } from 'node:util'
+import { promisifyMultiResult, callbackify } from '@overleaf/promise-utils'
+import OError from '@overleaf/o-error'
+import logger from '@overleaf/logger'
+import settings from '@overleaf/settings'
+import Errors from '../Errors/Errors.js'
+import { fetchJson } from '@overleaf/fetch-utils'
+import Request from 'request'
+const request = Request.defaults({ jar: false })
 
 const TIMEOUT = 30 * 1000 // request timeout
 
@@ -303,7 +304,7 @@ function _operateOnProject(projectId, method, callback) {
   })
 }
 
-module.exports = {
+export default {
   deleteDoc,
   getAllDocs,
   getAllDeletedDocs,

+ 2 - 1
services/web/app/src/Features/Documents/DocumentHelper.mjs

@@ -12,7 +12,8 @@
  * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  */
 let DocumentHelper
-module.exports = DocumentHelper = {
+
+export default DocumentHelper = {
   getTitleFromTexContent(content, maxContentToScan) {
     if (maxContentToScan == null) {
       maxContentToScan = 30000

+ 6 - 6
services/web/app/src/Features/Editor/EditorRealTimeController.mjs

@@ -10,19 +10,19 @@
  * DS102: Remove unnecessary code created because of implicit returns
  * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  */
+import Settings from '@overleaf/settings'
+import Metrics from '@overleaf/metrics'
+import RedisWrapper from '../../infrastructure/RedisWrapper.js'
+import os from 'node:os'
+import crypto from 'node:crypto'
 let EditorRealTimeController
-const Settings = require('@overleaf/settings')
-const Metrics = require('@overleaf/metrics')
-const RedisWrapper = require('../../infrastructure/RedisWrapper')
 const rclient = RedisWrapper.client('pubsub')
-const os = require('os')
-const crypto = require('crypto')
 
 const HOST = os.hostname()
 const RND = crypto.randomBytes(4).toString('hex') // generate a random key for this process
 let COUNT = 0
 
-module.exports = EditorRealTimeController = {
+export default EditorRealTimeController = {
   emitToRoom(roomId, message, ...payload) {
     // create a unique message id using a counter
     const messageId = `web:${HOST}:${RND}-${COUNT++}`

+ 10 - 10
services/web/app/src/Features/Email/EmailBuilder.mjs

@@ -1,12 +1,12 @@
-const _ = require('lodash')
-const settings = require('@overleaf/settings')
-const moment = require('moment')
-const EmailMessageHelper = require('./EmailMessageHelper')
-const StringHelper = require('../Helpers/StringHelper')
-const BaseWithHeaderEmailLayout = require('./Layouts/BaseWithHeaderEmailLayout')
-const SpamSafe = require('./SpamSafe')
-const ctaEmailBody = require('./Bodies/cta-email')
-const NoCTAEmailBody = require('./Bodies/NoCTAEmailBody')
+import _ from 'lodash'
+import settings from '@overleaf/settings'
+import moment from 'moment'
+import EmailMessageHelper from './EmailMessageHelper.js'
+import StringHelper from '../Helpers/StringHelper.mjs'
+import BaseWithHeaderEmailLayout from './Layouts/BaseWithHeaderEmailLayout.js'
+import SpamSafe from './SpamSafe.mjs'
+import ctaEmailBody from './Bodies/cta-email.js'
+import NoCTAEmailBody from './Bodies/NoCTAEmailBody.js'
 
 function _emailBodyPlainText(content, opts, ctaEmail) {
   let emailBody = `${content.greeting(opts, true)}`
@@ -1017,7 +1017,7 @@ function _formatUserNameAndEmail(user, placeholder) {
   return SpamSafe.safeEmail(user.email, placeholder)
 }
 
-module.exports = {
+export default {
   templates,
   ctaTemplate,
   NoCTAEmailTemplate,

+ 7 - 7
services/web/app/src/Features/Email/EmailHandler.mjs

@@ -1,9 +1,9 @@
-const { callbackify } = require('util')
-const Settings = require('@overleaf/settings')
-const logger = require('@overleaf/logger')
-const EmailBuilder = require('./EmailBuilder')
-const EmailSender = require('./EmailSender')
-const Queues = require('../../infrastructure/Queues')
+import { callbackify } from 'node:util'
+import Settings from '@overleaf/settings'
+import logger from '@overleaf/logger'
+import EmailBuilder from './EmailBuilder.mjs'
+import EmailSender from './EmailSender.mjs'
+import Queues from '../../infrastructure/Queues.js'
 
 const EMAIL_SETTINGS = Settings.email || {}
 
@@ -32,7 +32,7 @@ function sendDeferredEmail(emailType, opts, delay) {
   })
 }
 
-module.exports = {
+export default {
   sendEmail: callbackify(sendEmail),
   sendDeferredEmail,
   promises: {

+ 1 - 1
services/web/app/src/Features/Email/EmailOptionsHelper.mjs

@@ -24,6 +24,6 @@ function linkOrUnlink(accountLinked, providerName, email) {
   }
 }
 
-module.exports = {
+export default {
   linkOrUnlink,
 }

+ 10 - 10
services/web/app/src/Features/Email/EmailSender.mjs

@@ -1,16 +1,16 @@
-const { callbackify } = require('util')
-const logger = require('@overleaf/logger')
-const metrics = require('@overleaf/metrics')
-const Settings = require('@overleaf/settings')
-const nodemailer = require('nodemailer')
-const aws = require('@aws-sdk/client-ses')
-const OError = require('@overleaf/o-error')
-const { RateLimiter } = require('../../infrastructure/RateLimiter')
-const _ = require('lodash')
+import { callbackify } from 'node:util'
+import logger from '@overleaf/logger'
+import metrics from '@overleaf/metrics'
+import Settings from '@overleaf/settings'
+import nodemailer from 'nodemailer'
+import aws from '@aws-sdk/client-ses'
+import OError from '@overleaf/o-error'
+import { RateLimiter } from '../../infrastructure/RateLimiter.js'
+import _ from 'lodash'
 
 const EMAIL_SETTINGS = Settings.email || {}
 
-module.exports = {
+export default {
   sendEmail: callbackify(sendEmail),
   promises: {
     sendEmail,

+ 2 - 2
services/web/app/src/Features/Email/SpamSafe.mjs

@@ -1,4 +1,4 @@
-const XRegExp = require('xregexp')
+import XRegExp from 'xregexp'
 
 // A note about SAFE_REGEX:
 // We have to escape the escape characters because XRegExp compiles it first.
@@ -69,4 +69,4 @@ const SpamSafe = {
   },
 }
 
-module.exports = SpamSafe
+export default SpamSafe

+ 5 - 4
services/web/app/src/Features/Errors/HttpErrorHandler.mjs

@@ -1,6 +1,6 @@
-const logger = require('@overleaf/logger')
-const Settings = require('@overleaf/settings')
-const { plainTextResponse } = require('../../infrastructure/Response')
+import logger from '@overleaf/logger'
+import Settings from '@overleaf/settings'
+import { plainTextResponse } from '../../infrastructure/Response.js'
 
 function renderJSONError(res, message, info = {}) {
   if (info.message) {
@@ -44,7 +44,8 @@ function handleGeneric400Error(req, res, statusCode, message, info = {}) {
 }
 
 let HttpErrorHandler
-module.exports = HttpErrorHandler = {
+
+export default HttpErrorHandler = {
   handleErrorByStatusCode(req, res, err, statusCode) {
     const is400Error = statusCode >= 400 && statusCode < 500
     const is500Error = statusCode >= 500 && statusCode < 600

+ 5 - 5
services/web/app/src/Features/FileStore/FileHashManager.mjs

@@ -11,13 +11,13 @@
  * DS207: Consider shorter variations of null checks
  * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  */
+import crypto from 'node:crypto'
+import logger from '@overleaf/logger'
+import fs from 'node:fs'
+import _ from 'lodash'
 let FileHashManager
-const crypto = require('crypto')
-const logger = require('@overleaf/logger')
-const fs = require('fs')
-const _ = require('lodash')
 
-module.exports = FileHashManager = {
+export default FileHashManager = {
   computeHash(filePath, callback) {
     if (callback == null) {
       callback = function () {}

+ 2 - 4
services/web/app/src/Features/Helpers/AsyncFormHelper.mjs

@@ -1,8 +1,6 @@
-const {
-  acceptsJson,
-} = require('../../infrastructure/RequestContentTypeDetection')
+import { acceptsJson } from '../../infrastructure/RequestContentTypeDetection.js'
 
-module.exports = {
+export default {
   redirect,
 }
 

+ 2 - 2
services/web/app/src/Features/Helpers/SafeHTMLSubstitution.mjs

@@ -1,4 +1,4 @@
-const pug = require('pug-runtime')
+import pug from 'pug-runtime'
 
 const SPLIT_REGEX = /<(\d+)>(.*?)<\/\1>/g
 
@@ -40,7 +40,7 @@ function render(locale, components) {
   return output.join('')
 }
 
-module.exports = {
+export default {
   SPLIT_REGEX,
   render,
 }

+ 1 - 1
services/web/app/src/Features/Helpers/StringHelper.mjs

@@ -15,7 +15,7 @@ const JSON_ESCAPE = {
   '\u2029': '\\u2029',
 }
 
-module.exports = StringHelper = {
+export default StringHelper = {
   // stringifies and escapes a json object for use in a script. This ensures that &, < and > characters are escaped,
   // along with quotes. This ensures that the string can be safely rendered into HTML. See rationale at:
   // https://api.rubyonrails.org/classes/ERB/Util.html#method-c-json_escape

+ 3 - 3
services/web/app/src/Features/Helpers/UrlHelper.mjs

@@ -1,5 +1,5 @@
-const Settings = require('@overleaf/settings')
-const { URL } = require('url')
+import Settings from '@overleaf/settings'
+import { URL } from 'node:url'
 
 const PROTO = new URL(Settings.siteUrl).protocol
 
@@ -28,7 +28,7 @@ function getSafeAdminDomainRedirect(path) {
   return Settings.adminUrl + (getSafeRedirectPath(path) || '/')
 }
 
-module.exports = {
+export default {
   getCanonicalURL,
   getSafeRedirectPath,
   getSafeAdminDomainRedirect,

+ 3 - 3
services/web/app/src/Features/History/HistoryBackupDeletionHandler.mjs

@@ -1,5 +1,5 @@
-const { fetchNothing } = require('@overleaf/fetch-utils')
-const Settings = require('@overleaf/settings')
+import { fetchNothing } from '@overleaf/fetch-utils'
+import Settings from '@overleaf/settings'
 
 async function deleteProject(projectId) {
   if (!Settings.apis.historyBackupDeletion.enabled) return
@@ -15,6 +15,6 @@ async function deleteProject(projectId) {
   })
 }
 
-module.exports = {
+export default {
   deleteProject,
 }

+ 12 - 13
services/web/app/src/Features/Institutions/InstitutionsAPI.mjs

@@ -1,17 +1,16 @@
-const { callbackify } = require('util')
-const OError = require('@overleaf/o-error')
-const logger = require('@overleaf/logger')
-const settings = require('@overleaf/settings')
-const request = require('requestretry')
-const { promisifyAll } = require('@overleaf/promise-utils')
-const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
-const {
+import { callbackify } from 'node:util'
+import OError from '@overleaf/o-error'
+import logger from '@overleaf/logger'
+import settings from '@overleaf/settings'
+import request from 'requestretry'
+import { promisifyAll, promiseMapWithLimit } from '@overleaf/promise-utils'
+import NotificationsBuilder from '../Notifications/NotificationsBuilder.mjs'
+import {
   V1ConnectionError,
   InvalidInstitutionalEmailError,
-} = require('../Errors/Errors')
-const { fetchJson, fetchNothing } = require('@overleaf/fetch-utils')
-const { promiseMapWithLimit } = require('@overleaf/promise-utils')
-const Modules = require('../../infrastructure/Modules')
+} from '../Errors/Errors.js'
+import { fetchJson, fetchNothing } from '@overleaf/fetch-utils'
+import Modules from '../../infrastructure/Modules.js'
 
 function _makeRequestOptions(options) {
   const requestOptions = {
@@ -418,4 +417,4 @@ InstitutionsAPI.promises.removeAffiliation = removeAffiliation
 InstitutionsAPI.promises.getUsersNeedingReconfirmationsLapsedProcessed =
   getUsersNeedingReconfirmationsLapsedProcessed
 
-module.exports = InstitutionsAPI
+export default InstitutionsAPI

+ 6 - 5
services/web/app/src/Features/Institutions/InstitutionsFeatures.mjs

@@ -1,7 +1,7 @@
-const { callbackifyAll } = require('@overleaf/promise-utils')
-const UserGetter = require('../User/UserGetter')
-const PlansLocator = require('../Subscription/PlansLocator')
-const Settings = require('@overleaf/settings')
+import { callbackifyAll } from '@overleaf/promise-utils'
+import UserGetter from '../User/UserGetter.mjs'
+import PlansLocator from '../Subscription/PlansLocator.mjs'
+import Settings from '@overleaf/settings'
 
 async function getInstitutionsFeatures(userId) {
   const planCode = await getInstitutionsPlan(userId)
@@ -26,7 +26,8 @@ const InstitutionsFeatures = {
   getInstitutionsPlan,
   hasLicence,
 }
-module.exports = {
+
+export default {
   promises: InstitutionsFeatures,
   ...callbackifyAll(InstitutionsFeatures),
 }

+ 1 - 1
services/web/app/src/Features/Institutions/InstitutionsHelper.mjs

@@ -23,6 +23,6 @@ function emailHasLicence(emailData) {
   return affiliation.licence !== 'free'
 }
 
-module.exports = {
+export default {
   emailHasLicence,
 }

+ 2 - 2
services/web/app/src/Features/Newsletter/MailChimpClient.mjs

@@ -1,4 +1,4 @@
-const { fetchJson, fetchNothing } = require('@overleaf/fetch-utils')
+import { fetchJson, fetchNothing } from '@overleaf/fetch-utils'
 
 class MailChimpClient {
   constructor(apiKey) {
@@ -65,4 +65,4 @@ class MailChimpClient {
   }
 }
 
-module.exports = MailChimpClient
+export default MailChimpClient

+ 7 - 7
services/web/app/src/Features/Newsletter/MailChimpProvider.mjs

@@ -1,9 +1,9 @@
-const logger = require('@overleaf/logger')
-const Settings = require('@overleaf/settings')
-const crypto = require('crypto')
-const OError = require('@overleaf/o-error')
-const { callbackify } = require('util')
-const MailChimpClient = require('./MailChimpClient')
+import logger from '@overleaf/logger'
+import Settings from '@overleaf/settings'
+import crypto from 'node:crypto'
+import OError from '@overleaf/o-error'
+import { callbackify } from 'node:util'
+import MailChimpClient from './MailChimpClient.mjs'
 
 function mailchimpIsConfigured() {
   return Settings.mailchimp != null && Settings.mailchimp.api_key != null
@@ -29,7 +29,7 @@ function make(listName, listId) {
   }
 }
 
-module.exports = {
+export default {
   make,
 }
 

+ 3 - 3
services/web/app/src/Features/Newsletter/NewsletterManager.mjs

@@ -1,9 +1,9 @@
-const Settings = require('@overleaf/settings')
-const MailchimpProvider = require('./MailChimpProvider')
+import Settings from '@overleaf/settings'
+import MailchimpProvider from './MailChimpProvider.mjs'
 
 const provider = MailchimpProvider.make(
   'newsletter',
   Settings.mailchimp ? Settings.mailchimp.list_id : null
 )
 
-module.exports = provider
+export default provider

+ 9 - 7
services/web/app/src/Features/Notifications/NotificationsBuilder.mjs

@@ -1,9 +1,11 @@
-const NotificationsHandler = require('./NotificationsHandler')
-const { callbackifyAll } = require('@overleaf/promise-utils')
-const { fetchJson } = require('@overleaf/fetch-utils')
-const settings = require('@overleaf/settings')
-const path = require('path')
-const { ObjectId } = require('mongodb-legacy')
+import NotificationsHandler from './NotificationsHandler.mjs'
+import { callbackifyAll } from '@overleaf/promise-utils'
+import { fetchJson } from '@overleaf/fetch-utils'
+import settings from '@overleaf/settings'
+import path from 'node:path'
+import mongodb from 'mongodb-legacy'
+
+const { ObjectId } = mongodb
 
 function dropboxDuplicateProjectNames(userId) {
   return {
@@ -279,4 +281,4 @@ NotificationsBuilder.promises = {
   tpdsFileLimit,
 }
 
-module.exports = NotificationsBuilder
+export default NotificationsBuilder

+ 6 - 6
services/web/app/src/Features/Notifications/NotificationsHandler.mjs

@@ -1,8 +1,8 @@
-const settings = require('@overleaf/settings')
-const request = require('request')
-const logger = require('@overleaf/logger')
-const _ = require('lodash')
-const { promisifyAll } = require('@overleaf/promise-utils')
+import settings from '@overleaf/settings'
+import request from 'request'
+import logger from '@overleaf/logger'
+import _ from 'lodash'
+import { promisifyAll } from '@overleaf/promise-utils'
 
 const notificationsApi = _.get(settings, ['apis', 'notifications', 'url'])
 const oneSecond = 1000
@@ -139,4 +139,4 @@ const NotificationsHandler = {
 }
 
 NotificationsHandler.promises = promisifyAll(NotificationsHandler)
-module.exports = NotificationsHandler
+export default NotificationsHandler

+ 6 - 6
services/web/app/src/Features/OnboardingDataCollection/OnboardingDataCollectionManager.mjs

@@ -1,8 +1,8 @@
-const {
-  OnboardingDataCollection,
-  OnboardingDataCollectionSchema,
-} = require('../../models/OnboardingDataCollection')
-const OError = require('@overleaf/o-error')
+import OnboardingDataCollectionModel from '../../models/OnboardingDataCollection.js'
+import OError from '@overleaf/o-error'
+
+const { OnboardingDataCollection, OnboardingDataCollectionSchema } =
+  OnboardingDataCollectionModel
 
 async function getOnboardingDataCollection(userId, projection = {}) {
   try {
@@ -69,7 +69,7 @@ function deleteOnboardingDataCollection(id) {
   return OnboardingDataCollection.deleteOne({ _id: id })
 }
 
-module.exports = {
+export default {
   getOnboardingDataCollection,
   upsertOnboardingDataCollection,
   deleteOnboardingDataCollection,

+ 6 - 4
services/web/app/src/Features/Project/FolderStructureBuilder.mjs

@@ -1,8 +1,10 @@
-const Path = require('path')
-const OError = require('@overleaf/o-error')
-const { ObjectId } = require('mongodb-legacy')
+import Path from 'node:path'
+import OError from '@overleaf/o-error'
+import mongodb from 'mongodb-legacy'
 
-module.exports = { buildFolderStructure }
+const { ObjectId } = mongodb
+
+export default { buildFolderStructure }
 
 function buildFolderStructure(docEntries, fileEntries) {
   const builder = new FolderStructureBuilder()

+ 3 - 3
services/web/app/src/Features/Project/ProjectEditorHandler.mjs

@@ -1,8 +1,8 @@
+import _ from 'lodash'
+import Path from 'node:path'
 let ProjectEditorHandler
-const _ = require('lodash')
-const Path = require('path')
 
-module.exports = ProjectEditorHandler = {
+export default ProjectEditorHandler = {
   trackChangesAvailable: false,
 
   buildProjectModelView(

+ 7 - 5
services/web/app/src/Features/Project/ProjectHelper.mjs

@@ -1,7 +1,9 @@
-// @ts-check
-const { ObjectId } = require('mongodb-legacy')
-const _ = require('lodash')
-const Settings = require('@overleaf/settings')
+import mongodb from 'mongodb-legacy'
+
+import _ from 'lodash'
+import Settings from '@overleaf/settings'
+
+const { ObjectId } = mongodb
 
 /**
  * @import { MongoProject } from "./types"
@@ -14,7 +16,7 @@ const ENGINE_TO_COMPILER_MAP = {
   lualatex: 'lualatex',
 }
 
-module.exports = {
+export default {
   compilerFromV1Engine,
   isArchived,
   isTrashed,

+ 9 - 7
services/web/app/src/Features/Project/ProjectOptionsHandler.mjs

@@ -1,11 +1,13 @@
-const { Project } = require('../../models/Project')
-const settings = require('@overleaf/settings')
-const { callbackify } = require('util')
-const { db, ObjectId } = require('../../infrastructure/mongodb')
-const Errors = require('../Errors/Errors')
-const { ReturnDocument } = require('mongodb-legacy')
+import { Project } from '../../models/Project.js'
+import settings from '@overleaf/settings'
+import { callbackify } from 'node:util'
+import { db, ObjectId } from '../../infrastructure/mongodb.js'
+import Errors from '../Errors/Errors.js'
+import mongodb from 'mongodb-legacy'
 const safeCompilers = ['xelatex', 'pdflatex', 'latex', 'lualatex']
 
+const { ReturnDocument } = mongodb
+
 const ProjectOptionsHandler = {
   async setCompiler(projectId, compiler) {
     if (!compiler) {
@@ -92,7 +94,7 @@ const ProjectOptionsHandler = {
   },
 }
 
-module.exports = {
+export default {
   setCompiler: callbackify(ProjectOptionsHandler.setCompiler),
   setImageName: callbackify(ProjectOptionsHandler.setImageName),
   setSpellCheckLanguage: callbackify(

+ 3 - 3
services/web/app/src/Features/Project/ProjectUpdateHandler.mjs

@@ -1,5 +1,5 @@
-const { Project } = require('../../models/Project')
-const { callbackify } = require('util')
+import { Project } from '../../models/Project.js'
+import { callbackify } from 'node:util'
 
 const ProjectUpdateHandler = {
   async markAsUpdated(projectId, lastUpdatedAt, lastUpdatedBy) {
@@ -38,7 +38,7 @@ const ProjectUpdateHandler = {
   },
 }
 
-module.exports = {
+export default {
   markAsUpdated: callbackify(ProjectUpdateHandler.markAsUpdated),
   markAsOpened: callbackify(ProjectUpdateHandler.markAsOpened),
   markAsInactive: callbackify(ProjectUpdateHandler.markAsInactive),

+ 1 - 1
services/web/app/src/Features/Project/SafePath.mjs

@@ -132,4 +132,4 @@ prototype\
   })
 }
 
-module.exports = load()
+export default load()

+ 7 - 7
services/web/app/src/Features/Publishers/PublishersGetter.mjs

@@ -1,9 +1,9 @@
-const Settings = require('@overleaf/settings')
-const logger = require('@overleaf/logger')
-const { fetchJson } = require('@overleaf/fetch-utils')
-const { callbackify } = require('@overleaf/promise-utils')
-const UserMembershipsHandler = require('../UserMembership/UserMembershipsHandler')
-const UserMembershipEntityConfigs = require('../UserMembership/UserMembershipEntityConfigs')
+import Settings from '@overleaf/settings'
+import logger from '@overleaf/logger'
+import { fetchJson } from '@overleaf/fetch-utils'
+import { callbackify } from '@overleaf/promise-utils'
+import UserMembershipsHandler from '../UserMembership/UserMembershipsHandler.mjs'
+import UserMembershipEntityConfigs from '../UserMembership/UserMembershipEntityConfigs.mjs'
 
 async function getManagedPublishers(userId) {
   return await UserMembershipsHandler.promises.getEntitiesByUser(
@@ -33,7 +33,7 @@ async function fetchV1Data(publisher) {
   }
 }
 
-module.exports = {
+export default {
   getManagedPublishers: callbackify(getManagedPublishers),
   promises: {
     getManagedPublishers,

+ 5 - 5
services/web/app/src/Features/Referal/ReferalFeatures.mjs

@@ -1,7 +1,7 @@
-const _ = require('lodash')
-const { callbackify } = require('util')
-const { User } = require('../../models/User')
-const Settings = require('@overleaf/settings')
+import _ from 'lodash'
+import { callbackify } from 'node:util'
+import { User } from '../../models/User.js'
+import Settings from '@overleaf/settings'
 
 const ReferalFeatures = {
   async getBonusFeatures(userId) {
@@ -42,7 +42,7 @@ const ReferalFeatures = {
   },
 }
 
-module.exports = {
+export default {
   getBonusFeatures: callbackify(ReferalFeatures.getBonusFeatures),
   promises: ReferalFeatures,
 }

+ 1 - 1
services/web/app/src/Features/SplitTests/LocalsHelper.mjs

@@ -12,7 +12,7 @@ function setSplitTestInfo(locals, splitTestName, info) {
   locals.splitTestInfo[splitTestName] = info
 }
 
-module.exports = {
+export default {
   setSplitTestVariant,
   setSplitTestInfo,
 }

+ 4 - 4
services/web/app/src/Features/SplitTests/SplitTestCache.mjs

@@ -1,6 +1,6 @@
-const Metrics = require('@overleaf/metrics')
-const SplitTestManager = require('./SplitTestManager')
-const { CacheLoader } = require('cache-flow')
+import Metrics from '@overleaf/metrics'
+import SplitTestManager from './SplitTestManager.mjs'
+import { CacheLoader } from 'cache-flow'
 
 class SplitTestCache extends CacheLoader {
   constructor() {
@@ -24,4 +24,4 @@ class SplitTestCache extends CacheLoader {
   }
 }
 
-module.exports = new SplitTestCache()
+export default new SplitTestCache()

+ 19 - 19
services/web/app/src/Features/SplitTests/SplitTestHandler.mjs

@@ -1,21 +1,21 @@
-const Metrics = require('@overleaf/metrics')
-const UserUpdater = require('../User/UserUpdater')
-const AnalyticsManager = require('../Analytics/AnalyticsManager')
-const LocalsHelper = require('./LocalsHelper')
-const crypto = require('crypto')
-const _ = require('lodash')
-const { callbackify } = require('util')
-const SplitTestCache = require('./SplitTestCache')
-const { SplitTest } = require('../../models/SplitTest')
-const UserAnalyticsIdCache = require('../Analytics/UserAnalyticsIdCache')
-const Features = require('../../infrastructure/Features')
-const SplitTestUtils = require('./SplitTestUtils')
-const Settings = require('@overleaf/settings')
-const SessionManager = require('../Authentication/SessionManager')
-const logger = require('@overleaf/logger')
-const SplitTestSessionHandler = require('./SplitTestSessionHandler')
-const SplitTestUserGetter = require('./SplitTestUserGetter')
-const SplitTestManager = require('./SplitTestManager')
+import Metrics from '@overleaf/metrics'
+import UserUpdater from '../User/UserUpdater.mjs'
+import AnalyticsManager from '../Analytics/AnalyticsManager.mjs'
+import LocalsHelper from './LocalsHelper.mjs'
+import crypto from 'node:crypto'
+import _ from 'lodash'
+import { callbackify } from 'node:util'
+import SplitTestCache from './SplitTestCache.mjs'
+import { SplitTest } from '../../models/SplitTest.js'
+import UserAnalyticsIdCache from '../Analytics/UserAnalyticsIdCache.mjs'
+import Features from '../../infrastructure/Features.js'
+import SplitTestUtils from './SplitTestUtils.mjs'
+import Settings from '@overleaf/settings'
+import SessionManager from '../Authentication/SessionManager.mjs'
+import logger from '@overleaf/logger'
+import SplitTestSessionHandler from './SplitTestSessionHandler.mjs'
+import SplitTestUserGetter from './SplitTestUserGetter.mjs'
+import SplitTestManager from './SplitTestManager.mjs'
 
 /**
  * @import { Assignment } from "./types"
@@ -799,7 +799,7 @@ function _isGradualRollout(featureFlag) {
   return !SplitTestUtils.getCurrentVersion(featureFlag).analyticsEnabled
 }
 
-module.exports = {
+export default {
   getPercentile,
   getAssignment: callbackify(getAssignment),
   getAssignmentForUser: callbackify(getAssignmentForUser),

+ 6 - 6
services/web/app/src/Features/SplitTests/SplitTestManager.mjs

@@ -1,8 +1,8 @@
-const { SplitTest } = require('../../models/SplitTest')
-const SplitTestUtils = require('./SplitTestUtils')
-const OError = require('@overleaf/o-error')
-const _ = require('lodash')
-const { CacheFlow } = require('cache-flow')
+import { SplitTest } from '../../models/SplitTest.js'
+import SplitTestUtils from './SplitTestUtils.mjs'
+import OError from '@overleaf/o-error'
+import _ from 'lodash'
+import { CacheFlow } from 'cache-flow'
 
 const ALPHA_PHASE = 'alpha'
 const BETA_PHASE = 'beta'
@@ -531,7 +531,7 @@ function _mergeFlags(incomingTests, baseTests) {
   return mergedSet
 }
 
-module.exports = {
+export default {
   getSplitTest,
   getSplitTests,
   getRuntimeTests,

+ 12 - 10
services/web/app/src/Features/SplitTests/SplitTestSessionHandler.mjs

@@ -1,12 +1,14 @@
-const { callbackify } = require('util')
-const _ = require('lodash')
-const { ObjectId } = require('mongodb-legacy')
-const logger = require('@overleaf/logger')
-const Metrics = require('@overleaf/metrics')
-const SessionManager = require('../Authentication/SessionManager')
-const SplitTestCache = require('./SplitTestCache')
-const SplitTestUtils = require('./SplitTestUtils')
-const SplitTestUserGetter = require('./SplitTestUserGetter')
+import { callbackify } from 'node:util'
+import _ from 'lodash'
+import mongodb from 'mongodb-legacy'
+import logger from '@overleaf/logger'
+import Metrics from '@overleaf/metrics'
+import SessionManager from '../Authentication/SessionManager.mjs'
+import SplitTestCache from './SplitTestCache.mjs'
+import SplitTestUtils from './SplitTestUtils.mjs'
+import SplitTestUserGetter from './SplitTestUserGetter.mjs'
+
+const { ObjectId } = mongodb
 
 const CACHE_TOMBSTONE_SPLIT_TEST_NOT_ACTIVE_FOR_USER = null
 const TOKEN_SEP = ';'
@@ -242,7 +244,7 @@ function _convertIdToBase64(id) {
   return new ObjectId(id).toString('base64')
 }
 
-module.exports = {
+export default {
   getAssignments: callbackify(getAssignments),
   appendAssignment: callbackify(appendAssignment),
   getCachedVariant,

+ 4 - 4
services/web/app/src/Features/SplitTests/SplitTestUserGetter.mjs

@@ -1,6 +1,6 @@
-const { callbackify } = require('util')
-const Metrics = require('@overleaf/metrics')
-const UserGetter = require('../User/UserGetter')
+import { callbackify } from 'node:util'
+import Metrics from '@overleaf/metrics'
+import UserGetter from '../User/UserGetter.mjs'
 
 async function getUser(id, splitTestName) {
   const projection = {
@@ -22,7 +22,7 @@ async function getUser(id, splitTestName) {
   return user
 }
 
-module.exports = {
+export default {
   getUser: callbackify(getUser),
   promises: {
     getUser,

+ 2 - 2
services/web/app/src/Features/SplitTests/SplitTestUtils.mjs

@@ -1,4 +1,4 @@
-const _ = require('lodash')
+import _ from 'lodash'
 
 function getCurrentVersion(splitTest) {
   if (splitTest?.versions?.length > 0) {
@@ -14,7 +14,7 @@ function getVersion(splitTest, versionNumber) {
   })
 }
 
-module.exports = {
+export default {
   getCurrentVersion,
   getVersion,
 }

+ 3 - 3
services/web/app/src/Features/Subscription/FeaturesHelper.mjs

@@ -1,5 +1,5 @@
-const _ = require('lodash')
-const Settings = require('@overleaf/settings')
+import _ from 'lodash'
+import Settings from '@overleaf/settings'
 
 /**
  * merges an array of feature sets to produce a final feature set
@@ -113,7 +113,7 @@ function getMatchedFeatureSet(features) {
   return 'mixed'
 }
 
-module.exports = {
+export default {
   mergeFeatures,
   computeFeatureSet,
   isFeatureSetBetter,

+ 19 - 19
services/web/app/src/Features/Subscription/FeaturesUpdater.mjs

@@ -1,21 +1,21 @@
-const _ = require('lodash')
-const { callbackify } = require('util')
-const { callbackifyMultiResult } = require('@overleaf/promise-utils')
-const PlansLocator = require('./PlansLocator')
-const SubscriptionLocator = require('./SubscriptionLocator')
-const SubscriptionHelper = require('./SubscriptionHelper')
-const UserFeaturesUpdater = require('./UserFeaturesUpdater')
-const FeaturesHelper = require('./FeaturesHelper')
-const Settings = require('@overleaf/settings')
-const logger = require('@overleaf/logger')
-const ReferalFeatures = require('../Referal/ReferalFeatures')
-const V1SubscriptionManager = require('./V1SubscriptionManager')
-const InstitutionsFeatures = require('../Institutions/InstitutionsFeatures')
-const UserGetter = require('../User/UserGetter')
-const AnalyticsManager = require('../Analytics/AnalyticsManager')
-const Queues = require('../../infrastructure/Queues')
-const Modules = require('../../infrastructure/Modules')
-const { AI_ADD_ON_CODE } = require('./AiHelper')
+import _ from 'lodash'
+import { callbackify } from 'node:util'
+import { callbackifyMultiResult } from '@overleaf/promise-utils'
+import PlansLocator from './PlansLocator.mjs'
+import SubscriptionLocator from './SubscriptionLocator.mjs'
+import SubscriptionHelper from './SubscriptionHelper.js'
+import UserFeaturesUpdater from './UserFeaturesUpdater.mjs'
+import FeaturesHelper from './FeaturesHelper.mjs'
+import Settings from '@overleaf/settings'
+import logger from '@overleaf/logger'
+import ReferalFeatures from '../Referal/ReferalFeatures.mjs'
+import V1SubscriptionManager from './V1SubscriptionManager.mjs'
+import InstitutionsFeatures from '../Institutions/InstitutionsFeatures.mjs'
+import UserGetter from '../User/UserGetter.mjs'
+import AnalyticsManager from '../Analytics/AnalyticsManager.mjs'
+import Queues from '../../infrastructure/Queues.js'
+import Modules from '../../infrastructure/Modules.js'
+import { AI_ADD_ON_CODE } from './AiHelper.js'
 
 /**
  * Enqueue a job for refreshing features for the given user
@@ -204,7 +204,7 @@ async function doSyncFromV1(v1UserId) {
   return refreshFeatures(user._id, 'sync-v1')
 }
 
-module.exports = {
+export default {
   featuresEpochIsCurrent,
   computeFeatures: callbackify(computeFeatures),
   refreshFeatures: callbackifyMultiResult(refreshFeatures, [

+ 9 - 8
services/web/app/src/Features/Subscription/PaymentProviderEntities.mjs

@@ -16,14 +16,15 @@
  * @property {boolean} [isAiAssist]
  */
 
-const OError = require('@overleaf/o-error')
-const { DuplicateAddOnError, AddOnNotPresentError } = require('./Errors')
-const PlansLocator = require('./PlansLocator')
-const SubscriptionHelper = require('./SubscriptionHelper')
-const { AI_ADD_ON_CODE, isStandaloneAiAddOnPlanCode } = require('./AiHelper')
+import OError from '@overleaf/o-error'
+
+import { DuplicateAddOnError, AddOnNotPresentError } from './Errors.js'
+import PlansLocator from './PlansLocator.mjs'
+import SubscriptionHelper from './SubscriptionHelper.js'
+import { AI_ADD_ON_CODE, isStandaloneAiAddOnPlanCode } from './AiHelper.js'
 const MEMBERS_LIMIT_ADD_ON_CODE = 'additional-license'
 
-class PaymentProviderSubscription {
+export class PaymentProviderSubscription {
   /**
    * @param {object} props
    * @param {string} props.id
@@ -644,7 +645,7 @@ class PaymentProviderCoupon {
 /**
  * An account in the payment provider
  */
-class PaymentProviderAccount {
+export class PaymentProviderAccount {
   /**
    * @param {object} props
    * @param {string} props.code
@@ -661,7 +662,7 @@ class PaymentProviderAccount {
   }
 }
 
-module.exports = {
+export default {
   MEMBERS_LIMIT_ADD_ON_CODE,
   PaymentProviderSubscription,
   PaymentProviderSubscriptionAddOn,

+ 4 - 3
services/web/app/src/Features/Subscription/PlansLocator.mjs

@@ -1,7 +1,8 @@
 // @ts-check
 
-const Settings = require('@overleaf/settings')
-const logger = require('@overleaf/logger')
+import Settings from '@overleaf/settings'
+
+import logger from '@overleaf/logger'
 
 /**
  * @typedef {import('../../../../types/subscription/plan').RecurlyPlanCode} RecurlyPlanCode
@@ -173,7 +174,7 @@ function convertLegacyGroupPlanCodeToConsolidatedGroupPlanCodeIfNeeded(
   return { planCode: newPlanCode, quantity: Number(size) }
 }
 
-module.exports = {
+export default {
   ensurePlansAreSetupCorrectly,
   findLocalPlanInSettings,
   buildStripeLookupKey,

+ 17 - 14
services/web/app/src/Features/Subscription/RecurlyClient.mjs

@@ -1,11 +1,20 @@
 // @ts-check
 
-const recurly = require('recurly')
-const Settings = require('@overleaf/settings')
-const logger = require('@overleaf/logger')
-const OError = require('@overleaf/o-error')
-const { callbackify } = require('util')
-const UserGetter = require('../User/UserGetter')
+import recurly from 'recurly'
+
+import Settings from '@overleaf/settings'
+import logger from '@overleaf/logger'
+import OError from '@overleaf/o-error'
+import { callbackify } from 'node:util'
+import UserGetter from '../User/UserGetter.mjs'
+import PaymentProviderEntities from './PaymentProviderEntities.mjs'
+import {
+  MissingBillingInfoError,
+  SubtotalLimitExceededError,
+} from './Errors.js'
+import RecurlyMetrics from './RecurlyMetrics.mjs'
+import { isStandaloneAiAddOnPlanCode, AI_ADD_ON_CODE } from './AiHelper.js'
+
 const {
   PaymentProviderSubscription,
   PaymentProviderSubscriptionAddOn,
@@ -17,13 +26,7 @@ const {
   PaymentProviderCoupon,
   PaymentProviderAccount,
   PaymentProviderImmediateCharge,
-} = require('./PaymentProviderEntities')
-const {
-  MissingBillingInfoError,
-  SubtotalLimitExceededError,
-} = require('./Errors')
-const RecurlyMetrics = require('./RecurlyMetrics')
-const { isStandaloneAiAddOnPlanCode, AI_ADD_ON_CODE } = require('./AiHelper')
+} = PaymentProviderEntities
 
 /**
  * @import { PaymentProviderSubscriptionChangeRequest } from './PaymentProviderEntities'
@@ -798,7 +801,7 @@ async function terminateSubscriptionByUuid(subscriptionUuid) {
   return subscription
 }
 
-module.exports = {
+export default {
   errors: recurly.errors,
 
   getAccountForUserId: callbackify(getAccountForUserId),

+ 2 - 2
services/web/app/src/Features/Subscription/RecurlyMetrics.mjs

@@ -1,4 +1,4 @@
-const Metrics = require('@overleaf/metrics')
+import Metrics from '@overleaf/metrics'
 
 /**
  * @param {number} status
@@ -32,7 +32,7 @@ function recordMetricsFromResponse(response) {
   recordMetrics(response.status, rateLimit, rateLimitRemaining, rateLimitReset)
 }
 
-module.exports = {
+export default {
   recordMetrics,
   recordMetricsFromResponse,
 }

+ 11 - 11
services/web/app/src/Features/Subscription/RecurlyWrapper.mjs

@@ -1,15 +1,15 @@
-const OError = require('@overleaf/o-error')
-const {
+import OError from '@overleaf/o-error'
+import {
   fetchStringWithResponse,
   RequestFailedError,
-} = require('@overleaf/fetch-utils')
-const Settings = require('@overleaf/settings')
-const xml2js = require('xml2js')
-const logger = require('@overleaf/logger')
-const Errors = require('../Errors/Errors')
-const SubscriptionErrors = require('./Errors')
-const { callbackify } = require('@overleaf/promise-utils')
-const RecurlyMetrics = require('./RecurlyMetrics')
+} from '@overleaf/fetch-utils'
+import Settings from '@overleaf/settings'
+import xml2js from 'xml2js'
+import logger from '@overleaf/logger'
+import Errors from '../Errors/Errors.js'
+import SubscriptionErrors from './Errors.js'
+import { callbackify } from '@overleaf/promise-utils'
+import RecurlyMetrics from './RecurlyMetrics.mjs'
 
 /**
  * Updates the email address of a Recurly account
@@ -911,7 +911,7 @@ RecurlyWrapper.promises = {
   updateAccountEmailAddress,
 }
 
-module.exports = RecurlyWrapper
+export default RecurlyWrapper
 
 function getCustomFieldsFromSubscriptionDetails(subscriptionDetails) {
   if (!subscriptionDetails.ITMCampaign) {

+ 9 - 8
services/web/app/src/Features/Subscription/SubscriptionLocator.mjs

@@ -2,13 +2,14 @@
  * @import { AddOn } from '../../../../types/subscription/plan'
  */
 
-const { callbackifyAll } = require('@overleaf/promise-utils')
-const { Subscription } = require('../../models/Subscription')
-const SubscriptionHelper = require('./SubscriptionHelper')
-const { DeletedSubscription } = require('../../models/DeletedSubscription')
-const logger = require('@overleaf/logger')
-const { AI_ADD_ON_CODE, isStandaloneAiAddOnPlanCode } = require('./AiHelper')
-require('./GroupPlansData') // make sure dynamic group plans are loaded
+import { callbackifyAll } from '@overleaf/promise-utils'
+
+import { Subscription } from '../../models/Subscription.js'
+import SubscriptionHelper from './SubscriptionHelper.js'
+import { DeletedSubscription } from '../../models/DeletedSubscription.js'
+import logger from '@overleaf/logger'
+import { AI_ADD_ON_CODE, isStandaloneAiAddOnPlanCode } from './AiHelper.js'
+import './GroupPlansData.js' // make sure dynamic group plans are loaded
 
 const SubscriptionLocator = {
   async getUsersSubscription(userOrId) {
@@ -215,7 +216,7 @@ const SubscriptionLocator = {
   },
 }
 
-module.exports = {
+export default {
   ...callbackifyAll(SubscriptionLocator),
   promises: SubscriptionLocator,
 }

+ 18 - 18
services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs

@@ -1,20 +1,20 @@
-const { db, ObjectId } = require('../../infrastructure/mongodb')
-const { callbackify } = require('@overleaf/promise-utils')
-const { Subscription } = require('../../models/Subscription')
-const SubscriptionLocator = require('./SubscriptionLocator')
-const PlansLocator = require('./PlansLocator')
-const FeaturesUpdater = require('./FeaturesUpdater')
-const FeaturesHelper = require('./FeaturesHelper')
-const AnalyticsManager = require('../Analytics/AnalyticsManager')
-const { DeletedSubscription } = require('../../models/DeletedSubscription')
-const logger = require('@overleaf/logger')
-const Features = require('../../infrastructure/Features')
-const UserAuditLogHandler = require('../User/UserAuditLogHandler')
-const UserUpdater = require('../User/UserUpdater')
-const AccountMappingHelper = require('../Analytics/AccountMappingHelper')
-const { SSOConfig } = require('../../models/SSOConfig')
-const mongoose = require('../../infrastructure/Mongoose')
-const Modules = require('../../infrastructure/Modules')
+import { db, ObjectId } from '../../infrastructure/mongodb.js'
+import { callbackify } from '@overleaf/promise-utils'
+import { Subscription } from '../../models/Subscription.js'
+import SubscriptionLocator from './SubscriptionLocator.mjs'
+import PlansLocator from './PlansLocator.mjs'
+import FeaturesUpdater from './FeaturesUpdater.mjs'
+import FeaturesHelper from './FeaturesHelper.mjs'
+import AnalyticsManager from '../Analytics/AnalyticsManager.mjs'
+import { DeletedSubscription } from '../../models/DeletedSubscription.js'
+import logger from '@overleaf/logger'
+import Features from '../../infrastructure/Features.js'
+import UserAuditLogHandler from '../User/UserAuditLogHandler.mjs'
+import UserUpdater from '../User/UserUpdater.mjs'
+import AccountMappingHelper from '../Analytics/AccountMappingHelper.mjs'
+import { SSOConfig } from '../../models/SSOConfig.js'
+import mongoose from '../../infrastructure/Mongoose.js'
+import Modules from '../../infrastructure/Modules.js'
 
 /**
  * @typedef {import('../../../../types/subscription/dashboard/subscription').Subscription} Subscription
@@ -553,7 +553,7 @@ async function voidRestorePoint(subscriptionId) {
   await setRestorePoint(subscriptionId, null, null, false)
 }
 
-module.exports = {
+export default {
   updateAdmin: callbackify(updateAdmin),
   syncSubscription: callbackify(syncSubscription),
   createNewSubscription: callbackify(createNewSubscription),

+ 4 - 4
services/web/app/src/Features/Subscription/UserFeaturesUpdater.mjs

@@ -1,6 +1,6 @@
-const { User } = require('../../models/User')
-const { callbackify } = require('util')
-const Settings = require('@overleaf/settings')
+import { User } from '../../models/User.js'
+import { callbackify } from 'node:util'
+import Settings from '@overleaf/settings'
 
 function _featuresChanged(newFeatures, featuresBefore) {
   for (const feature in newFeatures) {
@@ -49,7 +49,7 @@ async function createFeaturesOverride(userId, featuresOverride) {
   ).exec()
 }
 
-module.exports = {
+export default {
   updateFeatures: callbackify(updateFeatures),
   overrideFeatures: callbackify(overrideFeatures),
   createFeaturesOverride: callbackify(createFeaturesOverride),

+ 9 - 8
services/web/app/src/Features/Subscription/V1SubscriptionManager.mjs

@@ -1,11 +1,10 @@
-let V1SubscriptionManager
-const UserGetter = require('../User/UserGetter')
-const request = require('requestretry')
-const settings = require('@overleaf/settings')
-const { V1ConnectionError, NotFoundError } = require('../Errors/Errors')
-const { promisifyAll } = require('@overleaf/promise-utils')
+import UserGetter from '../User/UserGetter.mjs'
+import request from 'requestretry'
+import settings from '@overleaf/settings'
+import { V1ConnectionError, NotFoundError } from '../Errors/Errors.js'
+import { promisifyAll } from '@overleaf/promise-utils'
 
-module.exports = V1SubscriptionManager = {
+const V1SubscriptionManager = {
   cancelV1Subscription(userId, callback) {
     V1SubscriptionManager._v1Request(
       userId,
@@ -118,6 +117,8 @@ module.exports = V1SubscriptionManager = {
   },
 }
 
-module.exports.promises = promisifyAll(module.exports, {
+V1SubscriptionManager.promises = promisifyAll(V1SubscriptionManager, {
   without: ['getGrandfatheredFeaturesForV1User'],
 })
+
+export default V1SubscriptionManager

+ 3 - 3
services/web/app/src/Features/Tags/TagsHandler.mjs

@@ -1,5 +1,5 @@
-const { Tag } = require('../../models/Tag')
-const { callbackify } = require('@overleaf/promise-utils')
+import { Tag } from '../../models/Tag.js'
+import { callbackify } from '@overleaf/promise-utils'
 
 const MAX_TAG_LENGTH = 50
 
@@ -133,7 +133,7 @@ async function addProjectToTags(userId, tagIds, projectId) {
   await Tag.updateMany(searchOps, insertOperation)
 }
 
-module.exports = {
+export default {
   getAllTags: callbackify(getAllTags),
   countTagsForProject: callbackify(countTagsForProject),
   getTagsForProject: callbackify(getTagsForProject),

+ 16 - 13
services/web/app/src/Features/TokenAccess/TokenAccessHandler.mjs

@@ -1,15 +1,18 @@
-const { Project } = require('../../models/Project')
-const PublicAccessLevels = require('../Authorization/PublicAccessLevels')
-const PrivilegeLevels = require('../Authorization/PrivilegeLevels')
-const { ObjectId } = require('mongodb-legacy')
-const Metrics = require('@overleaf/metrics')
-const Settings = require('@overleaf/settings')
-const logger = require('@overleaf/logger')
-const V1Api = require('../V1/V1Api')
-const crypto = require('crypto')
-const { callbackifyAll } = require('@overleaf/promise-utils')
-const Analytics = require('../Analytics/AnalyticsManager')
-const Features = require('../../infrastructure/Features')
+import { Project } from '../../models/Project.js'
+import PublicAccessLevels from '../Authorization/PublicAccessLevels.mjs'
+import PrivilegeLevels from '../Authorization/PrivilegeLevels.js'
+import mongodb from 'mongodb-legacy'
+import Metrics from '@overleaf/metrics'
+import Settings from '@overleaf/settings'
+import logger from '@overleaf/logger'
+import V1Api from '../V1/V1Api.js'
+import crypto from 'node:crypto'
+import { callbackifyAll } from '@overleaf/promise-utils'
+import Analytics from '../Analytics/AnalyticsManager.mjs'
+import Features from '../../infrastructure/Features.js'
+
+const { ObjectId } = mongodb
+
 const READ_AND_WRITE_TOKEN_PATTERN = '([0-9]+[a-z]{6,12})'
 const READ_ONLY_TOKEN_PATTERN = '([a-z]{12})'
 
@@ -337,7 +340,7 @@ const TokenAccessHandler = {
   },
 }
 
-module.exports = {
+export default {
   ...TokenAccessHandler,
   ...callbackifyAll(TokenAccessHandler, {
     multiResult: {

+ 13 - 12
services/web/app/src/Features/Uploads/ArchiveManager.mjs

@@ -12,20 +12,21 @@
  * DS207: Consider shorter variations of null checks
  * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  */
-const logger = require('@overleaf/logger')
-const OError = require('@overleaf/o-error')
-const metrics = require('@overleaf/metrics')
-const fs = require('fs')
-const Path = require('path')
-const yauzl = require('yauzl')
-const Settings = require('@overleaf/settings')
-const {
+import logger from '@overleaf/logger'
+
+import OError from '@overleaf/o-error'
+import metrics from '@overleaf/metrics'
+import fs from 'node:fs'
+import Path from 'node:path'
+import yauzl from 'yauzl'
+import Settings from '@overleaf/settings'
+import {
   InvalidZipFileError,
   EmptyZipFileError,
   ZipContentsTooLargeError,
-} = require('./ArchiveErrors')
-const _ = require('lodash')
-const { promisifyAll } = require('@overleaf/promise-utils')
+} from './ArchiveErrors.js'
+import _ from 'lodash'
+import { promisifyAll } from '@overleaf/promise-utils'
 
 const ONE_MEG = 1024 * 1024
 
@@ -267,4 +268,4 @@ const ArchiveManager = {
 }
 
 ArchiveManager.promises = promisifyAll(ArchiveManager)
-module.exports = ArchiveManager
+export default ArchiveManager

+ 8 - 7
services/web/app/src/Features/Uploads/FileTypeManager.mjs

@@ -1,11 +1,12 @@
 // @ts-check
 
-const fs = require('fs/promises')
-const Path = require('path')
-const { callbackify } = require('util')
-const isUtf8 = require('utf-8-validate')
-const Settings = require('@overleaf/settings')
-const Minimatch = require('minimatch').Minimatch
+import fs from 'node:fs/promises'
+
+import Path from 'node:path'
+import { callbackify } from 'node:util'
+import isUtf8 from 'utf-8-validate'
+import Settings from '@overleaf/settings'
+import { Minimatch } from 'minimatch'
 
 const FILE_IGNORE_MATCHER = new Minimatch(Settings.fileIgnorePattern, {
   // make the whole path matching case-insensitive (previously we were only
@@ -110,7 +111,7 @@ function _detectEncoding(bytes) {
   return 'latin1'
 }
 
-module.exports = {
+export default {
   shouldIgnore,
   isEditable,
   getType: callbackify(getType),

+ 11 - 11
services/web/app/src/Features/User/ThirdPartyIdentityManager.mjs

@@ -1,13 +1,13 @@
-const UserAuditLogHandler = require('../../../../app/src/Features/User/UserAuditLogHandler')
-const EmailHandler = require('../../../../app/src/Features/Email/EmailHandler')
-const EmailOptionsHelper = require('../../../../app/src/Features/Email/EmailOptionsHelper')
-const Errors = require('../Errors/Errors')
-const _ = require('lodash')
-const logger = require('@overleaf/logger')
-const settings = require('@overleaf/settings')
-const { User } = require('../../../../app/src/models/User')
-const { callbackify } = require('@overleaf/promise-utils')
-const OError = require('@overleaf/o-error')
+import UserAuditLogHandler from '../../../../app/src/Features/User/UserAuditLogHandler.mjs'
+import EmailHandler from '../../../../app/src/Features/Email/EmailHandler.mjs'
+import EmailOptionsHelper from '../../../../app/src/Features/Email/EmailOptionsHelper.mjs'
+import Errors from '../Errors/Errors.js'
+import _ from 'lodash'
+import logger from '@overleaf/logger'
+import settings from '@overleaf/settings'
+import { User } from '../../../../app/src/models/User.js'
+import { callbackify } from '@overleaf/promise-utils'
+import OError from '@overleaf/o-error'
 
 const oauthProviders = settings.oauthProviders || {}
 
@@ -214,4 +214,4 @@ ThirdPartyIdentityManager.promises = {
   unlink,
 }
 
-module.exports = ThirdPartyIdentityManager
+export default ThirdPartyIdentityManager

+ 6 - 6
services/web/app/src/Features/User/UserAuditLogHandler.mjs

@@ -1,8 +1,8 @@
-const OError = require('@overleaf/o-error')
-const logger = require('@overleaf/logger')
-const { UserAuditLogEntry } = require('../../models/UserAuditLogEntry')
-const { callbackify } = require('util')
-const SubscriptionLocator = require('../Subscription/SubscriptionLocator')
+import OError from '@overleaf/o-error'
+import logger from '@overleaf/logger'
+import { UserAuditLogEntry } from '../../models/UserAuditLogEntry.js'
+import { callbackify } from 'node:util'
+import SubscriptionLocator from '../Subscription/SubscriptionLocator.mjs'
 
 function _canHaveNoIpAddressId(operation, info) {
   if (operation === 'join-group-subscription') return true
@@ -98,4 +98,4 @@ const UserAuditLogHandler = {
   },
 }
 
-module.exports = UserAuditLogHandler
+export default UserAuditLogHandler

+ 16 - 16
services/web/app/src/Features/User/UserGetter.mjs

@@ -1,18 +1,18 @@
-const { callbackify } = require('util')
-const { db } = require('../../infrastructure/mongodb')
-const moment = require('moment')
-const settings = require('@overleaf/settings')
-const {
-  promises: InstitutionsAPIPromises,
-} = require('../Institutions/InstitutionsAPI')
-const InstitutionsHelper = require('../Institutions/InstitutionsHelper')
-const Errors = require('../Errors/Errors')
-const Features = require('../../infrastructure/Features')
-const { User } = require('../../models/User')
-const { normalizeQuery, normalizeMultiQuery } = require('../Helpers/Mongo')
-const Modules = require('../../infrastructure/Modules')
-const FeaturesHelper = require('../Subscription/FeaturesHelper')
-const AsyncLocalStorage = require('../../infrastructure/AsyncLocalStorage')
+import { callbackify } from 'node:util'
+import { db } from '../../infrastructure/mongodb.js'
+import moment from 'moment'
+import settings from '@overleaf/settings'
+import InstitutionsAPI from '../Institutions/InstitutionsAPI.mjs'
+import InstitutionsHelper from '../Institutions/InstitutionsHelper.mjs'
+import Errors from '../Errors/Errors.js'
+import Features from '../../infrastructure/Features.js'
+import { User } from '../../models/User.js'
+import { normalizeQuery, normalizeMultiQuery } from '../Helpers/Mongo.js'
+import Modules from '../../infrastructure/Modules.js'
+import FeaturesHelper from '../Subscription/FeaturesHelper.mjs'
+import AsyncLocalStorage from '../../infrastructure/AsyncLocalStorage.js'
+
+const InstitutionsAPIPromises = InstitutionsAPI.promises
 
 function _lastDayToReconfirm(emailData, institutionData) {
   const globalReconfirmPeriod = settings.reconfirmNotificationDays
@@ -369,4 +369,4 @@ UserGetter.promises = {
   getWritefullData,
 }
 
-module.exports = UserGetter
+export default UserGetter

+ 7 - 7
services/web/app/src/Features/User/UserSessionsManager.mjs

@@ -1,8 +1,8 @@
-const Settings = require('@overleaf/settings')
-const logger = require('@overleaf/logger')
-const _ = require('lodash')
-const { callbackifyAll } = require('@overleaf/promise-utils')
-const UserSessionsRedis = require('./UserSessionsRedis')
+import Settings from '@overleaf/settings'
+import logger from '@overleaf/logger'
+import _ from 'lodash'
+import { callbackifyAll } from 'node:util'
+import UserSessionsRedis from './UserSessionsRedis.mjs'
 const rclient = UserSessionsRedis.client()
 
 const UserSessionsManager = {
@@ -161,7 +161,7 @@ const UserSessionsManager = {
   },
 }
 
-module.exports = {
+export default {
   ...callbackifyAll(UserSessionsManager),
-  promises: UserSessionsManager,
+  promises: UserSessionsManager
 }

+ 2 - 2
services/web/app/src/Features/User/UserSessionsRedis.mjs

@@ -1,4 +1,4 @@
-const RedisWrapper = require('../../infrastructure/RedisWrapper')
+import RedisWrapper from '../../infrastructure/RedisWrapper.js'
 const rclient = RedisWrapper.client('websessions')
 
 const UserSessionsRedis = {
@@ -10,4 +10,4 @@ const UserSessionsRedis = {
     return `UserSessions:{${user._id}}`
   },
 }
-module.exports = UserSessionsRedis
+export default UserSessionsRedis

+ 24 - 24
services/web/app/src/Features/User/UserUpdater.mjs

@@ -1,26 +1,26 @@
-const logger = require('@overleaf/logger')
-const OError = require('@overleaf/o-error')
-const { db } = require('../../infrastructure/mongodb')
-const { normalizeQuery } = require('../Helpers/Mongo')
-const { callbackify } = require('util')
-const UserGetter = require('./UserGetter')
-const InstitutionsAPI = require('../Institutions/InstitutionsAPI')
-const Features = require('../../infrastructure/Features')
-const FeaturesUpdater = require('../Subscription/FeaturesUpdater')
-const EmailHandler = require('../Email/EmailHandler')
-const EmailHelper = require('../Helpers/EmailHelper')
-const Errors = require('../Errors/Errors')
-const NewsletterManager = require('../Newsletter/NewsletterManager')
-const UserAuditLogHandler = require('./UserAuditLogHandler')
-const AnalyticsManager = require('../Analytics/AnalyticsManager')
-const EmailChangeHelper = require('../Analytics/EmailChangeHelper')
-const SubscriptionLocator = require('../Subscription/SubscriptionLocator')
-const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
-const _ = require('lodash')
-const Modules = require('../../infrastructure/Modules')
-const UserSessionsManager = require('./UserSessionsManager')
-const ThirdPartyIdentityManager = require('./ThirdPartyIdentityManager')
-const AsyncLocalStorage = require('../../infrastructure/AsyncLocalStorage')
+import logger from '@overleaf/logger'
+import OError from '@overleaf/o-error'
+import { db } from '../../infrastructure/mongodb.js'
+import { normalizeQuery } from '../Helpers/Mongo.js'
+import { callbackify } from 'node:util'
+import UserGetter from './UserGetter.mjs'
+import InstitutionsAPI from '../Institutions/InstitutionsAPI.mjs'
+import Features from '../../infrastructure/Features.js'
+import FeaturesUpdater from '../Subscription/FeaturesUpdater.mjs'
+import EmailHandler from '../Email/EmailHandler.mjs'
+import EmailHelper from '../Helpers/EmailHelper.js'
+import Errors from '../Errors/Errors.js'
+import NewsletterManager from '../Newsletter/NewsletterManager.mjs'
+import UserAuditLogHandler from './UserAuditLogHandler.mjs'
+import AnalyticsManager from '../Analytics/AnalyticsManager.mjs'
+import EmailChangeHelper from '../Analytics/EmailChangeHelper.mjs'
+import SubscriptionLocator from '../Subscription/SubscriptionLocator.mjs'
+import NotificationsBuilder from '../Notifications/NotificationsBuilder.mjs'
+import _ from 'lodash'
+import Modules from '../../infrastructure/Modules.js'
+import UserSessionsManager from './UserSessionsManager.mjs'
+import ThirdPartyIdentityManager from './ThirdPartyIdentityManager.mjs'
+import AsyncLocalStorage from '../../infrastructure/AsyncLocalStorage.js'
 
 async function _sendSecurityAlertPrimaryEmailChanged(
   userId,
@@ -683,7 +683,7 @@ function _securityAlertPrimaryEmailChangedExtraRecipients(
   return Array.from(recipients)
 }
 
-module.exports = {
+export default {
   addAffiliationForNewUser: callbackify(addAffiliationForNewUser),
   addEmailAddress: callbackify(addEmailAddress),
   changeEmailAddress: callbackify(changeEmailAddress),

+ 1 - 1
services/web/app/src/Features/UserMembership/UserMembershipEntityConfigs.mjs

@@ -1,4 +1,4 @@
-module.exports = {
+export default {
   group: {
     modelName: 'Subscription',
     readOnly: true,

+ 12 - 7
services/web/app/src/Features/UserMembership/UserMembershipsHandler.mjs

@@ -9,14 +9,19 @@
  * DS207: Consider shorter variations of null checks
  * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  */
-const async = require('async')
-const { promisifyAll } = require('@overleaf/promise-utils')
+import async from 'async'
+
+import { promisifyAll } from '@overleaf/promise-utils'
+import UserMembershipEntityConfigs from './UserMembershipEntityConfigs.mjs'
+import InstitutionModel from '../../models/Institution.js'
+import SubscriptionModel from '../../models/Subscription.js'
+import PublisherModel from '../../models/Publisher.js'
+
 const EntityModels = {
-  Institution: require('../../models/Institution').Institution,
-  Subscription: require('../../models/Subscription').Subscription,
-  Publisher: require('../../models/Publisher').Publisher,
+  Institution: InstitutionModel.Institution,
+  Subscription: SubscriptionModel.Subscription,
+  Publisher: PublisherModel.Publisher,
 }
-const UserMembershipEntityConfigs = require('./UserMembershipEntityConfigs')
 
 const UserMembershipsHandler = {
   removeUserFromAllEntities(userId, callback) {
@@ -80,4 +85,4 @@ const UserMembershipsHandler = {
 }
 
 UserMembershipsHandler.promises = promisifyAll(UserMembershipsHandler)
-module.exports = UserMembershipsHandler
+export default UserMembershipsHandler