From c4edd2fffaf07c11d83a47e0aa5a7f544b1ae101 Mon Sep 17 00:00:00 2001 From: Miguel Serrano Date: Mon, 21 Oct 2024 11:56:43 +0200 Subject: [PATCH] Merge pull request #21154 from overleaf/msm-esm-ce-scrits [web] Migrate `modules/server-ce-scripts` to ESM GitOrigin-RevId: 8856f83b12d5d092e51e5765763737259c4b3985 --- ...back_fill_gitBridge_feature_server_pro.mjs | 2 +- .../server-ce-scripts/{index.js => index.mjs} | 2 +- ...-timeout.js => change-compile-timeout.mjs} | 6 +- .../{check-mongodb.js => check-mongodb.mjs} | 9 ++- .../{check-redis.js => check-redis.mjs} | 2 +- ...ive-images.js => check-texlive-images.mjs} | 2 +- .../{create-user.js => create-user.mjs} | 6 +- .../{delete-user.js => delete-user.mjs} | 6 +- ...user-emails.js => migrate-user-emails.mjs} | 18 ++--- .../scripts/{rename-tag.js => rename-tag.mjs} | 4 +- ...-features.js => upgrade-user-features.mjs} | 15 ++-- ...riptsTests.js => ServerCEScriptsTests.mjs} | 79 +++++++++++-------- 12 files changed, 83 insertions(+), 68 deletions(-) rename services/web/modules/server-ce-scripts/{index.js => index.mjs} (75%) rename services/web/modules/server-ce-scripts/scripts/{change-compile-timeout.js => change-compile-timeout.mjs} (91%) rename services/web/modules/server-ce-scripts/scripts/{check-mongodb.js => check-mongodb.mjs} (84%) rename services/web/modules/server-ce-scripts/scripts/{check-redis.js => check-redis.mjs} (82%) rename services/web/modules/server-ce-scripts/scripts/{check-texlive-images.js => check-texlive-images.mjs} (97%) rename services/web/modules/server-ce-scripts/scripts/{create-user.js => create-user.mjs} (84%) rename services/web/modules/server-ce-scripts/scripts/{delete-user.js => delete-user.mjs} (80%) rename services/web/modules/server-ce-scripts/scripts/{migrate-user-emails.js => migrate-user-emails.mjs} (91%) rename services/web/modules/server-ce-scripts/scripts/{rename-tag.js => rename-tag.mjs} (85%) rename services/web/modules/server-ce-scripts/scripts/{upgrade-user-features.js => upgrade-user-features.mjs} (77%) rename services/web/modules/server-ce-scripts/test/acceptance/src/{ServerCEScriptsTests.js => ServerCEScriptsTests.mjs} (91%) diff --git a/services/web/migrations/20230817081910_back_fill_gitBridge_feature_server_pro.mjs b/services/web/migrations/20230817081910_back_fill_gitBridge_feature_server_pro.mjs index 3090d66d88..2325394c76 100644 --- a/services/web/migrations/20230817081910_back_fill_gitBridge_feature_server_pro.mjs +++ b/services/web/migrations/20230817081910_back_fill_gitBridge_feature_server_pro.mjs @@ -3,7 +3,7 @@ const tags = ['server-ce', 'server-pro'] const migrate = async () => { // Run-time import as SaaS does not ship with the server-ce-scripts module const { default: runScript } = await import( - '../modules/server-ce-scripts/scripts/upgrade-user-features.js' + '../modules/server-ce-scripts/scripts/upgrade-user-features.mjs' ) await runScript(false, { gitBridge: 1, diff --git a/services/web/modules/server-ce-scripts/index.js b/services/web/modules/server-ce-scripts/index.mjs similarity index 75% rename from services/web/modules/server-ce-scripts/index.js rename to services/web/modules/server-ce-scripts/index.mjs index 28c3d81419..e6df0f30af 100644 --- a/services/web/modules/server-ce-scripts/index.js +++ b/services/web/modules/server-ce-scripts/index.mjs @@ -3,4 +3,4 @@ /** @type {WebModule} */ const ServerCeScriptsModule = {} -module.exports = ServerCeScriptsModule +export default ServerCeScriptsModule diff --git a/services/web/modules/server-ce-scripts/scripts/change-compile-timeout.js b/services/web/modules/server-ce-scripts/scripts/change-compile-timeout.mjs similarity index 91% rename from services/web/modules/server-ce-scripts/scripts/change-compile-timeout.js rename to services/web/modules/server-ce-scripts/scripts/change-compile-timeout.mjs index ca99e6233f..3a2d982688 100644 --- a/services/web/modules/server-ce-scripts/scripts/change-compile-timeout.js +++ b/services/web/modules/server-ce-scripts/scripts/change-compile-timeout.mjs @@ -1,9 +1,9 @@ -const minimist = require('minimist') -const { +import minimist from 'minimist' +import { db, ObjectId, waitForDb, -} = require('../../../app/src/infrastructure/mongodb') +} from '../../../app/src/infrastructure/mongodb.js' async function main() { await waitForDb() diff --git a/services/web/modules/server-ce-scripts/scripts/check-mongodb.js b/services/web/modules/server-ce-scripts/scripts/check-mongodb.mjs similarity index 84% rename from services/web/modules/server-ce-scripts/scripts/check-mongodb.js rename to services/web/modules/server-ce-scripts/scripts/check-mongodb.mjs index 3dd9f33b61..401e780632 100644 --- a/services/web/modules/server-ce-scripts/scripts/check-mongodb.js +++ b/services/web/modules/server-ce-scripts/scripts/check-mongodb.mjs @@ -1,6 +1,9 @@ -const { ObjectId } = require('mongodb-legacy') -const { waitForDb, db } = require('../../../app/src/infrastructure/mongodb') -const { getMongoClient } = require('../../../app/src/infrastructure/Mongoose') +import mongodb from 'mongodb-legacy' +import { waitForDb, db } from '../../../app/src/infrastructure/mongodb.js' +import mongoose from '../../../app/src/infrastructure/Mongoose.js' + +const { ObjectId } = mongodb +const { getMongoClient } = mongoose const MIN_MONGO_VERSION = [5, 0] diff --git a/services/web/modules/server-ce-scripts/scripts/check-redis.js b/services/web/modules/server-ce-scripts/scripts/check-redis.mjs similarity index 82% rename from services/web/modules/server-ce-scripts/scripts/check-redis.js rename to services/web/modules/server-ce-scripts/scripts/check-redis.mjs index 6402619eaa..213bcc9714 100644 --- a/services/web/modules/server-ce-scripts/scripts/check-redis.js +++ b/services/web/modules/server-ce-scripts/scripts/check-redis.mjs @@ -1,4 +1,4 @@ -const RedisWrapper = require('../../../app/src/infrastructure/RedisWrapper') +import RedisWrapper from '../../../app/src/infrastructure/RedisWrapper.js' const rclient = RedisWrapper.client('health_check') rclient.on('error', err => { console.error('Cannot connect to redis.') diff --git a/services/web/modules/server-ce-scripts/scripts/check-texlive-images.js b/services/web/modules/server-ce-scripts/scripts/check-texlive-images.mjs similarity index 97% rename from services/web/modules/server-ce-scripts/scripts/check-texlive-images.js rename to services/web/modules/server-ce-scripts/scripts/check-texlive-images.mjs index 4f474650ff..7765b278cc 100644 --- a/services/web/modules/server-ce-scripts/scripts/check-texlive-images.js +++ b/services/web/modules/server-ce-scripts/scripts/check-texlive-images.mjs @@ -1,4 +1,4 @@ -const { waitForDb, db } = require('../../../app/src/infrastructure/mongodb') +import { waitForDb, db } from '../../../app/src/infrastructure/mongodb.js' async function readImagesInUse() { await waitForDb() diff --git a/services/web/modules/server-ce-scripts/scripts/create-user.js b/services/web/modules/server-ce-scripts/scripts/create-user.mjs similarity index 84% rename from services/web/modules/server-ce-scripts/scripts/create-user.js rename to services/web/modules/server-ce-scripts/scripts/create-user.mjs index 031c78fff2..2ec64081fc 100644 --- a/services/web/modules/server-ce-scripts/scripts/create-user.js +++ b/services/web/modules/server-ce-scripts/scripts/create-user.mjs @@ -1,6 +1,6 @@ -const minimist = require('minimist') -const { db, waitForDb } = require('../../../app/src/infrastructure/mongodb') -const UserRegistrationHandler = require('../../../app/src/Features/User/UserRegistrationHandler') +import minimist from 'minimist' +import { db, waitForDb } from '../../../app/src/infrastructure/mongodb.js' +import UserRegistrationHandler from '../../../app/src/Features/User/UserRegistrationHandler.js' async function main() { await waitForDb() diff --git a/services/web/modules/server-ce-scripts/scripts/delete-user.js b/services/web/modules/server-ce-scripts/scripts/delete-user.mjs similarity index 80% rename from services/web/modules/server-ce-scripts/scripts/delete-user.js rename to services/web/modules/server-ce-scripts/scripts/delete-user.mjs index ff1060984a..68f060c386 100644 --- a/services/web/modules/server-ce-scripts/scripts/delete-user.js +++ b/services/web/modules/server-ce-scripts/scripts/delete-user.mjs @@ -1,6 +1,6 @@ -const { waitForDb } = require('../../../app/src/infrastructure/mongodb') -const UserGetter = require('../../../app/src/Features/User/UserGetter') -const UserDeleter = require('../../../app/src/Features/User/UserDeleter') +import { waitForDb } from '../../../app/src/infrastructure/mongodb.js' +import UserGetter from '../../../app/src/Features/User/UserGetter.js' +import UserDeleter from '../../../app/src/Features/User/UserDeleter.js' async function main() { await waitForDb() diff --git a/services/web/modules/server-ce-scripts/scripts/migrate-user-emails.js b/services/web/modules/server-ce-scripts/scripts/migrate-user-emails.mjs similarity index 91% rename from services/web/modules/server-ce-scripts/scripts/migrate-user-emails.js rename to services/web/modules/server-ce-scripts/scripts/migrate-user-emails.mjs index d266ad46d2..39d44f5369 100644 --- a/services/web/modules/server-ce-scripts/scripts/migrate-user-emails.js +++ b/services/web/modules/server-ce-scripts/scripts/migrate-user-emails.mjs @@ -9,16 +9,16 @@ // Intended for Server Pro customers migrating user emails from one domain to // another. -const minimist = require('minimist') -const { waitForDb } = require('../../../app/src/infrastructure/mongodb') +import minimist from 'minimist' -const os = require('os') -const fs = require('fs') -const csv = require('csv/sync') -const { parseEmail } = require('../../../app/src/Features/Helpers/EmailHelper') -const UserGetter = require('../../../app/src/Features/User/UserGetter') -const UserUpdater = require('../../../app/src/Features/User/UserUpdater') -const UserSessionsManager = require('../../../app/src/Features/User/UserSessionsManager') +import { waitForDb } from '../../../app/src/infrastructure/mongodb.js' +import os from 'node:os' +import fs from 'node:fs' +import * as csv from 'csv/sync' +import { parseEmail } from '../../../app/src/Features/Helpers/EmailHelper.js' +import UserGetter from '../../../app/src/Features/User/UserGetter.js' +import UserUpdater from '../../../app/src/Features/User/UserUpdater.js' +import UserSessionsManager from '../../../app/src/Features/User/UserSessionsManager.js' const hostname = os.hostname() const scriptTimestamp = new Date().toISOString() diff --git a/services/web/modules/server-ce-scripts/scripts/rename-tag.js b/services/web/modules/server-ce-scripts/scripts/rename-tag.mjs similarity index 85% rename from services/web/modules/server-ce-scripts/scripts/rename-tag.js rename to services/web/modules/server-ce-scripts/scripts/rename-tag.mjs index 51fa4377b6..28501a3674 100644 --- a/services/web/modules/server-ce-scripts/scripts/rename-tag.js +++ b/services/web/modules/server-ce-scripts/scripts/rename-tag.mjs @@ -1,5 +1,5 @@ -const minimist = require('minimist') -const { db, waitForDb } = require('../../../app/src/infrastructure/mongodb') +import minimist from 'minimist' +import { db, waitForDb } from '../../../app/src/infrastructure/mongodb.js' async function main() { await waitForDb() diff --git a/services/web/modules/server-ce-scripts/scripts/upgrade-user-features.js b/services/web/modules/server-ce-scripts/scripts/upgrade-user-features.mjs similarity index 77% rename from services/web/modules/server-ce-scripts/scripts/upgrade-user-features.js rename to services/web/modules/server-ce-scripts/scripts/upgrade-user-features.mjs index eb511fc298..7cbef16dd7 100644 --- a/services/web/modules/server-ce-scripts/scripts/upgrade-user-features.js +++ b/services/web/modules/server-ce-scripts/scripts/upgrade-user-features.mjs @@ -1,10 +1,11 @@ -const Settings = require('@overleaf/settings') -const logger = require('@overleaf/logger') -const { db, waitForDb } = require('../../../app/src/infrastructure/mongodb') -const { +import { fileURLToPath } from 'node:url' +import Settings from '@overleaf/settings' +import logger from '@overleaf/logger' +import { db, waitForDb } from '../../../app/src/infrastructure/mongodb.js' +import { mergeFeatures, compareFeatures, -} = require('../../../app/src/Features/Subscription/FeaturesHelper') +} from '../../../app/src/Features/Subscription/FeaturesHelper.js' const DRY_RUN = !process.argv.includes('--dry-run=false') async function main(DRY_RUN, defaultFeatures) { @@ -40,9 +41,9 @@ async function main(DRY_RUN, defaultFeatures) { } } -module.exports = main +export default main -if (require.main === module) { +if (fileURLToPath(import.meta.url) === process.argv[1]) { if (DRY_RUN) { console.error('---') console.error('Dry-run enabled, use --dry-run=false to commit changes') diff --git a/services/web/modules/server-ce-scripts/test/acceptance/src/ServerCEScriptsTests.js b/services/web/modules/server-ce-scripts/test/acceptance/src/ServerCEScriptsTests.mjs similarity index 91% rename from services/web/modules/server-ce-scripts/test/acceptance/src/ServerCEScriptsTests.js rename to services/web/modules/server-ce-scripts/test/acceptance/src/ServerCEScriptsTests.mjs index 0c304e14f1..0069a46105 100644 --- a/services/web/modules/server-ce-scripts/test/acceptance/src/ServerCEScriptsTests.js +++ b/services/web/modules/server-ce-scripts/test/acceptance/src/ServerCEScriptsTests.mjs @@ -1,9 +1,11 @@ -const { execSync } = require('child_process') -const fs = require('fs') -const Settings = require('@overleaf/settings') -const { expect } = require('chai') -const { db } = require('../../../../../app/src/infrastructure/mongodb') -const User = require('../../../../../test/acceptance/src/helpers/User').promises +import { execSync } from 'node:child_process' +import fs from 'node:fs' +import Settings from '@overleaf/settings' +import { expect } from 'chai' +import { db } from '../../../../../app/src/infrastructure/mongodb.js' +import UserHelper from '../../../../../test/acceptance/src/helpers/User.js' + +const { promises: User } = UserHelper /** * @param {string} cmd @@ -42,7 +44,7 @@ async function getUser(email) { describe('ServerCEScripts', function () { describe('check-mongodb', function () { it('should exit with code 0 on success', function () { - run('node modules/server-ce-scripts/scripts/check-mongodb') + run('node modules/server-ce-scripts/scripts/check-mongodb.mjs') }) it('should exit with code 1 on error', function () { @@ -50,7 +52,7 @@ describe('ServerCEScripts', function () { run( 'MONGO_SERVER_SELECTION_TIMEOUT=1' + 'MONGO_CONNECTION_STRING=mongodb://127.0.0.1:4242 ' + - 'node modules/server-ce-scripts/scripts/check-mongodb' + 'node modules/server-ce-scripts/scripts/check-mongodb.mjs' ) } catch (e) { expect(e.status).to.equal(1) @@ -62,12 +64,14 @@ describe('ServerCEScripts', function () { describe('check-redis', function () { it('should exit with code 0 on success', function () { - run('node modules/server-ce-scripts/scripts/check-redis') + run('node modules/server-ce-scripts/scripts/check-redis.mjs') }) it('should exit with code 1 on error', function () { try { - run('REDIS_PORT=42 node modules/server-ce-scripts/scripts/check-redis') + run( + 'REDIS_PORT=42 node modules/server-ce-scripts/scripts/check-redis.mjs' + ) } catch (e) { expect(e.status).to.equal(1) return @@ -79,28 +83,28 @@ describe('ServerCEScripts', function () { describe('create-user', function () { it('should exit with code 0 on success', function () { const out = run( - 'node modules/server-ce-scripts/scripts/create-user --email=foo@bar.com' + 'node modules/server-ce-scripts/scripts/create-user.mjs --email=foo@bar.com' ) expect(out).to.include('/user/activate?token=') }) it('should create a regular user by default', async function () { run( - 'node modules/server-ce-scripts/scripts/create-user --email=foo@bar.com' + 'node modules/server-ce-scripts/scripts/create-user.mjs --email=foo@bar.com' ) expect(await getUser('foo@bar.com')).to.deep.equal({ isAdmin: false }) }) it('should create an admin user with --admin flag', async function () { run( - 'node modules/server-ce-scripts/scripts/create-user --admin --email=foo@bar.com' + 'node modules/server-ce-scripts/scripts/create-user.mjs --admin --email=foo@bar.com' ) expect(await getUser('foo@bar.com')).to.deep.equal({ isAdmin: true }) }) it('should exit with code 1 on missing email', function () { try { - run('node modules/server-ce-scripts/scripts/create-user') + run('node modules/server-ce-scripts/scripts/create-user.mjs') } catch (e) { expect(e.status).to.equal(1) return @@ -119,19 +123,26 @@ describe('ServerCEScripts', function () { it('should log missing user', function () { const email = 'does-not-exist@example.com' const out = run( - 'node modules/server-ce-scripts/scripts/delete-user --email=' + email + 'node modules/server-ce-scripts/scripts/delete-user.mjs --email=' + + email ) expect(out).to.include('not in database, potentially already deleted') }) it('should exit with code 0 on success', function () { const email = user.email - run('node modules/server-ce-scripts/scripts/delete-user --email=' + email) + run( + 'node modules/server-ce-scripts/scripts/delete-user.mjs --email=' + + email + ) }) it('should have deleted the user on success', async function () { const email = user.email - run('node modules/server-ce-scripts/scripts/delete-user --email=' + email) + run( + 'node modules/server-ce-scripts/scripts/delete-user.mjs --email=' + + email + ) const dbEntry = await user.get() expect(dbEntry).to.not.exist const softDeletedEntry = await db.deletedUsers.findOne({ @@ -143,7 +154,7 @@ describe('ServerCEScripts', function () { it('should exit with code 1 on missing email', function () { try { - run('node modules/server-ce-scripts/scripts/delete-user') + run('node modules/server-ce-scripts/scripts/delete-user.mjs') } catch (e) { expect(e.status).to.equal(1) return @@ -199,7 +210,7 @@ describe('ServerCEScripts', function () { it('should do a dry run by default', async function () { run( - `node modules/server-ce-scripts/scripts/migrate-user-emails.js ${csv}` + `node modules/server-ce-scripts/scripts/migrate-user-emails.mjs ${csv}` ) for (const user of usersToMigrate) { const dbEntry = await user.get() @@ -213,13 +224,13 @@ describe('ServerCEScripts', function () { it('should exit with code 0 when successfully migrating user emails', function () { run( - `node modules/server-ce-scripts/scripts/migrate-user-emails.js --commit ${csv}` + `node modules/server-ce-scripts/scripts/migrate-user-emails.mjs --commit ${csv}` ) }) it('should migrate the user emails with the --commit option', async function () { run( - `node modules/server-ce-scripts/scripts/migrate-user-emails.js --commit ${csv}` + `node modules/server-ce-scripts/scripts/migrate-user-emails.mjs --commit ${csv}` ) for (const user of usersToMigrate) { const dbEntry = await user.get() @@ -233,7 +244,7 @@ describe('ServerCEScripts', function () { it('should leave other user emails unchanged', async function () { run( - `node modules/server-ce-scripts/scripts/migrate-user-emails.js --commit ${csv}` + `node modules/server-ce-scripts/scripts/migrate-user-emails.mjs --commit ${csv}` ) for (const user of otherUsers) { const dbEntry = await user.get() @@ -244,7 +255,7 @@ describe('ServerCEScripts', function () { it('should exit with code 1 when there are failures migrating user emails', function () { try { run( - `node modules/server-ce-scripts/scripts/migrate-user-emails.js --commit ${csvfail}` + `node modules/server-ce-scripts/scripts/migrate-user-emails.mjs --commit ${csvfail}` ) } catch (e) { expect(e.status).to.equal(1) @@ -256,12 +267,12 @@ describe('ServerCEScripts', function () { it('should migrate other users when there are failures with the --continue option', async function () { try { run( - `node modules/server-ce-scripts/scripts/migrate-user-emails.js --commit ${csvfail}` + `node modules/server-ce-scripts/scripts/migrate-user-emails.mjs --commit ${csvfail}` ) } catch (e) { expect(e.status).to.equal(1) run( - `node modules/server-ce-scripts/scripts/migrate-user-emails.js --commit --continue ${csvfail}` + `node modules/server-ce-scripts/scripts/migrate-user-emails.mjs --commit --continue ${csvfail}` ) for (const user of usersToMigrate) { const dbEntry = await user.get() @@ -301,7 +312,7 @@ describe('ServerCEScripts', function () { expect(await getTagNames()).to.deep.equal([oldName]) run( - `node modules/server-ce-scripts/scripts/rename-tag --user-id=${user.id} --old-name=${oldName} --new-name=${newName}` + `node modules/server-ce-scripts/scripts/rename-tag.mjs --user-id=${user.id} --old-name=${oldName} --new-name=${newName}` ) expect(await getTagNames()).to.deep.equal([newName]) @@ -334,7 +345,7 @@ describe('ServerCEScripts', function () { beforeEach('run script on user a', function () { newUserATimeout = userATimeout - 1 run( - `node modules/server-ce-scripts/scripts/change-compile-timeout --user-id=${userA.id} --compile-timeout=${newUserATimeout}` + `node modules/server-ce-scripts/scripts/change-compile-timeout.mjs --user-id=${userA.id} --compile-timeout=${newUserATimeout}` ) }) @@ -353,7 +364,7 @@ describe('ServerCEScripts', function () { it('should reject zero timeout', async function () { try { run( - `node modules/server-ce-scripts/scripts/change-compile-timeout --user-id=${userA.id} --compile-timeout=0` + `node modules/server-ce-scripts/scripts/change-compile-timeout.mjs --user-id=${userA.id} --compile-timeout=0` ) expect.fail('should error out') } catch (err) { @@ -366,7 +377,7 @@ describe('ServerCEScripts', function () { it('should reject a 20min timeout', async function () { try { run( - `node modules/server-ce-scripts/scripts/change-compile-timeout --user-id=${userA.id} --compile-timeout=1200` + `node modules/server-ce-scripts/scripts/change-compile-timeout.mjs --user-id=${userA.id} --compile-timeout=1200` ) expect.fail('should error out') } catch (err) { @@ -410,13 +421,13 @@ describe('ServerCEScripts', function () { beforeEach('downgrade userCustomTimeoutLower', async function () { run( - `node modules/server-ce-scripts/scripts/change-compile-timeout --user-id=${userCustomTimeoutLower.id} --compile-timeout=42` + `node modules/server-ce-scripts/scripts/change-compile-timeout.mjs --user-id=${userCustomTimeoutLower.id} --compile-timeout=42` ) }) beforeEach('upgrade userCustomTimeoutHigher', async function () { run( - `node modules/server-ce-scripts/scripts/change-compile-timeout --user-id=${userCustomTimeoutHigher.id} --compile-timeout=360` + `node modules/server-ce-scripts/scripts/change-compile-timeout.mjs --user-id=${userCustomTimeoutHigher.id} --compile-timeout=360` ) }) @@ -451,7 +462,7 @@ describe('ServerCEScripts', function () { let output beforeEach('run script', function () { output = run( - `node modules/server-ce-scripts/scripts/upgrade-user-features` + `node modules/server-ce-scripts/scripts/upgrade-user-features.mjs` ) }) @@ -480,7 +491,7 @@ describe('ServerCEScripts', function () { let output beforeEach('run script', function () { output = run( - `node modules/server-ce-scripts/scripts/upgrade-user-features --dry-run=false` + `node modules/server-ce-scripts/scripts/upgrade-user-features.mjs --dry-run=false` ) }) @@ -537,7 +548,7 @@ describe('ServerCEScripts', function () { cmd += ` OVERLEAF_IS_SERVER_PRO=${OVERLEAF_IS_SERVER_PRO}` } return ( - cmd + ' node modules/server-ce-scripts/scripts/check-texlive-images' + cmd + ' node modules/server-ce-scripts/scripts/check-texlive-images.mjs' ) }