Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@spinajs/log

Package Overview
Dependencies
Maintainers
1
Versions
292
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@spinajs/log - npm Package Compare versions

Comparing version 1.1.9 to 1.2.7

.eslintignore

6

lib/config/log.js

@@ -10,8 +10,8 @@ "use strict";

dirs: {
schemas: [dir('./../schemas')],
}
schemas: [dir("./../schemas")],
},
},
log: {}
log: {},
};
exports.default = config;
//# sourceMappingURL=log.js.map
/**
* Creates ( if not exists ) new logger instance with given name and optional variables
* @param name name of logger
* @param variables optional log variables
* @param name - name of logger
* @param variables - optional log variables
*/
export declare function Logger(name: string, variables?: {}): (target: any, key: string) => any;
export declare function Logger(name: string, variables?: Record<string, unknown>): (target: any, key: string) => any;

@@ -8,4 +8,4 @@ "use strict";

* Creates ( if not exists ) new logger instance with given name and optional variables
* @param name name of logger
* @param variables optional log variables
* @param name - name of logger
* @param variables - optional log variables
*/

@@ -19,3 +19,3 @@ function Logger(name, variables) {

const allLoggers = di_1.DI.get(Array.ofType(log_1.Log));
const found = allLoggers.find(l => l.Name);
const found = allLoggers.find((l) => l.Name);
if (found) {

@@ -34,3 +34,3 @@ logger = found;

enumerable: false,
configurable: false
configurable: false,
});

@@ -37,0 +37,0 @@ };

@@ -9,4 +9,8 @@ /**

*/
export * from "./config/log";
export * from "./types";
export * as config from "./config/log";
/**
* Same issue with schemas
*/
export * as CONFIGURATION_SCHEMA from "./schemas/log.configuration";
export * from "@spinajs/log-common";
export * from "./targets";

@@ -13,0 +17,0 @@ export * from "./variables";

@@ -13,2 +13,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.CONFIGURATION_SCHEMA = exports.config = void 0;
/**

@@ -22,4 +23,8 @@ * We export default configuration for webpack modules

*/
__exportStar(require("./config/log"), exports);
__exportStar(require("./types"), exports);
exports.config = require("./config/log");
/**
* Same issue with schemas
*/
exports.CONFIGURATION_SCHEMA = require("./schemas/log.configuration");
__exportStar(require("@spinajs/log-common"), exports);
__exportStar(require("./targets"), exports);

@@ -26,0 +31,0 @@ __exportStar(require("./variables"), exports);

@@ -1,13 +0,8 @@

import { IContainer, SyncModule } from "@spinajs/di";
import { LogTarget } from "./targets/LogTarget";
import { ICommonTargetOptions, LogLevel, ILogOptions, ILogRule, ILogTargetData, ITargetsOption } from "./types";
interface ILogTargetDesc {
instance: LogTarget<ICommonTargetOptions>;
options?: ITargetsOption;
rule: ILogRule;
}
import { Container, SyncModule } from "@spinajs/di";
import { ILogTargetDesc } from "./targets/LogTarget";
import { ILogOptions, ILogRule, ILogEntry, LogVariables, ILog } from "@spinajs/log-common";
/**
* Default log implementation interface. Taken from bunyan. Feel free to implement own.
*/
export declare class Log extends SyncModule {
export declare class Log extends SyncModule implements ILog {
Name: string;

@@ -23,27 +18,10 @@ Variables?: any;

static Loggers: Map<string, Log>;
static trace(message: string, name: string, ...args: any[]): void;
static trace(err: Error, message: string, name: string, ...args: any[]): void;
static debug(message: string, name: string, ...args: any[]): void;
static debug(err: Error, message: string, name: string, ...args: any[]): void;
static info(message: string, name: string, ...args: any[]): void;
static info(err: Error, message: string, name: string, ...args: any[]): void;
static warn(message: string, name: string, ...args: any[]): void;
static warn(err: Error, message: string, name: string, ...args: any[]): void;
static error(message: string, name: string, ...args: any[]): void;
static error(err: Error, message: string, name: string, ...args: any[]): void;
static fatal(message: string, name: string, ...args: any[]): void;
static fatal(err: Error, message: string, name: string, ...args: any[]): void;
static security(message: string, name: string, ...args: any[]): void;
static security(err: Error, message: string, name: string, ...args: any[]): void;
static success(message: string, name: string, ...args: any[]): void;
static success(err: Error, message: string, name: string, ...args: any[]): void;
static clearLoggers(): void;
protected static LogBuffer: Map<string, ILogTargetData[]>;
protected static AttachedToExitEvents: boolean;
protected static write(err: Error | string, message: string | any[], level: LogLevel, name: string, ...args: any[]): void;
protected Options: ILogOptions;
protected Rules: ILogRule[];
protected Targets: ILogTargetDesc[];
protected Container: Container;
constructor(Name: string, Variables?: any, Parent?: Log);
resolve(container: IContainer): void;
resolve(): void;
trace(message: string, ...args: any[]): void;

@@ -65,8 +43,6 @@ trace(err: Error, message: string, ...args: any[]): void;

success(err: Error, message: string, ...args: any[]): void;
child(name: string, variables?: {}): Log;
protected writeBufferedMessages(): void;
write(entry: ILogEntry): Promise<PromiseSettledResult<void>[]>;
child(name: string, variables?: LogVariables): Log;
protected resolveLogTargets(): void;
protected matchRulesToLogger(): void;
protected write(err: Error | string, message: string | any[], level: LogLevel, ...args: any[]): void;
}
export {};
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

@@ -20,45 +8,27 @@ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;

};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var Log_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Log = void 0;
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
const types_1 = require("@spinajs/configuration/lib/types");
const di_1 = require("@spinajs/di");
const types_2 = require("./types");
const util = __importStar(require("util"));
const glob_to_regexp_1 = __importDefault(require("glob-to-regexp"));
const log_common_1 = require("@spinajs/log-common");
const globToRegexp = require("glob-to-regexp");
const exceptions_1 = require("@spinajs/exceptions");
function createLogMessageObject(err, message, level, logger, variables, ...args) {
const sMsg = (err instanceof Error) ? message : err;
const tMsg = args.length !== 0 ? util.format(sMsg, ...args) : sMsg;
const lName = logger !== null && logger !== void 0 ? logger : message;
return {
Level: level,
Variables: Object.assign({ error: (err instanceof Error) ? err : undefined, level: types_2.LogLevelStrings[level].toUpperCase(), logger: lName, message: tMsg }, variables)
};
}
function wrapWrite(level) {
const self = this;
return (err, message, ...args) => {
if (err instanceof Error) {
self.write(err, message, level, ...args);
return this.write((0, log_common_1.createLogMessageObject)(err, message, level, this.Name, this.Variables, ...args));
}
else {
if (message) {
self.write(err, null, level, ...[message, ...args]);
return this.write((0, log_common_1.createLogMessageObject)(err, null, level, this.Name, this.Variables, ...[message, ...args]));
}
else {
self.write(err, null, level, ...args);
return this.write((0, log_common_1.createLogMessageObject)(err, null, level, this.Name, this.Variables, ...args));
}

@@ -78,101 +48,64 @@ }

}
static trace(err, message, name, ...args) {
Log_1.write(err, message, types_2.LogLevel.Trace, name, ...args);
}
static debug(err, message, name, ...args) {
Log_1.write(err, message, types_2.LogLevel.Debug, name, ...args);
}
static info(err, message, name, ...args) {
Log_1.write(err, message, types_2.LogLevel.Info, name, ...args);
}
static warn(err, message, name, ...args) {
Log_1.write(err, message, types_2.LogLevel.Warn, name, ...args);
}
static error(err, message, name, ...args) {
Log_1.write(err, message, types_2.LogLevel.Error, name, ...args);
}
static fatal(err, message, name, ...args) {
Log_1.write(err, message, types_2.LogLevel.Fatal, name, ...args);
}
static security(err, message, name, ...args) {
Log_1.write(err, message, types_2.LogLevel.Security, name, ...args);
}
static success(err, message, name, ...args) {
Log_1.write(err, message, types_2.LogLevel.Success, name, ...args);
}
static clearLoggers() {
Log_1.Loggers.clear();
}
static write(err, message, level, name, ...args) {
const msg = createLogMessageObject(err, message, level, name, {}, ...args);
const logName = name !== null && name !== void 0 ? name : message;
// if we have already created logger write to it
if (Log_1.Loggers.has(logName)) {
Log_1.Loggers.get(logName).Targets.forEach(t => t.instance.write(msg));
return;
}
// otherwise store in buffer
if (Log_1.LogBuffer.has(logName)) {
Log_1.LogBuffer.get(logName).push(msg);
}
else {
Log_1.LogBuffer.set(logName, [msg]);
}
}
resolve(container) {
const config = container.get(types_1.Configuration);
resolve() {
const config = this.Container.get(types_1.Configuration);
this.Options = config.get("logger");
this.matchRulesToLogger();
this.resolveLogTargets();
this.writeBufferedMessages();
super.resolve(container);
super.resolve();
Log_1.Loggers.set(this.Name, this);
}
trace(err, message, ...args) {
wrapWrite.apply(this, [types_2.LogLevel.Trace])(err, message, ...args);
wrapWrite.apply(this, [log_common_1.LogLevel.Trace])(err, message, ...args);
}
debug(err, message, ...args) {
wrapWrite.apply(this, [types_2.LogLevel.Debug])(err, message, ...args);
wrapWrite.apply(this, [log_common_1.LogLevel.Debug])(err, message, ...args);
}
info(err, message, ...args) {
wrapWrite.apply(this, [types_2.LogLevel.Info])(err, message, ...args);
wrapWrite.apply(this, [log_common_1.LogLevel.Info])(err, message, ...args);
}
warn(err, message, ...args) {
wrapWrite.apply(this, [types_2.LogLevel.Warn])(err, message, ...args);
wrapWrite.apply(this, [log_common_1.LogLevel.Warn])(err, message, ...args);
}
error(err, message, ...args) {
wrapWrite.apply(this, [types_2.LogLevel.Error])(err, message, ...args);
wrapWrite.apply(this, [log_common_1.LogLevel.Error])(err, message, ...args);
}
fatal(err, message, ...args) {
wrapWrite.apply(this, [types_2.LogLevel.Fatal])(err, message, ...args);
wrapWrite.apply(this, [log_common_1.LogLevel.Fatal])(err, message, ...args);
}
security(err, message, ...args) {
wrapWrite.apply(this, [types_2.LogLevel.Security])(err, message, ...args);
wrapWrite.apply(this, [log_common_1.LogLevel.Security])(err, message, ...args);
}
success(err, message, ...args) {
wrapWrite.apply(this, [types_2.LogLevel.Success])(err, message, ...args);
wrapWrite.apply(this, [log_common_1.LogLevel.Success])(err, message, ...args);
}
write(entry) {
if (entry.Variables.logger === this.Name) {
return Promise.allSettled(this.Targets.filter((t) => entry.Level >= log_common_1.StrToLogLevel[t.rule.level]).map((t) => t.instance.write(entry)));
}
}
child(name, variables) {
return di_1.DI.resolve(Log_1, [`${this.Name}.${name}`, Object.assign(Object.assign({}, this.Variables), variables), this]);
return di_1.DI.resolve(Log_1, [
`${this.Name}.${name}`,
Object.assign(Object.assign({}, this.Variables), variables),
this,
]);
}
writeBufferedMessages() {
if (Log_1.LogBuffer.has(this.Name)) {
Log_1.LogBuffer.get(this.Name).filter((msg) => msg.Variables.logger === this.Name).forEach((msg) => {
this.Targets.forEach(t => t.instance.write(msg));
});
}
}
resolveLogTargets() {
this.Targets = this.Rules.map(r => {
const found = this.Options.targets.filter(t => {
return Array.isArray(r.target) ? r.target.includes(t.name) : r.target === t.name;
this.Targets = this.Rules.map((r) => {
const found = this.Options.targets.filter((t) => {
return Array.isArray(r.target)
? r.target.includes(t.name)
: r.target === t.name;
});
if (!found) {
throw new exceptions_1.InvalidOption(`No target matching rule ${r.target}`);
throw new exceptions_1.InvalidOption(`No target matching rule ${r.name}`);
}
return found.map(f => {
return found.map((f) => {
return {
instance: di_1.DI.resolve(f.type, [f]),
options: f,
rule: r
rule: r,
};

@@ -183,14 +116,6 @@ });

matchRulesToLogger() {
this.Rules = this.Options.rules.filter(r => {
return (0, glob_to_regexp_1.default)(r.name).test(this.Name);
this.Rules = this.Options.rules.filter((r) => {
return globToRegexp(r.name).test(this.Name);
});
}
write(err, message, level, ...args) {
const lMsg = createLogMessageObject(err, message, level, this.Name, this.Variables, ...args);
this.Targets.forEach(t => {
if (level >= types_2.StrToLogLevel[t.rule.level]) {
t.instance.write(lMsg);
}
});
}
};

@@ -204,4 +129,7 @@ /**

Log.Loggers = new Map();
Log.LogBuffer = new Map();
Log.AttachedToExitEvents = false;
__decorate([
(0, di_1.Autoinject)(),
__metadata("design:type", di_1.Container)
], Log.prototype, "Container", void 0);
Log = Log_1 = __decorate([

@@ -212,13 +140,21 @@ (0, di_1.NewInstance)(),

exports.Log = Log;
di_1.DI.register(Log).as("__logImplementation__");
di_1.DI.register((container, ...args) => {
if (!args || args.length === 0 || typeof args[0] !== "string") {
throw new di_1.ResolveException(`invalid arguments for Log constructor (logger name)`);
}
const logName = args[0];
const logFactoryFunction = (container, logName) => {
if (Log.Loggers.has(logName)) {
return Log.Loggers.get(logName);
}
return container.resolve("__logImplementation__", [...args]);
}).as(Log);
return container.resolve("__logImplementation__", [logName]);
};
// register as string identifier to allow for
// resolving logs without referencing class
// to avoid circular dependencies in some @spinajs packages
// it should not be used in production code
di_1.DI.register(logFactoryFunction).as("__log__");
// register log factory function as Log class
// this way we can create or return already created
// log objects
di_1.DI.register(logFactoryFunction).as(Log);
// register Log class as string literal
// so we can resolve Log class
// it should not be used in production code
di_1.DI.register(Log).as("__logImplementation__");
//# sourceMappingURL=log.js.map

@@ -1,8 +0,4 @@

import { AsyncModule, IContainer } from "@spinajs/di";
import { DataValidator } from "@spinajs/validation";
import { ILogOptions } from "./types";
export declare class LogBootstrap extends AsyncModule {
protected Validator: DataValidator;
protected Options: ILogOptions;
resolveAsync(_: IContainer): Promise<void>;
import { Bootstrapper } from "@spinajs/di";
export declare class Logger extends Bootstrapper {
bootstrap(): Promise<void>;
}

@@ -8,34 +8,24 @@ "use strict";

};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LogBootstrap = void 0;
const decorators_1 = require("@spinajs/configuration/lib/decorators");
exports.Logger = void 0;
const di_1 = require("@spinajs/di");
const validation_1 = require("@spinajs/validation");
const log_1 = require("./log");
class LogBootstrap extends di_1.AsyncModule {
async resolveAsync(_) {
/**
* Check if options are valid, if not break, break, break
*/
this.Validator.validate("spinajs/log.configuration.schema.json", this.Options);
const log_configuration_1 = require("./schemas/log.configuration");
let Logger = class Logger extends di_1.Bootstrapper {
async bootstrap() {
di_1.DI.register(log_configuration_1.default).asValue("__configurationSchema__");
process.on("uncaughtException", (err) => {
log_1.Log.fatal(err, "Unhandled exception occured", "process");
const log = di_1.DI.resolve(log_1.Log, ["process"]);
log.fatal(err, "Unhandled exception occured");
});
process.on("unhandledRejection", (reason, p) => {
log_1.Log.fatal(reason, "Unhandled rejection at Promise %s", "process", p);
const log = di_1.DI.resolve(log_1.Log, ["process"]);
log.fatal(reason, "Unhandled rejection at Promise %s", p);
});
}
}
__decorate([
(0, di_1.Autoinject)(),
__metadata("design:type", validation_1.DataValidator)
], LogBootstrap.prototype, "Validator", void 0);
__decorate([
(0, decorators_1.Config)("logger"),
__metadata("design:type", Object)
], LogBootstrap.prototype, "Options", void 0);
exports.LogBootstrap = LogBootstrap;
};
Logger = __decorate([
di_1.Autoinject
], Logger);
exports.Logger = Logger;
//# sourceMappingURL=logger.js.map
declare const CONFIGURATION_SCHEMA: {
$id: string;
$configurationModule: string;
description: string;

@@ -4,0 +5,0 @@ type: string;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CONFIGURATION_SCHEMA = {
"$id": "spinajs/log.configuration.schema.json",
"description": "Logger configuration option validation",
"type": "object",
"properties": {
"targets": {
"description": "Log target, where log messages should be written to, and their options",
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "object",
"properties": {
"layout": {
"type": "string"
$id: "spinajs/log.configuration.schema.json",
$configurationModule: "logger",
description: "Logger configuration option validation",
type: "object",
properties: {
targets: {
description: "Log target, where log messages should be written to, and their options",
type: "array",
minItems: 1,
uniqueItems: true,
items: {
type: "object",
properties: {
layout: {
type: "string",
},
"name": {
"type": "string"
name: {
type: "string",
},
"type": {
"type": "string"
type: {
type: "string",
},
"theme": {
"type": "object",
"properties": {
"security": {
"type": "string"
theme: {
type: "object",
properties: {
security: {
type: "string",
},
"fatal": {
"type": "string"
fatal: {
type: "string",
},
"error": {
"type": "string"
error: {
type: "string",
},
"warn": {
"type": "string"
warn: {
type: "string",
},
"success": {
"type": "string"
success: {
type: "string",
},
"info": {
"type": "string"
info: {
type: "string",
},
"debug": {
"type": "string"
debug: {
type: "string",
},
"trace": {
"type": "string"
}
}
trace: {
type: "string",
},
},
},
"enabled": {
"type": "boolean"
enabled: {
type: "boolean",
},
"path": {
"type": "string"
path: {
type: "string",
},
"archivePath": {
"type": "string"
archivePath: {
type: "string",
},
"maxSize": {
"type": "integer",
"minimum": 10000
maxSize: {
type: "integer",
minimum: 10000,
},
"compress": {
"type": "boolean"
compress: {
type: "boolean",
},
"rotate": {
"type": "string"
rotate: {
type: "string",
},
"maxArchiveFiles": {
"type": "integer",
"minimum": 1
maxArchiveFiles: {
type: "integer",
minimum: 1,
},
"bufferSize": {
"type": "integer",
"minimum": 1000
}
bufferSize: {
type: "integer",
minimum: 1000,
},
},
"required": [
"name",
"type"
]
}
required: ["name", "type"],
},
},
"rules": {
"description": "Log rules, what log should be write where",
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
rules: {
description: "Log rules, what log should be write where",
type: "array",
minItems: 1,
uniqueItems: true,
items: {
type: "object",
properties: {
name: {
type: "string",
},
"level": {
"type": "string",
"enum": [
level: {
type: "string",
enum: [
"trace",

@@ -109,29 +107,25 @@ "debug",

"security",
"success"
]
"success",
],
},
"target": {
"oneOf": [
target: {
oneOf: [
{
"type": "string"
type: "string",
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
type: "array",
items: {
type: "string",
},
},
],
},
},
"required": [
"name",
"level",
"target"
]
}
}
}
required: ["name", "level", "target"],
},
},
},
};
exports.default = CONFIGURATION_SCHEMA;
//# sourceMappingURL=log.configuration.js.map

@@ -1,8 +0,8 @@

import { IBlackHoleTargetOptions } from './../types';
import { LogTarget } from './LogTarget';
import { ICommonTargetOptions } from "@spinajs/log-common";
import { LogTarget } from "./LogTarget";
/**
* Empty writer, usefull for tests or when we dont want to get any messages
*/
export declare class BlackHoleTarget extends LogTarget<IBlackHoleTargetOptions> {
export declare class BlackHoleTarget extends LogTarget<ICommonTargetOptions> {
write(): Promise<void>;
}

@@ -1,4 +0,3 @@

import { IColoredConsoleTargetOptions, ILogTargetData } from './../types';
import { IContainer } from '@spinajs/di';
import { LogTarget } from './LogTarget';
import { IColoredConsoleTargetOptions, ILogEntry } from "@spinajs/log-common";
import { LogTarget } from "./LogTarget";
export declare const DEFAULT_THEME: {

@@ -49,4 +48,4 @@ security: string[];

};
resolve(_: IContainer): void;
write(data: ILogTargetData): Promise<void>;
resolve(): void;
write(data: ILogEntry): Promise<void>;
}

@@ -10,17 +10,16 @@ "use strict";

exports.ColoredConsoleTarget = exports.DEFAULT_THEME = void 0;
const types_1 = require("./../types");
const log_common_1 = require("@spinajs/log-common");
const di_1 = require("@spinajs/di");
const LogTarget_1 = require("./LogTarget");
const __1 = require("..");
// tslint:disable-next-line
const colors = require('colors/safe');
const colors = require("colors/safe");
exports.DEFAULT_THEME = {
security: ['red', "bgBrightWhite"],
fatal: 'red',
error: 'brightRed',
warn: 'yellow',
success: 'green',
info: 'white',
debug: 'gray',
trace: 'gray',
security: ["red", "bgBrightWhite"],
fatal: "red",
error: "brightRed",
warn: "yellow",
success: "green",
info: "white",
debug: "gray",
trace: "gray",
};

@@ -41,6 +40,6 @@ let ColoredConsoleTarget = class ColoredConsoleTarget extends LogTarget_1.LogTarget {

}
resolve(_) {
resolve() {
var _a;
colors.setTheme((_a = this.Options.theme) !== null && _a !== void 0 ? _a : exports.DEFAULT_THEME);
super.resolve(_);
super.resolve();
}

@@ -51,3 +50,8 @@ async write(data) {

}
this.StdConsoleCallbackMap[data.Level](colors[types_1.LogLevelStrings[data.Level]](this.format(data.Variables, this.Options.layout)));
this.StdConsoleCallbackMap[data.Level](
/**
* we are safe to call, disable eslint
*/
/* eslint-disable */
colors[log_common_1.LogLevelStrings[data.Level]](this.format(data.Variables, this.Options.layout)));
}

@@ -54,0 +58,0 @@ };

@@ -1,4 +0,3 @@

import { IContainer } from "@spinajs/di";
import { LogTarget } from "./LogTarget";
import { IFileTargetOptions, ILogTargetData } from "../types";
import { IFileTargetOptions, ILogEntry } from "@spinajs/log-common";
import { Job } from "node-schedule";

@@ -18,4 +17,4 @@ export declare class FileTarget extends LogTarget<IFileTargetOptions> {

protected Buffer: any[];
resolve(_: IContainer): void;
write(data: ILogTargetData): Promise<void>;
resolve(): void;
write(data: ILogEntry): Promise<void>;
protected archive(): void;

@@ -22,0 +21,0 @@ protected flush(): void;

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
/* eslint security/detect-non-literal-fs-filename:0 -- Safe as no value holds user input */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

@@ -20,12 +9,2 @@ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;

};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -35,9 +14,9 @@ exports.FileTarget = void 0;

const LogTarget_1 = require("./LogTarget");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const fs = require("fs");
const path = require("path");
const node_schedule_1 = require("node-schedule");
const exceptions_1 = require("@spinajs/exceptions");
const os_1 = require("os");
const glob = __importStar(require("glob"));
const zlib = __importStar(require("zlib"));
const glob = require("glob");
const zlib = require("zlib");
let FileTarget = class FileTarget extends LogTarget_1.LogTarget {

@@ -49,3 +28,3 @@ constructor() {

}
resolve(_) {
resolve() {
this.Options.options = Object.assign({

@@ -56,3 +35,3 @@ compress: true,

bufferSize: 8 * 1024,
flushTimeout: 10 * 1000
flushTimeout: 10 * 1000,
}, this.Options.options);

@@ -64,8 +43,8 @@ this.initialize();

if (this.LogFileDescriptor) {
fs_1.default.closeSync(this.LogFileDescriptor);
fs.closeSync(this.LogFileDescriptor);
}
});
super.resolve(_);
super.resolve();
}
async write(data) {
write(data) {
if (!this.Options.enabled) {

@@ -86,40 +65,43 @@ return;

archive() {
const files = glob.sync(path_1.default.join(this.ArchiveDirPath, `archived_${this.LogBaseName}*{${this.LogFileExt},.gzip}`)).map(f => {
const files = glob
.sync(path.join(this.ArchiveDirPath, `archived_${this.LogBaseName}*{${this.LogFileExt},.gzip}`))
.map((f) => {
return {
name: f,
stat: fs_1.default.statSync(f)
stat: fs.statSync(f),
};
}).sort(x => x.stat.mtime.getTime());
})
.sort((x) => x.stat.mtime.getTime());
const newestFile = files.length !== 0 ? files[files.length - 1].name : undefined;
const fIndex = newestFile ? parseInt(newestFile.substring(newestFile.lastIndexOf("_") + 1, newestFile.lastIndexOf("_") + 2), 10) + 1 : 1;
const archPath = path_1.default.join(this.ArchiveDirPath, `archived_${this.LogBaseName}_${fIndex}${this.LogFileExt}`);
try {
this.flush();
if (!fs_1.default.existsSync(this.LogPath)) {
return;
}
fs_1.default.closeSync(this.LogFileDescriptor);
fs_1.default.copyFileSync(this.LogPath, archPath);
fs_1.default.unlinkSync(this.LogPath);
this.initialize();
if (this.Options.options.compress) {
const zippedPath = path_1.default.join(this.ArchiveDirPath, `archived_${this.LogBaseName}_${fIndex}${this.LogFileExt}.gzip`);
const zip = zlib.createGzip();
const read = fs_1.default.createReadStream(archPath);
const write = fs_1.default.createWriteStream(zippedPath);
read.pipe(zip).pipe(write);
write.on("finish", () => {
read.close();
zip.close();
write.close();
fs_1.default.unlink(archPath, () => { return; });
const fIndex = newestFile
? parseInt(newestFile.substring(newestFile.lastIndexOf("_") + 1, newestFile.lastIndexOf("_") + 2), 10) + 1
: 1;
const archPath = path.join(this.ArchiveDirPath, `archived_${this.LogBaseName}_${fIndex}${this.LogFileExt}`);
this.flush();
if (!fs.existsSync(this.LogPath)) {
return;
}
fs.closeSync(this.LogFileDescriptor);
fs.copyFileSync(this.LogPath, archPath);
fs.unlinkSync(this.LogPath);
this.initialize();
if (this.Options.options.compress) {
const zippedPath = path.join(this.ArchiveDirPath, `archived_${this.LogBaseName}_${fIndex}${this.LogFileExt}.gzip`);
const zip = zlib.createGzip();
const read = fs.createReadStream(archPath);
const write = fs.createWriteStream(zippedPath);
read.pipe(zip).pipe(write);
write.on("finish", () => {
read.close();
zip.close();
write.close();
fs.unlink(archPath, () => {
return;
});
}
if (files.length >= this.Options.options.maxArchiveFiles) {
fs_1.default.unlink(files[0].name, () => { return; });
}
});
}
catch (err) {
this.Error = err;
this.HasError = true;
if (files.length >= this.Options.options.maxArchiveFiles) {
fs.unlink(files[0].name, () => {
return;
});
}

@@ -131,12 +113,6 @@ }

}
try {
fs_1.default.writeFileSync(this.LogFileDescriptor, this.Buffer.join());
this.CurrentFileSize += this.BufferSize;
this.Buffer = [];
this.BufferSize = 0;
}
catch (err) {
this.HasError = true;
this.Error = err;
}
fs.writeFileSync(this.LogFileDescriptor, this.Buffer.join());
this.CurrentFileSize += this.BufferSize;
this.Buffer = [];
this.BufferSize = 0;
}

@@ -151,44 +127,40 @@ rotate() {

initialize() {
try {
this.flush();
if (this.LogFileDescriptor >= 0) {
fs_1.default.closeSync(this.LogFileDescriptor);
this.LogFileDescriptor = 0;
this.flush();
if (this.LogFileDescriptor >= 0) {
fs.closeSync(this.LogFileDescriptor);
this.LogFileDescriptor = 0;
}
this.CurrentFileSize = 0;
this.LogDirPath = this.format(null, path.dirname(path.resolve(this.Options.options.path)));
this.ArchiveDirPath = this.Options.options.archivePath
? this.format(null, path.resolve(this.Options.options.archivePath))
: this.LogDirPath;
this.LogFileName = this.format(null, path.basename(this.Options.options.path));
this.LogPath = path.join(this.LogDirPath, this.LogFileName);
const { name, ext } = path.parse(this.LogFileName);
this.LogFileExt = ext;
this.LogBaseName = name;
if (!this.LogDirPath) {
throw new exceptions_1.InvalidOption("Missing LogDirPath log option");
}
if (!fs.existsSync(this.LogDirPath)) {
fs.mkdirSync(this.LogDirPath);
}
if (this.ArchiveDirPath) {
if (!fs.existsSync(this.ArchiveDirPath)) {
fs.mkdirSync(this.ArchiveDirPath);
}
this.CurrentFileSize = 0;
this.LogDirPath = this.format({}, path_1.default.dirname(path_1.default.resolve(this.Options.options.path)));
this.ArchiveDirPath = this.Options.options.archivePath ? this.format({}, path_1.default.resolve(this.Options.options.archivePath)) : this.LogDirPath;
this.LogFileName = this.format({}, path_1.default.basename(this.Options.options.path));
this.LogPath = path_1.default.join(this.LogDirPath, this.LogFileName);
const { name, ext } = path_1.default.parse(this.LogFileName);
this.LogFileExt = ext;
this.LogBaseName = name;
if (!this.LogDirPath) {
throw new exceptions_1.InvalidOption("Missing LogDirPath log option");
}
if (!fs_1.default.existsSync(this.LogDirPath)) {
fs_1.default.mkdirSync(this.LogDirPath);
}
if (this.ArchiveDirPath) {
if (!fs_1.default.existsSync(this.ArchiveDirPath)) {
fs_1.default.mkdirSync(this.ArchiveDirPath);
}
}
if (fs_1.default.existsSync(this.LogPath)) {
const { size } = fs_1.default.statSync(this.LogPath);
this.CurrentFileSize = size;
}
this.LogFileDescriptor = fs_1.default.openSync(this.LogPath, "a");
if (this.Options.options.flushTimeout !== 0) {
setTimeout(() => {
this.flush();
}, this.Options.options.flushTimeout);
}
this.HasError = false;
this.Error = null;
}
catch (err) {
this.HasError = true;
this.Error = err;
if (fs.existsSync(this.LogPath)) {
const { size } = fs.statSync(this.LogPath);
this.CurrentFileSize = size;
}
this.LogFileDescriptor = fs.openSync(this.LogPath, "a");
if (this.Options.options.flushTimeout !== 0) {
setTimeout(() => {
this.flush();
}, this.Options.options.flushTimeout);
}
this.HasError = false;
this.Error = null;
}

@@ -195,0 +167,0 @@ };

@@ -0,3 +1,4 @@

export * from "./BlackHoleTarget";
export * from "./ColoredConsoleTarget";
export * from "./FileTarget";
export * from "./LogTarget";

@@ -13,2 +13,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./BlackHoleTarget"), exports);
__exportStar(require("./ColoredConsoleTarget"), exports);

@@ -15,0 +16,0 @@ __exportStar(require("./FileTarget"), exports);

@@ -1,8 +0,12 @@

import { ICommonTargetOptions } from './../types';
import { SyncModule } from "@spinajs/di";
import { LogVariable, ILogTargetData } from "../types";
import { LogVariable, ILogEntry, ICommonTargetOptions, LogVariables, ILogRule, ITargetsOption } from "@spinajs/log-common";
export interface ILogTargetDesc {
instance: LogTarget<ICommonTargetOptions>;
options?: ITargetsOption;
rule: ILogRule;
}
export declare abstract class LogTarget<T extends ICommonTargetOptions> extends SyncModule {
protected Variables: LogVariable[];
HasError: boolean;
Error: Error | null;
Error: Error | null | unknown;
protected VariablesDictionary: Map<string, LogVariable>;

@@ -12,4 +16,5 @@ protected LayoutRegexp: RegExp;

constructor(Variables: LogVariable[], options: T);
abstract write(data: ILogTargetData): Promise<void>;
protected format(customVars: {}, layout: string): string;
abstract write(data: ILogEntry): Promise<void>;
protected format(customVars: LogVariables | null, layout: string): string;
protected _format(vars: LogVariables, txt: string): string;
}

@@ -11,10 +11,7 @@ "use strict";

};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LogTarget = void 0;
const di_1 = require("@spinajs/di");
const lodash_1 = __importDefault(require("lodash"));
const types_1 = require("../types");
const _ = require("lodash");
const log_common_1 = require("@spinajs/log-common");
let LogTarget = class LogTarget extends di_1.SyncModule {

@@ -27,3 +24,3 @@ constructor(Variables, options) {

this.VariablesDictionary = new Map();
this.Variables.forEach(v => {
this.Variables.forEach((v) => {
this.VariablesDictionary.set(v.Name, v);

@@ -33,5 +30,5 @@ });

if (options) {
this.Options = lodash_1.default.merge(lodash_1.default.merge(this.Options, {
this.Options = _.merge(_.merge(this.Options, {
enabled: true,
layout: "{datetime} {level} {message} {error} ({logger})"
layout: "{datetime} {level} {message} {error} ({logger})",
}), options);

@@ -41,40 +38,45 @@ }

format(customVars, layout) {
const self = this;
if (customVars.message) {
return _format(Object.assign(Object.assign({}, customVars), { message: _format(customVars, customVars.message) }), layout);
if (customVars === null || customVars === void 0 ? void 0 : customVars.message) {
return this._format(Object.assign(Object.assign({}, customVars), { message: this._format(customVars, customVars.message) }), layout);
}
return _format(customVars, layout);
function _format(vars, txt) {
self.LayoutRegexp.lastIndex = 0;
const varMatch = [...txt.matchAll(self.LayoutRegexp)];
if (!varMatch) {
return "";
}
let result = txt;
varMatch.forEach(v => {
if (vars[v[2]]) {
result = result.replace(v[0], vars[v[2]]);
return this._format(customVars, layout);
}
_format(vars, txt) {
this.LayoutRegexp.lastIndex = 0;
const varMatch = [...txt.matchAll(this.LayoutRegexp)];
if (!varMatch) {
return "";
}
let result = txt;
varMatch.forEach((v) => {
if (vars && vars[v[2]]) {
const fVar = vars[v[2]];
if (fVar instanceof Function) {
result = result.replace(v[0], fVar());
}
else {
const variable = self.VariablesDictionary.get(v[2]);
if (variable) {
// optional parameter eg. {env:PORT}
if (v[3]) {
result = result.replace(v[0], variable.Value(v[4]));
}
else {
result = result.replace(v[0], variable.Value());
}
result = result.replace(v[0], fVar);
}
}
else {
const variable = this.VariablesDictionary.get(v[2]);
if (variable) {
// optional parameter eg. {env:PORT}
if (v[4]) {
result = result.replace(v[0], variable.Value(v[4]));
}
else {
result = result.replace(v[0], "");
result = result.replace(v[0], variable.Value());
}
}
});
return result;
}
else {
result = result.replace(v[0], "");
}
}
});
return result;
}
};
LogTarget = __decorate([
(0, di_1.Inject)(Array.ofType(types_1.LogVariable)),
(0, di_1.Inject)(Array.ofType(log_common_1.LogVariable)),
__metadata("design:paramtypes", [Array, Object])

@@ -81,0 +83,0 @@ ], LogTarget);

@@ -48,3 +48,3 @@ export declare enum LogLevel {

rules: ILogRule[];
variables: {};
variables: Record<string, unknown>;
}

@@ -55,3 +55,3 @@ export interface ICommonTargetOptions {

*
* Default message layout is: {datetime} {level} {message} ({logger})
* Default message layout is: datetime level message (logger)
*/

@@ -72,4 +72,2 @@ layout: string;

}
export interface IBlackHoleTargetOptions extends ICommonTargetOptions {
}
export interface IColoredConsoleTargetOptions extends ICommonTargetOptions {

@@ -140,10 +138,15 @@ /**

}
export interface ILogStaticVariables {
error: Error | undefined;
level: string;
logger: string;
message: string;
}
export interface ILogVariable {
[key: string]: string | (() => string);
}
export interface ILogTargetData {
Level: LogLevel;
Variables: {
error: Error | undefined;
level: string;
logger: string;
message: string;
};
Variables: LogVariables;
}
export declare type LogVariables = ILogStaticVariables & ILogVariable;

@@ -16,10 +16,10 @@ "use strict";

exports.StrToLogLevel = {
"trace": LogLevel.Trace,
"debug": LogLevel.Debug,
"info": LogLevel.Info,
"success": LogLevel.Success,
"warn": LogLevel.Warn,
"error": LogLevel.Error,
"fatal": LogLevel.Fatal,
"security": LogLevel.Security
trace: LogLevel.Trace,
debug: LogLevel.Debug,
info: LogLevel.Info,
success: LogLevel.Success,
warn: LogLevel.Warn,
error: LogLevel.Error,
fatal: LogLevel.Fatal,
security: LogLevel.Security,
};

@@ -26,0 +26,0 @@ exports.LogLevelStrings = {

@@ -1,2 +0,2 @@

import { LogVariable } from "../types";
import { LogVariable } from "@spinajs/log-common";
export declare class DateTimeLogVariable extends LogVariable {

@@ -3,0 +3,0 @@ get Name(): string;

@@ -15,4 +15,4 @@ "use strict";

const luxon_1 = require("luxon");
const types_1 = require("../types");
let DateTimeLogVariable = class DateTimeLogVariable extends types_1.LogVariable {
const log_common_1 = require("@spinajs/log-common");
let DateTimeLogVariable = class DateTimeLogVariable extends log_common_1.LogVariable {
get Name() {

@@ -26,6 +26,6 @@ return "datetime";

DateTimeLogVariable = __decorate([
(0, di_1.Injectable)(types_1.LogVariable)
(0, di_1.Injectable)(log_common_1.LogVariable)
], DateTimeLogVariable);
exports.DateTimeLogVariable = DateTimeLogVariable;
let DateLogVariable = class DateLogVariable extends types_1.LogVariable {
let DateLogVariable = class DateLogVariable extends log_common_1.LogVariable {
constructor(format) {

@@ -43,7 +43,7 @@ super();

DateLogVariable = __decorate([
(0, di_1.Injectable)(types_1.LogVariable),
(0, di_1.Injectable)(log_common_1.LogVariable),
__metadata("design:paramtypes", [String])
], DateLogVariable);
exports.DateLogVariable = DateLogVariable;
let TimeLogVariable = class TimeLogVariable extends types_1.LogVariable {
let TimeLogVariable = class TimeLogVariable extends log_common_1.LogVariable {
constructor(format) {

@@ -61,3 +61,3 @@ super();

TimeLogVariable = __decorate([
(0, di_1.Injectable)(types_1.LogVariable),
(0, di_1.Injectable)(log_common_1.LogVariable),
__metadata("design:paramtypes", [String])

@@ -64,0 +64,0 @@ ], TimeLogVariable);

@@ -1,2 +0,2 @@

import { LogVariable } from "../types";
import { LogVariable } from "@spinajs/log-common";
export declare class EnvVariable extends LogVariable {

@@ -3,0 +3,0 @@ get Name(): string;

@@ -11,4 +11,4 @@ "use strict";

const di_1 = require("@spinajs/di");
const types_1 = require("../types");
let EnvVariable = class EnvVariable extends types_1.LogVariable {
const log_common_1 = require("@spinajs/log-common");
let EnvVariable = class EnvVariable extends log_common_1.LogVariable {
get Name() {

@@ -19,9 +19,9 @@ return "env";

var _a;
return (_a = process.env[option]) !== null && _a !== void 0 ? _a : "";
return (_a = process.env[`${option}`]) !== null && _a !== void 0 ? _a : "";
}
};
EnvVariable = __decorate([
(0, di_1.Injectable)(types_1.LogVariable)
(0, di_1.Injectable)(log_common_1.LogVariable)
], EnvVariable);
exports.EnvVariable = EnvVariable;
//# sourceMappingURL=env.js.map

@@ -1,6 +0,5 @@

import { LogVariable } from "../types";
import { LogVariable } from "@spinajs/log-common";
export declare class ProcVariable extends LogVariable {
protected ALLOWED_PROPS: string[];
get Name(): string;
Value(option: string): string;
Value(option: "title" | "version" | "pid" | "platform"): string;
}

@@ -11,13 +11,4 @@ "use strict";

const di_1 = require("@spinajs/di");
const types_1 = require("../types");
let ProcVariable = class ProcVariable extends types_1.LogVariable {
constructor() {
super(...arguments);
this.ALLOWED_PROPS = [
"title",
"version",
"pid",
"platform",
];
}
const log_common_1 = require("@spinajs/log-common");
let ProcVariable = class ProcVariable extends log_common_1.LogVariable {
get Name() {

@@ -27,12 +18,9 @@ return "proc";

Value(option) {
if (this.ALLOWED_PROPS.indexOf(option) !== -1) {
return process[option];
}
return `[${option} is undefined]`;
return process[`${option}`];
}
};
ProcVariable = __decorate([
(0, di_1.Injectable)(types_1.LogVariable)
(0, di_1.Injectable)(log_common_1.LogVariable)
], ProcVariable);
exports.ProcVariable = ProcVariable;
//# sourceMappingURL=process.js.map
{
"name": "@spinajs/log",
"version": "1.1.9",
"version": "1.2.7",
"description": "Log lib for all spinejs related libs",

@@ -11,7 +11,8 @@ "main": "lib/index.js",

"build-docs": "rimraf docs && typedoc --options typedoc.json src/",
"build": "tsc",
"build-watch": "tsc -w",
"build": "npm run clean && npm run compile",
"compile": "tsc -p tsconfig.build.json",
"clean": "",
"prepare": "npm run build",
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
"lint": "tslint -p tsconfig.json",
"format": "prettier --write \"src/**/*.ts\"",
"lint": "eslint -c .eslintrc.js --ext .ts src",
"prepublishOnly": "npm test && npm run lint",

@@ -29,6 +30,7 @@ "preversion": "npm run lint",

"dependencies": {
"@spinajs/configuration": "^1.1.9",
"@spinajs/di": "^1.1.7",
"@spinajs/exceptions": "^1.0.5",
"@spinajs/validation": "^1.1.9",
"@spinajs/configuration": "^1.2.7",
"@spinajs/di": "^1.2.7",
"@spinajs/exceptions": "^1.2.7",
"@spinajs/log-common": "^1.2.7",
"ajv": "^8.8.2",
"colors": "^1.4.0",

@@ -42,32 +44,5 @@ "glob": "^7.2.0",

"devDependencies": {
"@types/bunyan": "^1.8.6",
"@types/chai": "^4.1.7",
"@types/chai-as-promised": "^7.1.0",
"@types/chai-subset": "^1.3.3",
"@types/colors": "^1.2.1",
"@types/glob": "^7.2.0",
"@types/glob-to-regexp": "^0.4.1",
"@types/lodash": "^4.14.136",
"@types/luxon": "^2.0.8",
"@types/mocha": "^5.2.7",
"@types/node": "^17.0.8",
"@types/node-schedule": "^1.3.2",
"@types/sinon": "^10.0.6",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-subset": "^1.6.0",
"mocha": "^6.1.4",
"nyc": "^14.1.1",
"prettier": "^1.18.2",
"sinon": "^12.0.1",
"ts-mocha": "^6.0.0",
"ts-node": "^8.3.0",
"tslint": "^5.20.1",
"tslint-circular-dependencies": "^0.1.0",
"tslint-config-prettier": "^1.18.0",
"tslint-config-standard": "^8.0.1",
"tslint-no-unused-expression-chai": "^0.1.4",
"typedoc": "^0.14.2",
"typescript": "^4.2.3"
}
"@types/color": "^3.0.3"
},
"gitHead": "389cf142b4ca63b7850b93fc858184ddcbb43ce1"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc