diff --git a/.changeset/clever-pugs-warn.md b/.changeset/clever-pugs-warn.md
new file mode 100644
index 000000000..bf590ac28
--- /dev/null
+++ b/.changeset/clever-pugs-warn.md
@@ -0,0 +1,12 @@
+---
+'@verdaccio/cli': major
+'@verdaccio/core': major
+'@verdaccio/types': major
+'@verdaccio/logger': major
+'@verdaccio/logger-prettify': major
+'verdaccio-audit': major
+'@verdaccio/eslint-config': major
+'@verdaccio/mock': major
+---
+
+feat: migrate to pino.js 8
diff --git a/.gitignore b/.gitignore
index c8c6c7338..1019f5a64 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,7 +46,8 @@ api-results.json
hyper-results.json
hyper-results*.json
api-results*.json
+.clinic/
#docs
./api
-packages/core/core/docs
+**/docs/**
diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts
index 46d257430..3c5042cd1 100644
--- a/packages/cli/src/commands/init.ts
+++ b/packages/cli/src/commands/init.ts
@@ -2,9 +2,8 @@ import { Command, Option } from 'clipanion';
import { findConfigFile, parseConfigFile } from '@verdaccio/config';
import { logger, setup } from '@verdaccio/logger';
-import { LoggerConfigItem } from '@verdaccio/logger';
import { initServer } from '@verdaccio/node-api';
-import { ConfigYaml } from '@verdaccio/types';
+import { ConfigYaml, LoggerConfigItem } from '@verdaccio/types';
export const DEFAULT_PROCESS_NAME: string = 'verdaccio';
diff --git a/packages/core/core/src/warning-utils.ts b/packages/core/core/src/warning-utils.ts
index ad2f7f483..c91f78be8 100644
--- a/packages/core/core/src/warning-utils.ts
+++ b/packages/core/core/src/warning-utils.ts
@@ -6,7 +6,6 @@ const verdaccioDeprecation = 'VerdaccioDeprecation';
export enum Codes {
VERWAR001 = 'VERWAR001',
- VERWAR002 = 'VERWAR002',
VERWAR003 = 'VERWAR003',
VERWAR004 = 'VERWAR004',
// deprecation warnings
@@ -19,8 +18,6 @@ warningInstance.create(
`Verdaccio doesn't need superuser privileges. don't run it under root`
);
-warningInstance.create(verdaccioWarning, Codes.VERWAR002, 'logger is not defined');
-
warningInstance.create(
verdaccioWarning,
Codes.VERWAR003,
diff --git a/packages/core/types/README.md b/packages/core/types/README.md
index cf4bc25cb..ced51f640 100644
--- a/packages/core/types/README.md
+++ b/packages/core/types/README.md
@@ -1,30 +1,8 @@
-# TypeScript types for Verdaccio
+# @verdaccio/types
TypeScript definitions for Verdaccio plugins and internal code.
-# TypeScript
-
-For usage with the library, the `tsconfig.json` should looks like this.
-
-```json5
-// tsconfig.json
-{
- compilerOptions: {
- target: 'esnext',
- module: 'commonjs',
- declaration: true,
- noImplicitAny: false,
- strict: true,
- outDir: 'lib',
- allowSyntheticDefaultImports: true,
- esModuleInterop: true,
- typeRoots: ['./node_modules/@verdaccio/types/lib/verdaccio', './node_modules/@types'],
- },
- include: ['src/*.ts', 'types/*.d.ts'],
-}
-```
-
-### Imports
+### Usage
```ts
import type {ILocalData, LocalStorage, Logger, Config} from '@verdaccio/types';
@@ -38,3 +16,11 @@ class LocalData implements ILocalData {
...
}
```
+
+### Run docs
+
+Generate the package types documentation at `./docs` folder.
+
+```bash
+ pnpm build:docs
+```
diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts
deleted file mode 100644
index 216e5b1f6..000000000
--- a/packages/core/types/index.d.ts
+++ /dev/null
@@ -1,694 +0,0 @@
-///
-import { PassThrough, PipelinePromise, Readable, Stream, Writable } from 'stream';
-
-declare module '@verdaccio/types' {
- type StringValue = string | void | null;
-
- type StorageList = string[];
- type Callback = Function;
- // FIXME: err should be something flexible enough for any implementation
- type CallbackAction = (err: any | null) => void;
- interface Author {
- username?: string;
- name: string;
- email?: string;
- url?: string;
- }
-
- type PackageManagers = 'pnpm' | 'yarn' | 'npm';
-
- // FUTURE: WebConf and TemplateUIOptions should be merged .
- type CommonWebConf = {
- title?: string;
- logo?: string;
- favicon?: string;
- gravatar?: boolean;
- sort_packages?: string;
- darkMode?: boolean;
- url_prefix?: string;
- language?: string;
- login?: boolean;
- scope?: string;
- pkgManagers?: PackageManagers[];
- };
-
- /**
- * Options are passed to the index.html
- */
- export type TemplateUIOptions = {
- uri?: string;
- darkMode?: boolean;
- protocol?: string;
- host?: string;
- // deprecated
- basename?: string;
- scope?: string;
- showInfo?: boolean;
- showSettings?: boolean;
- showSearch?: boolean;
- showFooter?: boolean;
- showThemeSwitch?: boolean;
- showDownloadTarball?: boolean;
- showRaw?: boolean;
- base: string;
- primaryColor?: string;
- version?: string;
- logoURI?: string;
- flags: FlagsConfig;
- } & CommonWebConf;
-
- /**
- * Options on config.yaml for web
- */
- type WebConf = {
- // FIXME: rename to primaryColor and move it to CommonWebConf
- primary_color?: string;
- enable?: boolean;
- scriptsHead?: string[];
- scriptsBodyAfter?: string[];
- metaScripts?: string[];
- bodyBefore?: string[];
- bodyAfter?: string[];
- } & CommonWebConf;
-
- interface Signatures {
- keyid: string;
- sig: string;
- }
-
- interface Dist {
- 'npm-signature'?: string;
- signatures?: Signatures[];
- fileCount?: number;
- integrity?: string;
- shasum: string;
- unpackedSize?: number;
- tarball: string;
- }
-
- interface RemoteUser {
- real_groups: string[];
- groups: string[];
- name: string | void;
- error?: string;
- }
-
- interface LocalStorage {
- list: any;
- secret: string;
- }
-
- interface Version {
- name: string;
- version: string;
- devDependencies?: string;
- directories?: any;
- dist: Dist;
- author: string | Author;
- main: string;
- homemage?: string;
- license?: string;
- readme: string;
- readmeFileName?: string;
- readmeFilename?: string;
- description: string;
- bin?: string;
- bugs?: any;
- files?: string[];
- gitHead?: string;
- maintainers?: Author[];
- contributors?: Author[];
- repository?: string | any;
- scripts?: any;
- homepage?: string;
- etag?: string;
- dependencies: any;
- keywords?: string | string[];
- nodeVersion?: string;
- _id: string;
- _npmVersion?: string;
- _npmUser: Author;
- _hasShrinkwrap?: boolean;
- deprecated?: string;
- }
-
- interface Logger {
- child: (conf: any) => any;
- debug: (conf: any, template?: string) => void;
- error: (conf: any, template?: string) => void;
- http: (conf: any, template?: string) => void;
- trace: (conf: any, template?: string) => void;
- warn: (conf: any, template?: string) => void;
- info: (conf: any, template?: string) => void;
- }
-
- interface Versions {
- [key: string]: Version;
- }
-
- interface DistFile {
- url: string;
- sha: string;
- registry?: string;
- }
-
- interface MergeTags {
- [key: string]: string;
- }
-
- interface DistFiles {
- [key: string]: DistFile;
- }
-
- interface AttachMents {
- [key: string]: AttachMentsItem;
- }
-
- interface AttachMentsItem {
- data?: string;
- content_type?: string;
- length?: number;
- shasum?: string;
- version?: string;
- }
-
- interface GenericBody {
- [key: string]: string;
- }
-
- interface UpLinkMetadata {
- etag: string;
- fetched: number;
- }
-
- interface UpLinks {
- [key: string]: UpLinkMetadata;
- }
-
- interface Tags {
- [key: string]: Version;
- }
-
- interface Headers {
- [key: string]: string;
- }
-
- interface PackageUsers {
- [key: string]: boolean;
- }
-
- /**
- * @deprecated use Manifest instead
- */
- interface Package {
- _id?: string;
- name: string;
- versions: Versions;
- 'dist-tags': GenericBody;
- time: GenericBody;
- readme?: string;
- users?: PackageUsers;
- _distfiles: DistFiles;
- _attachments: AttachMents;
- _uplinks: UpLinks;
- _rev: string;
- }
-
- interface PublishManifest {
- /**
- * The `_attachments` object has different usages:
- *
- * - When a package is published, it contains the tarball as an string, this string is used to be
- * converted as a tarball, usually attached to the package but not stored in the database.
- * - If user runs `npm star` the _attachments will be at the manifest body but empty.
- *
- * It has also an internal usage:
- *
- * - Used as a cache for the tarball, quick access to the tarball shasum, etc. Instead
- * iterate versions and find the right one, just using the tarball as a key which is what
- * the package manager sends to the registry.
- *
- * - A `_attachments` object is added every time a private tarball is published, upstream cached tarballs are
- * not being part of this object, only for published private packages.
- *
- * Note: This field is removed when the package is accesed through the web user interface.
- * */
- _attachments: AttachMents;
- }
-
- /**
- * Represents upstream manifest from another registry
- */
- interface FullRemoteManifest {
- _id?: string;
- _rev?: string;
- name: string;
- description?: string;
- 'dist-tags': GenericBody;
- time: GenericBody;
- versions: Versions;
- maintainers?: Author[];
- /** store the latest readme **/
- readme?: string;
- /** store star assigned to this packages by users */
- users?: PackageUsers;
- // TODO: not clear what access exactly means
- access?: any;
- bugs?: { url: string };
- license?: string;
- homepage?: string;
- repository?: string | { type?: string; url: string; directory?: string };
- keywords?: string[];
- }
-
- interface Manifest extends FullRemoteManifest, PublishManifest {
- // private fields only used by verdaccio
- /**
- * store fast access to the dist url of an specific tarball, instead search version
- * by id, just the tarball id is faster.
- *
- * The _distfiles is created only when a package is being sync from an upstream.
- * also used to fetch tarballs from upstream, the private publish tarballs are not stored in
- * this object because they are not published in the upstream registry.
- */
- _distfiles: DistFiles;
- /**
- * Store access cache metadata, to avoid to fetch the same metadata multiple times.
- *
- * The key represents the uplink id which is composed of a etag and a fetched timestamp.
- *
- * The fetched timestamp is the time when the metadata was fetched, used to avoid to fetch the
- * same metadata until the metadata is older than the last fetch.
- */
- _uplinks: UpLinks;
- /**
- * store the revision of the manifest
- */
- _rev: string;
- }
-
- interface UpLinkTokenConf {
- type: 'Bearer' | 'Basic';
- token?: string;
- token_env?: boolean | string;
- }
-
- interface UpLinkConf {
- url: string;
- ca?: string;
- cache?: boolean;
- timeout?: string | void;
- maxage?: string | void;
- max_fails?: number | void;
- fail_timeout?: string | void;
- headers?: Headers;
- auth?: UpLinkTokenConf;
- strict_ssl?: boolean | void;
- _autogenerated?: boolean;
- }
-
- interface AuthPluginPackage {
- packageName: string;
- packageVersion?: string;
- tag?: string;
- }
-
- interface PackageAccess {
- storage?: string;
- publish?: string[];
- proxy?: string[];
- access?: string[];
- unpublish: string[];
- }
-
- interface PackageAccessYaml {
- storage?: string;
- publish?: string;
- proxy?: string;
- access?: string;
- unpublish?: string;
- }
-
- // info passed to the auth plugin when a package is package is being published
- interface AllowAccess {
- name: string;
- version?: string;
- tag?: string;
- }
-
- interface AuthPackageAllow extends PackageAccess, AllowAccess {}
-
- interface PackageList {
- [key: string]: PackageAccess;
- }
-
- interface PackageListYaml {
- [key: string]: PackageAccessYaml;
- }
- interface UpLinksConfList {
- [key: string]: UpLinkConf;
- }
-
- type LoggerType = 'stdout' | 'stderr' | 'file';
- type LoggerFormat = 'pretty' | 'pretty-timestamped' | 'file' | 'json';
- type LoggerLevel = 'http' | 'fatal' | 'warn' | 'info' | 'debug' | 'trace';
-
- interface LoggerConfItem {
- type: LoggerType;
- format: LoggerFormat;
- level: LoggerLevel;
- }
-
- interface PublishOptions {
- allow_offline: boolean;
- }
-
- type AuthConf = any | AuthHtpasswd;
-
- interface AuthHtpasswd {
- file: string;
- max_users: number;
- }
-
- // FUTURE: rename to Notification
- interface Notifications {
- method: string;
- packagePattern: RegExp;
- packagePatternFlags: string;
- endpoint: string;
- content: string;
- headers: Headers;
- }
-
- type Notification = Notifications;
-
- interface Token {
- user: string;
- token: string;
- key: string;
- cidr?: string[];
- readonly: boolean;
- created: number | string;
- updated?: number | string;
- }
-
- interface TokenFilter {
- user: string;
- }
-
- type IPackageStorage = ILocalPackageManager | undefined;
- type IPackageStorageManager = ILocalPackageManager;
- type IPluginStorage = ILocalData;
-
- interface AuthHtpasswd {
- file: string;
- max_users: number;
- }
-
- interface ILocalStorage {
- add(name: string): void;
- remove(name: string): void;
- get(): StorageList;
- sync(): void;
- }
-
- interface ListenAddress {
- [key: string]: string;
- }
- interface HttpsConfKeyCert {
- key: string;
- cert: string;
- ca?: string;
- }
-
- interface HttpsConfPfx {
- pfx: string;
- passphrase?: string;
- }
-
- type HttpsConf = HttpsConfKeyCert | HttpsConfPfx;
-
- interface JWTOptions {
- sign: JWTSignOptions;
- verify: JWTVerifyOptions;
- }
-
- interface JWTVerifyOptions {
- algorithm?: string;
- expiresIn?: string;
- notBefore?: string | number;
- ignoreExpiration?: boolean;
- maxAge?: string | number;
- clockTimestamp?: number;
- }
-
- interface JWTSignOptions {
- algorithm?: string;
- expiresIn?: string;
- notBefore?: string;
- ignoreExpiration?: boolean;
- maxAge?: string | number;
- clockTimestamp?: number;
- }
-
- interface APITokenOptions {
- legacy: boolean;
- jwt?: JWTOptions;
- }
-
- interface Security {
- web: JWTOptions;
- api: APITokenOptions;
- }
-
- export type FlagsConfig = {
- searchRemote?: boolean;
- changePassword?: boolean;
- };
-
- export type RateLimit = {
- windowMs: number;
- max: number;
- };
-
- export type ServerSettingsConf = {
- // express-rate-limit settings
- rateLimit: RateLimit;
- keepAliveTimeout?: number;
- // force http2 if https is defined
- http2?: boolean;
- };
-
- type URLPrefix = {
- // if is false, it would be relative by default
- absolute: boolean;
- // base path
- // eg: absolute: true, https://somedomain.com/xxx/
- // eg: absolute: false, /xxx/ (default) if url_prefix is an string instead an object
- basePath: string;
- };
-
- /**
- * YAML configuration file available options.
- */
- interface ConfigYaml {
- _debug?: boolean;
- storage?: string | void;
- packages?: PackageListYaml;
- uplinks: UpLinksConfList;
- // FUTURE: log should be mandatory
- log?: LoggerConfItem;
- web?: WebConf;
- auth?: AuthConf;
- security?: Security;
- publish?: PublishOptions;
- store?: any;
- listen?: ListenAddress;
- https?: HttpsConf;
- http_proxy?: string;
- plugins?: string | void;
- https_proxy?: string;
- no_proxy?: string;
- max_body_size?: string;
- notifications?: Notifications;
- notify?: Notifications | Notifications[];
- middlewares?: any;
- filters?: any;
- url_prefix?: string;
- server?: ServerSettingsConf;
- flags?: FlagsConfig;
- // internal objects, added by internal yaml to JS config parser
- // @deprecated use configPath instead
- config_path?: string;
- // save the configuration file path
- configPath?: string;
- }
-
- /**
- * Configuration object with additonal methods for configuration, includes yaml and internal medatada.
- * @interface Config
- * @extends {ConfigYaml}
- */
- interface Config extends Omit {
- user_agent: string;
- server_id: string;
- secret: string;
- // save the configuration file path, it's fails without thi configPath
- configPath: string;
- // packages from yaml file looks different from packages inside the config file
- packages: PackageList;
- // security object defaults is added by the config file but optional in the yaml file
- security: Security;
- // @deprecated (pending adding the replacement)
- checkSecretKey(token: string): string;
- getMatchedPackagesSpec(storage: string): PackageAccess | void;
- // TODO: verify how to handle this in the future
- [key: string]: any;
- }
-
- type PublisherMaintainer = {
- username: string;
- email: string;
- };
-
- type SearchPackageBody = {
- name: string;
- scope: string;
- description: string;
- author: string | PublisherMaintainer;
- version: string;
- keywords: string | string[] | undefined;
- date: string;
- links?: {
- npm: string; // only include placeholder for URL eg: {url}/{packageName}
- homepage?: string;
- repository?: string;
- bugs?: string;
- };
- publisher?: any;
- maintainers?: PublisherMaintainer[];
- };
-
- interface ConfigWithHttps extends Config {
- https: HttpsConf;
- }
-
- export interface ITokenActions {
- saveToken(token: Token): Promise;
- deleteToken(user: string, tokenKey: string): Promise;
- readTokens(filter: TokenFilter): Promise;
- }
-
- /**
- * @deprecated use @verdaccio/core pluginUtils instead
- */
- interface ILocalData extends IPlugin, ITokenActions {
- logger: Logger;
- config: T & Config;
- add(name: string): Promise;
- remove(name: string): Promise;
- get(): Promise;
- init(): Promise;
- getSecret(): Promise;
- setSecret(secret: string): Promise;
- getPackageStorage(packageInfo: string): IPackageStorage;
- }
-
- interface ILocalPackageManager {
- logger: Logger;
- deletePackage(fileName: string): Promise;
- removePackage(): Promise;
- // next packages migration (this list is meant to replace the callback parent functions)
- updatePackage(
- packageName: string,
- handleUpdate: (manifest: Manifest) => Promise
- ): Promise;
- readPackage(name: string): Promise;
- savePackage(pkgName: string, value: Manifest): Promise;
- readTarball(pkgName: string, { signal }): Promise;
- createPackage(name: string, manifest: Manifest): Promise;
- writeTarball(tarballName: string, { signal }): Promise;
- // verify if tarball exist in the storage
- hasTarball(fileName: string): Promise;
- // verify if package exist in the storage
- hasPackage(): Promise;
- }
-
- // @deprecated use IBasicAuth from @verdaccio/auth
- interface IBasicAuth {
- config: T & Config;
- aesEncrypt(buf: string): string;
- authenticate(user: string, password: string, cb: Callback): void;
- changePassword(user: string, password: string, newPassword: string, cb: Callback): void;
- allow_access(pkg: AuthPluginPackage, user: RemoteUser, callback: Callback): void;
- add_user(user: string, password: string, cb: Callback): any;
- }
-
- export interface Plugin {
- new (config: T, options: PluginOptions): T;
- }
-
- interface IPlugin {
- version?: string;
- // In case a plugin needs to be cleaned up/removed
- close?(): void;
- }
-
- interface PluginOptions {
- config: T & Config;
- logger: Logger;
- }
-
- // FIXME: error should be export type `VerdaccioError = HttpError & { code: number };`
- // instead of AuthError
- // but this type is on @verdaccio/core and cannot be used here yet (I don't know why)
- interface HttpError extends Error {
- status: number;
- statusCode: number;
- expose: boolean;
- headers?: {
- [key: string]: string;
- };
- [key: string]: any;
- }
-
- type AuthError = HttpError & { code: number };
- type AuthAccessCallback = (error: AuthError | null, access: boolean) => void;
- type AuthCallback = (error: AuthError | null, groups: string[] | false) => void;
-
- interface IPluginAuth extends IPlugin {
- authenticate(user: string, password: string, cb: AuthCallback): void;
- adduser?(user: string, password: string, cb: AuthCallback): void;
- changePassword?(user: string, password: string, newPassword: string, cb: AuthCallback): void;
- allow_publish?(user: RemoteUser, pkg: T & AuthPackageAllow, cb: AuthAccessCallback): void;
- allow_access?(user: RemoteUser, pkg: T & PackageAccess, cb: AuthAccessCallback): void;
- allow_unpublish?(user: RemoteUser, pkg: T & AuthPackageAllow, cb: AuthAccessCallback): void;
- allow_publish?(
- user: RemoteUser,
- pkg: AllowAccess & PackageAccess,
- cb: AuthAccessCallback
- ): void;
- allow_access?(user: RemoteUser, pkg: AllowAccess & PackageAccess, cb: AuthAccessCallback): void;
- allow_unpublish?(
- user: RemoteUser,
- pkg: AllowAccess & PackageAccess,
- cb: AuthAccessCallback
- ): void;
- apiJWTmiddleware?(helpers: any): Function;
- }
-
- // @deprecated use @verdaccio/server
- interface IPluginMiddleware extends IPlugin {
- register_middlewares(app: any, auth: IBasicAuth, storage: any): void;
- }
-
- interface IPluginStorageFilter extends IPlugin {
- filter_metadata(packageInfo: Manifest): Promise;
- }
-
- export type SearchResultWeb = {
- name: string;
- version: string;
- description: string;
- };
-}
diff --git a/packages/core/types/package.json b/packages/core/types/package.json
index 157dc48f7..7b9e62375 100644
--- a/packages/core/types/package.json
+++ b/packages/core/types/package.json
@@ -31,15 +31,24 @@
"publishConfig": {
"access": "public"
},
- "main": "index.d.ts",
- "types": "index.d.ts",
+ "main": "build/types.d.ts",
+ "types": "build/types.d.ts",
"scripts": {
- "test": "exit 0",
- "build": "exit 0"
+ "clean": "rimraf ./build",
+ "test": "pnpm type-check",
+ "build:docs": "typedoc --options ./typedoc.json --excludeExternals --tsconfig tsconfig.build.json",
+ "type-check": "tsc --noEmit -p tsconfig.build.json",
+ "build": "tsc --emitDeclarationOnly -p tsconfig.build.json"
},
"devDependencies": {
"@types/node": "16.11.47",
- "tsd": "0.22.0"
+ "typedoc": "beta",
+ "typedoc-plugin-missing-exports": "1.0.0"
+ },
+ "typedoc": {
+ "entryPoint": "./src/types.ts",
+ "readmeFile": "./README.md",
+ "displayName": "@verdaccio/types"
},
"funding": {
"type": "opencollective",
diff --git a/packages/core/types/src/commons.ts b/packages/core/types/src/commons.ts
new file mode 100644
index 000000000..988f70bdd
--- /dev/null
+++ b/packages/core/types/src/commons.ts
@@ -0,0 +1,37 @@
+// @deprecated add proper type fot the callback
+export type Callback = Function;
+// FIXME: err should be something flexible enough for any implementation
+export type CallbackAction = (err: any | null) => void;
+// eslint-disable-next-line no-undef
+export type CallbackError = (err: NodeJS.ErrnoException) => void;
+
+export interface RemoteUser {
+ real_groups: string[];
+ groups: string[];
+ name: string | void;
+ error?: string;
+}
+
+export type StringValue = string | void | null;
+
+// FIXME: error should be export type `VerdaccioError = HttpError & { code: number };`
+// instead of AuthError
+// but this type is on @verdaccio/core and cannot be used here yet (I don't know why)
+export interface HttpError extends Error {
+ status: number;
+ statusCode: number;
+ expose: boolean;
+ headers?: {
+ [key: string]: string;
+ };
+ [key: string]: any;
+}
+
+export type URLPrefix = {
+ // if is false, it would be relative by default
+ absolute: boolean;
+ // base path
+ // eg: absolute: true, https://somedomain.com/xxx/
+ // eg: absolute: false, /xxx/ (default) if url_prefix is an string instead an object
+ basePath: string;
+};
diff --git a/packages/core/types/src/configuration.ts b/packages/core/types/src/configuration.ts
new file mode 100644
index 000000000..3ccfb34a3
--- /dev/null
+++ b/packages/core/types/src/configuration.ts
@@ -0,0 +1,296 @@
+import { PackageAccess, PackageList } from './manifest';
+
+export type TypeToken = 'Bearer' | 'Basic';
+
+export interface Logger {
+ child: (conf: any) => any;
+ debug: (conf: any, template?: string) => void;
+ error: (conf: any, template?: string) => void;
+ http: (conf: any, template?: string) => void;
+ trace: (conf: any, template?: string) => void;
+ warn: (conf: any, template?: string) => void;
+ info: (conf: any, template?: string) => void;
+}
+
+export type LoggerType = 'stdout' | 'file';
+export type LoggerFormat = 'pretty' | 'pretty-timestamped' | 'json';
+export type LoggerLevel = 'http' | 'fatal' | 'warn' | 'info' | 'debug' | 'trace';
+
+export type LoggerConfigItem = {
+ type?: LoggerType;
+ /**
+ * The format
+ */
+ format?: LoggerFormat;
+ path?: string;
+ level?: string;
+ colors?: boolean;
+ async?: boolean;
+};
+
+export interface ConfigWithHttps extends Config {
+ https: HttpsConf;
+}
+
+export interface PackageAccessYaml {
+ storage?: string;
+ publish?: string;
+ proxy?: string;
+ access?: string;
+ unpublish?: string;
+}
+
+export interface LoggerConfItem {
+ type: LoggerType;
+ format: LoggerFormat;
+ level: LoggerLevel;
+}
+
+export interface Headers {
+ [key: string]: string;
+}
+
+export interface UpLinkTokenConf {
+ type: TypeToken;
+ token?: string;
+ token_env?: boolean | string;
+}
+
+export interface UpLinkConf {
+ url: string;
+ ca?: string;
+ cache?: boolean;
+ timeout?: string | void;
+ maxage?: string | void;
+ max_fails?: number | void;
+ fail_timeout?: string | void;
+ headers?: Headers;
+ auth?: UpLinkTokenConf;
+ strict_ssl?: boolean | void;
+ _autogenerated?: boolean;
+}
+
+export type RateLimit = {
+ windowMs?: number;
+ max?: number;
+};
+
+// export interface WebConf {
+// enable?: boolean;
+// title?: string;
+// logo?: string;
+// favicon?: string;
+// gravatar?: boolean;
+// sort_packages?: string;
+// rateLimit?: RateLimit;
+// }
+
+export type FlagsConfig = {
+ searchRemote?: boolean;
+ changePassword?: boolean;
+};
+
+export type PackageManagers = 'pnpm' | 'yarn' | 'npm';
+
+// FUTURE: WebConf and TemplateUIOptions should be merged .
+export type CommonWebConf = {
+ title?: string;
+ logo?: string;
+ favicon?: string;
+ gravatar?: boolean;
+ sort_packages?: string;
+ darkMode?: boolean;
+ url_prefix?: string;
+ language?: string;
+ login?: boolean;
+ scope?: string;
+ pkgManagers?: PackageManagers[];
+};
+
+/**
+ * Options are passed to the index.html
+ */
+export type TemplateUIOptions = {
+ uri?: string;
+ darkMode?: boolean;
+ protocol?: string;
+ host?: string;
+ // deprecated
+ basename?: string;
+ scope?: string;
+ showInfo?: boolean;
+ showSettings?: boolean;
+ showSearch?: boolean;
+ showFooter?: boolean;
+ showThemeSwitch?: boolean;
+ showDownloadTarball?: boolean;
+ showRaw?: boolean;
+ base: string;
+ primaryColor?: string;
+ version?: string;
+ logoURI?: string;
+ flags: FlagsConfig;
+} & CommonWebConf;
+
+/**
+ * Options on config.yaml for web
+ */
+export type WebConf = {
+ // FIXME: rename to primaryColor and move it to CommonWebConf
+ primary_color?: string;
+ enable?: boolean;
+ scriptsHead?: string[];
+ scriptsBodyAfter?: string[];
+ metaScripts?: string[];
+ bodyBefore?: string[];
+ bodyAfter?: string[];
+} & CommonWebConf;
+
+export interface UpLinksConfList {
+ [key: string]: UpLinkConf;
+}
+
+export interface AuthHtpasswd {
+ file: string;
+ max_users: number;
+}
+
+export type AuthConf = any | AuthHtpasswd;
+
+export interface JWTOptions {
+ sign: JWTSignOptions;
+ verify: JWTVerifyOptions;
+}
+
+export interface JWTSignOptions {
+ algorithm?: string;
+ expiresIn?: string;
+ notBefore?: string;
+ ignoreExpiration?: boolean;
+ maxAge?: string | number;
+ clockTimestamp?: number;
+}
+
+export interface JWTVerifyOptions {
+ algorithm?: string;
+ expiresIn?: string;
+ notBefore?: string | number;
+ ignoreExpiration?: boolean;
+ maxAge?: string | number;
+ clockTimestamp?: number;
+}
+
+export interface APITokenOptions {
+ legacy: boolean;
+ jwt?: JWTOptions;
+}
+
+export interface Security {
+ web: JWTOptions;
+ api: APITokenOptions;
+}
+
+export interface PublishOptions {
+ allow_offline: boolean;
+}
+
+export interface ListenAddress {
+ [key: string]: string;
+}
+
+export interface HttpsConfKeyCert {
+ key: string;
+ cert: string;
+ ca?: string;
+}
+
+export interface HttpsConfPfx {
+ pfx: string;
+ passphrase?: string;
+}
+
+export type HttpsConf = HttpsConfKeyCert | HttpsConfPfx;
+
+export interface Notifications {
+ method: string;
+ packagePattern: RegExp;
+ packagePatternFlags: string;
+ endpoint: string;
+ content: string;
+ headers: Headers;
+}
+
+export type Notification = Notifications;
+
+export type ServerSettingsConf = {
+ // express-rate-limit settings
+ rateLimit: RateLimit;
+ keepAliveTimeout?: number;
+};
+
+/**
+ * YAML configuration file available options.
+ */
+export interface ConfigYaml {
+ _debug?: boolean;
+ storage?: string | void;
+ packages: PackageList;
+ uplinks: UpLinksConfList;
+ log?: LoggerConfItem;
+ web?: WebConf;
+ auth?: AuthConf;
+ security: Security;
+ publish?: PublishOptions;
+ store?: any;
+ listen?: ListenAddress;
+ https?: HttpsConf;
+ http_proxy?: string;
+ plugins?: string | void;
+ https_proxy?: string;
+ no_proxy?: string;
+ max_body_size?: string;
+ notifications?: Notifications;
+ notify?: Notifications | Notifications[];
+ middlewares?: any;
+ filters?: any;
+ url_prefix?: string;
+ server?: ServerSettingsConf;
+ flags?: FlagsConfig;
+ // internal objects, added by internal yaml to JS config parser
+ // @deprecated use configPath instead
+ config_path?: string;
+ // save the configuration file path
+ configPath?: string;
+}
+
+/**
+ * Configuration object with additonal methods for configuration, includes yaml and internal medatada.
+ * @interface Config
+ * @extends {ConfigYaml}
+ */
+export interface Config extends Omit {
+ user_agent: string;
+ server_id: string;
+ secret: string;
+ // save the configuration file path, it's fails without thi configPath
+ configPath: string;
+ // packages from yaml file looks different from packages inside the config file
+ packages: PackageList;
+ // security object defaults is added by the config file but optional in the yaml file
+ security: Security;
+ // @deprecated (pending adding the replacement)
+ checkSecretKey(token: string): string;
+ getMatchedPackagesSpec(storage: string): PackageAccess | void;
+ // TODO: verify how to handle this in the future
+ [key: string]: any;
+}
+
+export interface AllowAccess {
+ name: string;
+ version?: string;
+ tag?: string;
+}
+
+// info passed to the auth plugin when a package is package is being published
+
+export interface AuthPackageAllow extends PackageAccess, AllowAccess {}
diff --git a/packages/core/types/src/manifest.ts b/packages/core/types/src/manifest.ts
new file mode 100644
index 000000000..cc72daa6d
--- /dev/null
+++ b/packages/core/types/src/manifest.ts
@@ -0,0 +1,217 @@
+export interface PackageAccess {
+ storage?: string;
+ publish?: string[];
+ proxy?: string[];
+ access?: string[];
+ unpublish: string[];
+}
+
+export interface PackageList {
+ [key: string]: PackageAccess;
+}
+
+export interface MergeTags {
+ [key: string]: string;
+}
+
+export interface DistFile {
+ url: string;
+ sha: string;
+ registry?: string;
+}
+
+export interface DistFiles {
+ [key: string]: DistFile;
+}
+
+export interface Token {
+ user: string;
+ token: string;
+ key: string;
+ cidr?: string[];
+ readonly: boolean;
+ created: number | string;
+ updated?: number | string;
+}
+
+export interface AttachMents {
+ [key: string]: AttachMentsItem;
+}
+
+export interface AttachMentsItem {
+ content_type?: string;
+ data?: string;
+ length?: number;
+ shasum?: string;
+ version?: string;
+}
+
+export interface GenericBody {
+ [key: string]: string;
+}
+
+export interface UpLinkMetadata {
+ etag: string;
+ fetched: number;
+}
+
+export interface UpLinks {
+ [key: string]: UpLinkMetadata;
+}
+
+export interface Signatures {
+ keyid: string;
+ sig: string;
+}
+
+export interface Dist {
+ 'npm-signature'?: string;
+ signatures?: Signatures[];
+ fileCount?: number;
+ integrity?: string;
+ shasum: string;
+ unpackedSize?: number;
+ tarball: string;
+}
+
+export interface Author {
+ username?: string;
+ name: string;
+ email?: string;
+ url?: string;
+}
+
+export interface PackageUsers {
+ [key: string]: boolean;
+}
+
+export interface Tags {
+ [key: string]: Version;
+}
+
+export interface Version {
+ name: string;
+ version: string;
+ devDependencies?: string;
+ directories?: any;
+ dist: Dist;
+ author: string | Author;
+ main: string;
+ homemage?: string;
+ license?: string;
+ readme: string;
+ readmeFileName?: string;
+ readmeFilename?: string;
+ description: string;
+ bin?: string;
+ bugs?: any;
+ files?: string[];
+ gitHead?: string;
+ maintainers?: Author[];
+ contributors?: Author[];
+ repository?: string | any;
+ scripts?: any;
+ homepage?: string;
+ etag?: string;
+ dependencies: any;
+ keywords?: string | string[];
+ nodeVersion?: string;
+ _id: string;
+ _npmVersion?: string;
+ _npmUser: Author;
+ _hasShrinkwrap?: boolean;
+ deprecated?: string;
+}
+
+export interface Versions {
+ [key: string]: Version;
+}
+
+/**
+ * @deprecated use Manifest instead
+ */
+export interface Package {
+ _id?: string;
+ name: string;
+ versions: Versions;
+ 'dist-tags': GenericBody;
+ time: GenericBody;
+ readme?: string;
+ users?: PackageUsers;
+ _distfiles: DistFiles;
+ _attachments: AttachMents;
+ _uplinks: UpLinks;
+ _rev: string;
+}
+
+/**
+ * Represents upstream manifest from another registry
+ */
+export interface FullRemoteManifest {
+ _id?: string;
+ _rev?: string;
+ name: string;
+ description?: string;
+ 'dist-tags': GenericBody;
+ time: GenericBody;
+ versions: Versions;
+ maintainers?: Author[];
+ /** store the latest readme **/
+ readme?: string;
+ /** store star assigned to this packages by users */
+ users?: PackageUsers;
+ // TODO: not clear what access exactly means
+ access?: any;
+ bugs?: { url: string };
+ license?: string;
+ homepage?: string;
+ repository?: string | { type?: string; url: string; directory?: string };
+ keywords?: string[];
+}
+
+export interface Manifest extends FullRemoteManifest, PublishManifest {
+ // private fields only used by verdaccio
+ /**
+ * store fast access to the dist url of an specific tarball, instead search version
+ * by id, just the tarball id is faster.
+ *
+ * The _distfiles is created only when a package is being sync from an upstream.
+ * also used to fetch tarballs from upstream, the private publish tarballs are not stored in
+ * this object because they are not published in the upstream registry.
+ */
+ _distfiles: DistFiles;
+ /**
+ * Store access cache metadata, to avoid to fetch the same metadata multiple times.
+ *
+ * The key represents the uplink id which is composed of a etag and a fetched timestamp.
+ *
+ * The fetched timestamp is the time when the metadata was fetched, used to avoid to fetch the
+ * same metadata until the metadata is older than the last fetch.
+ */
+ _uplinks: UpLinks;
+ /**
+ * store the revision of the manifest
+ */
+ _rev: string;
+}
+export interface PublishManifest {
+ /**
+ * The `_attachments` object has different usages:
+ *
+ * - When a package is published, it contains the tarball as an string, this string is used to be
+ * converted as a tarball, usually attached to the package but not stored in the database.
+ * - If user runs `npm star` the _attachments will be at the manifest body but empty.
+ *
+ * It has also an internal usage:
+ *
+ * - Used as a cache for the tarball, quick access to the tarball shasum, etc. Instead
+ * iterate versions and find the right one, just using the tarball as a key which is what
+ * the package manager sends to the registry.
+ *
+ * - A `_attachments` object is added every time a private tarball is published, upstream cached tarballs are
+ * not being part of this object, only for published private packages.
+ *
+ * Note: This field is removed when the package is accesed through the web user interface.
+ * */
+ _attachments: AttachMents;
+}
diff --git a/packages/core/types/src/plugins/auth.ts b/packages/core/types/src/plugins/auth.ts
new file mode 100644
index 000000000..93060384d
--- /dev/null
+++ b/packages/core/types/src/plugins/auth.ts
@@ -0,0 +1,22 @@
+import { Callback, HttpError, RemoteUser } from '../commons';
+import { Config } from '../configuration';
+
+export interface AuthPluginPackage {
+ packageName: string;
+ packageVersion?: string;
+ tag?: string;
+}
+
+export type AuthError = HttpError & { code: number };
+export type AuthAccessCallback = (error: AuthError | null, access: boolean) => void;
+export type AuthCallback = (error: AuthError | null, groups: string[] | false) => void;
+
+// @deprecated use IBasicAuth from @verdaccio/auth
+export interface IBasicAuth {
+ config: T & Config;
+ aesEncrypt(buf: Buffer): Buffer;
+ authenticate(user: string, password: string, cb: Callback): void;
+ changePassword(user: string, password: string, newPassword: string, cb: Callback): void;
+ allow_access(pkg: AuthPluginPackage, user: RemoteUser, callback: Callback): void;
+ add_user(user: string, password: string, cb: Callback): any;
+}
diff --git a/packages/core/types/src/plugins/commons.ts b/packages/core/types/src/plugins/commons.ts
new file mode 100644
index 000000000..6d415ce2a
--- /dev/null
+++ b/packages/core/types/src/plugins/commons.ts
@@ -0,0 +1,15 @@
+import { Config, Logger } from '../configuration';
+
+export class Plugin {
+ public constructor(config: T, options: PluginOptions) {}
+}
+
+export interface IPlugin {
+ // TODO: not used on core yet
+ version?: string;
+}
+
+export interface PluginOptions {
+ config: T & Config;
+ logger: Logger;
+}
diff --git a/packages/core/types/src/plugins/filter.ts b/packages/core/types/src/plugins/filter.ts
new file mode 100644
index 000000000..2c8bc1315
--- /dev/null
+++ b/packages/core/types/src/plugins/filter.ts
@@ -0,0 +1,6 @@
+import { Manifest } from '../manifest';
+import { IPlugin } from './commons';
+
+export interface IPluginStorageFilter extends IPlugin {
+ filter_metadata(packageInfo: Manifest): Promise;
+}
diff --git a/packages/core/types/src/plugins/index.ts b/packages/core/types/src/plugins/index.ts
new file mode 100644
index 000000000..a94492efb
--- /dev/null
+++ b/packages/core/types/src/plugins/index.ts
@@ -0,0 +1,31 @@
+import { RemoteUser } from '../commons';
+import { AllowAccess } from '../configuration';
+import { PackageAccess } from '../manifest';
+import { AuthAccessCallback, AuthCallback } from './auth';
+import { IPlugin } from './commons';
+
+export interface IPluginAuth extends IPlugin {
+ /**
+ * @param props user from Application component
+ */
+ authenticate(user: string, password: string, cb: AuthCallback): void;
+ adduser?(user: string, password: string, cb: AuthCallback): void;
+ changePassword?(user: string, password: string, newPassword: string, cb: AuthCallback): void;
+ allow_publish?(user: RemoteUser, pkg: T & PackageAccess, cb: AuthAccessCallback): void;
+ allow_access?(user: RemoteUser, pkg: T & PackageAccess, cb: AuthAccessCallback): void;
+ allow_unpublish?(user: RemoteUser, pkg: T & PackageAccess, cb: AuthAccessCallback): void;
+ allow_publish?(user: RemoteUser, pkg: AllowAccess & PackageAccess, cb: AuthAccessCallback): void;
+ allow_access?(user: RemoteUser, pkg: AllowAccess & PackageAccess, cb: AuthAccessCallback): void;
+ allow_unpublish?(
+ user: RemoteUser,
+ pkg: AllowAccess & PackageAccess,
+ cb: AuthAccessCallback
+ ): void;
+ apiJWTmiddleware?(helpers: any): Function;
+}
+
+export * from './auth';
+export * from './storage';
+export * from './middleware';
+export * from './commons';
+export * from './filter';
diff --git a/packages/core/types/src/plugins/middleware.ts b/packages/core/types/src/plugins/middleware.ts
new file mode 100644
index 000000000..fb71c76a7
--- /dev/null
+++ b/packages/core/types/src/plugins/middleware.ts
@@ -0,0 +1,8 @@
+import { Config } from '../configuration';
+import { IBasicAuth } from './auth';
+import { IPlugin } from './commons';
+
+// TODO: convert to generic storage should come from implementation
+export interface IPluginMiddleware extends IPlugin {
+ register_middlewares(app: any, auth: IBasicAuth, storage: K): void;
+}
diff --git a/packages/core/types/src/plugins/storage.ts b/packages/core/types/src/plugins/storage.ts
new file mode 100644
index 000000000..595e587c6
--- /dev/null
+++ b/packages/core/types/src/plugins/storage.ts
@@ -0,0 +1,95 @@
+import { PassThrough, PipelinePromise, Readable, Stream, Writable } from 'stream';
+
+import { Callback, CallbackAction, StringValue } from '../commons';
+import { Config, Logger } from '../configuration';
+import { Manifest, MergeTags, Token, Version } from '../manifest';
+import { IPlugin } from './commons';
+
+export type StorageList = string[];
+
+export interface LocalStorage {
+ list: any;
+ secret: string;
+}
+
+export interface ILocalStorage {
+ add(name: string): void;
+ remove(name: string): void;
+ get(): StorageList;
+ sync(): void;
+}
+
+export interface TokenFilter {
+ user: string;
+}
+
+export interface ITokenActions {
+ saveToken(token: Token): Promise;
+ deleteToken(user: string, tokenKey: string): Promise;
+ readTokens(filter: TokenFilter): Promise;
+}
+
+/**
+ * This method expect return a Package object
+ * eg:
+ * {
+ * name: string;
+ * time: number;
+ * ... and other props
+ * }
+ *
+ * The `cb` callback object will be executed if:
+ * - it might return object (truly)
+ * - it might reutrn null
+ */
+export type onSearchPackage = (item: Manifest, cb: CallbackAction) => void;
+// FIXME: error should be export type `VerdaccioError = HttpError & { code: number };`
+// but this type is on @verdaccio/commons-api and cannot be used here yet
+export type onEndSearchPackage = (error?: any) => void;
+export type onValidatePackage = (name: string) => boolean;
+
+export type StorageUpdateCallback = (data: Manifest, cb: CallbackAction) => void;
+
+export type StorageWriteCallback = (name: string, json: Manifest, callback: Callback) => void;
+export type PackageTransformer = (pkg: Manifest) => Manifest;
+export type ReadPackageCallback = (err: any | null, data?: Manifest) => void;
+
+export interface ILocalPackageManager {
+ logger: Logger;
+ deletePackage(fileName: string): Promise;
+ removePackage(): Promise;
+ // next packages migration (this list is meant to replace the callback parent functions)
+ updatePackage(
+ packageName: string,
+ handleUpdate: (manifest: Manifest) => Promise
+ ): Promise;
+ readPackage(name: string): Promise;
+ savePackage(pkgName: string, value: Manifest): Promise;
+ readTarball(pkgName: string, { signal }): Promise;
+ createPackage(name: string, manifest: Manifest): Promise;
+ writeTarball(tarballName: string, { signal }): Promise;
+ // verify if tarball exist in the storage
+ hasTarball(fileName: string): Promise;
+ // verify if package exist in the storage
+ hasPackage(): Promise;
+}
+
+export type IPackageStorage = ILocalPackageManager | void;
+
+export type IPluginStorage = ILocalData;
+export type IPackageStorageManager = ILocalPackageManager;
+
+/**
+ * @deprecated use @verdaccio/core pluginUtils instead
+ */
+interface ILocalData extends IPlugin, ITokenActions {
+ logger: Logger;
+ config: T & Config;
+ add(name: string): Promise;
+ remove(name: string): Promise;
+ get(): Promise;
+ init(): Promise;
+ getSecret(): Promise;
+ setSecret(secret: string): Promise;
+ getPackageStorage(packageInfo: string): IPackageStorage;
+}
diff --git a/packages/core/types/src/plugins/theme.ts b/packages/core/types/src/plugins/theme.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/core/types/src/search.ts b/packages/core/types/src/search.ts
new file mode 100644
index 000000000..d1e04af2e
--- /dev/null
+++ b/packages/core/types/src/search.ts
@@ -0,0 +1,28 @@
+export type PublisherMaintainer = {
+ username: string;
+ email: string;
+};
+
+export type SearchPackageBody = {
+ name: string;
+ scope: string;
+ description: string;
+ author: string | PublisherMaintainer;
+ version: string;
+ keywords: string | string[] | undefined;
+ date: string;
+ links?: {
+ npm: string; // only include placeholder for URL eg: {url}/{packageName}
+ homepage?: string;
+ repository?: string;
+ bugs?: string;
+ };
+ publisher?: any;
+ maintainers?: PublisherMaintainer[];
+};
+
+export type SearchResultWeb = {
+ name: string;
+ version: string;
+ description: string;
+};
diff --git a/packages/core/types/src/types.ts b/packages/core/types/src/types.ts
new file mode 100644
index 000000000..20d526d5e
--- /dev/null
+++ b/packages/core/types/src/types.ts
@@ -0,0 +1,5 @@
+export * from './plugins';
+export * from './manifest';
+export * from './search';
+export * from './commons';
+export * from './configuration';
diff --git a/packages/core/types/tsconfig.build.json b/packages/core/types/tsconfig.build.json
new file mode 100644
index 000000000..79f1f81e0
--- /dev/null
+++ b/packages/core/types/tsconfig.build.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "compilerOptions": {
+ "rootDir": "./src",
+ "outDir": "./build"
+ },
+ "include": ["src/**/*"],
+ "exclude": ["src/**/*.test.ts"]
+}
diff --git a/packages/core/types/tsconfig.json b/packages/core/types/tsconfig.json
new file mode 100644
index 000000000..35b3cee58
--- /dev/null
+++ b/packages/core/types/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../../tsconfig.reference.json",
+ "compilerOptions": {
+ "rootDir": "./src",
+ "outDir": "./build"
+ },
+ "include": ["src/**/*"],
+ "exclude": ["src/**/*.test.ts"]
+}
diff --git a/packages/core/types/typedoc.json b/packages/core/types/typedoc.json
new file mode 100644
index 000000000..3e320f069
--- /dev/null
+++ b/packages/core/types/typedoc.json
@@ -0,0 +1,5 @@
+{
+ "$schema": "https://typedoc.org/schema.json",
+ "entryPoints": ["src/types.ts"],
+ "sort": ["source-order"]
+}
diff --git a/packages/logger-prettify/jest.config.js b/packages/logger-prettify/jest.config.js
index 7da7d2da8..44aa5663a 100644
--- a/packages/logger-prettify/jest.config.js
+++ b/packages/logger-prettify/jest.config.js
@@ -1,3 +1,10 @@
const config = require('../../jest/config');
-module.exports = Object.assign({}, config, {});
+module.exports = Object.assign({}, config, {
+ coverageThreshold: {
+ global: {
+ // FIXME: increase to 90
+ lines: 60,
+ },
+ },
+});
diff --git a/packages/logger-prettify/package.json b/packages/logger-prettify/package.json
index 5c838f45b..590e07699 100644
--- a/packages/logger-prettify/package.json
+++ b/packages/logger-prettify/package.json
@@ -31,7 +31,7 @@
},
"scripts": {
"clean": "rimraf ./build",
- "test": "jest",
+ "test": "cross-env TZ=utc jest",
"type-check": "tsc --noEmit -p tsconfig.build.json",
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
@@ -40,13 +40,13 @@
},
"dependencies": {
"dayjs": "1.11.4",
- "fast-safe-stringify": "2.1.1",
- "kleur": "3.0.3",
+ "pino-abstract-transport": "1.0.0",
+ "colorette": "2.0.7",
"lodash": "4.17.21",
- "prettier-bytes": "1.0.4"
+ "sonic-boom": "3.2.0"
},
"devDependencies": {
- "pino": "7.11.0"
+ "pino": "8.4.1"
},
"funding": {
"type": "opencollective",
diff --git a/packages/logger-prettify/src/formatter.ts b/packages/logger-prettify/src/formatter.ts
index ff1a5d8d1..601cd8c08 100644
--- a/packages/logger-prettify/src/formatter.ts
+++ b/packages/logger-prettify/src/formatter.ts
@@ -1,4 +1,4 @@
-import { green, red, white } from 'kleur';
+import { green, red, white } from 'colorette';
import { inspect } from 'util';
import { LevelCode, calculateLevel, levelsColors, subSystemLevels } from './levels';
@@ -19,7 +19,11 @@ export interface ObjectTemplate {
[key: string]: string | number | object | null | void;
}
-export function fillInMsgTemplate(msg, templateOptions: ObjectTemplate, colors): string {
+export function fillInMsgTemplate(
+ msg: string,
+ templateOptions: ObjectTemplate,
+ colors: boolean
+): string {
const templateRegex = /@{(!?[$A-Za-z_][$0-9A-Za-z\._]*)}/g;
return msg.replace(templateRegex, (_, name): string => {
@@ -53,10 +57,12 @@ export function fillInMsgTemplate(msg, templateOptions: ObjectTemplate, colors):
});
}
-function getMessage(debugLevel, msg, sub, templateObjects, hasColors) {
+function getMessage(debugLevel, msg, sub, templateObjects, hasColors: boolean) {
const finalMessage = fillInMsgTemplate(msg, templateObjects, hasColors);
- const subSystemType = subSystemLevels.color[sub ?? 'default'];
+ const subSystemType = hasColors
+ ? subSystemLevels.color[sub ?? 'default']
+ : subSystemLevels.white[sub ?? 'default'];
if (hasColors) {
const logString = `${levelsColors[debugLevel](padRight(debugLevel, LEVEL_VALUE_MAX))}${white(
`${subSystemType} ${finalMessage}`
@@ -71,8 +77,8 @@ function getMessage(debugLevel, msg, sub, templateObjects, hasColors) {
export function printMessage(
templateObjects: ObjectTemplate,
- options: PrettyOptionsExtended,
- hasColors = true
+ options: Pick,
+ hasColors: boolean
): string {
const { prettyStamp } = options;
const { level, msg, sub } = templateObjects;
diff --git a/packages/logger-prettify/src/index.ts b/packages/logger-prettify/src/index.ts
index efbc0ec09..2e02f5dfe 100644
--- a/packages/logger-prettify/src/index.ts
+++ b/packages/logger-prettify/src/index.ts
@@ -1,20 +1,2 @@
-import { fillInMsgTemplate, printMessage } from './formatter';
-import { PrettyOptionsExtended } from './types';
-
-export { fillInMsgTemplate };
-
-export type PrettyFactory = (param) => string;
-
-/*
- options eg:
- { messageKey: 'msg', levelFirst: true, prettyStamp: false }
- */
-
-export default function prettyFactory(options: PrettyOptionsExtended): PrettyFactory {
- // the break line must happens in the prettify component
- const breakLike = '\n';
- return (inputData): string => {
- // FIXME: review colors by default is true
- return printMessage(inputData, options, true) + breakLike;
- };
-}
+export { default, buildPretty } from './prettify';
+export { fillInMsgTemplate } from './formatter';
diff --git a/packages/logger-prettify/src/levels.ts b/packages/logger-prettify/src/levels.ts
index c6b6f2ef5..03a2514c8 100644
--- a/packages/logger-prettify/src/levels.ts
+++ b/packages/logger-prettify/src/levels.ts
@@ -53,6 +53,7 @@ export const subSystemLevels = {
white: {
in: ARROWS.LEFT,
out: ARROWS.RIGHT,
+ auth: ARROWS.NEUTRAL,
fs: ARROWS.EQUAL,
default: ARROWS.NEUTRAL,
},
diff --git a/packages/logger-prettify/src/prettify.ts b/packages/logger-prettify/src/prettify.ts
new file mode 100644
index 000000000..cb444c585
--- /dev/null
+++ b/packages/logger-prettify/src/prettify.ts
@@ -0,0 +1,118 @@
+import { isColorSupported } from 'colorette';
+import { WriteStream } from 'fs';
+import build from 'pino-abstract-transport';
+import SonicBoom, { SonicBoomOpts } from 'sonic-boom';
+import { Transform, pipeline } from 'stream';
+import { isMainThread } from 'worker_threads';
+
+import { fillInMsgTemplate, printMessage } from './formatter';
+import { PrettyOptionsExtended } from './types';
+
+export { fillInMsgTemplate };
+
+function noop() {}
+
+/**
+ * Creates a safe SonicBoom instance
+ *
+ * @param {object} opts Options for SonicBoom
+ *
+ * @returns {object} A new SonicBoom stream
+ */
+function buildSafeSonicBoom(opts: SonicBoomOpts) {
+ const stream = new SonicBoom(opts);
+ stream.on('error', filterBrokenPipe);
+ if (!opts.sync && isMainThread) {
+ setupOnExit(stream);
+ }
+ return stream;
+
+ function filterBrokenPipe(err) {
+ if (err.code === 'EPIPE') {
+ // @ts-ignore
+ stream.write = noop;
+ stream.end = noop;
+ stream.flushSync = noop;
+ stream.destroy = noop;
+ return;
+ }
+ stream.removeListener('error', filterBrokenPipe);
+ }
+}
+
+function setupOnExit(stream) {
+ /* istanbul ignore next */
+ if (global.WeakRef && global.WeakMap && global.FinalizationRegistry) {
+ // This is leak free, it does not leave event handlers
+ const onExit = require('on-exit-leak-free');
+
+ onExit.register(stream, autoEnd);
+
+ stream.on('close', function () {
+ onExit.unregister(stream);
+ });
+ }
+}
+
+/* istanbul ignore next */
+function autoEnd(stream, eventName) {
+ // This check is needed only on some platforms
+
+ if (stream.destroyed) {
+ return;
+ }
+
+ if (eventName === 'beforeExit') {
+ // We still have an event loop, let's use it
+ stream.flush();
+ stream.on('drain', function () {
+ stream.end();
+ });
+ } else {
+ // We do not have an event loop, so flush synchronously
+ stream.flushSync();
+ }
+}
+
+export function hasColors(colors: boolean | undefined) {
+ if (colors) {
+ return isColorSupported;
+ }
+ return typeof colors === 'undefined' ? true : colors;
+}
+
+export function buildPretty(opts: PrettyOptionsExtended) {
+ return (chunk) => {
+ const colors = hasColors(opts.colors);
+ return printMessage(chunk, { prettyStamp: opts.prettyStamp }, colors);
+ };
+}
+
+export default function (opts) {
+ const pretty = buildPretty(opts);
+ // @ts-ignore
+ return build(function (source) {
+ const stream = new Transform({
+ objectMode: true,
+ autoDestroy: true,
+ transform(chunk, enc, cb) {
+ const line = pretty(chunk) + '\n';
+ cb(null, line);
+ },
+ });
+ const destination = buildSafeSonicBoom({
+ dest: opts.destination || 1,
+ sync: opts.sync || true,
+ }) as unknown as WriteStream;
+
+ source.on('unknown', function (line) {
+ destination.write(line + '\n');
+ });
+
+ pipeline(source, stream, destination, (err) => {
+ // eslint-disable-next-line no-console
+ console.error('prettify pipeline error ', err);
+ });
+ return stream;
+ });
+}
diff --git a/packages/logger-prettify/src/types.ts b/packages/logger-prettify/src/types.ts
index e41d4b765..cbf1a0e5e 100644
--- a/packages/logger-prettify/src/types.ts
+++ b/packages/logger-prettify/src/types.ts
@@ -2,4 +2,5 @@ import { PrettyOptions } from 'pino';
export interface PrettyOptionsExtended extends PrettyOptions {
prettyStamp: boolean;
+ colors?: boolean;
}
diff --git a/packages/logger-prettify/src/utils.ts b/packages/logger-prettify/src/utils.ts
index 0fe1460da..16b1e6d31 100644
--- a/packages/logger-prettify/src/utils.ts
+++ b/packages/logger-prettify/src/utils.ts
@@ -16,7 +16,7 @@ export function padRight(message: string, max = message.length + CUSTOM_PAD_LENG
return message.padEnd(max, ' ');
}
-export function formatLoggingDate(time: number, message): string {
+export function formatLoggingDate(time: number, message: string): string {
const timeFormatted = dayjs(time).format(FORMAT_DATE);
return `[${timeFormatted}]${message}`;
diff --git a/packages/logger-prettify/test/__snapshots__/formatter.spec.ts.snap b/packages/logger-prettify/test/__snapshots__/formatter.spec.ts.snap
index 6d335d769..5fdc83f08 100644
--- a/packages/logger-prettify/test/__snapshots__/formatter.spec.ts.snap
+++ b/packages/logger-prettify/test/__snapshots__/formatter.spec.ts.snap
@@ -1,21 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`formatter printMessage should display a bytes request 1`] = `" [31mfatal[39m[37m[32m<--[39m[37m [33m200[39m[37m, user: [1mnull[22m([32m127.0.0.1[39m[37m), req: '[32mGET[39m[37m [32m/verdaccio[39m[37m', bytes: [33m0[39m[37m/[33m150186[39m[37m[39m"`;
+exports[`formatter printMessage should display a bytes request 1`] = `"fatal<-- 200, user: null(127.0.0.1), req: 'GET /verdaccio', bytes: 0/150186 "`;
-exports[`formatter printMessage should display a resource request 1`] = `"info [32m<--[39m 127.0.0.1 requested 'GET /verdaccio' "`;
+exports[`formatter printMessage should display a resource request 1`] = `"info <-- 127.0.0.1 requested 'GET /verdaccio' "`;
-exports[`formatter printMessage should display a streaming request 1`] = `" [31mfatal[39m[37m[33m-->[39m[37m [33m304[39m[37m, req: '[32mGET[39m[37m [32mhttps://registry.npmjs.org/verdaccio[39m[37m' (streaming)[39m"`;
+exports[`formatter printMessage should display a streaming request 1`] = `"fatal--> 304, req: 'GET https://registry.npmjs.org/verdaccio' (streaming) "`;
-exports[`formatter printMessage should display an error request 1`] = `" [31mfatal[39m[37m[33m-->[39m[37m [31mERR[39m[37m, req: '[32mGET[39m[37m [32mhttps://registry.fake.org/aaa[39m[37m', error: [31mgetaddrinfo ENOTFOUND registry.fake.org[39m[37m[39m"`;
+exports[`formatter printMessage should display an error request 1`] = `"fatal--> ERR, req: 'GET https://registry.fake.org/aaa', error: getaddrinfo ENOTFOUND registry.fake.org "`;
-exports[`formatter printMessage should display an fatal request 1`] = `" [31mfatal[39m[37m[33m-->[39m[37m [31mERR[39m[37m, req: '[32mGET[39m[37m [32mhttps://registry.fake.org/aaa[39m[37m', error: [31mfatal error[39m[37m[39m"`;
+exports[`formatter printMessage should display an fatal request 1`] = `"fatal--> ERR, req: 'GET https://registry.fake.org/aaa', error: fatal error "`;
-exports[`formatter printMessage should display config file 1`] = `" [33mwarn [39m[37m[34m---[39m[37m config file - [32m/Users/user/.config/verdaccio/config/config.yaml[39m[37m[39m"`;
+exports[`formatter printMessage should display config file 1`] = `"warn --- config file - /Users/user/.config/verdaccio/config/config.yaml "`;
-exports[`formatter printMessage should display custom log message 1`] = `" [31mfatal[39m[37m[34m---[39m[37m custom - [32mfoo[39m[37m - [90mundefined[39m[37m[39m"`;
+exports[`formatter printMessage should display custom log message 1`] = `"fatal--- custom - foo - undefined "`;
-exports[`formatter printMessage should display trace level 1`] = `" [37mtrace[39m[37m[34m---[39m[37m [trace] - [32mfoo[39m[37m[39m"`;
+exports[`formatter printMessage should display trace level 1`] = `"trace--- [trace] - foo "`;
-exports[`formatter printMessage should display trace level with pretty stamp 1`] = `"[formatted-date] [37mtrace[39m[37m[34m---[39m[37m [trace] - [32mfoo[39m[37m[39m"`;
+exports[`formatter printMessage should display trace level with pretty stamp 1`] = `"[formatted-date]trace--- [trace] - foo "`;
-exports[`formatter printMessage should display version and http address 1`] = `" [33mwarn [39m[37m[34m---[39m[37m http address - [32mhttp://localhost:4873/[39m[37m - [32mverdaccio/5.0.0[39m[37m[39m"`;
+exports[`formatter printMessage should display version and http address 1`] = `"warn --- http address - http://localhost:4873/ - verdaccio/5.0.0 "`;
diff --git a/packages/logger-prettify/test/__snapshots__/index.spec.ts.snap b/packages/logger-prettify/test/__snapshots__/index.spec.ts.snap
deleted file mode 100644
index 8ef4256c0..000000000
--- a/packages/logger-prettify/test/__snapshots__/index.spec.ts.snap
+++ /dev/null
@@ -1,6 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`prettyFactory should return a function with options 1`] = `
-" [37mtrace[39m[37m[34m---[39m[37m [trace] - [32mfoo[39m[37m[39m
-"
-`;
diff --git a/packages/logger-prettify/test/formatter.spec.ts b/packages/logger-prettify/test/formatter.spec.ts
index a22eba88c..1f4d011d7 100644
--- a/packages/logger-prettify/test/formatter.spec.ts
+++ b/packages/logger-prettify/test/formatter.spec.ts
@@ -22,7 +22,7 @@ describe('formatter', () => {
msg: 'config file - @{file}',
};
- expect(printMessage(log, prettyfierOptions)).toMatchSnapshot();
+ expect(printMessage(log, prettyfierOptions, false)).toMatchSnapshot();
});
test('should display trace level', () => {
@@ -32,7 +32,7 @@ describe('formatter', () => {
msg: '[trace] - @{foo}',
};
- expect(printMessage(log, prettyfierOptions)).toMatchSnapshot();
+ expect(printMessage(log, prettyfierOptions, false)).toMatchSnapshot();
});
test('should display trace level with pretty stamp', () => {
@@ -48,7 +48,8 @@ describe('formatter', () => {
log,
Object.assign({}, prettyfierOptions, {
prettyStamp: true,
- })
+ }),
+ false
)
).toMatchSnapshot();
});
@@ -72,7 +73,7 @@ describe('formatter', () => {
'bytes: @{bytes.in}/@{bytes.out}',
};
- expect(printMessage(log, prettyfierOptions)).toMatchSnapshot();
+ expect(printMessage(log, prettyfierOptions, false)).toMatchSnapshot();
});
test('should display an error request', () => {
@@ -101,7 +102,7 @@ describe('formatter', () => {
msg: "@{!status}, req: '@{request.method} @{request.url}', error: @{!error}",
};
- expect(printMessage(log, prettyfierOptions)).toMatchSnapshot();
+ expect(printMessage(log, prettyfierOptions, false)).toMatchSnapshot();
});
test('should display an fatal request', () => {
@@ -126,7 +127,7 @@ describe('formatter', () => {
msg: "@{!status}, req: '@{request.method} @{request.url}', error: @{!error}",
};
- expect(printMessage(log, prettyfierOptions)).toMatchSnapshot();
+ expect(printMessage(log, prettyfierOptions, false)).toMatchSnapshot();
});
test('should display a streaming request', () => {
@@ -142,7 +143,7 @@ describe('formatter', () => {
msg: "@{!status}, req: '@{request.method} @{request.url}' (streaming)",
};
- expect(printMessage(log, prettyfierOptions)).toMatchSnapshot();
+ expect(printMessage(log, prettyfierOptions, false)).toMatchSnapshot();
});
test('should display version and http address', () => {
@@ -157,7 +158,7 @@ describe('formatter', () => {
msg: 'http address - @{addr} - @{version}',
};
- expect(printMessage(log, prettyfierOptions)).toMatchSnapshot();
+ expect(printMessage(log, prettyfierOptions, false)).toMatchSnapshot();
});
test('should display custom log message', () => {
@@ -168,7 +169,7 @@ describe('formatter', () => {
msg: 'custom - @{something} - @{missingParam}',
};
- expect(printMessage(log, prettyfierOptions)).toMatchSnapshot();
+ expect(printMessage(log, prettyfierOptions, false)).toMatchSnapshot();
});
test('should display a resource request', () => {
diff --git a/packages/logger-prettify/test/index.spec.ts b/packages/logger-prettify/test/index.spec.ts
index 3f7c388f1..898777b8b 100644
--- a/packages/logger-prettify/test/index.spec.ts
+++ b/packages/logger-prettify/test/index.spec.ts
@@ -1,18 +1,28 @@
-import * as factory from '../src';
+import pino from 'pino';
+import { Writable } from 'stream';
+
+import { buildPretty } from '../src';
describe('prettyFactory', () => {
- const prettyfierOptions = { messageKey: 'msg', levelFirst: true, prettyStamp: false };
- test('should return a function', () => {
- expect(typeof factory['default']({})).toEqual('function');
- });
-
- test('should return a function with options', () => {
- const log = {
- level: 10,
- foo: 'foo',
- msg: '[trace] - @{foo}',
- };
-
- expect(factory['default'](prettyfierOptions)(log)).toMatchSnapshot();
+ const prettyfierOptions = {
+ messageKey: 'msg',
+ levelFirst: true,
+ prettyStamp: false,
+ colors: false,
+ };
+ test('should return a function', (done) => {
+ const pretty = buildPretty(prettyfierOptions);
+ const log = pino(
+ new Writable({
+ objectMode: true,
+ write(chunk, enc, cb) {
+ const formatted = pretty(JSON.parse(chunk));
+ expect(formatted).toBe('info --- test message ');
+ cb();
+ done();
+ },
+ })
+ );
+ log.info({ test: 'test' }, '@{test} message');
});
});
diff --git a/packages/logger-prettify/test/utils.test.ts b/packages/logger-prettify/test/utils.test.ts
new file mode 100644
index 000000000..c12ba8265
--- /dev/null
+++ b/packages/logger-prettify/test/utils.test.ts
@@ -0,0 +1,20 @@
+import { formatLoggingDate, padLeft, padRight } from '../src/utils';
+
+describe('formatLoggingDate', () => {
+ test('basic', () => {
+ expect(formatLoggingDate(1585411248203, ' message')).toEqual('[2020-03-28 16:00:48] message');
+ });
+});
+
+describe('pad', () => {
+ test('pad right with custom length', () => {
+ expect(padRight('message right', 20)).toEqual('message right ');
+ });
+
+ test('pad right 2', () => {
+ expect(padRight('message right')).toEqual('message right ');
+ });
+ test('pad left', () => {
+ expect(padLeft('message left')).toEqual(' message left');
+ });
+});
diff --git a/packages/logger/package.json b/packages/logger/package.json
index dd4646a85..0a417fb7e 100644
--- a/packages/logger/package.json
+++ b/packages/logger/package.json
@@ -31,7 +31,7 @@
},
"scripts": {
"clean": "rimraf ./build",
- "test": "jest",
+ "test": "cross-env TZ=utc jest",
"type-check": "tsc --noEmit -p tsconfig.build.json",
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
@@ -41,10 +41,9 @@
"dependencies": {
"@verdaccio/core": "workspace:6.0.0-6-next.5",
"@verdaccio/logger-prettify": "workspace:6.0.0-6-next.6",
- "pino-pretty": "7.6.1",
"debug": "4.3.4",
- "lodash": "4.17.21",
- "pino": "7.11.0"
+ "colorette": "2.0.7",
+ "pino": "8.4.1"
},
"devDependencies": {
"@verdaccio/types": "workspace:11.0.0-6-next.12"
diff --git a/packages/logger/src/index.ts b/packages/logger/src/index.ts
index 43fa3a9d0..45f5e8114 100644
--- a/packages/logger/src/index.ts
+++ b/packages/logger/src/index.ts
@@ -1 +1 @@
-export { setup, createLogger, logger, LoggerConfigItem } from './logger';
+export { setup, createLogger, logger, prepareSetup } from './logger';
diff --git a/packages/logger/src/logger.ts b/packages/logger/src/logger.ts
index 3b8b59dba..f57e82eec 100644
--- a/packages/logger/src/logger.ts
+++ b/packages/logger/src/logger.ts
@@ -1,18 +1,24 @@
+//
+import { isColorSupported } from 'colorette';
import buildDebug from 'debug';
-import _ from 'lodash';
-import pino from 'pino';
+import pino, { Logger } from 'pino';
-import { warningUtils } from '@verdaccio/core';
-import prettifier, { fillInMsgTemplate } from '@verdaccio/logger-prettify';
+import { fillInMsgTemplate } from '@verdaccio/logger-prettify';
+import { LoggerConfigItem, LoggerFormat } from '@verdaccio/types';
const debug = buildDebug('verdaccio:logger');
-export let logger;
-
function isProd() {
return process.env.NODE_ENV === 'production';
}
+function hasColors(colors: boolean | undefined) {
+ if (colors) {
+ return isColorSupported;
+ }
+ return typeof colors === 'undefined' ? true : colors;
+}
+
const DEFAULT_LOG_FORMAT = isProd() ? 'json' : 'pretty';
export type LogPlugin = {
@@ -20,28 +26,19 @@ export type LogPlugin = {
options?: any[];
};
-export type LogType = 'file' | 'stdout';
-export type LogFormat = 'json' | 'pretty-timestamped' | 'pretty';
+type LoggerOptions = { level?: string; path?: string; colors?: boolean; sync?: boolean };
export function createLogger(
- options = { level: 'http' },
- destination = pino.destination(1),
- prettyPrintOptions = {
- // we hide warning since the prettifier should not be used in production
- // https://getpino.io/#/docs/pretty?id=prettifier-api
- suppressFlushSyncWarning: true,
- },
- format: LogFormat = DEFAULT_LOG_FORMAT
+ options: LoggerOptions = { level: 'http' },
+ // eslint-disable-next-line no-undef
+ destination: NodeJS.WritableStream = pino.destination(1),
+ format: LoggerFormat = DEFAULT_LOG_FORMAT
) {
- if (_.isNil(format)) {
- format = DEFAULT_LOG_FORMAT;
- }
-
+ debug('setup logger');
let pinoConfig = {
customLevels: {
http: 25,
},
- ...options,
level: options.level,
serializers: {
err: pino.stdSerializers.err,
@@ -52,23 +49,32 @@ export function createLogger(
debug('has prettifier? %o', !isProd());
// pretty logs are not allowed in production for performance reasons
- if ((format === DEFAULT_LOG_FORMAT || format !== 'json') && isProd() === false) {
+ if (['pretty-timestamped', 'pretty'].includes(format) && isProd() === false) {
pinoConfig = Object.assign({}, pinoConfig, {
- prettifier,
- // more info
- // https://github.com/pinojs/pino-pretty/issues/37
- prettyPrint: {
- levelFirst: true,
- prettyStamp: format === 'pretty-timestamped',
- ...prettyPrintOptions,
+ transport: {
+ target: '@verdaccio/logger-prettify',
+ options: {
+ // string or 1 (file descriptor for process.stdout)
+ destination: options.path || 1,
+ colors: hasColors(options.colors),
+ prettyStamp: format === 'pretty-timestamped',
+ },
},
});
} else {
- pinoConfig = Object.assign({}, pinoConfig, {
+ pinoConfig = {
+ ...pinoConfig,
// more info
// https://github.com/pinojs/pino/blob/v7.1.0/docs/api.md#hooks-object
+ // TODO: improve typings here
+ // @ts-ignore
hooks: {
- logMethod(inputArgs, method) {
+ logMethod(
+ inputArgs: [any, any, ...any[]],
+ method: {
+ apply: (arg0: { logMethod: (inputArgs: any, method: any) => any }, arg1: any[]) => any;
+ }
+ ) {
const [templateObject, message, ...otherArgs] = inputArgs;
const templateVars =
!!templateObject && typeof templateObject === 'object'
@@ -79,10 +85,12 @@ export function createLogger(
return method.apply(this, [templateObject, hydratedMessage, ...otherArgs]);
},
},
- });
+ };
}
const logger = pino(pinoConfig, destination);
+ /* eslint-disable */
+ /* istanbul ignore next */
if (process.env.DEBUG) {
logger.on('level-change', (lvl, val, prevLvl, prevVal) => {
debug('%s (%d) was changed to %s (%d)', lvl, val, prevLvl, prevVal);
@@ -92,34 +100,20 @@ export function createLogger(
return logger;
}
-export function getLogger() {
- if (_.isNil(logger)) {
- // FIXME: not sure about display here a warning
- warningUtils.emit(warningUtils.Codes.VERWAR002);
- return;
- }
-
- return logger;
-}
-
const DEFAULT_LOGGER_CONF: LoggerConfigItem = {
type: 'stdout',
format: 'pretty',
level: 'http',
};
-export type LoggerConfigItem = {
- type?: LogType;
- plugin?: LogPlugin;
- format?: LogFormat;
- path?: string;
- level?: string;
-};
-
export type LoggerConfig = LoggerConfigItem;
-export function setup(options: LoggerConfigItem = DEFAULT_LOGGER_CONF) {
- debug('setup logger');
+export function prepareSetup(options: LoggerConfigItem = DEFAULT_LOGGER_CONF) {
+ let logger: Logger<{
+ customLevels: { http: number };
+ level: string | undefined;
+ serializers: { err: any; req: any; res: any };
+ }>;
let loggerConfig = options;
if (!loggerConfig?.level) {
loggerConfig = Object.assign(
@@ -134,40 +128,35 @@ export function setup(options: LoggerConfigItem = DEFAULT_LOGGER_CONF) {
if (loggerConfig.type === 'file') {
debug('logging file enabled');
const destination = pino.destination(loggerConfig.path);
+ /* eslint-disable */
+ /* istanbul ignore next */
process.on('SIGUSR2', () => destination.reopen());
// @ts-ignore
- logger = createLogger(pinoConfig, destination, loggerConfig.format);
- // @ts-ignore
- } else if (loggerConfig.type === 'rotating-file') {
- warningUtils.emit(warningUtils.Codes.VERWAR003);
- debug('logging stdout enabled');
- // @ts-ignore
- logger = createLogger(pinoConfig, pino.destination(1), loggerConfig.format);
+ logger = createLogger(
+ { level: loggerConfig.level, path: loggerConfig.path, colors: loggerConfig.colors },
+ destination,
+ loggerConfig.format
+ );
+ return logger;
} else {
debug('logging stdout enabled');
// @ts-ignore
- logger = createLogger(pinoConfig, pino.destination(1), loggerConfig.format);
- }
-
- if (isProd()) {
- // why only on prod? https://github.com/pinojs/pino/issues/920#issuecomment-710807667
- const finalHandler = pino.final(logger, (err, finalLogger, event) => {
- finalLogger.info(`${event} caught`);
- if (err) {
- finalLogger.error(err, 'error caused exit');
- }
- process.exit(err ? 1 : 0);
- });
-
- process.on('uncaughtException', (err) => finalHandler(err, 'uncaughtException'));
- process.on('unhandledRejection', (err) => finalHandler(err as Error, 'unhandledRejection'));
- process.on('beforeExit', () => finalHandler(null, 'beforeExit'));
- process.on('exit', () => finalHandler(null, 'exit'));
- process.on('uncaughtException', (err) => finalHandler(err, 'uncaughtException'));
- process.on('SIGINT', () => finalHandler(null, 'SIGINT'));
- process.on('SIGQUIT', () => finalHandler(null, 'SIGQUIT'));
- process.on('SIGTERM', () => finalHandler(null, 'SIGTERM'));
+ logger = createLogger(
+ { level: loggerConfig.level, colors: loggerConfig.colors },
+ pino.destination(1),
+ loggerConfig.format
+ );
+ return logger;
+ }
+}
+
+export let logger: Logger;
+
+export function setup(options: LoggerConfigItem) {
+ if (typeof logger !== 'undefined') {
+ return logger;
}
+ logger = prepareSetup(options);
return logger;
}
diff --git a/packages/logger/test/createLogger.spec.ts b/packages/logger/test/createLogger.spec.ts
new file mode 100644
index 000000000..24cdc5670
--- /dev/null
+++ b/packages/logger/test/createLogger.spec.ts
@@ -0,0 +1,20 @@
+import { Writable } from 'stream';
+
+import { createLogger } from '../src';
+
+describe('logger test', () => {
+ describe('json format', () => {
+ test('should write json to a stream', () => {
+ const stream = new Writable({
+ write(chunk, encoding, callback) {
+ expect(JSON.parse(chunk.toString())).toEqual(
+ expect.objectContaining({ level: 30, msg: 'test' })
+ );
+ callback();
+ },
+ });
+ const logger = createLogger({ level: 'http' }, stream, 'json');
+ logger.info('test');
+ });
+ });
+});
diff --git a/packages/logger/test/logger.spec.ts b/packages/logger/test/logger.spec.ts
index 094c92d4d..f4d3bfeaa 100644
--- a/packages/logger/test/logger.spec.ts
+++ b/packages/logger/test/logger.spec.ts
@@ -1,51 +1,115 @@
-import { logger, setup } from '../src';
+import { readFile } from 'fs/promises';
+import { join } from 'path';
+import { setTimeout } from 'timers/promises';
-const mockWarningUtils = jest.fn();
+import { fileUtils } from '@verdaccio/core';
-jest.mock('@verdaccio/core', () => {
- const original = jest.requireActual('@verdaccio/core');
- return {
- warningUtils: {
- ...original.warningUtils,
- emit: (...args) => {
- mockWarningUtils(...args);
- },
- },
- };
-});
+import { prepareSetup } from '../src';
-describe('logger', () => {
- beforeEach(() => {
- jest.clearAllMocks();
+async function readLogFile(path: string) {
+ await setTimeout(1000, 'resolved');
+ return readFile(path, 'utf8');
+}
+
+async function createLogFile() {
+ const folder = await fileUtils.createTempFolder('logger-1');
+ const file = join(folder, 'logger.log');
+ return file;
+}
+
+const defaultOptions = {
+ format: 'json',
+ level: 'http',
+ colors: false,
+};
+
+describe('logger test', () => {
+ describe('basic', () => {
+ test('should include default level', async () => {
+ const file = await createLogFile();
+ const logger = prepareSetup({ type: 'file', path: file, colors: false });
+ logger.info({ packageName: 'test' }, `testing @{packageName}`);
+ // Note: this should not be logged
+ logger.debug(`this should not be logged`);
+ // Note: this should not be logged
+ logger.trace(`this should not be logged`);
+ logger.error(`this should logged`);
+ const content = await readLogFile(file);
+ expect(content).toBe('info --- testing test \nerror--- this should logged \n');
+ });
+
+ test('should include all logging level', async () => {
+ const file = await createLogFile();
+ const logger = prepareSetup({ type: 'file', level: 'trace', path: file, colors: false });
+ logger.info({ packageName: 'test' }, `testing @{packageName}`);
+ logger.debug(`this should not be logged`);
+ logger.trace(`this should not be logged`);
+ logger.error(`this should logged`);
+ const content = await readLogFile(file);
+ expect(content).toBe(
+ 'info --- testing test \ndebug--- this should not be logged \ntrace--- this should not be logged \nerror--- this should logged \n'
+ );
+ });
});
- test.skip('should write message logger', () => {
- jest.spyOn(process.stdout, 'write');
- setup([
- {
+ describe('json format', () => {
+ test('should log into a file with json format', async () => {
+ const file = await createLogFile();
+ const logger = prepareSetup({
+ ...defaultOptions,
+ format: 'json',
+ type: 'file',
+ path: file,
level: 'info',
- },
- ]);
-
- logger.info({ packageName: 'test' }, `publishing or updating a new version for @{packageName}`);
- // FIXME: check expect
- // expect(spyOn).toHaveBeenCalledTimes(2);
+ });
+ logger.info(
+ { packageName: 'test' },
+ `publishing or updating a new version for @{packageName}`
+ );
+ const content = await readLogFile(file);
+ expect(JSON.parse(content)).toEqual(
+ expect.objectContaining({
+ level: 30,
+ msg: 'publishing or updating a new version for test',
+ })
+ );
+ });
});
- test.skip('throw deprecation warning if multiple loggers configured', () => {
- setup([
- {
- level: 'info',
- },
- {
- level: 'http',
- },
- ]);
- // expect(mockWarningUtils).toHaveBeenCalledWith(warningUtils.Codes.VERDEP002);
- });
+ describe('pretty format', () => {
+ test('should log into a file with pretty', async () => {
+ const file = await createLogFile();
+ const logger = prepareSetup({
+ format: 'pretty',
+ type: 'file',
+ path: file,
+ level: 'trace',
+ colors: false,
+ });
+ logger.info(
+ { packageName: 'test' },
+ `publishing or updating a new version for @{packageName}`
+ );
+ const content = await readLogFile(file);
+ expect(content).toEqual('info --- publishing or updating a new version for test \n');
+ });
- test('regression: do not throw deprecation warning if no logger config is provided', () => {
- setup();
- expect(mockWarningUtils).not.toHaveBeenCalled();
+ test('should log into a file with pretty-timestamped', async () => {
+ const file = await createLogFile();
+ const logger = prepareSetup({
+ format: 'pretty-timestamped',
+ type: 'file',
+ path: file,
+ level: 'trace',
+ colors: false,
+ });
+ logger.info(
+ { packageName: 'test' },
+ `publishing or updating a new version for @{packageName}`
+ );
+ const content = await readLogFile(file);
+ // TODO: we might want mock time for testing
+ expect(content).toMatch('info --- publishing or updating a new version for test \n');
+ });
});
});
diff --git a/packages/plugins/audit/src/audit.ts b/packages/plugins/audit/src/audit.ts
index 21b367897..a27072e3a 100644
--- a/packages/plugins/audit/src/audit.ts
+++ b/packages/plugins/audit/src/audit.ts
@@ -11,7 +11,7 @@ import { ConfigAudit } from './types';
// FUTURE: we should be able to overwrite this
export const REGISTRY_DOMAIN = 'https://registry.npmjs.org';
-export default class ProxyAudit implements IPluginMiddleware<{}> {
+export default class ProxyAudit implements IPluginMiddleware<{}, {}> {
public enabled: boolean;
public logger: Logger;
public strict_ssl: boolean;
diff --git a/packages/tools/eslint/src/index.js b/packages/tools/eslint/src/index.js
index 942b8612c..e9679ff32 100644
--- a/packages/tools/eslint/src/index.js
+++ b/packages/tools/eslint/src/index.js
@@ -6,6 +6,7 @@ module.exports = {
},
globals: {
__APP_VERSION__: true,
+ NodeJS: true,
},
parserOptions: {
allowImportExportEverywhere: true,
diff --git a/packages/tools/mock/package.json b/packages/tools/mock/package.json
index f39067923..a2a732339 100644
--- a/packages/tools/mock/package.json
+++ b/packages/tools/mock/package.json
@@ -32,7 +32,7 @@
"types": "build/index.d.ts",
"scripts": {
"clean": "rimraf ./build",
- "test": "jest",
+ "test": "echo 0",
"type-check": "tsc --noEmit -p tsconfig.build.json",
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6d40cc157..243ebf884 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -381,10 +381,12 @@ importers:
packages/core/types:
specifiers:
'@types/node': 16.11.47
- tsd: 0.22.0
+ typedoc: beta
+ typedoc-plugin-missing-exports: 1.0.0
devDependencies:
'@types/node': 16.11.47
- tsd: 0.22.0
+ typedoc: 0.23.0-beta.7_typescript@4.7.4
+ typedoc-plugin-missing-exports: 1.0.0_typedoc@0.23.0-beta.7
packages/core/url:
specifiers:
@@ -452,36 +454,34 @@ importers:
'@verdaccio/core': workspace:6.0.0-6-next.5
'@verdaccio/logger-prettify': workspace:6.0.0-6-next.6
'@verdaccio/types': workspace:11.0.0-6-next.12
+ colorette: 2.0.7
debug: 4.3.4
- lodash: 4.17.21
- pino: 7.11.0
- pino-pretty: 7.6.1
+ pino: 8.4.1
dependencies:
'@verdaccio/core': link:../core/core
'@verdaccio/logger-prettify': link:../logger-prettify
+ colorette: 2.0.7
debug: 4.3.4
- lodash: 4.17.21
- pino: 7.11.0
- pino-pretty: 7.6.1
+ pino: 8.4.1
devDependencies:
'@verdaccio/types': link:../core/types
packages/logger-prettify:
specifiers:
+ colorette: 2.0.7
dayjs: 1.11.4
- fast-safe-stringify: 2.1.1
- kleur: 3.0.3
lodash: 4.17.21
- pino: 7.11.0
- prettier-bytes: 1.0.4
+ pino: 8.4.1
+ pino-abstract-transport: 1.0.0
+ sonic-boom: 3.2.0
dependencies:
+ colorette: 2.0.7
dayjs: 1.11.4
- fast-safe-stringify: 2.1.1
- kleur: 3.0.3
lodash: 4.17.21
- prettier-bytes: 1.0.4
+ pino-abstract-transport: 1.0.0
+ sonic-boom: 3.2.0
devDependencies:
- pino: 7.11.0
+ pino: 8.4.1
packages/middleware:
specifiers:
@@ -1291,7 +1291,7 @@ importers:
npm: next-8
dependencies:
'@verdaccio/test-cli-commons': link:../cli-commons
- npm: 8.16.0
+ npm: 8.18.0
test/cli/e2e-pnpm6:
specifiers:
@@ -1307,7 +1307,7 @@ importers:
pnpm: next-7
dependencies:
'@verdaccio/test-cli-commons': link:../cli-commons
- pnpm: 7.9.0
+ pnpm: 7.9.4-0
test/cli/e2e-yarn1:
specifiers:
@@ -7188,11 +7188,6 @@ packages:
/@tsconfig/node16/1.0.2:
resolution: {integrity: sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==}
- /@tsd/typescript/4.7.4:
- resolution: {integrity: sha512-jbtC+RgKZ9Kk65zuRZbKLTACf+tvFW4Rfq0JEMXrlmV3P3yme+Hm+pnb5fJRyt61SjIitcrC810wj7+1tgsEmg==}
- hasBin: true
- dev: true
-
/@types/aria-query/4.2.0:
resolution: {integrity: sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==}
dev: true
@@ -8587,16 +8582,6 @@ packages:
/argparse/2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
- /args/5.0.1:
- resolution: {integrity: sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==}
- engines: {node: '>= 6.0.0'}
- dependencies:
- camelcase: 5.0.0
- chalk: 2.4.2
- leven: 2.1.0
- mri: 1.1.4
- dev: false
-
/argv/0.0.2:
resolution: {integrity: sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=}
engines: {node: '>=0.6.10'}
@@ -9352,7 +9337,6 @@ packages:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
- dev: false
/braces/2.3.2:
resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==}
@@ -9558,11 +9542,6 @@ packages:
engines: {node: '>=4'}
dev: true
- /camelcase/5.0.0:
- resolution: {integrity: sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==}
- engines: {node: '>=6'}
- dev: false
-
/camelcase/5.3.1:
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
engines: {node: '>=6'}
@@ -9992,6 +9971,10 @@ packages:
/colorette/2.0.16:
resolution: {integrity: sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==}
+ /colorette/2.0.7:
+ resolution: {integrity: sha512-wSXeeDPxoi5xKvjvOGxyYlyqB3J+tbowaSsFm1rEsDsDE942aTLftbOE3XMqf3XaYC7QUtcd/3qadNAIEIsAYw==}
+ dev: false
+
/combine-promises/1.1.0:
resolution: {integrity: sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==}
engines: {node: '>=10'}
@@ -10962,10 +10945,6 @@ packages:
engines: {node: '>=0.11'}
dev: true
- /dateformat/4.6.3:
- resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
- dev: false
-
/dayjs/1.11.3:
resolution: {integrity: sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==}
dev: false
@@ -11586,14 +11565,6 @@ packages:
/duplexer3/0.1.4:
resolution: {integrity: sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=}
- /duplexify/4.1.2:
- resolution: {integrity: sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==}
- dependencies:
- end-of-stream: 1.4.4
- inherits: 2.0.4
- readable-stream: 3.6.0
- stream-shift: 1.0.1
-
/eastasianwidth/0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@@ -12202,20 +12173,6 @@ packages:
eslint: 8.21.0
dev: false
- /eslint-formatter-pretty/4.1.0:
- resolution: {integrity: sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==}
- engines: {node: '>=10'}
- dependencies:
- '@types/eslint': 7.28.2
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- eslint-rule-docs: 1.1.231
- log-symbols: 4.1.0
- plur: 4.0.0
- string-width: 4.2.3
- supports-hyperlinks: 2.2.0
- dev: true
-
/eslint-import-resolver-node/0.3.6:
resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==}
dependencies:
@@ -12405,10 +12362,6 @@ packages:
engines: {node: '>=4.0.0'}
dev: false
- /eslint-rule-docs/1.1.231:
- resolution: {integrity: sha512-egHz9A1WG7b8CS0x1P6P/Rj5FqZOjray/VjpJa14tMZalfRKvpE2ONJ3plCM7+PcinmU4tcmbPLv0VtwzSdLVA==}
- dev: true
-
/eslint-scope/5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'}
@@ -14640,11 +14593,6 @@ packages:
resolution: {integrity: sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==}
engines: {node: '>= 10'}
- /irregular-plurals/3.3.0:
- resolution: {integrity: sha512-MVBLKUTangM3EfRPFROhmWQQKRDsrgI83J8GS3jXy+OwYqiR2/aoWndYQ5416jLE3uaGgLH7ncme3X9y09gZ3g==}
- engines: {node: '>=8'}
- dev: true
-
/is-absolute-url/3.0.3:
resolution: {integrity: sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==}
engines: {node: '>=8'}
@@ -15607,11 +15555,6 @@ packages:
engines: {node: '>=10'}
dev: true
- /joycon/3.1.1:
- resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
- engines: {node: '>=10'}
- dev: false
-
/js-base64/3.7.2:
resolution: {integrity: sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==}
dev: true
@@ -15832,6 +15775,10 @@ packages:
engines: {node: '>=6'}
hasBin: true
+ /jsonc-parser/3.1.0:
+ resolution: {integrity: sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==}
+ dev: true
+
/jsonfile/4.0.0:
resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=}
optionalDependencies:
@@ -16124,11 +16071,6 @@ packages:
dependencies:
package-json: 6.5.0
- /leven/2.1.0:
- resolution: {integrity: sha1-wuep93IJTe6dNCAq6KzORoeHVYA=}
- engines: {node: '>=0.10.0'}
- dev: false
-
/leven/3.1.0:
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
engines: {node: '>=6'}
@@ -16506,7 +16448,6 @@ packages:
/lunr/2.3.9:
resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==}
- dev: false
/lz-string/1.4.4:
resolution: {integrity: sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=}
@@ -16582,7 +16523,6 @@ packages:
resolution: {integrity: sha512-wbLDJ7Zh0sqA0Vdg6aqlbT+yPxqLblpAZh1mK2+AO2twQkPywvvqQNfEPVwSSRjZ7dZcdeVBIAgiO7MMp3Dszw==}
engines: {node: '>= 12'}
hasBin: true
- dev: false
/mathml-tag-names/2.1.3:
resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
@@ -17270,7 +17210,6 @@ packages:
engines: {node: '>=10'}
dependencies:
brace-expansion: 2.0.1
- dev: false
/minimist-options/4.1.0:
resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
@@ -17331,11 +17270,6 @@ packages:
resolution: {integrity: sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==}
dev: false
- /mri/1.1.4:
- resolution: {integrity: sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==}
- engines: {node: '>=4'}
- dev: false
-
/mri/1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -17921,8 +17855,8 @@ packages:
- which
- write-file-atomic
- /npm/8.16.0:
- resolution: {integrity: sha512-UfLT/hCbcpV9uiTEBthyrOlQxwk8LG5tAGn283g7f7pRx41KcwFiHV7HYgYm2y2GabfnPtf897ptrXRQwxJWzQ==}
+ /npm/8.18.0:
+ resolution: {integrity: sha512-G07/yKvNUwhwxYhk8BxcuDPB/4s+y755i6CnH3lf9LQBHP5siUx66WbuNGWEnN3xaBER4+IR3OWApKX7eBO5Dw==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16}
hasBin: true
dev: false
@@ -18130,9 +18064,6 @@ packages:
/obuf/1.1.2:
resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
- /on-exit-leak-free/0.2.0:
- resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==}
-
/on-exit-leak-free/2.1.0:
resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==}
@@ -18560,47 +18491,22 @@ packages:
resolution: {integrity: sha1-clVrgM+g1IqXToDnckjoDtT3+HA=}
engines: {node: '>=0.10.0'}
- /pino-abstract-transport/0.5.0:
- resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==}
- dependencies:
- duplexify: 4.1.2
- split2: 4.1.0
-
/pino-abstract-transport/1.0.0:
resolution: {integrity: sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==}
dependencies:
readable-stream: 4.0.0
split2: 4.1.0
- /pino-pretty/7.6.1:
- resolution: {integrity: sha512-H7N6ZYkiyrfwBGW9CSjx0uyO9Q2Lyt73881+OTYk8v3TiTdgN92QHrWlEq/LeWw5XtDP64jeSk3mnc6T+xX9/w==}
- hasBin: true
- dependencies:
- args: 5.0.1
- colorette: 2.0.16
- dateformat: 4.6.3
- fast-safe-stringify: 2.1.1
- joycon: 3.1.1
- on-exit-leak-free: 0.2.0
- pino-abstract-transport: 0.5.0
- pump: 3.0.0
- readable-stream: 3.6.0
- rfdc: 1.3.0
- secure-json-parse: 2.4.0
- sonic-boom: 2.2.3
- strip-json-comments: 3.1.1
- dev: false
-
/pino-std-serializers/3.2.0:
resolution: {integrity: sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==}
dev: false
- /pino-std-serializers/4.0.0:
- resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==}
-
/pino-std-serializers/5.6.0:
resolution: {integrity: sha512-VdUXCw8gO+xhir7sFuoYSjTnzB+TMDGxhAC/ph3YS3sdHnXNdsK0wMtADNUltfeGkn2KDxEM21fnjF3RwXyC8A==}
+ /pino-std-serializers/6.0.0:
+ resolution: {integrity: sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ==}
+
/pino/6.14.0:
resolution: {integrity: sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==}
hasBin: true
@@ -18614,22 +18520,6 @@ packages:
sonic-boom: 1.1.0
dev: false
- /pino/7.11.0:
- resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==}
- hasBin: true
- dependencies:
- atomic-sleep: 1.0.0
- fast-redact: 3.1.1
- on-exit-leak-free: 0.2.0
- pino-abstract-transport: 0.5.0
- pino-std-serializers: 4.0.0
- process-warning: 1.0.0
- quick-format-unescaped: 4.0.3
- real-require: 0.1.0
- safe-stable-stringify: 2.3.1
- sonic-boom: 2.2.3
- thread-stream: 0.15.2
-
/pino/8.1.0:
resolution: {integrity: sha512-53jlxs+02UNTtF1XwVWfa0dHipBiM5GK73XhkHn8M2hUl9y3L94dNwB8BwQhpd5WdHjBkyJiO7v0LRt4SGgsPg==}
hasBin: true
@@ -18646,6 +18536,22 @@ packages:
sonic-boom: 3.0.0
thread-stream: 1.0.1
+ /pino/8.4.1:
+ resolution: {integrity: sha512-rZnbTUNFiYBH1H2OfYYVNBEFRDhN2nRaEmBD2+MDmGXSGyps+YPJ55LzWZP90zg7zyWKy0ZMqGlk47AO6OaBqQ==}
+ hasBin: true
+ dependencies:
+ atomic-sleep: 1.0.0
+ fast-redact: 3.1.1
+ on-exit-leak-free: 2.1.0
+ pino-abstract-transport: 1.0.0
+ pino-std-serializers: 6.0.0
+ process-warning: 2.0.0
+ quick-format-unescaped: 4.0.3
+ real-require: 0.2.0
+ safe-stable-stringify: 2.3.1
+ sonic-boom: 3.2.0
+ thread-stream: 2.0.1
+
/pirates/4.0.5:
resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
engines: {node: '>= 6'}
@@ -18679,21 +18585,14 @@ packages:
semver-compare: 1.0.0
dev: true
- /plur/4.0.0:
- resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==}
- engines: {node: '>=10'}
- dependencies:
- irregular-plurals: 3.3.0
- dev: true
-
/pnpm/6.34.0:
resolution: {integrity: sha512-K79DAT5WtGjrUyLtxAyehtN8uy5cXkzT1v+7RIJ3gygCffoLaLlBoG5gcfjfnX7oZH5rxznv/v8tlMIMfZyzTA==}
engines: {node: '>=12.17'}
hasBin: true
dev: false
- /pnpm/7.9.0:
- resolution: {integrity: sha512-xkIVw73yJm/h5M4VvFIS5Q+gQCRDrp3r92g58PtcCK86aZCa7EQ6q6ivdfTAz0KsAVgloA6Anub28n6wju5v3w==}
+ /pnpm/7.9.4-0:
+ resolution: {integrity: sha512-qTilkdOOxwKLXcH7eqReARfMetXZqfWoObZkJCYgPsKD+pJQS+IGuYf1S2w+J+/0Y5518icXnc+nZ6c0CX24Ew==}
engines: {node: '>=14.6'}
hasBin: true
dev: false
@@ -20383,6 +20282,10 @@ packages:
resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==}
engines: {node: '>= 12.13.0'}
+ /real-require/0.2.0:
+ resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
+ engines: {node: '>= 12.13.0'}
+
/rechoir/0.6.2:
resolution: {integrity: sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=}
engines: {node: '>= 0.10'}
@@ -21382,6 +21285,14 @@ packages:
interpret: 1.4.0
rechoir: 0.6.2
+ /shiki/0.10.1:
+ resolution: {integrity: sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==}
+ dependencies:
+ jsonc-parser: 3.1.0
+ vscode-oniguruma: 1.6.2
+ vscode-textmate: 5.2.0
+ dev: true
+
/side-channel/1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
dependencies:
@@ -21555,13 +21466,13 @@ packages:
flatstr: 1.0.12
dev: false
- /sonic-boom/2.2.3:
- resolution: {integrity: sha512-dm32bzlBchhXoJZe0yLY/kdYsHtXhZphidIcCzJib1aEjfciZyvHJ3NjA1zh6jJCO/OBLfdjc5iw6jLS/Go2fg==}
+ /sonic-boom/3.0.0:
+ resolution: {integrity: sha512-p5DiZOZHbJ2ZO5MADczp5qrfOd3W5Vr2vHxfCpe7G4AzPwVOweIjbfgku8wSQUuk+Y5Yuo8W7JqRe6XKmKistg==}
dependencies:
atomic-sleep: 1.0.0
- /sonic-boom/3.0.0:
- resolution: {integrity: sha512-p5DiZOZHbJ2ZO5MADczp5qrfOd3W5Vr2vHxfCpe7G4AzPwVOweIjbfgku8wSQUuk+Y5Yuo8W7JqRe6XKmKistg==}
+ /sonic-boom/3.2.0:
+ resolution: {integrity: sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA==}
dependencies:
atomic-sleep: 1.0.0
@@ -21799,9 +21710,6 @@ packages:
stubs: 3.0.0
dev: true
- /stream-shift/1.0.1:
- resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==}
-
/stream-transform/2.0.4:
resolution: {integrity: sha512-LQXH1pUksoef5Ijo6+2ihnjLLZtZuoqu1vhut6a7xZ77nrLA/shbbx2FAzVC/nkb6wwrPzOO98700mv4HDQcWg==}
dependencies:
@@ -22461,16 +22369,16 @@ packages:
/text-table/0.2.0:
resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=}
- /thread-stream/0.15.2:
- resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==}
- dependencies:
- real-require: 0.1.0
-
/thread-stream/1.0.1:
resolution: {integrity: sha512-JuZyfzx81e5MBk8uIr8ZH76bXyjEQvbRDEkSdlV1JFBdq/rbby2RuvzBYlTBd/xCljxy6lPxrTLXzB9Jl1bNrw==}
dependencies:
real-require: 0.1.0
+ /thread-stream/2.0.1:
+ resolution: {integrity: sha512-X7vWOdsHLkBq0si20ruEE2ttpS7WOVyD52xKu+TOjrRP9Qi9uB9ynHYpzZUbBptArBSuKYUn4mH+jEBnO2CRGg==}
+ dependencies:
+ real-require: 0.2.0
+
/throat/6.0.1:
resolution: {integrity: sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==}
@@ -22682,19 +22590,6 @@ packages:
strip-bom: 3.0.0
dev: false
- /tsd/0.22.0:
- resolution: {integrity: sha512-NH+tfEDQ0Ze8gH7TorB6IxYybD+M68EYawe45YNVrbQcydNBfdQHP9IiD0QbnqmwNXrv+l9GAiULT68mo4q/xA==}
- engines: {node: '>=14.16'}
- hasBin: true
- dependencies:
- '@tsd/typescript': 4.7.4
- eslint-formatter-pretty: 4.1.0
- globby: 11.1.0
- meow: 9.0.0
- path-exists: 4.0.0
- read-pkg-up: 7.0.1
- dev: true
-
/tslib/1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
@@ -22823,6 +22718,28 @@ packages:
dependencies:
is-typedarray: 1.0.0
+ /typedoc-plugin-missing-exports/1.0.0_typedoc@0.23.0-beta.7:
+ resolution: {integrity: sha512-7s6znXnuAj1eD9KYPyzVzR1lBF5nwAY8IKccP5sdoO9crG4lpd16RoFpLsh2PccJM+I2NASpr0+/NMka6ThwVA==}
+ peerDependencies:
+ typedoc: 0.22.x || 0.23.x
+ dependencies:
+ typedoc: 0.23.0-beta.7_typescript@4.7.4
+ dev: true
+
+ /typedoc/0.23.0-beta.7_typescript@4.7.4:
+ resolution: {integrity: sha512-k8GKXXY4z3HIs7HdSu92jcze1nl71cLiHR329ZflhiO4Ta1rJc4F5uEtwUjCSChXFQaVZUI2l3VaF9nWm1/p7A==}
+ engines: {node: '>= 14.14'}
+ hasBin: true
+ peerDependencies:
+ typescript: 4.6.x || 4.7.x
+ dependencies:
+ lunr: 2.3.9
+ marked: 4.0.18
+ minimatch: 5.1.0
+ shiki: 0.10.1
+ typescript: 4.7.4
+ dev: true
+
/typescript/4.7.4:
resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
engines: {node: '>=4.2.0'}
@@ -23567,6 +23484,14 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /vscode-oniguruma/1.6.2:
+ resolution: {integrity: sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==}
+ dev: true
+
+ /vscode-textmate/5.2.0:
+ resolution: {integrity: sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==}
+ dev: true
+
/w3c-hr-time/1.0.2:
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
dependencies: