From 5bc5b1af2aa5a93852d98d6f638b2036eec4b86f Mon Sep 17 00:00:00 2001 From: Alexandre Bourdin Date: Mon, 29 Jul 2024 10:58:07 +0200 Subject: [PATCH] Merge pull request #19562 from overleaf/ab-modules-dependencies [web] Modules dependencies GitOrigin-RevId: d8bbb25a754f2ed58b1b1e924aa760b87d3135c6 --- .../web/app/src/infrastructure/Modules.js | 13 +++- services/web/app/src/infrastructure/Server.js | 4 +- services/web/modules/history-v1/index.js | 7 ++- services/web/modules/launchpad/index.js | 9 ++- .../web/modules/server-ce-scripts/index.js | 7 ++- services/web/modules/user-activate/index.js | 10 +++- services/web/types/web-module.ts | 59 +++++++++++++++++++ 7 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 services/web/types/web-module.ts diff --git a/services/web/app/src/infrastructure/Modules.js b/services/web/app/src/infrastructure/Modules.js index 6e4d0dea25..b5daf62b06 100644 --- a/services/web/app/src/infrastructure/Modules.js +++ b/services/web/app/src/infrastructure/Modules.js @@ -41,6 +41,15 @@ function loadModules() { `${moduleName}: module.viewIncludes moved into Settings.viewIncludes` ) } + if (loadedModule.dependencies) { + for (const dependency of loadedModule.dependencies) { + if (!Settings.moduleImportSequence.includes(dependency)) { + throw new Error( + `Module '${dependency}' listed as a dependency of '${moduleName}' is missing in the moduleImportSequence. Please also verify that it is available in the current environment.` + ) + } + } + } } _modulesLoaded = true attachHooks() @@ -74,7 +83,7 @@ function loadViewIncludes(app) { _viewIncludes = Views.compileViewIncludes(app) } -function registerMiddleware(appOrRouter, middlewareName, options) { +function applyMiddleware(appOrRouter, middlewareName, options) { if (!middlewareName) { throw new Error( 'middleware name must be provided to register module middleware' @@ -173,7 +182,7 @@ module.exports = { loadViewIncludes, moduleIncludes, moduleIncludesAvailable, - registerMiddleware, + applyMiddleware, hooks: { attach: attachHook, fire: fireHook, diff --git a/services/web/app/src/infrastructure/Server.js b/services/web/app/src/infrastructure/Server.js index 43ae580ec4..6c6ffffeeb 100644 --- a/services/web/app/src/infrastructure/Server.js +++ b/services/web/app/src/infrastructure/Server.js @@ -144,7 +144,7 @@ if (Settings.enabledServices.includes('web')) { app.use(metrics.http.monitor(logger)) -Modules.registerMiddleware(app, 'appMiddleware') +Modules.applyMiddleware(app, 'appMiddleware') app.use(bodyParser.urlencoded({ extended: true, limit: '2mb' })) app.use(bodyParser.json({ limit: Settings.max_json_request_size })) app.use(methodOverride()) @@ -179,7 +179,7 @@ const sessionSecrets = [ webRouter.use(cookieParser(sessionSecrets)) webRouter.use(CookieMetrics.middleware) SessionAutostartMiddleware.applyInitialMiddleware(webRouter) -Modules.registerMiddleware(webRouter, 'sessionMiddleware', { +Modules.applyMiddleware(webRouter, 'sessionMiddleware', { store: sessionStore, }) webRouter.use( diff --git a/services/web/modules/history-v1/index.js b/services/web/modules/history-v1/index.js index 4ba52ba2c8..9c5c8a3c73 100644 --- a/services/web/modules/history-v1/index.js +++ b/services/web/modules/history-v1/index.js @@ -1 +1,6 @@ -module.exports = {} +/** @typedef {import("../../types/web-module").WebModule} WebModule */ + +/** @type {WebModule} */ +const HistoryModule = {} + +module.exports = HistoryModule diff --git a/services/web/modules/launchpad/index.js b/services/web/modules/launchpad/index.js index ad4ad6d3bf..30eefa56a2 100644 --- a/services/web/modules/launchpad/index.js +++ b/services/web/modules/launchpad/index.js @@ -1,3 +1,10 @@ const LaunchpadRouter = require('./app/src/LaunchpadRouter') -module.exports = { router: LaunchpadRouter } +/** @typedef {import("../../types/web-module").WebModule} WebModule */ + +/** @type {WebModule} */ +const LaunchpadModule = { + router: LaunchpadRouter, +} + +module.exports = LaunchpadModule diff --git a/services/web/modules/server-ce-scripts/index.js b/services/web/modules/server-ce-scripts/index.js index 4ba52ba2c8..2730f4b74a 100644 --- a/services/web/modules/server-ce-scripts/index.js +++ b/services/web/modules/server-ce-scripts/index.js @@ -1 +1,6 @@ -module.exports = {} +/** @typedef {import("../../types/web-module").WebModule} WebModule */ + +/** @type {WebModule} */ +const ServerCeScriptsModule = {} + +module.exports = ServerCeScriptsModule diff --git a/services/web/modules/user-activate/index.js b/services/web/modules/user-activate/index.js index 6adad0d022..a9dc5d56e4 100644 --- a/services/web/modules/user-activate/index.js +++ b/services/web/modules/user-activate/index.js @@ -1,2 +1,10 @@ const UserActivateRouter = require('./app/src/UserActivateRouter') -module.exports = { router: UserActivateRouter } + +/** @typedef {import("../../types/web-module").WebModule} WebModule */ + +/** @type {WebModule} */ +const UserActivateModule = { + router: UserActivateRouter, +} + +module.exports = UserActivateModule diff --git a/services/web/types/web-module.ts b/services/web/types/web-module.ts new file mode 100644 index 0000000000..11b1ca080f --- /dev/null +++ b/services/web/types/web-module.ts @@ -0,0 +1,59 @@ +type LinkedFileAgent = { + createLinkedFile: ( + projectId: string, + linkedFileData: object, + name: string, + parentFolderId: string, + userId: string, + callback: () => void + ) => void + refreshLinkedFile: ( + projectId: string, + linkedFileData: object, + name: string, + parentFolderId: string, + userId: string, + callback: () => void + ) => void + promises: { + createLinkedFile: ( + projectId: string, + linkedFileData: object, + name: string, + parentFolderId: string, + userId: string + ) => Promise + refreshLinkedFile: ( + projectId: string, + linkedFileData: object, + name: string, + parentFolderId: string, + userId: string + ) => Promise + } +} + +export type WebModule = { + dependencies?: string[] + router?: { + apply?: ( + webRouter: any, + privateApiRouter?: any, + publicApiRouter?: any + ) => void + } + nonCsrfRouter?: { + apply: (webRouter: any, privateApiRouter: any, publicApiRouter: any) => void + } + hooks?: { + [name: string]: (args: any[]) => void + } + middleware?: { + [name: string]: (req: any, res: any, next: any) => void + } + sessionMiddleware?: (webRouter: any, options: any) => void + appMiddleware?: (app: any) => void + linkedFileAgents?: { + [name: string]: () => LinkedFileAgent + } +}