🔀 Merge remote-tracking branch 'origin/main' into release/v1.0.5

This commit is contained in:
Eric Doughty-Papassideris
2024-11-18 15:13:02 +01:00
92 changed files with 18492 additions and 12036 deletions
@@ -70,12 +70,17 @@
}
},
"storage": {
"strategy": "STORAGE_STRATEGY",
"secret": "STORAGE_SECRET",
"iv": "STORAGE_SECRET_BASE_IV",
"type": "STORAGE_DRIVER",
"local": {
"path": "STORAGE_LOCAL_PATH"
},
"oneof": {
"__name": "STORAGE_ONEOF",
"__format": "json"
},
"S3": {
"homeDirectory": "STORAGE_S3_HOME_DIRECTORY",
"bucket": "STORAGE_S3_BUCKET",
+1
View File
@@ -93,6 +93,7 @@
"storage": {
"secret": "0ea28a329df23220fa814e005bfb671c",
"iv": "1234abcd00000000",
"strategy": "local",
"type": "local",
"S3": {
"endPoint": "play.min.io",
+52 -757
View File
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -29,7 +29,7 @@
"test:unit:watch": "npm run test:unit -- --watchAll --verbose false | pino-pretty",
"test:merge:json": "npx istanbul report --dir coverage/merged --include 'coverage/**/coverage-final.json' json-summary",
"test:merge:text": "npx istanbul report --dir coverage/merged --include 'coverage/**/coverage-final.json' text > coverage/merged/coverage-report.txt",
"test:all": "jest test --forceExit --coverage --detectOpenHandles --testTimeout=600000 --verbose false --runInBand",
"test:all": "jest test --forceExit --coverage --detectOpenHandles --testTimeout=600000 --verbose false",
"kill": "kill $(lsof -t -i:3000) | exit 0"
},
"jest": {
@@ -77,6 +77,7 @@
"@types/nodemailer": "^6.4.14",
"@types/pdf-image": "^2.0.1",
"@types/pg-pool": "^2.0.6",
"@types/pino": "^7.0.5",
"@types/pump": "^1.1.1",
"@types/random-useragent": "^0.3.1",
"@types/socket.io-client": "^1.4.36",
@@ -166,8 +167,7 @@
"pdf2pic": "^2.1.4",
"pg": "^8.11.3",
"pg-pool": "^3.6.1",
"pino": "^6.8.0",
"pino-std-serializers": "^6.1.0",
"pino": "^9.5.0",
"probe-image-size": "^7.2.3",
"pump": "^3.0.0",
"random-useragent": "^0.5.0",
@@ -182,7 +182,6 @@
"unzipper": "^0.11.6",
"uuid": "^8.3.2",
"uuid-time": "^1.0.0",
"v8-profiler-next": "^1.10.0",
"yargs": "^16.2.0"
}
}
@@ -12,6 +12,12 @@ export const logger = pino({
mixin() {
return executionStorage.getStore() ? executionStorage.getStore() : {};
},
formatters: {
level(label: string) {
return { level: label.toUpperCase() };
},
},
serializers: pino.stdSerializers,
});
export const getLogger = (name?: string): TdriveLogger =>
@@ -28,7 +28,7 @@ export async function buildDependenciesTree(
`The component dependency ${dependencyName} has not been found for component ${name}`,
);
} else {
console.warn(
logger.warn(
`(warning) The component dependency ${dependencyName} has not been found for component ${name} it will be imported asynchronously`,
);
@@ -209,7 +209,7 @@ export default class MongoSearch extends SearchAdapter implements SearchAdapterI
const { query, sort, project } = buildSearchQuery<EntityType>(entityType, filters, options);
logger.info(`Search query: ${JSON.stringify(query)}`);
console.log(query);
logger.info(query);
const sortMapped: any = sort
? Object.fromEntries(
@@ -1,6 +1,7 @@
import { buildSelectQuery } from "../../../database/services/orm/connectors/mongodb/query-builder";
import { EntityTarget, FindFilter, FindOptions, getEntityDefinition } from "../../api";
import { asciiFold } from "../utils";
import { logger } from "../../../../framework";
export function buildSearchQuery<Entity>(
entityType: EntityTarget<Entity>,
@@ -15,7 +16,7 @@ export function buildSearchQuery<Entity>(
try {
query = buildSelectQuery(entityType, filters, options);
} catch (e) {
console.log(e);
logger.info(e);
}
let sort: any = {};
@@ -2,8 +2,10 @@ import * as Minio from "minio";
import { logger } from "../../../../../../core/platform/framework";
import { Readable } from "stream";
import { StorageConnectorAPI, WriteMetadata } from "../../provider";
import { randomUUID } from "crypto";
export type S3Configuration = {
id: string;
bucket: string;
region: string;
endPoint: string;
@@ -17,10 +19,20 @@ export type S3Configuration = {
export default class S3ConnectorService implements StorageConnectorAPI {
client: Minio.Client;
minioConfiguration: S3Configuration;
id: string;
constructor(S3Configuration: S3Configuration) {
this.client = new Minio.Client(S3Configuration);
this.minioConfiguration = S3Configuration;
this.id = this.minioConfiguration.id;
if (!this.id) {
this.id = randomUUID();
logger.info(`Identifier for S3 storage haven't been set, initializing to '${this.id}'`);
}
}
getId() {
return this.id;
}
write(path: string, stream: Readable): Promise<WriteMetadata> {
@@ -101,7 +113,7 @@ export default class S3ConnectorService implements StorageConnectorAPI {
break;
}
} catch (e) {
logger.error("Error getting information from S3", e);
logger.error(e, `Error getting information from S3 for path: ${path}`);
}
if (i === tries) {
@@ -5,16 +5,28 @@ import { rm } from "fs/promises"; // Do not change the import, this is not the s
import { StorageConnectorAPI, WriteMetadata } from "../../provider";
import fs from "fs";
import { logger } from "../../../../framework/logger";
import { randomUUID } from "crypto";
export type LocalConfiguration = {
id: string;
path: string;
};
export default class LocalConnectorService implements StorageConnectorAPI {
id: string;
configuration: LocalConfiguration;
constructor(localConfiguration: LocalConfiguration) {
this.configuration = localConfiguration;
this.id = this.configuration.id;
if (!this.id) {
this.id = randomUUID();
logger.info(`Identifier for local storage haven't been set, initializing to '${this.id}'`);
}
}
getId() {
return this.id;
}
write(relativePath: string, stream: Readable): Promise<WriteMetadata> {
@@ -0,0 +1,46 @@
import { Readable, Stream } from "stream";
import { ExecutionContext } from "../../framework/api/crud-service";
import {
DeleteOptions,
ReadOptions,
StorageConnectorAPI,
WriteMetadata,
WriteOptions,
} from "../storage/provider";
export class DefaultStorageStrategy implements StorageConnectorAPI {
private connector: StorageConnectorAPI;
constructor(connector: StorageConnectorAPI) {
this.connector = connector;
}
getId() {
return this.connector.getId();
}
write = (
path: string,
stream: Stream,
options?: WriteOptions,
context?: ExecutionContext,
): Promise<WriteMetadata> => {
return this.connector.write(path, stream, options, context);
};
read = (path: string, options?: ReadOptions, context?: ExecutionContext): Promise<Readable> => {
return this.connector.read(path, options, context);
};
exists = (path: string, options?: ReadOptions, context?: ExecutionContext): Promise<boolean> => {
return this.connector.exists(path, options, context);
};
remove = (
path: string,
options?: DeleteOptions,
context?: ExecutionContext,
): Promise<boolean> => {
return this.connector.remove(path, options, context);
};
}
@@ -0,0 +1,2 @@
export class FileNotFountException extends Error {}
export class WriteFileException extends Error {}
@@ -0,0 +1,163 @@
import { Readable, Stream, PassThrough } from "stream";
import {
DeleteOptions,
ReadOptions,
StorageConnectorAPI,
WriteMetadata,
WriteOptions,
} from "../storage/provider";
import { logger } from "../../../platform/framework";
import { FileNotFountException, WriteFileException } from "./exceptions";
/**
* OneOfStorageStrategy is responsible for managing multiple storage backends.
* It writes to, reads from, removes, and checks for the existence of files
* across multiple storage systems.
*
* WARNING: Be careful using this strategy. There is a very big probability that
* all storages won't be synchronized. You need to use external synchronization
* tools like rclone to keep them in sync.
* As far as all the objects in a storage are immutable you won't have inconsistent
* state of the object except it could've been deleted, and it's still exists in one
* of the storages. So you will need to have external procedures to clean up storages
* and make "garbage" collection.
*/
export class OneOfStorageStrategy implements StorageConnectorAPI {
id: string;
constructor(private readonly storages: StorageConnectorAPI[]) {}
getId() {
if (!this.id) {
this.id = this.storages.map(s => s.getId()).join("_");
}
return this.id;
}
/**
* Writes a file to all configured storages.
* The write operation is considered successful if one of the storage succeed.
* @param path - The path where the file should be written.
* @param stream - The input stream to be written to storages.
* @param options - Write option: chunk number, encryption key, etc ...
* @throws Error if the write operation fails for one or more storages.
*/
write = async (path: string, stream: Stream, options?: WriteOptions): Promise<WriteMetadata> => {
logger.debug("Creating streams for all storages ...");
const passThroughStreams = this.storages.map(() => new PassThrough());
// destroy all streams if there is an error in the input stream
stream.on("error", err => {
logger.error(err, "Error in input stream, destroying all write streams");
passThroughStreams.forEach(stream => stream.destroy(err));
});
// Pipe the input stream to each PassThrough stream
stream
.pipe(new PassThrough())
.on("data", chunk => {
passThroughStreams.forEach(stream => stream.write(chunk));
})
.on("end", () => {
passThroughStreams.forEach(stream => stream.end());
});
// Write to all storages with error handling
const writeResults = await Promise.allSettled(
this.storages.map((storage, index) =>
storage.write(path, passThroughStreams[index], options),
),
);
// Log all errors and throw if all write operations fail
const errors = writeResults.filter(result => result.status === "rejected");
errors.forEach((error, index) => {
const storageId = this.storages[index].getId();
logger.error(
new OneOfStorageWriteOneFailedException(
storageId,
`Error writing to storage ${storageId}`,
(error as PromiseRejectedResult).reason,
),
);
});
if (errors.length === this.storages.length) {
throw new WriteFileException(`Write ${path} failed for all storages`);
}
const successResult = writeResults.filter(
result => result.status === "fulfilled",
)[0] as PromiseFulfilledResult<WriteMetadata>;
return successResult.value;
};
/**
* Reads a file from the primary storage. If it fails, attempts to read from other storages.
* @param path - The path of the file to be read.
* @param options
* @returns A readable stream of the file.
* @throws Error if all storage read attempts fail.
*/
read = async (path: string, options?: ReadOptions): Promise<Readable> => {
for (const storage of this.storages) {
try {
if (await storage.exists(path, options)) {
return await storage.read(path, options);
}
} catch (err) {
logger.error(
new OneOfStorageReadOneFailedException(
storage.getId(),
`Reading ${path} from storage ${storage} failed.`,
err,
),
);
}
}
throw new FileNotFountException(`Error reading ${path}`);
};
/**
* Checks if a file exists in any of the configured storages.
* @param path - The path of the file to check.
* @param options
* @returns A boolean indicating whether the file exists in any storage.
*/
exists = async (path: string, options?: ReadOptions): Promise<boolean> => {
for (const storage of this.storages) {
if (await storage.exists(path, options)) {
return true;
}
}
return false;
};
/**
* Removes a file from all configured storages.
* @param path - The path of the file to be removed.
* @param options
*/
remove = async (path: string, options?: DeleteOptions): Promise<boolean> => {
return Promise.all(this.storages.map(storage => storage.remove(path, options))).then(array => {
return array.reduce((a, b) => a && b);
});
};
}
/**
* Throw when read from one of the storages is filed.
*/
class StorageException extends Error {
constructor(readonly storageId: string, details: string, error: Error) {
super(details, error);
}
}
/**
* Throw when read from one of the storages is filed.
*/
class OneOfStorageReadOneFailedException extends StorageException {}
/**
* Thrown when write operation to one of the storages is failed.
*/
class OneOfStorageWriteOneFailedException extends StorageException {}
@@ -23,6 +23,12 @@ export type DeleteOptions = {
};
export interface StorageConnectorAPI {
/**
* Returns identifier of a storage that should've been set in configuration.
*
*/
getId(): string;
/**
* Write a stream to a path
*
@@ -9,7 +9,7 @@ import {
TdriveServiceOptions,
} from "../../framework";
import LocalConnectorService, { LocalConfiguration } from "./connectors/local/service";
import S3ConnectorService from "./connectors/S3/s3-service";
import S3ConnectorService, { S3Configuration } from "./connectors/S3/s3-service";
import StorageAPI, {
DeleteOptions,
ReadOptions,
@@ -18,6 +18,10 @@ import StorageAPI, {
WriteOptions,
} from "./provider";
import { OneOfStorageStrategy } from "./oneof-storage-strategy";
import { DefaultStorageStrategy } from "./default-storage-strategy";
import { FileNotFountException } from "./exceptions";
type EncryptionConfiguration = {
secret: string | null;
iv: string | null;
@@ -35,26 +39,14 @@ export default class StorageService extends TdriveService<StorageAPI> implements
* But for the local storage it's a default value
* @private
*/
private homeDir = "/tdrive";
private homeDir = "tdrive";
constructor(protected options?: TdriveServiceOptions<TdriveServiceConfiguration>) {
super(options);
const type = this.getConnectorType();
if (type === "S3") {
logger.info("Using 'S3' connector for storage.");
try {
this.homeDir = this.configuration.get<string>("S3.homeDirectory");
} catch (e) {
this.logger.warn("Home directory is not set, using S3.bucket instead");
}
if (!this.homeDir) {
this.homeDir = this.configuration.get<string>("S3.bucket");
}
if (this.homeDir && this.homeDir.startsWith("/")) {
this.logger.error("For S3 connector home directory MUST NOT start with '/'");
throw new Error("For S3 connector home directory MUST NOT start with '/'");
}
}
//init home directory variable
this.initHomeDirectory();
//init connector to storage
this.getConnector();
}
api(): StorageAPI {
@@ -67,31 +59,7 @@ export default class StorageService extends TdriveService<StorageAPI> implements
getConnector(): StorageConnectorAPI {
if (!this.connector) {
const type = this.getConnectorType();
if (type === "S3") {
logger.info("Using 'S3' connector for storage.");
this.connector = new S3ConnectorService({
bucket: this.configuration.get<string>("S3.bucket"),
region: this.configuration.get<string>("S3.region"),
endPoint: this.configuration.get<string>("S3.endPoint"),
port: Number(this.configuration.get<number>("S3.port")),
useSSL: Boolean(this.configuration.get<boolean>("S3.useSSL")),
accessKey: this.configuration.get<string>("S3.accessKey"),
secretKey: this.configuration.get<string>("S3.secretKey"),
disableRemove: this.configuration.get<boolean>("S3.disableRemove"),
});
} else {
logger.info(
`Using 'local' connector for storage${
type === "local" ? "" : " (no other connector recognized from configuration type: '%s')"
}.`,
type,
);
logger.trace(`Home directory for the storage: ${this.homeDir}`);
this.connector = new LocalConnectorService(
this.configuration.get<LocalConfiguration>("local"),
);
}
this.connector = this.getStorageStrategy();
}
return this.connector;
}
@@ -101,7 +69,8 @@ export default class StorageService extends TdriveService<StorageAPI> implements
}
exists(path: string, options?: ReadOptions): Promise<boolean> {
return this.getConnector().exists(path, options);
//TODO[ASH] check for all the file chunks
return this.getConnector().exists(path + "/chunk1", options);
}
async write(path: string, stream: Stream, options?: WriteOptions): Promise<WriteMetadata> {
@@ -134,15 +103,15 @@ export default class StorageService extends TdriveService<StorageAPI> implements
}
async read(path: string, options?: ReadOptions): Promise<Readable> {
if (!(await this.exists(path, options))) {
throw new FileNotFountException();
}
try {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
const chunks = options?.totalChunks || 1;
let count = 1;
// Check if the first chunk or file exists
await self._read(options?.totalChunks ? `${path}/chunk${count}` : path);
async function factory(callback: (err?: Error, stream?: Stream) => unknown) {
if (count > chunks) {
callback();
@@ -216,4 +185,113 @@ export default class StorageService extends TdriveService<StorageAPI> implements
return this;
}
/**
* Instantiates storage strategy with configuration.
* "storage": {
* "secret": "",
* "iv": "",
* "strategy": "oneof",
* "type": "local",
* "S3": {
* "endPoint": "play.min.io",
* "port": 9000,
* "useSSL": false,
* "accessKey": "ABCD",
* "secretKey": "x1yz",
* "disableRemove": false
* },
* "local": {
* "path": "/tdrive"
* },
* "oneof": [
* {
* "type": "S3",
* "S3": {}
* },
* {
* "type": "local",
* "local": {}
* }]
* },
*/
getStorageStrategy(): StorageConnectorAPI {
const strategy = this.configuration.get<string>("strategy");
if (strategy == "oneof") {
logger.info("Creating storage with 'oneof' strategy");
const connectors = this.configuration
.get<Array<StorageConfiguration>>("oneof")
.map(c => this.createConnector(c));
return new OneOfStorageStrategy(connectors);
} else {
logger.info("Creating storage with 'default' strategy");
return new DefaultStorageStrategy(this.createConnectorFromConfiguration(this.configuration));
}
}
createConnector(config: StorageConfiguration) {
const type = config.type;
if (type === "S3") {
return this.newS3Connector(config.S3);
} else {
return this.newLocalConnector(config.local, type);
}
}
createConnectorFromConfiguration(config: TdriveServiceConfiguration) {
const type = config.get<string>("type");
if (type === "S3") {
return this.newS3Connector(config.get("S3"));
} else {
return this.newLocalConnector(this.configuration.get<LocalConfiguration>("local"), type);
}
}
newS3Connector(config: S3Configuration) {
logger.info("Using 'S3' connector for storage.");
return new S3ConnectorService(config);
}
newLocalConnector(config: LocalConfiguration, type: string) {
logger.info(
`Using 'local' connector for storage${
type === "local" ? "" : " (no other connector recognized from configuration type: '%s')"
}.`,
type,
);
logger.trace(`Home directory for the storage: ${this.homeDir}`);
return new LocalConnectorService(config);
}
initHomeDirectory() {
const type = this.getConnectorType();
if (type === "S3") {
logger.info("Using 'S3' connector for storage.");
try {
this.homeDir = this.configuration.get<string>("S3.homeDirectory");
} catch (e) {
this.logger.warn("Home directory is not set, using S3.bucket instead");
}
if (!this.homeDir) {
this.homeDir = this.configuration.get<string>("S3.bucket");
}
if (this.homeDir && this.homeDir.startsWith("/")) {
this.logger.error("For S3 connector home directory MUST NOT start with '/'");
throw new Error("For S3 connector home directory MUST NOT start with '/'");
}
} else {
this.logger.info("For 'local' connector setting home directory to '/tdrive'");
this.homeDir = "/tdrive";
}
}
getId() {
return this.connector.getId();
}
}
type StorageConfiguration = {
type: string;
S3?: S3Configuration;
local?: LocalConfiguration;
};
@@ -1,6 +1,7 @@
import Analytics, { IdentifyParams, TrackParams } from "@segment/analytics-node";
import { Analytics as AnalyticsAbtract } from "./types";
import axios, { AxiosInstance } from "axios";
import { logger } from "../../../framework/logger";
export default class Segment implements AnalyticsAbtract {
protected version = "5.0.0"; //Segment analytics lib version
@@ -33,7 +34,7 @@ export default class Segment implements AnalyticsAbtract {
try {
this.analytics.identify(message as IdentifyParams, callback);
} catch (err) {
console.error(err);
logger.error(err);
}
}
@@ -47,7 +48,7 @@ export default class Segment implements AnalyticsAbtract {
try {
this.analytics.track(message as TrackParams, callback);
} catch (err) {
console.error(err);
logger.error(err);
}
}
@@ -1,8 +1,9 @@
import { FastifyInstance } from "fastify";
import { logger } from "../../framework/logger";
function serverErrorHandler(server: FastifyInstance): void {
server.setErrorHandler(async (err, request, reply) => {
console.error(`Got ${reply.statusCode} error on request ${request.id} : `, err);
logger.error(`Got ${reply.statusCode} error on request ${request.id} : `, err);
server.log.debug(`Got ${reply.statusCode} error on request ${request.id} : ${err.toString()}`);
await reply.send(
reply.statusCode == 500
@@ -1,4 +1,4 @@
import { Initializable, TdriveServiceProvider } from "../../../core/platform/framework";
import { Initializable, logger, TdriveServiceProvider } from "../../../core/platform/framework";
import { ListResult, Paginable } from "../../../core/platform/framework/api/crud-service";
import gr from "../../global-resolver";
import {
@@ -39,7 +39,7 @@ export class CompanyApplicationServiceImpl implements TdriveServiceProvider, Ini
app.application.api = null;
return app;
} catch (err) {
console.error(err);
logger.error(err);
return null;
}
}
@@ -285,7 +285,7 @@ export const getAccessLevel = async (
);
if (matchingChannel) return matchingChannel.level;
} catch (e) {
console.log(e);
logger.info(e);
}
}
@@ -406,7 +406,7 @@ export const getSharedByUser = (
return getGrantorAndThrowIfEmpty(entity);
}
if (entity.type === "company" && entity.id === context.company.id && entity.level != "none") {
console.log("company", entity);
logger.info("company", entity);
return getGrantorAndThrowIfEmpty(entity);
}
}
@@ -47,7 +47,7 @@ export class DocumentsProcessor
);
content_keywords = await getKeywordsOfFile(storedFile.mime, storedFile.name, storedFile.file);
} catch (error) {
console.debug(error);
logger.debug(error);
logger.error({ error: `${error}` }, "Failed to generate content keywords");
}
return { content_keywords, item: message.item };
@@ -470,7 +470,7 @@ export class DocumentsService {
}
}
} catch (error) {
console.error("🚀🚀 error:", error);
logger.error(error, "🚀🚀 error:");
}
await this.repository.save(driveItem);
@@ -557,6 +557,16 @@ export class DocumentsService {
throw Error("Move operation not permitted");
} else {
oldParent = item.parent_id;
const newParentId = content.parent_id;
const needRenameTo = await getItemName(
newParentId,
item.id,
item.name,
item.is_directory,
this.repository,
context,
);
if (needRenameTo !== item.name) renamedTo = item.name = needRenameTo;
}
if (key === "access_info") {
// if manage access is disabled, we don't allow changing access level
@@ -1,7 +1,6 @@
import { FastifyInstance, FastifyPluginCallback } from "fastify";
import { DocumentsController } from "./controllers";
import { createDocumentSchema, createVersionSchema, beginEditingSchema } from "./schemas";
// import profilerPlugin from "../../../utils/profiler";
const baseUrl = "/companies/:company_id";
const serviceUrl = `${baseUrl}/item`;
@@ -10,11 +9,6 @@ const editingSessionBase = "/editing_session/:editing_session_key";
const routes: FastifyPluginCallback = (fastify: FastifyInstance, _options, next) => {
const documentsController = new DocumentsController();
// fastify.register(profilerPlugin, {
// active: documentsController.profilingEnabled,
// outputDir: "profiles",
// });
fastify.route({
method: "GET",
url: `${serviceUrl}`,
@@ -431,7 +431,7 @@ export class FileServiceImpl {
id: externalId,
company_id: "00000000-0000-4000-0000-000000000000",
});
const exist = await gr.platformServices.storage.exists(getFilePath(file) + "/chunk1");
const exist = await gr.platformServices.storage.exists(getFilePath(file));
if (exist) {
return { exist: true, file };
} else {
@@ -6,6 +6,7 @@ import { UploadOptions } from "../../types";
import { PublicFile } from "../../entities/file";
import gr from "../../../global-resolver";
import { formatAttachmentContentDispositionHeader } from "../../utils";
import { logger } from "../../../../core/platform/framework";
export class FileController {
async save(
@@ -54,7 +55,7 @@ export class FileController {
response.type(data.mime);
return response.send(data.file);
} catch (e) {
console.log("!!!" + e);
logger.info(e);
throw e;
}
}
@@ -80,7 +81,7 @@ export class FileController {
response.send(data.file);
return response;
} catch (err) {
console.log(err);
logger.error(err);
response.statusCode = 500;
response.send("");
}
@@ -1,6 +1,9 @@
import { fromPath } from "pdf2pic";
import { mkdirSync } from "fs";
import { cleanFiles, getTmpFile } from "../../../../../utils/files";
import { logger } from "../../../../../core/platform/framework";
class PDFConversionError extends Error {}
export async function convertFromPdf(
inputPath: string,
@@ -33,11 +36,14 @@ export async function convertFromPdf(
//Just no more page to convert
}
} catch (error) {
console.error(error);
const pdfConversionError = new PDFConversionError("Can't convert file with pdf-image.", {
cause: error,
});
logger.error(pdfConversionError);
for (const file of pages) {
cleanFiles([file]);
}
throw Error("Can't convert file with pdf-image.");
throw pdfConversionError;
}
return { output: pages, done: true };
}
@@ -7,6 +7,7 @@ import {
CompanyStatsObject,
CompanyUserObject,
} from "./web/types";
import { logger } from "../../core/platform/framework";
export function formatCompany(
companyEntity: Company,
@@ -75,6 +76,8 @@ export function formatCompany(
},
);
logger.info("🚀🚀 res.plan.features: ", res.plan.features);
return res;
}
@@ -490,7 +490,7 @@ export class WorkspaceServiceImpl implements TdriveServiceProvider, Initializabl
}
}
} catch (err) {
console.log(err);
logger.warn(err);
}
}
}
@@ -35,6 +35,7 @@ import WorkspacePendingUser from "../../entities/workspace_pending_users";
import { ConsoleCompany, CreateConsoleUser } from "../../../console/types";
import { hasCompanyAdminLevel } from "../../../../utils/company";
import gr from "../../../global-resolver";
import { logger } from "../../../../core/platform/framework";
export class WorkspaceUsersCrudController
implements
@@ -525,7 +526,7 @@ export class WorkspaceUsersCrudController
return { status: "success" };
} catch (e) {
console.error(e);
logger.warn(e);
return {
status: "error",
};
+2 -1
View File
@@ -1,6 +1,7 @@
import { mkdirSync, existsSync, promises as fsPromise, createWriteStream, readFileSync } from "fs";
import { Readable } from "stream";
import { v4 as uuidv4 } from "uuid";
import { logger } from "../core/platform/framework";
const { unlink } = fsPromise;
@@ -50,7 +51,7 @@ export const writeToTemporaryFile = async (input: Readable, extension: string):
return temporaryFilePath;
} catch (error) {
console.debug(error);
logger.debug(error);
throw Error(error);
}
-61
View File
@@ -1,61 +0,0 @@
import fs from "fs";
import fp from "fastify-plugin";
import v8profiler from "v8-profiler-next";
export class Profiler {
title: string;
active: boolean;
outputDir: string;
constructor(options) {
const { title, active, outputDir } = options;
this.title = title;
this.active = active;
this.outputDir = outputDir;
}
start() {
if (this.active) {
v8profiler.startProfiling(this.title, true);
}
}
finish() {
if (this.active) {
const profile = v8profiler.stopProfiling(this.title);
if (profile === undefined) {
console.log("profile is undefined: ", this.title);
return;
}
profile.export((error, result) => {
if (error) {
console.log("Profiling error: ", error);
} else {
fs.writeFileSync(`${process.cwd()}/${this.outputDir}/${this.title}.cpuprofile`, result);
}
});
}
}
}
async function profilerPlugin(fastify, options) {
fastify.addHook("onRequest", async request => {
const profiler = new Profiler({
title: `${request.method}-${request.url}`,
active: options.active,
outputDir: options.outputDir || "profiles",
});
profiler.start();
// Attach profiler to request for access in routes or other hooks
request.profiler = profiler;
});
fastify.addHook("onResponse", async request => {
if (request.profiler) {
request.profiler.finish();
}
});
}
export default fp(profilerPlugin);
@@ -6,6 +6,9 @@ import UserApi from "../common/user-api";
describe("The Documents Browser Window and API", () => {
let platform: TestPlatform;
let currentUser: UserApi;
let sharedWIthMeFolder: string;
let myDriveId: string;
let files: any;
beforeEach(async () => {
platform = await init({
@@ -25,75 +28,63 @@ describe("The Documents Browser Window and API", () => {
],
});
currentUser = await UserApi.getInstance(platform);
sharedWIthMeFolder = "shared_with_me";
myDriveId = "user_" + currentUser.user.id;
files = await currentUser.uploadAllFilesOneByOne(myDriveId);
expect(files).toBeDefined();
expect(files.entries()).toBeDefined();
expect(Array.from(files.entries())).toHaveLength(UserApi.ALL_FILES.length);
});
afterAll(async () => {
await platform?.tearDown();
// @ts-ignore
platform = null;
});
describe("My Drive", () => {
it("Should successfully upload filed to the 'Shared Drive' and browse them", async () => {
const myDriveId = "user_" + currentUser.user.id;
const result = await currentUser.uploadAllFilesOneByOne(myDriveId);
expect(result).toBeDefined();
expect(result.entries()).toBeDefined();
expect(Array.from(result.entries())).toHaveLength(UserApi.ALL_FILES.length);
it("Should successfully upload filed to the 'My Drive' and browse them", async () => {
const docs = await currentUser.browseDocuments(myDriveId, {});
expect(docs).toBeDefined();
expect(docs.children).toBeDefined();
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length)
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length);
});
it("Should not be visible for other users", async () => {
const myDriveId = "user_" + currentUser.user.id;
const anotherUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
await currentUser.uploadAllFilesOneByOne(myDriveId);
await new Promise(r => setTimeout(r, 5000));
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
const docs = await currentUser.browseDocuments(myDriveId, {});
expect(docs).toBeDefined();
expect(docs.children).toBeDefined();
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length)
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length);
const anotherUserDocs = await anotherUser.searchDocument({});
expect(anotherUserDocs).toBeDefined();
expect(anotherUserDocs.entities).toBeDefined();
expect(anotherUserDocs.entities.length).toEqual(0);
});
});
describe("Shared Drive", () => {
it("Should successfully upload filed to the 'Shared Drive' and browse them", async () => {
const result = await currentUser.uploadAllFilesOneByOne("root");
expect(result).toBeDefined();
expect(result.entries()).toBeDefined();
expect(Array.from(result.entries())).toHaveLength(UserApi.ALL_FILES.length);
const docs = await currentUser.browseDocuments("root", {});
expect(docs).toBeDefined();
expect(docs.children).toBeDefined();
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length);
});
});
describe("Shared With Me", () => {
it("Shouldn't contain user personal files", async () => {
const sharedWIthMeFolder = "shared_with_me";
await currentUser.uploadAllFilesOneByOne("user_" + currentUser.user.id);
await new Promise(r => setTimeout(r, 5000));
let docs = await currentUser.browseDocuments(sharedWIthMeFolder, {});
expect(docs).toBeDefined();
expect(docs.children?.length).toEqual(0)
expect(docs.children?.length).toEqual(0);
await currentUser.uploadAllFilesOneByOne("root");
docs = await currentUser.browseDocuments("shared_with_me", {});
@@ -103,11 +94,7 @@ describe("The Documents Browser Window and API", () => {
});
it("Should contain files that were shared with the user", async () => {
const sharedWIthMeFolder = "shared_with_me";
const oneUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
const anotherUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
let files = await oneUser.uploadAllFilesOneByOne();
await new Promise(r => setTimeout(r, 5000));
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
//then:: files are not searchable for user without permissions
expect((await anotherUser.browseDocuments("shared_with_me", {})).children).toHaveLength(0);
@@ -119,48 +106,49 @@ describe("The Documents Browser Window and API", () => {
level: "read",
grantor: null,
});
await oneUser.updateDocument(files[0].id, files[0]);
await currentUser.updateDocument(files[0].id, files[0]);
await new Promise(r => setTimeout(r, 3000));
//then file become searchable
expect((await anotherUser.browseDocuments("shared_with_me", {pageSize: 1})).children).toHaveLength(1);
expect(
(await anotherUser.browseDocuments("shared_with_me", { pageSize: 1 })).children,
).toHaveLength(1);
});
it("Should return ALL the files that was share by user at one", async () => {
const oneUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
const anotherUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
let files = await oneUser.uploadAllFilesOneByOne();
await anotherUser.uploadAllFilesOneByOne();
await new Promise(r => setTimeout(r, 5000));
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
//give permissions to the file
files[2].access_info.entities.push({
type: "user",
id: anotherUser.user.id,
level: "read",
// @ts-ignore
grantor: null,
});
await oneUser.updateDocument(files[2].id, files[2]);
await currentUser.updateDocument(files[2].id, files[2]);
await new Promise(r => setTimeout(r, 3000));
//then file become searchable
expect((await anotherUser.browseDocuments("shared_with_me", {pagination: {limitStr: 100}})).children).toHaveLength(1);
expect(
(await anotherUser.browseDocuments("shared_with_me", { pagination: { limitStr: 100 } }))
.children,
).toHaveLength(1);
});
it("User should be able to delete file that was shared with him with 'manage' permissions", async () => {
const oneUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
const anotherUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
let files = await oneUser.uploadAllFilesOneByOne("user_" + oneUser.user.id);
await new Promise(r => setTimeout(r, 5000));
await new Promise(r => setTimeout(r, 3000));
let toDeleteDoc = files[2];
toDeleteDoc.access_info.entities.push({
type: "user",
id: anotherUser.user.id,
level: "manage",
// @ts-ignore
grantor: null,
});
await oneUser.updateDocument(toDeleteDoc.id, toDeleteDoc);
@@ -172,19 +160,20 @@ describe("The Documents Browser Window and API", () => {
it("User should be able to delete folder with the files that was shared with him with 'manage' permissions", async () => {
const oneUser = await UserApi.getInstance(platform, true);
const anotherUser = await UserApi.getInstance(platform, true);
const dir = await oneUser.createDirectory("user_" + oneUser.user.id);
const level2Dir = await oneUser.createDirectory(dir.id);
const level2Dir2 = await oneUser.createDirectory(dir.id);
await oneUser.uploadAllFilesOneByOne(level2Dir.id);
await oneUser.uploadAllFilesOneByOne(level2Dir2.id);
await oneUser.uploadAllFilesOneByOne(dir.id);
await new Promise(r => setTimeout(r, 5000));
await new Promise(r => setTimeout(r, 3000));
dir.access_info.entities.push({
type: "user",
id: anotherUser.user.id,
level: "manage",
// @ts-ignore
grantor: null,
});
await oneUser.updateDocument(dir.id, dir);
@@ -203,6 +192,7 @@ describe("The Documents Browser Window and API", () => {
type: "user",
id: anotherUser.user.id,
level: "manage",
// @ts-ignore
grantor: null,
});
await oneUser.updateDocument(dir.id, dir);
@@ -220,7 +210,5 @@ describe("The Documents Browser Window and API", () => {
sharedDocs = await anotherUser.browseDocuments("shared_with_me");
expect(sharedDocs.children.length).toBe(0);
});
});
});
@@ -64,7 +64,7 @@ describe("The Drive feature", () => {
const files = await oneUser.uploadAllFilesOneByOne();
// Wait for file processing
await new Promise(r => setTimeout(r, 5000));
await new Promise(r => setTimeout(r, 3000));
// Share the file with recipient user
await anotherUser.shareWithPermissions(files[1], anotherUser.user.id, "read");
@@ -3,8 +3,12 @@ import { init, TestPlatform } from "../setup";
import UserApi from "../common/user-api";
describe("The Documents Browser Window and API", () => {
let sharedWIthMeFolder: string;
let platform: TestPlatform;
let currentUser: UserApi;
let anotherUser: UserApi;
let myDriveId: string;
let files: any;
beforeAll(async () => {
platform = await init({
@@ -23,19 +27,24 @@ describe("The Documents Browser Window and API", () => {
"documents",
],
});
currentUser = await UserApi.getInstance(platform);
currentUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
myDriveId = "user_" + currentUser.user.id;
sharedWIthMeFolder = "shared_with_me";
files = await currentUser.uploadAllFilesOneByOne(myDriveId);
for (const file of files) {
await currentUser.shareWithPermissions(file, anotherUser.user.id, "read");
}
});
afterAll(async () => {
await platform?.tearDown();
// @ts-ignore
platform = null;
});
describe("Pagination and Sorting", () => {
it("Should paginate documents correctly", async () => {
const myDriveId = "user_" + currentUser.user.id;
await currentUser.uploadAllFilesOneByOne(myDriveId);
let page_token = "1";
const limitStr = "2";
let docs = await currentUser.browseDocuments(myDriveId, {
@@ -60,9 +69,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort documents by name in ascending order", async () => {
const myDriveId = "user_" + currentUser.user.id;
await currentUser.uploadAllFilesOneByOne(myDriveId);
const sortBy = "name";
const sortOrder = "asc";
const docs = await currentUser.browseDocuments(myDriveId, {
@@ -75,9 +81,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort documents by name in descending order", async () => {
const myDriveId = "user_" + currentUser.user.id;
await currentUser.uploadAllFilesOneByOne(myDriveId);
const sortBy = "name";
const sortOrder = "desc";
const docs = await currentUser.browseDocuments(myDriveId, {
@@ -90,9 +93,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort documents by date in ascending order", async () => {
const myDriveId = "user_" + currentUser.user.id;
await currentUser.uploadAllFilesOneByOne(myDriveId);
const sortBy = "date";
const sortOrder = "asc";
const docs = await currentUser.browseDocuments(myDriveId, {
@@ -107,9 +107,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort documents by date in descending order", async () => {
const myDriveId = "user_" + currentUser.user.id;
await currentUser.uploadAllFilesOneByOne(myDriveId);
const sortBy = "date";
const sortOrder = "desc";
const docs = await currentUser.browseDocuments(myDriveId, {
@@ -124,9 +121,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort documents by size in ascending order", async () => {
const myDriveId = "user_" + currentUser.user.id;
await currentUser.uploadAllFilesOneByOne(myDriveId);
const sortBy = "size";
const sortOrder = "asc";
const docs = await currentUser.browseDocuments(myDriveId, {
@@ -139,9 +133,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort documents by size in descending order", async () => {
const myDriveId = "user_" + currentUser.user.id;
await currentUser.uploadAllFilesOneByOne(myDriveId);
const sortBy = "size";
const sortOrder = "desc";
const docs = await currentUser.browseDocuments(myDriveId, {
@@ -154,17 +145,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should paginate shared with me ", async () => {
const sharedWIthMeFolder = "shared_with_me";
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
let files = await oneUser.uploadAllFilesOneByOne();
for (const file of files) {
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
}
// wait for files to be indexed
await new Promise(r => setTimeout(r, 5000));
let page_token: any = "1";
const limitStr = "2";
let docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
@@ -189,13 +169,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort shared with me by name in ascending order", async () => {
const sharedWIthMeFolder = "shared_with_me";
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
let files = await oneUser.uploadAllFilesOneByOne();
for (const file of files) {
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
}
const sortBy = "name";
const sortOrder = "asc";
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
@@ -208,13 +181,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort shared with me by name in descending order", async () => {
const sharedWIthMeFolder = "shared_with_me";
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
let files = await oneUser.uploadAllFilesOneByOne();
for (const file of files) {
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
}
const sortBy = "name";
const sortOrder = "desc";
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
@@ -227,13 +193,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort shared with me by size in ascending order", async () => {
const sharedWIthMeFolder = "shared_with_me";
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
let files = await oneUser.uploadAllFilesOneByOne();
for (const file of files) {
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
}
const sortBy = "size";
const sortOrder = "asc";
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
@@ -246,13 +205,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort shared with me by size in descending order", async () => {
const sharedWIthMeFolder = "shared_with_me";
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
let files = await oneUser.uploadAllFilesOneByOne();
for (const file of files) {
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
}
const sortBy = "size";
const sortOrder = "desc";
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
@@ -265,13 +217,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort shared with me by date in ascending order", async () => {
const sharedWIthMeFolder = "shared_with_me";
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
let files = await oneUser.uploadAllFilesOneByOne();
for (const file of files) {
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
}
const sortBy = "date";
const sortOrder = "asc";
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
@@ -286,13 +231,6 @@ describe("The Documents Browser Window and API", () => {
});
it("Should sort shared with me by date in descending order", async () => {
const sharedWIthMeFolder = "shared_with_me";
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
let files = await oneUser.uploadAllFilesOneByOne();
for (const file of files) {
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
}
const sortBy = "date";
const sortOrder = "desc";
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
@@ -0,0 +1,8 @@
// @ts-ignore
import path from "path";
// @ts-ignore
import config from "config";
const ourConfigDir = path.join(__dirname, 'oneof-storage');
let configs = config.util.loadFileConfigs(ourConfigDir);
config.util.extendDeep(config, configs);
@@ -0,0 +1,21 @@
{
"storage": {
"secret": "0ea28a329df23220fa814e005bfb671c",
"iv": "1234abcd00000000",
"strategy": "oneof",
"oneof": [
{
"type": "local",
"local": {
"path": "-tmp/storage1"
}
},
{
"type": "local",
"local": {
"path": "/tmp/storage2"
}
}]
}
}
@@ -0,0 +1,71 @@
import "./load_test_config"
import "reflect-metadata";
import { afterAll, beforeAll, afterEach, describe, expect, it } from "@jest/globals";
import { init, TestPlatform } from "../setup";
import UserApi from "../common/user-api";
import LocalConnectorService from "../../../src/core/platform/services/storage/connectors/local/service"
import { StorageConnectorAPI } from "../../../src/core/platform/services/storage/provider";
describe("The OneOf Storage feature", () => {
const url = "/internal/services/files/v1";
let platform: TestPlatform;
let helpers: UserApi;
beforeAll(async () => {
platform = await init({
services: ["webserver", "database", "storage", "files", "previews"],
});
helpers = await UserApi.getInstance(platform);
}, 300000000);
afterEach(async () => {
jest.restoreAllMocks();
});
afterAll(async () => {
await platform?.tearDown();
platform = null;
});
describe("On file upload", () => {
it("should fail an upload POST when ALL backend storage fails", async () => {
const thrower = () => {
throw new Error("<Mock error done on purpose on upload to storage (for the E2E test)>");
};
const writeLocalMock = jest.spyOn(LocalConnectorService.prototype, "write").mockRejectedValue("Error");
// expect(response.statusCode).toBe(500);
await expect(helpers.uploadRandomFile()).rejects.toThrow("Error code: 500");
// expect(response.statusCode).toBe(500);
expect(writeLocalMock.mock.calls.length).toEqual(2);
});
it("should successfully upload file when one backend storage fails", async () => {
const thrower = () => {
throw new Error("<Mock error done on purpose on upload to storage (for the E2E test)>");
};
const connectors = (platform.storage.getConnector() as any).storages as Array<StorageConnectorAPI>;
const writeLocalMock = jest.spyOn(connectors[0], "write").mockRejectedValue("Error");
// expect(response.statusCode).toBe(200);
const filesUpload = await helpers.uploadRandomFile();
expect(filesUpload.id).toBeTruthy();
// expect failed upload
expect(writeLocalMock.mock.calls.length).toBeGreaterThan(0);
//expect that file can be downloaded
const fileDownloadResponse = await platform.app.inject({
method: "GET",
url: `${url}/companies/${platform.workspace.company_id}/files/${filesUpload.id}/download`,
});
expect(fileDownloadResponse).toBeTruthy();
expect(fileDownloadResponse.statusCode).toBe(200);
});
});
});
@@ -0,0 +1,185 @@
import { Readable, PassThrough } from 'stream';
import { OneOfStorageStrategy } from "../../../../../src/core/platform/services/storage/oneof-storage-strategy"; // Adjust the import path as necessary
import {StorageConnectorAPI } from "../../../../../src/core/platform/services/storage/provider"; // Adjust the import path as necessary
function mockStream() {
const stream = new Readable();
stream.push("Test data");
stream.push(null);
return stream;
}
function mockStorage(size: number) {
return {
write: jest.fn().mockResolvedValue({ size: size }),
read: jest.fn(),
exists: jest.fn(),
remove: jest.fn().mockResolvedValue(true),
getId: jest.fn().mockResolvedValue("Mock Storage ID")
} as unknown as StorageConnectorAPI;
}
describe('OneOfStorageStrategy', () => {
let storage1: StorageConnectorAPI;
let storage2: StorageConnectorAPI;
let storage3: StorageConnectorAPI;
let oneOfStorageStrategy: OneOfStorageStrategy;
beforeEach(() => {
// Mocking two storage backends
storage1 = mockStorage(100);
storage2 = mockStorage(200);
storage3 = mockStorage(300);
oneOfStorageStrategy = new OneOfStorageStrategy([storage1, storage2, storage3]);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('write', () => {
it('should write to all configured storages', async () => {
const path = 'test/path';
const stream = mockStream();
const result = await oneOfStorageStrategy.write(path, stream);
expect(storage1.write).toHaveBeenCalled();
expect(storage2.write).toHaveBeenCalled();
expect(result.size).toBe(100); // Assuming the first storage returned this size
});
it('should throw an error if all storage writes fail', async () => {
storage1.write = jest.fn().mockRejectedValue(new Error('Write failed'));
storage2.write = jest.fn().mockRejectedValue(new Error('Write failed'));
storage3.write = jest.fn().mockRejectedValue(new Error('Write failed'));
const path = 'test/path';
const stream = mockStream();
await expect(oneOfStorageStrategy.write(path, stream)).rejects.toThrow('Write test/path failed for all storages');
});
it('should succeed if one storage write fails but the other succeeds', async () => {
//given
storage1.write = jest.fn().mockRejectedValue(new Error('Write failed'));
storage2.write = jest.fn().mockResolvedValue({ size: 200 });
storage3.write = jest.fn().mockRejectedValue(new Error('Write failed'));
const path = 'test/path';
const stream = mockStream();
//when
const result = await oneOfStorageStrategy.write(path, stream);
//then
expect(result.size).toBe(200); // Assuming the second storage returned this size
});
it('should verify that all data was written to the storage stream', async () => {
const data = "Test data";
const stream = new Readable();
stream.push(data);
stream.push(null);
storage1.write = jest.fn().mockImplementation((_, stream) => {
return new Promise((resolve, reject) => {
let writtenData = '';
stream.on('data', chunk => {
writtenData += chunk;
});
stream.on('end', () => {
if (writtenData === data) {
resolve({ size: writtenData.length });
} else {
reject(new Error('Data mismatch'));
}
});
});
});
const result = await oneOfStorageStrategy.write("test/path", stream);
expect(result.size).toBe(data.length);
});
});
describe('read', () => {
it('should read from the first storage that has the file', async () => {
const path = 'test/path';
const mockStream = new Readable();
mockStream.push('Test data');
mockStream.push(null);
storage1.read = jest.fn().mockResolvedValue(mockStream);
storage1.exists = jest.fn().mockResolvedValue(true);
const result = await oneOfStorageStrategy.read(path);
expect(storage1.exists).toHaveBeenCalledWith(path, undefined);
expect(storage1.read).toHaveBeenCalledWith(path, undefined);
expect(result).toBe(mockStream);
});
it('should fallback to the next storage if the first fails', async () => {
const path = 'test/path';
storage1.read = jest.fn().mockRejectedValue(new Error('Read failed'));
storage1.exists = jest.fn().mockResolvedValue(true);
const mockStream = new Readable();
mockStream.push('Test data');
mockStream.push(null);
storage2.read = jest.fn().mockResolvedValue(mockStream);
storage2.exists = jest.fn().mockResolvedValue(true);
const result = await oneOfStorageStrategy.read(path);
expect(storage1.exists).toHaveBeenCalled();
expect(storage1.read).toHaveBeenCalled();
expect(storage2.exists).toHaveBeenCalled();
expect(storage2.read).toHaveBeenCalled();
expect(result).toBe(mockStream);
});
});
describe('exists', () => {
it('should return true if the file exists in any storage', async () => {
storage1.exists = jest.fn().mockResolvedValue(false);
storage2.exists = jest.fn().mockResolvedValue(true);
const result = await oneOfStorageStrategy.exists('test/path');
expect(result).toBe(true);
expect(storage1.exists).toHaveBeenCalled();
expect(storage2.exists).toHaveBeenCalled();
});
it('should return false if the file does not exist in any storage', async () => {
storage1.exists = jest.fn().mockResolvedValue(false);
storage2.exists = jest.fn().mockResolvedValue(false);
const result = await oneOfStorageStrategy.exists('test/path');
expect(result).toBe(false);
expect(storage1.exists).toHaveBeenCalled();
expect(storage2.exists).toHaveBeenCalled();
});
});
describe('remove', () => {
it('should remove the file from all storages', async () => {
const result = await oneOfStorageStrategy.remove('test/path');
expect(storage1.remove).toHaveBeenCalledWith('test/path', undefined);
expect(storage2.remove).toHaveBeenCalledWith('test/path', undefined);
expect(result).toBe(true);
});
it('should return false if any storage fails to remove the file', async () => {
storage1.remove = jest.fn().mockResolvedValue(true);
storage2.remove = jest.fn().mockResolvedValue(false);
const result = await oneOfStorageStrategy.remove('test/path');
expect(result).toBe(false);
});
});
});
+72 -440
View File
@@ -493,11 +493,6 @@
rfdc "^1.3.0"
yaml "^2.2.2"
"@ffprobe-installer/darwin-arm64@5.0.1":
version "5.0.1"
resolved "https://registry.npmjs.org/@ffprobe-installer/darwin-arm64/-/darwin-arm64-5.0.1.tgz"
integrity sha512-vwNCNjokH8hfkbl6m95zICHwkSzhEvDC3GVBcUp5HX8+4wsX10SP3B+bGur7XUzTIZ4cQpgJmEIAx6TUwRepMg==
"@ffprobe-installer/ffprobe@^1.4.1":
version "1.4.1"
resolved "https://registry.npmjs.org/@ffprobe-installer/ffprobe/-/ffprobe-1.4.1.tgz"
@@ -512,10 +507,10 @@
"@ffprobe-installer/win32-ia32" "5.0.0"
"@ffprobe-installer/win32-x64" "5.0.0"
"@gar/promisify@^1.1.3":
version "1.1.3"
resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz"
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
"@ffprobe-installer/linux-x64@5.0.0":
version "5.0.0"
resolved "https://registry.npmjs.org/@ffprobe-installer/linux-x64/-/linux-x64-5.0.0.tgz"
integrity sha512-zgLnWJFvMGCaw1txGtz84sMEQt6mQUzdw86ih9S/kZOWnp06Gj/ams/EXxEkAxgAACCVM6/O0mkDe/6biY5tgA==
"@humanwhocodes/config-array@^0.11.14":
version "0.11.14"
@@ -536,17 +531,29 @@
resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz"
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
"@img/sharp-darwin-arm64@0.33.3":
version "0.33.3"
resolved "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.3.tgz"
integrity sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==
optionalDependencies:
"@img/sharp-libvips-darwin-arm64" "1.0.2"
"@img/sharp-libvips-darwin-arm64@1.0.2":
"@img/sharp-libvips-linux-x64@1.0.2":
version "1.0.2"
resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz"
integrity sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==
resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz"
integrity sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==
"@img/sharp-libvips-linuxmusl-x64@1.0.2":
version "1.0.2"
resolved "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz"
integrity sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==
"@img/sharp-linux-x64@0.33.3":
version "0.33.3"
resolved "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.3.tgz"
integrity sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==
optionalDependencies:
"@img/sharp-libvips-linux-x64" "1.0.2"
"@img/sharp-linuxmusl-x64@0.33.3":
version "0.33.3"
resolved "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.3.tgz"
integrity sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==
optionalDependencies:
"@img/sharp-libvips-linuxmusl-x64" "1.0.2"
"@isaacs/cliui@^8.0.2":
version "8.0.2"
@@ -904,22 +911,6 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@npmcli/fs@^2.1.0":
version "2.1.2"
resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz"
integrity sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==
dependencies:
"@gar/promisify" "^1.1.3"
semver "^7.3.5"
"@npmcli/move-file@^2.0.0":
version "2.0.1"
resolved "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz"
integrity sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==
dependencies:
mkdirp "^1.0.4"
rimraf "^3.0.2"
"@opensearch-project/opensearch@^2.4.0":
version "2.7.0"
resolved "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-2.7.0.tgz"
@@ -1087,11 +1078,6 @@
dependencies:
defer-to-connect "^2.0.0"
"@tootallnate/once@2":
version "2.0.0"
resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
"@tsconfig/node10@^1.0.7":
version "1.0.11"
resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz"
@@ -1430,6 +1416,13 @@
pg-protocol "*"
pg-types "^4.0.1"
"@types/pino@^7.0.5":
version "7.0.5"
resolved "https://registry.npmjs.org/@types/pino/-/pino-7.0.5.tgz"
integrity sha512-wKoab31pknvILkxAF8ss+v9iNyhw5Iu/0jLtRkUD74cNfOOLJNnqfFKAv0r7wVaTQxRZtWrMpGfShwwBjOcgcg==
dependencies:
pino "*"
"@types/pump@^1.1.1":
version "1.1.3"
resolved "https://registry.npmjs.org/@types/pump/-/pump-1.1.3.tgz"
@@ -1648,28 +1641,12 @@
resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz"
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
"@xprofiler/node-pre-gyp@^1.0.9":
version "1.0.11"
resolved "https://registry.npmjs.org/@xprofiler/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz"
integrity sha512-kNFT4XscrA+Hjh+jSHs49PiG/YGf08a6eNDo16qjSnCaT4B5ngrKDcNtEJ6CnS0sDP/1oZmHCBYECB6wGKP7lg==
dependencies:
detect-libc "^1.0.3"
https-proxy-agent "^5.0.0"
make-dir "^3.1.0"
node-fetch "^2.6.5"
node-gyp "9.3.1"
nopt "^5.0.0"
npmlog "^5.0.1"
rimraf "^3.0.2"
semver "^7.3.5"
tar "^6.1.11"
"@zxing/text-encoding@0.9.0":
version "0.9.0"
resolved "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz"
integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==
abbrev@^1.0.0, abbrev@1:
abbrev@1:
version "1.1.1"
resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
@@ -1718,28 +1695,13 @@ acorn-walk@^8.1.1:
resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz"
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
agent-base@^6.0.2, agent-base@6:
agent-base@6:
version "6.0.2"
resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
dependencies:
debug "4"
agentkeepalive@^4.2.1:
version "4.5.0"
resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz"
integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==
dependencies:
humanize-ms "^1.2.1"
aggregate-error@^3.0.0:
version "3.1.0"
resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz"
integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
dependencies:
clean-stack "^2.0.0"
indent-string "^4.0.0"
aggregate-error@^4.0.0:
version "4.0.1"
resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz"
@@ -1928,14 +1890,6 @@ are-we-there-yet@^2.0.0:
delegates "^1.0.0"
readable-stream "^3.6.0"
are-we-there-yet@^3.0.0:
version "3.0.1"
resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz"
integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==
dependencies:
delegates "^1.0.0"
readable-stream "^3.6.0"
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz"
@@ -2274,30 +2228,6 @@ buffer@^6.0.3:
base64-js "^1.3.1"
ieee754 "^1.2.1"
cacache@^16.1.0:
version "16.1.3"
resolved "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz"
integrity sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==
dependencies:
"@npmcli/fs" "^2.1.0"
"@npmcli/move-file" "^2.0.0"
chownr "^2.0.0"
fs-minipass "^2.1.0"
glob "^8.0.1"
infer-owner "^1.0.4"
lru-cache "^7.7.1"
minipass "^3.1.6"
minipass-collect "^1.0.2"
minipass-flush "^1.0.5"
minipass-pipeline "^1.2.4"
mkdirp "^1.0.4"
p-map "^4.0.0"
promise-inflight "^1.0.1"
rimraf "^3.0.2"
ssri "^9.0.0"
tar "^6.1.11"
unique-filename "^2.0.0"
cacheable-lookup@^5.0.3:
version "5.0.4"
resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz"
@@ -2447,11 +2377,6 @@ class-transformer@^0.3.1:
resolved "https://registry.npmjs.org/class-transformer/-/class-transformer-0.3.1.tgz"
integrity sha512-cKFwohpJbuMovS8xVLmn8N2AUbAuc8pVo4zEfsUVo8qgECOogns1WVk/FkOZoxhOPTyTYFckuoH+13FO+MQ8GA==
clean-stack@^2.0.0:
version "2.2.0"
resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz"
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
clean-stack@^4.0.0:
version "4.2.0"
resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz"
@@ -2555,7 +2480,7 @@ color-string@^1.9.0:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color-support@^1.1.2, color-support@^1.1.3:
color-support@^1.1.2:
version "1.1.3"
resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz"
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
@@ -2880,11 +2805,6 @@ detect-indent@^6.0.0:
resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz"
integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==
detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz"
integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
detect-libc@^2.0.0, detect-libc@^2.0.3:
version "2.0.3"
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz"
@@ -3024,7 +2944,7 @@ emojilib@^2.0.2:
resolved "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz"
integrity sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==
encoding@^0.1.0, encoding@^0.1.13:
encoding@^0.1.0:
version "0.1.13"
resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz"
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
@@ -3075,16 +2995,6 @@ entities@^2.0.0:
resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz"
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
env-paths@^2.2.0:
version "2.2.1"
resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz"
integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
err-code@^2.0.2:
version "2.0.3"
resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz"
integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz"
@@ -3413,12 +3323,12 @@ fast-querystring@^1.0.0:
dependencies:
fast-decode-uri-component "^1.0.1"
fast-redact@^3.0.0, fast-redact@^3.1.1:
fast-redact@^3.1.1:
version "3.5.0"
resolved "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz"
integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==
fast-safe-stringify@^2.0.8, fast-safe-stringify@^2.1.1, fast-safe-stringify@~2.1.0:
fast-safe-stringify@^2.1.1, fast-safe-stringify@~2.1.0:
version "2.1.1"
resolved "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz"
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
@@ -3583,11 +3493,6 @@ flat-cache@^3.0.4:
keyv "^4.5.3"
rimraf "^3.0.2"
flatstr@^1.0.12:
version "1.0.12"
resolved "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz"
integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==
flatted@^3.2.9:
version "3.3.1"
resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz"
@@ -3683,7 +3588,7 @@ fs-extra@^10.0.0:
jsonfile "^6.0.1"
universalify "^2.0.0"
fs-minipass@^2.0.0, fs-minipass@^2.1.0:
fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz"
integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
@@ -3695,11 +3600,6 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
fsevents@^2.3.2, fsevents@~2.3.2:
version "2.3.3"
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
fstream@^1.0.12:
version "1.0.12"
resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz"
@@ -3730,20 +3630,6 @@ gauge@^3.0.0:
strip-ansi "^6.0.1"
wide-align "^1.1.2"
gauge@^4.0.3:
version "4.0.4"
resolved "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz"
integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==
dependencies:
aproba "^1.0.3 || ^2.0.0"
color-support "^1.1.3"
console-control-strings "^1.1.0"
has-unicode "^2.0.1"
signal-exit "^3.0.7"
string-width "^4.2.3"
strip-ansi "^6.0.1"
wide-align "^1.1.5"
generate-password@^1.6.0:
version "1.7.1"
resolved "https://registry.npmjs.org/generate-password/-/generate-password-1.7.1.tgz"
@@ -3860,17 +3746,6 @@ glob@^7.2.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^8.0.1:
version "8.1.0"
resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz"
integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^5.0.1"
once "^1.3.0"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz"
@@ -3940,7 +3815,7 @@ got@~11.8.5:
p-cancelable "^2.0.0"
responselike "^2.0.0"
graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.9:
version "4.2.11"
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -4055,7 +3930,7 @@ htmlparser2@^6.1.0:
domutils "^2.5.2"
entities "^2.0.0"
http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
http-cache-semantics@^4.0.0:
version "4.1.1"
resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz"
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
@@ -4071,15 +3946,6 @@ http-errors@^2.0.0, http-errors@2.0.0:
statuses "2.0.1"
toidentifier "1.0.1"
http-proxy-agent@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz"
integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==
dependencies:
"@tootallnate/once" "2"
agent-base "6"
debug "4"
http2-wrapper@^1.0.0-beta.5.2:
version "1.0.3"
resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz"
@@ -4101,13 +3967,6 @@ human-signals@^2.1.0:
resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
humanize-ms@^1.2.1:
version "1.2.1"
resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz"
integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
dependencies:
ms "^2.0.0"
i18n@^0.15.1:
version "0.15.1"
resolved "https://registry.npmjs.org/i18n/-/i18n-0.15.1.tgz"
@@ -4170,21 +4029,11 @@ imurmurhash@^0.1.4:
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
indent-string@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz"
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
indent-string@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz"
integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==
infer-owner@^1.0.4:
version "1.0.4"
resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz"
integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
@@ -4287,11 +4136,6 @@ is-interactive@^1.0.0:
resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz"
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
is-lambda@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz"
integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
@@ -5175,11 +5019,6 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
lru-cache@^7.7.1:
version "7.18.3"
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz"
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
lru-cache@~4.0.0:
version "4.0.2"
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz"
@@ -5215,28 +5054,6 @@ make-error@^1.1.1, make-error@1.x:
resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
make-fetch-happen@^10.0.3:
version "10.2.1"
resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz"
integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==
dependencies:
agentkeepalive "^4.2.1"
cacache "^16.1.0"
http-cache-semantics "^4.1.0"
http-proxy-agent "^5.0.0"
https-proxy-agent "^5.0.0"
is-lambda "^1.0.1"
lru-cache "^7.7.1"
minipass "^3.1.6"
minipass-collect "^1.0.2"
minipass-fetch "^2.0.3"
minipass-flush "^1.0.5"
minipass-pipeline "^1.2.4"
negotiator "^0.6.3"
promise-retry "^2.0.1"
socks-proxy-agent "^7.0.0"
ssri "^9.0.0"
make-plural@^7.0.0:
version "7.4.0"
resolved "https://registry.npmjs.org/make-plural/-/make-plural-7.4.0.tgz"
@@ -5388,13 +5205,6 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
dependencies:
brace-expansion "^1.1.7"
minimatch@^5.0.1:
version "5.1.6"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz"
integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
dependencies:
brace-expansion "^2.0.1"
minimatch@^5.1.0:
version "5.1.6"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz"
@@ -5443,45 +5253,6 @@ minio@^7.1.3:
xml "^1.0.1"
xml2js "^0.5.0"
minipass-collect@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz"
integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==
dependencies:
minipass "^3.0.0"
minipass-fetch@^2.0.3:
version "2.1.2"
resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz"
integrity sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==
dependencies:
minipass "^3.1.6"
minipass-sized "^1.0.3"
minizlib "^2.1.2"
optionalDependencies:
encoding "^0.1.13"
minipass-flush@^1.0.5:
version "1.0.5"
resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz"
integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==
dependencies:
minipass "^3.0.0"
minipass-pipeline@^1.2.4:
version "1.2.4"
resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz"
integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==
dependencies:
minipass "^3.0.0"
minipass-sized@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz"
integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==
dependencies:
minipass "^3.0.0"
minipass@^3.0.0:
version "3.3.6"
resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz"
@@ -5489,20 +5260,6 @@ minipass@^3.0.0:
dependencies:
yallist "^4.0.0"
minipass@^3.1.1:
version "3.3.6"
resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz"
integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
dependencies:
yallist "^4.0.0"
minipass@^3.1.6:
version "3.3.6"
resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz"
integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
dependencies:
yallist "^4.0.0"
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4:
version "7.1.0"
resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz"
@@ -5513,7 +5270,7 @@ minipass@^5.0.0:
resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz"
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
minizlib@^2.1.1, minizlib@^2.1.2:
minizlib@^2.1.1:
version "2.1.2"
resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz"
integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
@@ -5569,7 +5326,7 @@ moo@^0.5.0, moo@^0.5.1:
resolved "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz"
integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==
ms@^2.0.0, ms@^2.1.1, ms@^2.1.3:
ms@^2.1.1, ms@^2.1.3:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@@ -5597,11 +5354,6 @@ mustache@^4.2.0:
resolved "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz"
integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==
nan@^2.18.0:
version "2.19.0"
resolved "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz"
integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==
natural-compare-lite@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz"
@@ -5631,7 +5383,7 @@ needle@^2.5.2:
iconv-lite "^0.4.4"
sax "^1.2.4"
negotiator@^0.6.3, negotiator@0.6.3:
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
@@ -5684,29 +5436,13 @@ node-ensure@^0.0.0:
resolved "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz"
integrity sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==
node-fetch@^2.6.5, node-fetch@^2.6.7:
node-fetch@^2.6.7:
version "2.7.0"
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz"
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
dependencies:
whatwg-url "^5.0.0"
node-gyp@9.3.1:
version "9.3.1"
resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz"
integrity sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==
dependencies:
env-paths "^2.2.0"
glob "^7.1.4"
graceful-fs "^4.2.6"
make-fetch-happen "^10.0.3"
nopt "^6.0.0"
npmlog "^6.0.0"
rimraf "^3.0.2"
semver "^7.3.5"
tar "^6.1.2"
which "^2.0.2"
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz"
@@ -5753,13 +5489,6 @@ nopt@^5.0.0:
dependencies:
abbrev "1"
nopt@^6.0.0:
version "6.0.0"
resolved "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz"
integrity sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==
dependencies:
abbrev "^1.0.0"
nopt@~1.0.10:
version "1.0.10"
resolved "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz"
@@ -5809,16 +5538,6 @@ npmlog@^5.0.1:
gauge "^3.0.0"
set-blocking "^2.0.0"
npmlog@^6.0.0:
version "6.0.2"
resolved "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz"
integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==
dependencies:
are-we-there-yet "^3.0.0"
console-control-strings "^1.1.0"
gauge "^4.0.3"
set-blocking "^2.0.0"
object-assign@^4, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
@@ -5957,13 +5676,6 @@ p-locate@^5.0.0:
dependencies:
p-limit "^3.0.2"
p-map@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz"
integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
dependencies:
aggregate-error "^3.0.0"
p-map@^5.1.0, p-map@^5.3.0:
version "5.5.0"
resolved "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz"
@@ -6153,7 +5865,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1:
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pino-abstract-transport@^1.0.0, pino-abstract-transport@^1.2.0:
pino-abstract-transport@^1.0.0:
version "1.2.0"
resolved "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz"
integrity sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==
@@ -6161,6 +5873,13 @@ pino-abstract-transport@^1.0.0, pino-abstract-transport@^1.2.0:
readable-stream "^4.0.0"
split2 "^4.0.0"
pino-abstract-transport@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz"
integrity sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==
dependencies:
split2 "^4.0.0"
pino-pretty@^10.0.0:
version "10.3.1"
resolved "https://registry.npmjs.org/pino-pretty/-/pino-pretty-10.3.1.tgz"
@@ -6181,45 +5900,22 @@ pino-pretty@^10.0.0:
sonic-boom "^3.0.0"
strip-json-comments "^3.1.1"
pino-std-serializers@^3.1.0:
version "3.2.0"
resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz"
integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==
pino-std-serializers@^6.1.0:
version "6.2.2"
resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz"
integrity sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==
pino-std-serializers@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz"
integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==
pino@^6.8.0:
version "6.14.0"
resolved "https://registry.npmjs.org/pino/-/pino-6.14.0.tgz"
integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==
dependencies:
fast-redact "^3.0.0"
fast-safe-stringify "^2.0.8"
flatstr "^1.0.12"
pino-std-serializers "^3.1.0"
process-warning "^1.0.0"
quick-format-unescaped "^4.0.3"
sonic-boom "^1.0.2"
pino@^9.0.0:
version "9.1.0"
resolved "https://registry.npmjs.org/pino/-/pino-9.1.0.tgz"
integrity sha512-qUcgfrlyOtjwhNLdbhoL7NR4NkHjzykAPw0V2QLFbvu/zss29h4NkRnibyFzBrNCbzCOY3WZ9hhKSwfOkNggYA==
pino@*, pino@^9.0.0, pino@^9.5.0:
version "9.5.0"
resolved "https://registry.npmjs.org/pino/-/pino-9.5.0.tgz"
integrity sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==
dependencies:
atomic-sleep "^1.0.0"
fast-redact "^3.1.1"
on-exit-leak-free "^2.1.0"
pino-abstract-transport "^1.2.0"
pino-abstract-transport "^2.0.0"
pino-std-serializers "^7.0.0"
process-warning "^3.0.0"
process-warning "^4.0.0"
quick-format-unescaped "^4.0.3"
real-require "^0.2.0"
safe-stable-stringify "^2.3.1"
@@ -6332,16 +6028,16 @@ process-nextick-args@~2.0.0:
resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
process-warning@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz"
integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==
process-warning@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz"
integrity sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==
process-warning@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/process-warning/-/process-warning-4.0.0.tgz"
integrity sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==
process@^0.11.10:
version "0.11.10"
resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz"
@@ -6352,19 +6048,6 @@ promise-breaker@^5.0.0:
resolved "https://registry.npmjs.org/promise-breaker/-/promise-breaker-5.0.0.tgz"
integrity sha512-mgsWQuG4kJ1dtO6e/QlNDLFtMkMzzecsC69aI5hlLEjGHFNpHrvGhFi4LiK5jg2SMQj74/diH+wZliL9LpGsyA==
promise-inflight@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz"
integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==
promise-retry@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz"
integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==
dependencies:
err-code "^2.0.2"
retry "^0.12.0"
promise@~1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/promise/-/promise-1.3.0.tgz"
@@ -6745,11 +6428,6 @@ ret@~0.4.0:
resolved "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz"
integrity sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==
retry@^0.12.0:
version "0.12.0"
resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz"
integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==
reusify@^1.0.0, reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
@@ -7050,16 +6728,7 @@ socket.io@^4.6.2:
socket.io-adapter "~2.5.2"
socket.io-parser "~4.2.4"
socks-proxy-agent@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz"
integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==
dependencies:
agent-base "^6.0.2"
debug "^4.3.3"
socks "^2.6.2"
socks@^2.6.2, socks@^2.7.1:
socks@^2.7.1:
version "2.8.3"
resolved "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz"
integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==
@@ -7067,14 +6736,6 @@ socks@^2.6.2, socks@^2.7.1:
ip-address "^9.0.5"
smart-buffer "^4.2.0"
sonic-boom@^1.0.2:
version "1.4.1"
resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz"
integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==
dependencies:
atomic-sleep "^1.0.0"
flatstr "^1.0.12"
sonic-boom@^3.0.0:
version "3.8.1"
resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz"
@@ -7083,9 +6744,9 @@ sonic-boom@^3.0.0:
atomic-sleep "^1.0.0"
sonic-boom@^4.0.1:
version "4.0.1"
resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz"
integrity sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==
version "4.2.0"
resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz"
integrity sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==
dependencies:
atomic-sleep "^1.0.0"
@@ -7169,13 +6830,6 @@ sprintf-js@~1.0.2:
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
ssri@^9.0.0:
version "9.0.1"
resolved "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz"
integrity sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==
dependencies:
minipass "^3.1.1"
stack-utils@^2.0.3:
version "2.0.6"
resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz"
@@ -7400,7 +7054,7 @@ tar-stream@^2.2.0:
inherits "^2.0.3"
readable-stream "^3.1.1"
tar@^6.1.11, tar@^6.1.2:
tar@^6.1.11:
version "6.2.1"
resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz"
integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==
@@ -7691,20 +7345,6 @@ undici-types@~5.26.4:
resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
unique-filename@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz"
integrity sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==
dependencies:
unique-slug "^3.0.0"
unique-slug@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz"
integrity sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==
dependencies:
imurmurhash "^0.1.4"
universalify@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz"
@@ -7784,14 +7424,6 @@ v8-compile-cache-lib@^3.0.1:
resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
v8-profiler-next@^1.10.0:
version "1.10.0"
resolved "https://registry.npmjs.org/v8-profiler-next/-/v8-profiler-next-1.10.0.tgz"
integrity sha512-HME7CR3V8gkBEAutcMyGS0vK0XH2hFQhF5SvSdrF/mdjWIGoaiY+WH3RpY7ePY7J7vNDbQfP+Ikefdi1z/mJXg==
dependencies:
"@xprofiler/node-pre-gyp" "^1.0.9"
nan "^2.18.0"
v8-to-istanbul@^9.0.1:
version "9.2.0"
resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz"
@@ -7888,14 +7520,14 @@ which@^1.2.9:
dependencies:
isexe "^2.0.0"
which@^2.0.1, which@^2.0.2:
which@^2.0.1:
version "2.0.2"
resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
wide-align@^1.1.2, wide-align@^1.1.5:
wide-align@^1.1.2:
version "1.1.5"
resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz"
integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==