chore(types): Improve TS types for renderHTML and related functions (#4605)

* chore(types): Improve TS types for renderHTML

* changeset

* Add author and PR to changeset

* Use RequestOptions instead of Request

* Update changeset text

* Separate type import

* Explain isArray check

* Add verdaccio/url to changeset

* Reverting: throw on wrong type
This commit is contained in:
Tobbe Lundberg 2024-05-02 20:55:52 +02:00 committed by GitHub
parent 3293c9a281
commit b0946b2a3b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 12 deletions

View File

@ -0,0 +1,6 @@
---
'@verdaccio/middleware': patch
'@verdaccio/url': patch
---
Improved TS types for renderHTML() and related functions (by @tobbe in #4605)

View File

@ -1,4 +1,5 @@
import buildDebug from 'debug';
import type { IncomingHttpHeaders } from 'node:http';
import { URL } from 'url';
import validator from 'validator';
@ -31,7 +32,7 @@ export function isHost(url: string = '', options = {}): boolean {
/**
* Detect running protocol (http or https)
*/
export function getWebProtocol(headerProtocol: string | void, protocol: string): string {
export function getWebProtocol(headerProtocol: string | undefined, protocol: string): string {
let returnProtocol;
const [, defaultProtocol] = validProtocols;
// HAProxy variant might return http,http with X-Forwarded-Proto
@ -101,7 +102,7 @@ export type RequestOptions = {
/**
* Request headers.
*/
headers: { [key: string]: string };
headers: IncomingHttpHeaders;
remoteAddress?: string;
/**
* Logged username the request, usually after token verification.
@ -119,10 +120,13 @@ export function getPublicUrl(url_prefix: string = '', requestOptions: RequestOpt
if (!isHost(host)) {
throw new Error('invalid host');
}
const protoHeader =
const protoHeader: string =
process.env.VERDACCIO_FORWARDED_PROTO?.toLocaleLowerCase() ??
HEADERS.FORWARDED_PROTO.toLowerCase();
const protocol = getWebProtocol(requestOptions.headers[protoHeader], requestOptions.protocol);
const forwardedProtocolHeaderValue = requestOptions.headers[protoHeader] as string | undefined;
const protocol = getWebProtocol(forwardedProtocolHeaderValue, requestOptions.protocol);
const combinedUrl = combineBaseUrl(protocol, host, url_prefix);
debug('public url by request %o', combinedUrl);
return combinedUrl;

View File

@ -1,4 +1,5 @@
import buildDebug from 'debug';
import type { Response } from 'express';
import LRU from 'lru-cache';
import path from 'path';
import { URL } from 'url';
@ -6,10 +7,12 @@ import { URL } from 'url';
import { WEB_TITLE } from '@verdaccio/config';
import { HEADERS } from '@verdaccio/core';
import { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';
import { isURLhasValidProtocol } from '@verdaccio/url';
import { getPublicUrl } from '@verdaccio/url';
import type { RequestOptions } from '@verdaccio/url';
import { getPublicUrl, isURLhasValidProtocol } from '@verdaccio/url';
import type { Manifest } from './manifest';
import renderTemplate from './template';
import type { WebpackManifest } from './template';
import { hasLogin, validatePrimaryColor } from './web-utils';
const DEFAULT_LANGUAGE = 'es-US';
@ -17,19 +20,20 @@ const cache = new LRU({ max: 500, ttl: 1000 * 60 * 60 });
const debug = buildDebug('verdaccio:web:render');
const defaultManifestFiles = {
const defaultManifestFiles: Manifest = {
js: ['runtime.js', 'vendors.js', 'main.js'],
ico: 'favicon.ico',
css: [],
};
export function resolveLogo(config: ConfigYaml, req) {
export function resolveLogo(config: ConfigYaml, requestOptions: RequestOptions) {
if (typeof config?.web?.logo !== 'string') {
return '';
}
const isLocalFile = config?.web?.logo && !isURLhasValidProtocol(config?.web?.logo);
if (isLocalFile) {
return `${getPublicUrl(config?.url_prefix, req)}-/static/${path.basename(config?.web?.logo)}`;
return `${getPublicUrl(config?.url_prefix, requestOptions)}-/static/${path.basename(config?.web?.logo)}`;
} else if (isURLhasValidProtocol(config?.web?.logo)) {
return config?.web?.logo;
} else {
@ -37,9 +41,15 @@ export function resolveLogo(config: ConfigYaml, req) {
}
}
export default function renderHTML(config: ConfigYaml, manifest, manifestFiles, req, res) {
export default function renderHTML(
config: ConfigYaml,
manifest: WebpackManifest,
manifestFiles: Manifest | null | undefined,
requestOptions: RequestOptions,
res: Response
) {
const { url_prefix } = config;
const base = getPublicUrl(config?.url_prefix, req);
const base = getPublicUrl(config?.url_prefix, requestOptions);
const basename = new URL(base).pathname;
const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;
const hideDeprecatedVersions = config?.web?.hideDeprecatedVersions ?? false;
@ -51,7 +61,7 @@ export default function renderHTML(config: ConfigYaml, manifest, manifestFiles,
const title = config?.web?.title ?? WEB_TITLE;
const login = hasLogin(config);
const scope = config?.web?.scope ?? '';
const logo = resolveLogo(config, req);
const logo = resolveLogo(config, requestOptions);
const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm'];
const version = res.locals.app_version ?? '';
const flags = {