From ef55d3631a72d5bf1fee5c809acd4bf17056f804 Mon Sep 17 00:00:00 2001 From: Jeff Wilcox <427913+jeffwilcox@users.noreply.github.com> Date: Sat, 16 Dec 2023 18:16:42 -0800 Subject: [PATCH] Typings: more interfaces to types --- .vscode/launch.json | 15 +++++++++++++ api/extension.ts | 2 +- interfaces/app.ts | 14 ++++++------- interfaces/providers.ts | 4 ++-- job.ts | 2 +- middleware/alternateApps.ts | 6 +++--- middleware/business/administration.ts | 3 +-- middleware/business/authentication.ts | 11 +++++----- .../business/corporateAdministrators.ts | 6 +++--- .../{links/index.ts => business/links.ts} | 0 middleware/correlationId.ts | 8 +++++-- .../{error-routes.ts => errorRoutes.ts} | 12 +++++------ middleware/index.ts | 18 +++++++++------- middleware/initialize.ts | 20 ++++++++++-------- middleware/keyVault.ts | 2 +- middleware/onboarding.ts | 4 ++-- middleware/passport/githubRoutes.ts | 9 ++++---- middleware/passport/githubStrategy.ts | 21 ++++++++++++------- .../{passport-config.ts => passportConfig.ts} | 0 middleware/react.ts | 4 ++-- middleware/scrubbedUrl.ts | 2 +- middleware/sslify.ts | 1 + middleware/staticClientApp.ts | 5 ++++- middleware/staticClientApp2.ts | 7 ++++++- middleware/types.ts | 10 +++++++++ 25 files changed, 119 insertions(+), 67 deletions(-) rename middleware/{links/index.ts => business/links.ts} (100%) rename middleware/{error-routes.ts => errorRoutes.ts} (77%) rename middleware/{passport-config.ts => passportConfig.ts} (100%) create mode 100644 middleware/types.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 38c56eb00..85e46fc66 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -138,6 +138,21 @@ "EXIT_IMMEDIATELY": "1" } }, + { + "type": "node", + "request": "launch", + "name": "66: Order 66 Terminations", + "program": "${workspaceRoot}/dist/microsoft/jobs/terminations.js", + "args": ["all"], + "cwd": "${workspaceRoot}/dist", + "preLaunchTask": "tsbuild", + "sourceMaps": true, + "console": "integratedTerminal", + "env": { + "NODE_ENV": "development", + "DEBUG": "startup,appinsights" + } + }, { "type": "node", "request": "launch", diff --git a/api/extension.ts b/api/extension.ts index fefd43b91..07fc294d8 100644 --- a/api/extension.ts +++ b/api/extension.ts @@ -9,7 +9,7 @@ const router: Router = Router(); import { getProviders } from '../transitional'; import { setIdentity } from '../middleware/business/authentication'; -import { AddLinkToRequest } from '../middleware/links'; +import { AddLinkToRequest } from '../middleware/business/links'; import { jsonError } from '../middleware'; import { apiContextMiddleware } from '../middleware/business/setContext'; import { ILocalExtensionKeyProvider } from '../entities/localExtensionKey'; diff --git a/interfaces/app.ts b/interfaces/app.ts index 2b3bda593..ba5d2f2d0 100644 --- a/interfaces/app.ts +++ b/interfaces/app.ts @@ -4,12 +4,12 @@ // import { Application, Response, NextFunction } from 'express'; -import { IProviders } from './providers'; -import type { RuntimeConfiguration } from './config'; -import { ReposAppRequest } from './web'; +import type { IProviders } from './providers'; +import type { RuntimeConfiguration, SiteConfiguration } from './config'; +import type { ReposAppRequest } from './web'; -export interface IApplicationProfile { +export type ApplicationProfile = { applicationName: string; customErrorHandlerRender?: ( errorView: unknown, @@ -26,7 +26,7 @@ export interface IApplicationProfile { startup?: (providers: IProviders) => Promise; sessions: boolean; webServer: boolean; -} +}; export interface IReposApplication extends Application { // Standard Express @@ -34,7 +34,7 @@ export interface IReposApplication extends Application { // Local things providers: IProviders; - config: any; + config: SiteConfiguration; isBackgroundJob: boolean; enableAllGitHubApps: boolean; runtimeConfiguration: RuntimeConfiguration; @@ -45,7 +45,7 @@ export interface IReposApplication extends Application { initializeApplication: ( executionEnvironment: ExecutionEnvironment, - config: any, + config: SiteConfiguration, configurationError: Error ) => Promise; diff --git a/interfaces/providers.ts b/interfaces/providers.ts index fbe0ae2e5..0f8b16c4b 100644 --- a/interfaces/providers.ts +++ b/interfaces/providers.ts @@ -9,7 +9,7 @@ import redis, { RedisClientType } from 'redis'; import { Pool as PostgresPool } from 'pg'; import { - IApplicationProfile, + ApplicationProfile, ICorporationAdministrationSection, IReposApplication, SiteConfiguration, @@ -48,7 +48,7 @@ type ProviderGenerator = (value: string) => IEntityMetadataProvider; export interface IProviders { app: IReposApplication; - applicationProfile: IApplicationProfile; + applicationProfile: ApplicationProfile; authorizationCodeClient?: AuthorizationCode; corporateAdministrationProfile?: ICorporationAdministrationSection; corporateViews?: any; diff --git a/job.ts b/job.ts index 268428c6d..e0063b8a4 100644 --- a/job.ts +++ b/job.ts @@ -154,7 +154,7 @@ function initializeJob( ); } -const job = { +export const job = { runBackgroundJob: async ( script: (providers: IProviders, jobParameters?: IReposJob) => Promise, options?: IReposJobOptions diff --git a/middleware/alternateApps.ts b/middleware/alternateApps.ts index 9f6ec74ae..76e783e49 100644 --- a/middleware/alternateApps.ts +++ b/middleware/alternateApps.ts @@ -8,13 +8,13 @@ const debug = Debug.debug('startup'); import path from 'path'; -import { IApplicationProfile, IReposApplication } from '../interfaces'; +import type { ApplicationProfile, IReposApplication, SiteConfiguration } from '../interfaces'; export default async function initializeAlternateApps( - config, + config: SiteConfiguration, app: IReposApplication, appName: string -): Promise { +): Promise { const appPath = path.resolve(path.join(__dirname, '..', appName, '/')); debug(`Alternate app requested: name=${appName}, path=${appPath}`); try { diff --git a/middleware/business/administration.ts b/middleware/business/administration.ts index b2ff44558..fb0760a5b 100644 --- a/middleware/business/administration.ts +++ b/middleware/business/administration.ts @@ -4,13 +4,12 @@ // import { NextFunction, Response, Router } from 'express'; -const router: Router = Router(); import { ReposAppRequest } from '../../interfaces'; import { wrapError } from '../../utils'; -function denyRoute(next) { +function denyRoute(next: NextFunction) { next( wrapError( null, diff --git a/middleware/business/authentication.ts b/middleware/business/authentication.ts index 695897d17..4d9dc1ede 100644 --- a/middleware/business/authentication.ts +++ b/middleware/business/authentication.ts @@ -3,6 +3,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +import { Response, NextFunction } from 'express'; + import { ReposAppRequest, IAppSession } from '../../interfaces'; import Debug from 'debug'; @@ -17,13 +19,12 @@ import { } from '../../business/user'; import { storeOriginalUrlAsReferrer } from '../../utils'; import getCompanySpecificDeployment from '../companySpecificDeployment'; -import { Response, NextFunction } from 'express'; export async function requireAuthenticatedUserOrSignInExcluding( exclusionPaths: string[], req: ReposAppRequest, - res, - next + res: Response, + next: NextFunction ) { const url = req.url; for (let i = 0; i < exclusionPaths.length; i++) { @@ -64,7 +65,7 @@ export async function requireAccessTokenClient(req: ReposAppRequest, res: Respon return next(); } -function signoutThenSignIn(req: ReposAppRequest, res) { +function signoutThenSignIn(req: ReposAppRequest, res: Response) { const { insights } = getProviders(req); req.logout({ keepSessionInfo: false }, (err) => { if (err) { @@ -74,7 +75,7 @@ function signoutThenSignIn(req: ReposAppRequest, res) { }); } -function redirectToSignIn(req, res) { +function redirectToSignIn(req: ReposAppRequest, res: Response) { const config = getProviders(req).config; storeOriginalUrlAsReferrer( req, diff --git a/middleware/business/corporateAdministrators.ts b/middleware/business/corporateAdministrators.ts index 99b985047..728936f48 100644 --- a/middleware/business/corporateAdministrators.ts +++ b/middleware/business/corporateAdministrators.ts @@ -18,7 +18,7 @@ export interface IReposAppRequestWithSystemAdministration extends ReposAppReques isSystemAdministrator: boolean; } -function denyRoute(next, isApi: boolean) { +function denyRoute(next: NextFunction, isApi: boolean) { if (isApi) { return next(jsonError('This API is unavailable for you', 403)); } @@ -48,8 +48,8 @@ export async function AuthorizeOnlyCorporateAdministrators( export async function checkIsCorporateAdministrator( req: IReposAppRequestWithSystemAdministration, - res, - next + res: Response, + next: NextFunction ) { await getIsCorporateAdministrator(req); return next(); diff --git a/middleware/links/index.ts b/middleware/business/links.ts similarity index 100% rename from middleware/links/index.ts rename to middleware/business/links.ts diff --git a/middleware/correlationId.ts b/middleware/correlationId.ts index 4ceaf7a50..9f491d1a5 100644 --- a/middleware/correlationId.ts +++ b/middleware/correlationId.ts @@ -3,11 +3,15 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -import { NextFunction, Response } from 'express'; +import { NextFunction, Request, Response } from 'express'; import { randomUUID } from 'crypto'; +export type WithCorrelationId = T & { + correlationId?: string; +}; + // Generate a correlation ID -export default function (req, res: Response, next: NextFunction) { +export default function (req: WithCorrelationId, res: Response, next: NextFunction) { req.correlationId = randomUUID(); return next(); } diff --git a/middleware/error-routes.ts b/middleware/errorRoutes.ts similarity index 77% rename from middleware/error-routes.ts rename to middleware/errorRoutes.ts index a4bb9134f..f0b92c709 100644 --- a/middleware/error-routes.ts +++ b/middleware/errorRoutes.ts @@ -3,10 +3,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -import { NextFunction, Response } from 'express'; +import { NextFunction, Request, Response } from 'express'; import { IReposApplication, IReposError } from '../interfaces'; -import RouteErrorHandler from './errorHandler'; +import routeErrorHandler from './errorHandler'; export default async function configureErrorRoutes(app: IReposApplication, initializationError: Error) { if (!app) { @@ -19,7 +19,7 @@ export default async function configureErrorRoutes(app: IReposApplication, initi // for any request. Should evaluate whether to hide for // production scenarios or if there is a risk of the // error message leaking sensitive data. - app.use((req, res: Response, next: NextFunction) => { + app.use((req: Request, res: Response, next: NextFunction) => { const error: IReposError = new Error('Application initialization error', { cause: initializationError, }); @@ -28,12 +28,12 @@ export default async function configureErrorRoutes(app: IReposApplication, initi }); } - app.use(function (req, res: Response, next: NextFunction) { + app.use(function (req: Request, res: Response, next: NextFunction) { const err: IReposError = new Error('Not Found'); err.status = 404; err.skipLog = true; - next(err); + return next(err); }); - app.use(RouteErrorHandler); + app.use(routeErrorHandler); } diff --git a/middleware/index.ts b/middleware/index.ts index f784b5f4b..1a47e000f 100644 --- a/middleware/index.ts +++ b/middleware/index.ts @@ -6,12 +6,14 @@ import bodyParser from 'body-parser'; import compression from 'compression'; import path from 'path'; +import { Express } from 'express'; +import passport from 'passport'; import Debug from 'debug'; const debug = Debug.debug('startup'); export * from './react'; -export * from './links'; +export * from './business/links'; export * from './business'; export * from './jsonError'; @@ -20,7 +22,7 @@ import { StaticClientApp } from './staticClientApp'; import { StaticReactClientApp } from './staticClientApp2'; import { StaticSiteFavIcon, StaticSiteAssets } from './staticSiteAssets'; import connectSession from './session'; -import passportConfig from './passport-config'; +import passportConfig from './passportConfig'; import onboard from './onboarding'; import viewServices from '../lib/pugViewServices'; @@ -35,12 +37,13 @@ import routePassport from './passport-routes'; import routeApi from '../api'; -import { IProviders, IReposApplication, SiteConfiguration } from '../interfaces'; +import type { IProviders, IReposApplication, SiteConfiguration } from '../interfaces'; import { codespacesDevAssistant } from './codespaces'; +import { ExpressWithStatic } from './types'; export default async function initMiddleware( app: IReposApplication, - express, + express: Express, providers: IProviders, config: SiteConfiguration, dirname: string, @@ -78,14 +81,15 @@ export default async function initMiddleware( if (applicationProfile.serveStaticAssets) { StaticSiteAssets(app, express); } + const expressWithStatic = express as ExpressWithStatic; if (hasStaticReactClientApp()) { - StaticReactClientApp(app, express, config); + StaticReactClientApp(app, expressWithStatic, config); } if (applicationProfile.serveClientAssets) { - StaticClientApp(app, express); + StaticClientApp(app, expressWithStatic); } providers.campaign = campaign(app); - let passport; + let passport: passport.PassportStatic; if (!initializationError) { if (config.containers && config.containers.deployment) { app.enable('trust proxy'); diff --git a/middleware/initialize.ts b/middleware/initialize.ts index 106c62e7c..ef2ea4c7f 100644 --- a/middleware/initialize.ts +++ b/middleware/initialize.ts @@ -3,7 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -import { NextFunction, Response } from 'express'; +import { Express, NextFunction, Response } from 'express'; import path from 'path'; import CosmosSessionStore from '../lib/cosmosSession'; @@ -19,7 +19,7 @@ import { createAndInitializeRepositoryMetadataProviderInstance } from '../entiti import createAndInitializeOrganizationAnnotationProviderInstance from '../entities/organizationAnnotation'; import { createMailAddressProviderInstance, IMailAddressProvider } from '../lib/mailAddressProvider'; -import ErrorRoutes from './error-routes'; +import ErrorRoutes from './errorRoutes'; import { createClient, RedisClientType } from 'redis'; import { Pool as PostgresPool } from 'pg'; @@ -76,7 +76,7 @@ import middlewareIndex from '.'; import type { ICacheHelper } from '../lib/caching'; import type { ExecutionEnvironment, - IApplicationProfile, + ApplicationProfile, IProviders, IReposApplication, SiteConfiguration, @@ -85,7 +85,7 @@ import initializeRepositoryProvider from '../entities/repository'; import { tryGetImmutableStorageProvider } from '../lib/immutable'; import { GitHubAppPurposes } from '../lib/github/appPurposes'; -const DefaultApplicationProfile: IApplicationProfile = { +const DefaultApplicationProfile: ApplicationProfile = { applicationName: 'Open Source Management Portal', serveStaticAssets: true, serveClientAssets: true, @@ -121,7 +121,6 @@ async function initializeAsync( } else if (config.github.cache.provider === 'redis') { const redisClient = await connectRedis(config, config.redis, 'cache'); const redisHelper = new RedisHelper({ redisClient, prefix: config.redis.prefix }); - // providers.redisClient = redisClient; providers.cacheProvider = redisHelper; } else { throw new Error('No cache provider available'); @@ -318,7 +317,7 @@ async function initializeAsync( } } -function configureGitHubLibrary(cacheProvider: ICacheHelper, config): RestLibrary { +function configureGitHubLibrary(cacheProvider: ICacheHelper, config: SiteConfiguration): RestLibrary { const libraryContext = new RestLibrary({ config, cacheProvider, @@ -330,7 +329,7 @@ function configureGitHubLibrary(cacheProvider: ICacheHelper, config): RestLibrar export default async function initialize( executionEnvironment: ExecutionEnvironment, app: IReposApplication, - express, + express: Express, rootdir: string, config: SiteConfiguration, exception: Error @@ -541,7 +540,7 @@ export default async function initialize( return executionEnvironment; } -function createGraphProvider(providers: IProviders, config: any): Promise { +function createGraphProvider(providers: IProviders, config: SiteConfiguration): Promise { return new Promise((resolve, reject) => { // The graph provider is optional. A graph provider can connect to a // corporate directory to validate or lookup employees and other @@ -642,7 +641,10 @@ async function connectRedis( return redisClient; } -async function createMailAddressProvider(config: any, providers: IProviders): Promise { +async function createMailAddressProvider( + config: SiteConfiguration, + providers: IProviders +): Promise { const options = { config: config, providers: providers, diff --git a/middleware/keyVault.ts b/middleware/keyVault.ts index f03629d5d..77c90a60b 100644 --- a/middleware/keyVault.ts +++ b/middleware/keyVault.ts @@ -4,7 +4,7 @@ // import { ClientSecretCredential } from '@azure/identity'; -import { KeyVaultSecret, SecretClient } from '@azure/keyvault-secrets'; +import { SecretClient } from '@azure/keyvault-secrets'; export interface IKeyVaultConfigurationOptions { tenantId: string; diff --git a/middleware/onboarding.ts b/middleware/onboarding.ts index 225bbbe2b..6a6b34535 100644 --- a/middleware/onboarding.ts +++ b/middleware/onboarding.ts @@ -3,7 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -import { IProviders } from '../interfaces'; +import { IProviders, IReposApplication, SiteConfiguration } from '../interfaces'; // ---------------------------------------------------------------------------- // Onboarding helper @@ -14,7 +14,7 @@ import { IProviders } from '../interfaces'; // rather a configuration/app initialization method just stored here to keep it // out of the way. // ---------------------------------------------------------------------------- -export default async function Onboard(app, config) { +export default async function Onboard(app: IReposApplication, config: SiteConfiguration) { const { operations } = app.settings.providers as IProviders; const onboardingOrganizations = config.github.organizations?.onboarding || []; for (const orgEntry of onboardingOrganizations) { diff --git a/middleware/passport/githubRoutes.ts b/middleware/passport/githubRoutes.ts index 07e0a287c..07826ff0d 100644 --- a/middleware/passport/githubRoutes.ts +++ b/middleware/passport/githubRoutes.ts @@ -5,8 +5,9 @@ import { NextFunction, Response } from 'express'; import querystring from 'querystring'; +import { PassportStatic } from 'passport'; -import { ReposAppRequest } from '../../interfaces'; +import { IReposApplication, ReposAppRequest, SiteConfiguration } from '../../interfaces'; import { getProviders } from '../../transitional'; import { isCodespacesAuthenticating } from '../../utils'; import { IAuthenticationHelperMethods } from '../passport-routes'; @@ -19,9 +20,9 @@ import { } from '../passport/githubStrategy'; export function attachGitHubPassportRoutes( - app, - config: any, - passport, + app: IReposApplication, + config: SiteConfiguration, + passport: PassportStatic, helpers: IAuthenticationHelperMethods ) { const signinPath = isCodespacesAuthenticating(config, 'github') ? 'sign-in' : 'signin'; diff --git a/middleware/passport/githubStrategy.ts b/middleware/passport/githubStrategy.ts index ff98687dd..ff23f32e5 100644 --- a/middleware/passport/githubStrategy.ts +++ b/middleware/passport/githubStrategy.ts @@ -5,10 +5,17 @@ import { Strategy as GithubStrategy } from 'passport-github'; -import { IGitHubAccountDetails, IProviders } from '../../interfaces'; import { getCodespacesHostname, isCodespacesAuthenticating, isEnterpriseManagedUserLogin } from '../../utils'; +import type { + IGitHubAccountDetails, + IProviders, + IReposApplication, + SiteConfiguration, +} from '../../interfaces'; +import type { ConfigGitHubCodespaces } from '../../config/github.codespaces.types'; import Debug from 'debug'; +import { ConfigGitHubOAuth2 } from '../../config/github.oauth2.types'; const debug = Debug.debug('startup'); export const githubStrategyName = 'github'; @@ -55,7 +62,7 @@ function impersonatedIdentityFromDetails( } function githubResponseToSubset( - app, + app: IReposApplication, modernAppInUse: boolean, accessToken: string, refreshToken: string, @@ -73,7 +80,7 @@ function githubResponseToSubset( } async function githubResponseToSubsetEx( - app, + app: IReposApplication, modernAppInUse: boolean, accessToken: string, refreshToken: string, @@ -142,7 +149,7 @@ function githubResponseToIncreasedScopeSubset( return done(null, subset); } -export function getGithubAppConfigurationOptions(config) { +export function getGithubAppConfigurationOptions(config: SiteConfiguration) { let legacyOAuthApp = config?.github?.oauth2?.clientId && config?.github?.oauth2?.clientSecret ? config.github.oauth2 : null; const customerFacingApp = @@ -168,9 +175,9 @@ export function getGithubAppConfigurationOptions(config) { }; } -export default function createGithubStrategy(app, config) { +export default function createGithubStrategy(app: IReposApplication, config: SiteConfiguration) { const strategies = {}; - const codespaces = config?.github?.codespaces || {}; + const codespaces = config?.github?.codespaces || ({} as ConfigGitHubCodespaces); const { modernAppInUse, githubAppConfiguration, useIncreasedScopeLegacyAppIfNeeded } = getGithubAppConfigurationOptions(config); if (!githubAppConfiguration?.clientId) { @@ -183,7 +190,7 @@ export default function createGithubStrategy(app, config) { const finalCallbackUrl = isCodespacesAuthenticating(config, 'github') && !codespaces?.block ? getCodespacesHostname(config) + redirectSuffix - : githubAppConfiguration.callbackUrl; + : (githubAppConfiguration as ConfigGitHubOAuth2)?.callbackUrl; let clientId = githubAppConfiguration.clientId; let clientSecret = githubAppConfiguration.clientSecret; let codespacesOverrideText = ''; diff --git a/middleware/passport-config.ts b/middleware/passportConfig.ts similarity index 100% rename from middleware/passport-config.ts rename to middleware/passportConfig.ts diff --git a/middleware/react.ts b/middleware/react.ts index c21749b1d..96cb9f365 100644 --- a/middleware/react.ts +++ b/middleware/react.ts @@ -11,7 +11,7 @@ import appPackage from '../package.json'; import { getStaticBlobCacheFallback } from '../lib/staticBlobCacheFallback'; import { getProviders, splitSemiColonCommas } from '../transitional'; -import { ReposAppRequest } from '../interfaces'; +import type { ReposAppRequest, SiteConfiguration } from '../interfaces'; import { IndividualContext } from '../business/user'; const staticReactPackageNameKey = 'static-react-package-name'; @@ -169,7 +169,7 @@ function evaluateFlightConditions(req: ReposAppRequest): FlightingOptions | Basi }; } -function getUserClientFeatureFlags(config: any, corporateId: string) { +function getUserClientFeatureFlags(config: SiteConfiguration, corporateId: string) { const featureFlagList = config?.client?.flighting?.featureFlagUsers; if (featureFlagList && typeof featureFlagList === 'object') { const flights = []; diff --git a/middleware/scrubbedUrl.ts b/middleware/scrubbedUrl.ts index d498a6cdd..1600724a8 100644 --- a/middleware/scrubbedUrl.ts +++ b/middleware/scrubbedUrl.ts @@ -19,5 +19,5 @@ export default function (req: ReposAppRequest, res: Response, next: NextFunction } } req.scrubbedUrl = url; - next(); + return next(); } diff --git a/middleware/sslify.ts b/middleware/sslify.ts index 4fd121d2d..2b7a83dc5 100644 --- a/middleware/sslify.ts +++ b/middleware/sslify.ts @@ -4,6 +4,7 @@ // import sslify from 'express-sslify'; + import type { ConfigWebServer } from '../config/webServer.types'; export default function (webServerConfig: ConfigWebServer) { diff --git a/middleware/staticClientApp.ts b/middleware/staticClientApp.ts index 14af5da60..2cebc2dbe 100644 --- a/middleware/staticClientApp.ts +++ b/middleware/staticClientApp.ts @@ -8,10 +8,13 @@ import appPackage from '../package.json'; const packageVariableName = 'static-client-package-name'; const otherPackageVariableName = 'static-react-package-name'; +import type { IReposApplication } from '../interfaces'; +import type { ExpressWithStatic } from './types'; + import Debug from 'debug'; const debug = Debug.debug('startup'); -export function StaticClientApp(app, express) { +export function StaticClientApp(app: IReposApplication, express: ExpressWithStatic) { // Serve/host the static client app from the location reported by the private // NPM module for the Ember app. Assumes that the inclusion of the package // returns the path to host. diff --git a/middleware/staticClientApp2.ts b/middleware/staticClientApp2.ts index 7fdc795bd..3b71797dc 100644 --- a/middleware/staticClientApp2.ts +++ b/middleware/staticClientApp2.ts @@ -16,6 +16,7 @@ const staticReactFlightingPackageNameKey = 'static-react-flight-package-name'; const staticClientFlightingPackageName = appPackage[staticReactFlightingPackageNameKey]; import Debug from 'debug'; +import { ExpressWithStatic } from './types'; const debug = Debug.debug('startup'); export type RuntimeConfigurationClient = { @@ -31,7 +32,11 @@ export type RootRuntimeConfigurationClient = { client?: RuntimeConfigurationClient; }; -export function StaticReactClientApp(app: IReposApplication, express, config: SiteConfiguration) { +export function StaticReactClientApp( + app: IReposApplication, + express: ExpressWithStatic, + config: SiteConfiguration +) { const clientRuntimeConfiguration: RuntimeConfigurationClient = {}; app.runtimeConfiguration.client = clientRuntimeConfiguration; diff --git a/middleware/types.ts b/middleware/types.ts new file mode 100644 index 000000000..50b8e1de7 --- /dev/null +++ b/middleware/types.ts @@ -0,0 +1,10 @@ +// +// Copyright (c) Microsoft. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +import { Express } from 'express'; + +export type ExpressWithStatic = Express & { + static: (path: string, options?: any) => Express; +};